From caf573dab9913dc0f11be5acab0fb41ea5b583ee Mon Sep 17 00:00:00 2001 From: real Date: Sat, 1 Aug 2020 18:55:27 +0300 Subject: [PATCH 001/478] Initial sqlite3 database test --- Cargo.lock | 73 +++++++++++++++++++ components/database/Cargo.toml | 2 +- components/database/src/db_check.rs | 107 ++++++++++++++++++++++++++++ components/database/src/lib.rs | 1 + 4 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 components/database/src/db_check.rs diff --git a/Cargo.lock b/Cargo.lock index c7f323b43..9ca554f55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -503,6 +503,16 @@ name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fastrand" version = "1.3.2" @@ -752,6 +762,21 @@ name = "libc" version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libsqlite3-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "log" version = "0.4.8" @@ -760,6 +785,14 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "memchr" version = "2.3.3" @@ -988,6 +1021,7 @@ dependencies = [ "im 14.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "offset-common 0.1.0", + "rusqlite 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1378,6 +1412,11 @@ name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pkg-config" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "poly1305" version = "0.6.0" @@ -1618,6 +1657,21 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rusqlite" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libsqlite3-sys 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rust-argon2" version = "0.7.0" @@ -1751,6 +1805,11 @@ name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "smallvec" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "smol" version = "0.1.18" @@ -1971,6 +2030,11 @@ dependencies = [ "subtle 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vcpkg" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vec_map" version = "0.8.2" @@ -2188,6 +2252,8 @@ dependencies = [ "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +"checksum fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +"checksum fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" "checksum fastrand 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b90eb1dec02087df472ab9f0db65f27edaa654a746830042688bcc2eaf68090f" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" @@ -2217,7 +2283,10 @@ dependencies = [ "checksum kv-log-macro 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4ff57d6d215f7ca7eb35a9a64d656ba4d9d2bef114d741dc08048e75e2f5d418" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +"checksum libsqlite3-sys 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e704a02bcaecd4a08b93a23f6be59d0bd79cd161e0963e9499165a0a35df7bd" +"checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" "checksum num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" @@ -2234,6 +2303,7 @@ dependencies = [ "checksum pin-project-internal 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "10b4b44893d3c370407a1d6a5cfde7c41ae0478e31c516c85f67eb3adc51be6d" "checksum pin-project-lite 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715" "checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +"checksum pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" "checksum poly1305 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b42192ab143ed7619bf888a7f9c6733a9a2153b218e2cd557cfdb52fbf9bb1" "checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" "checksum pretty_env_logger 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8d1e63042e889b85228620629b51c011d380eed2c7e0015f8a644def280c28" @@ -2263,6 +2333,7 @@ dependencies = [ "checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +"checksum rusqlite 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)" = "45d0fd62e1df63d254714e6cb40d0a0e82e7a1623e7a27f679d851af092ae58b" "checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -2280,6 +2351,7 @@ dependencies = [ "checksum simple_logger 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fea0c4611f32f4c2bac73754f22dca1f57e6c1945e0590dae4e5f2a077b92367" "checksum sized-chunks 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d59044ea371ad781ff976f7b06480b9f0180e834eda94114f2afb4afc12b7718" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +"checksum smallvec 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f" "checksum smol 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "620cbb3c6e34da57d3a248cda0cd01cd5848164dc062e764e65d06fe3ea7aed5" "checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" "checksum stream-cipher 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09f8ed9974042b8c3672ff3030a69fcc03b74c47c3d1ecb7755e8a3626011e88" @@ -2305,6 +2377,7 @@ dependencies = [ "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum universal-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +"checksum vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" "checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" "checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/components/database/Cargo.toml b/components/database/Cargo.toml index 252ae8eab..9f87e1633 100644 --- a/components/database/Cargo.toml +++ b/components/database/Cargo.toml @@ -18,8 +18,8 @@ atomicwrites = "0.2.2" serde = {version = "1.0.104", features = ["derive"]} base64 = "0.9" -# bincode = "1.1.2" serde_json = "1.0.44" +rusqlite = {version = "0.23.1", features = ["bundled"]} [dev-dependencies] diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs new file mode 100644 index 000000000..144850861 --- /dev/null +++ b/components/database/src/db_check.rs @@ -0,0 +1,107 @@ +use rusqlite::{self, params, Connection}; + +#[allow(unused)] +fn create_database(conn: &Connection) -> rusqlite::Result<()> { + // A single row table. TODO: How to enforce a single row? + // See also: https://stackoverflow.com/questions/2300356/using-a-single-row-configuration-table-in-sql-server-database-bad-idea + conn.execute( + "CREATE TABLE funder( + local_public_key BLOB NOT NULL PRIMARY KEY + + + );", + params![], + )?; + + conn.execute( + "CREATE TABLE friends( + friend_public_key BLOB NOT NULL PRIMARY KEY + + + );", + params![], + )?; + + conn.execute( + "CREATE TABLE currencies( + public_key BLOB NOT NULL PRIMARY KEY + + + );", + params![], + )?; + + conn.execute( + "CREATE TABLE payments( + uid BLOB NOT NULL PRIMARY KEY + + + );", + params![], + )?; + + conn.execute( + "CREATE TABLE invoices ( + uid BLOB NOT NULL PRIMARY KEY + + + );", + params![], + )?; + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use rusqlite::{self, params}; + + #[derive(Debug)] + struct Person { + id: i32, + name: String, + data: Option>, + } + + fn inner_db_check() -> rusqlite::Result<()> { + let conn = Connection::open_in_memory()?; + + conn.execute( + "CREATE TABLE person ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + data BLOB + )", + params![], + )?; + let me = Person { + id: 0, + name: "Steven".to_string(), + data: None, + }; + conn.execute( + "INSERT INTO person (name, data) VALUES (?1, ?2)", + params![me.name, me.data], + )?; + + let mut stmt = conn.prepare("SELECT id, name, data FROM person")?; + let person_iter = stmt.query_map(params![], |row| { + Ok(Person { + id: row.get(0)?, + name: row.get(1)?, + data: row.get(2)?, + }) + })?; + + for person in person_iter { + println!("Found person {:?}", person.unwrap()); + } + Ok(()) + } + + #[test] + fn test_db_check() { + inner_db_check().unwrap(); + } +} diff --git a/components/database/src/lib.rs b/components/database/src/lib.rs index 66d5f1e46..3e4fb1fae 100644 --- a/components/database/src/lib.rs +++ b/components/database/src/lib.rs @@ -14,6 +14,7 @@ extern crate serde; mod atomic_db; mod database; +mod db_check; pub mod file_db; pub use self::atomic_db::AtomicDb; From 9cdadb961e1a3587b7fc34786052f551704c760b Mon Sep 17 00:00:00 2001 From: real Date: Tue, 4 Aug 2020 20:06:26 +0300 Subject: [PATCH 002/478] Some foreign keys checks --- components/database/src/db_check.rs | 144 ++++++++++++++++++++++++++-- 1 file changed, 136 insertions(+), 8 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index 144850861..a45a5c70b 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -7,43 +7,169 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { conn.execute( "CREATE TABLE funder( local_public_key BLOB NOT NULL PRIMARY KEY + );", + params![], + )?; + conn.execute( + "CREATE TABLE friends( + friend_public_key BLOB NOT NULL PRIMARY KEY, + sent_local_relays BLOB NOT NULL, + name TEXT NOT NULL + );", + params![], + )?; + // TODO: Fix primary key? + conn.execute( + "CREATE TABLE local_active_currencies( + friend_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + FOREIGN KEY(friend_public_key) + REFERENCES friends(friend_public_key) + ON DELETE CASCADE );", params![], )?; + // TODO: Fix primary key? conn.execute( - "CREATE TABLE friends( - friend_public_key BLOB NOT NULL PRIMARY KEY + "CREATE TABLE remote_active_currencies( + friend_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + FOREIGN KEY(friend_public_key) + REFERENCES friends(friend_public_key) + ON DELETE CASCADE + );", + params![], + )?; + // TODO: + conn.execute( + "CREATE TABLE active_currencies( + friend_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + FOREIGN KEY(friend_public_key, currency) + REFERENCES local_active_currencies(friend_public_key, currency) + ON DELETE CASCADE + FOREIGN KEY(friend_public_key, currency) + REFERENCES remote_active_currencies(friend_public_key, currency) + ON DELETE CASCADE + );", + params![], + )?; + // TODO: + conn.execute( + "CREATE TABLE local_pending_transactions( + friend_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + FOREIGN KEY(friend_public_key, currency) + REFERENCES active_currencies(friend_public_key, currency) + ON DELETE CASCADE );", params![], )?; + // TODO: conn.execute( - "CREATE TABLE currencies( - public_key BLOB NOT NULL PRIMARY KEY + "CREATE TABLE remote_pending_transactions( + friend_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + FOREIGN KEY(friend_public_key, currency) + REFERENCES active_currencies(friend_public_key, currency) + ON DELETE CASCADE + );", + params![], + )?; + conn.execute( + "CREATE TABLE currency_configs( + friend_public_key BLOB NOT NULL PRIMARY KEY, + currency TEXT NOT NULL, + rate BLOB NOT NULL, + remote_max_debt BLOB NOT NULL, + is_open BOOL NOT NULL, + is_enabled BOOL NOT NULL, + is_consistent BOOL NOT NULL, + is_token_channel_incoming BOOL + );", + params![], + )?; + // TODO: + conn.execute( + "CREATE TABLE pending_user_requests( + friend_public_key BLOB NOT NULL PRIMARY KEY );", params![], )?; + // TODO: conn.execute( - "CREATE TABLE payments( - uid BLOB NOT NULL PRIMARY KEY + "CREATE TABLE pending_requests( + friend_public_key BLOB NOT NULL, + currency BLOB NOT NULL PRIMARY KEY + );", + params![], + )?; + // TODO: + conn.execute( + "CREATE TABLE pending_responses( + friend_public_key BLOB NOT NULL PRIMARY KEY + );", + params![], + )?; + conn.execute( + "CREATE TABLE friend_relays( + friend_public_key BLOB NOT NULL, + relay_public_key BLOB NOT NULL, + address TEXT );", params![], )?; conn.execute( - "CREATE TABLE invoices ( - uid BLOB NOT NULL PRIMARY KEY + "CREATE TABLE relays( + relay_public_key BLOB NOT NULL PRIMARY KEY, + address TEXT, + name TEXT + );", + params![], + )?; + + conn.execute( + "CREATE TABLE index_servers( + index_public_key BLOB NOT NULL PRIMARY KEY, + address TEXT, + name TEXT + );", + params![], + )?; + + conn.execute( + "CREATE TABLE currencies( + friend_public_key BLOB NOT NULL PRIMARY KEY + + );", + params![], + )?; + + // TODO: + conn.execute( + "CREATE TABLE payments( + counter BLOB NOT NULL PRIMARY KEY + + );", + params![], + )?; + // TODO: + conn.execute( + "CREATE TABLE invoices ( + counter BLOB NOT NULL PRIMARY KEY );", params![], @@ -67,6 +193,8 @@ mod tests { fn inner_db_check() -> rusqlite::Result<()> { let conn = Connection::open_in_memory()?; + create_database(&conn).unwrap(); + conn.execute( "CREATE TABLE person ( id INTEGER PRIMARY KEY, From 66728d0bd90b41aa4391dfee484108e0704370d8 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 6 Aug 2020 20:36:10 +0300 Subject: [PATCH 003/478] db: Restrict instead of cascade --- components/database/src/db_check.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index a45a5c70b..24f6d8ba9 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -51,10 +51,10 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { currency TEXT NOT NULL, FOREIGN KEY(friend_public_key, currency) REFERENCES local_active_currencies(friend_public_key, currency) - ON DELETE CASCADE + ON DELETE RESTRICT FOREIGN KEY(friend_public_key, currency) REFERENCES remote_active_currencies(friend_public_key, currency) - ON DELETE CASCADE + ON DELETE RESTRICT );", params![], )?; From 30160e463d4b12512bbe7f4f2fd914e3b5606fb7 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 7 Aug 2020 13:06:47 +0300 Subject: [PATCH 004/478] db: Enforcing single row --- components/database/src/db_check.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index 24f6d8ba9..fa0525915 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -6,7 +6,8 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { // See also: https://stackoverflow.com/questions/2300356/using-a-single-row-configuration-table-in-sql-server-database-bad-idea conn.execute( "CREATE TABLE funder( - local_public_key BLOB NOT NULL PRIMARY KEY + id INTEGER PRIMARY KEY CHECK (id = 0), -- enforce single row + local_public_key BLOB NOT NULL );", params![], )?; From 7b197d1f02f6758ebd2edbe4fd36a2452a292df9 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 7 Aug 2020 14:13:50 +0300 Subject: [PATCH 005/478] db: Added external transaction + some work on tables --- components/database/src/db_check.rs | 125 ++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 34 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index fa0525915..b4283f002 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -1,10 +1,17 @@ use rusqlite::{self, params, Connection}; +const TC_CONSISTENT_IN: &str = &"C-IN"; +const TC_CONSISTENT_OUT: &str = &"C-OUT"; +const TC_INCONSISTENT: &str = &"I"; + #[allow(unused)] -fn create_database(conn: &Connection) -> rusqlite::Result<()> { - // A single row table. TODO: How to enforce a single row? - // See also: https://stackoverflow.com/questions/2300356/using-a-single-row-configuration-table-in-sql-server-database-bad-idea - conn.execute( +fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { + let tx = conn.transaction()?; + // TODO: A better way to do this? + tx.execute("PRAGMA foreign_keys = ON;", params![])?; + + // Single row is enforced in this table according to https://stackoverflow.com/a/33104119 + tx.execute( "CREATE TABLE funder( id INTEGER PRIMARY KEY CHECK (id = 0), -- enforce single row local_public_key BLOB NOT NULL @@ -12,41 +19,94 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { params![], )?; - conn.execute( + tx.execute( + "CREATE TABLE token_channel_statuses( + status TEXT PRIMARY KEY + );", + params![], + )?; + + // Initialize token_channel_status table: + for value in &[TC_CONSISTENT_IN, TC_CONSISTENT_OUT, TC_INCONSISTENT] { + tx.execute( + "INSERT INTO token_channel_statuses VALUES (?1);", + params![value], + )?; + } + + // TODO: Add index on primary key? + tx.execute( "CREATE TABLE friends( - friend_public_key BLOB NOT NULL PRIMARY KEY, - sent_local_relays BLOB NOT NULL, - name TEXT NOT NULL + friend_public_key BLOB NOT NULL PRIMARY KEY, + sent_local_relays BLOB NOT NULL, + -- Last local relays we have sent to the friend + remote_relays BLOB NOT NULL, + -- Friend's relays + name TEXT NOT NULL, + -- Friend's name + is_enabled BOOL NOT NULL, + -- Do we allow connectivity with this friend? + is_consistent BOOL NOT NULL, + -- Is the channel with this friend consistent? + token_channel_status TEXT NOT NULL, + -- Current status of the token channel + FOREIGN KEY(token_channel_status) + REFERENCES token_channel_statuses(status) + );", + params![], + )?; + + // TODO: Make sure that consistent and inconsistent channels tables are disjoint, but still + // refer to the friends table. Add constraints to make sure that when an item is removed from + // the consistent_channels table, active currencies will also be affected. + + tx.execute( + "CREATE TABLE consistent_channels( + friend_public_key BLOB NOT NULL PRIMARY KEY, + is_incoming BOOL NOT NULL, + FOREIGN KEY(friend_public_key) + REFERENCES friends(friend_public_key) + );", + params![], + )?; + + tx.execute( + "CREATE TABLE inconsistent_channels( + friend_public_key BLOB NOT NULL PRIMARY KEY, + is_incoming BOOL NOT NULL, + FOREIGN KEY(friend_public_key) + REFERENCES friends(friend_public_key) );", params![], )?; - // TODO: Fix primary key? - conn.execute( + // Should only exist if relevant token channel is alive + tx.execute( "CREATE TABLE local_active_currencies( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, FOREIGN KEY(friend_public_key) REFERENCES friends(friend_public_key) - ON DELETE CASCADE + ON DELETE CASCADE, + PRIMARY KEY(friend_public_key, currency) );", params![], )?; - // TODO: Fix primary key? - conn.execute( + tx.execute( "CREATE TABLE remote_active_currencies( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, FOREIGN KEY(friend_public_key) REFERENCES friends(friend_public_key) - ON DELETE CASCADE + ON DELETE CASCADE, + PRIMARY KEY(friend_public_key, currency) );", params![], )?; // TODO: - conn.execute( + tx.execute( "CREATE TABLE active_currencies( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, @@ -61,7 +121,7 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { )?; // TODO: - conn.execute( + tx.execute( "CREATE TABLE local_pending_transactions( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, @@ -73,7 +133,7 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { )?; // TODO: - conn.execute( + tx.execute( "CREATE TABLE remote_pending_transactions( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, @@ -84,22 +144,19 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { params![], )?; - conn.execute( + tx.execute( "CREATE TABLE currency_configs( friend_public_key BLOB NOT NULL PRIMARY KEY, currency TEXT NOT NULL, rate BLOB NOT NULL, remote_max_debt BLOB NOT NULL, - is_open BOOL NOT NULL, - is_enabled BOOL NOT NULL, - is_consistent BOOL NOT NULL, - is_token_channel_incoming BOOL + is_open BOOL NOT NULL );", params![], )?; // TODO: - conn.execute( + tx.execute( "CREATE TABLE pending_user_requests( friend_public_key BLOB NOT NULL PRIMARY KEY );", @@ -107,7 +164,7 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { )?; // TODO: - conn.execute( + tx.execute( "CREATE TABLE pending_requests( friend_public_key BLOB NOT NULL, currency BLOB NOT NULL PRIMARY KEY @@ -116,14 +173,14 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { )?; // TODO: - conn.execute( + tx.execute( "CREATE TABLE pending_responses( friend_public_key BLOB NOT NULL PRIMARY KEY );", params![], )?; - conn.execute( + tx.execute( "CREATE TABLE friend_relays( friend_public_key BLOB NOT NULL, relay_public_key BLOB NOT NULL, @@ -132,7 +189,7 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { params![], )?; - conn.execute( + tx.execute( "CREATE TABLE relays( relay_public_key BLOB NOT NULL PRIMARY KEY, address TEXT, @@ -141,7 +198,7 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { params![], )?; - conn.execute( + tx.execute( "CREATE TABLE index_servers( index_public_key BLOB NOT NULL PRIMARY KEY, address TEXT, @@ -150,7 +207,7 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { params![], )?; - conn.execute( + tx.execute( "CREATE TABLE currencies( friend_public_key BLOB NOT NULL PRIMARY KEY @@ -159,7 +216,7 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { )?; // TODO: - conn.execute( + tx.execute( "CREATE TABLE payments( counter BLOB NOT NULL PRIMARY KEY @@ -168,7 +225,7 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { )?; // TODO: - conn.execute( + tx.execute( "CREATE TABLE invoices ( counter BLOB NOT NULL PRIMARY KEY @@ -176,7 +233,7 @@ fn create_database(conn: &Connection) -> rusqlite::Result<()> { params![], )?; - Ok(()) + tx.commit() } #[cfg(test)] @@ -192,9 +249,9 @@ mod tests { } fn inner_db_check() -> rusqlite::Result<()> { - let conn = Connection::open_in_memory()?; + let mut conn = Connection::open_in_memory()?; - create_database(&conn).unwrap(); + create_database(&mut conn).unwrap(); conn.execute( "CREATE TABLE person ( From 4345097eb7635ade0f49e55af0069793efb745db Mon Sep 17 00:00:00 2001 From: real Date: Wed, 12 Aug 2020 12:53:16 +0300 Subject: [PATCH 006/478] db: Some work on tables. Not done yet --- components/database/src/db_check.rs | 133 ++++++++++++++++------------ 1 file changed, 75 insertions(+), 58 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index b4283f002..c9d014d33 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -1,15 +1,12 @@ use rusqlite::{self, params, Connection}; -const TC_CONSISTENT_IN: &str = &"C-IN"; -const TC_CONSISTENT_OUT: &str = &"C-OUT"; -const TC_INCONSISTENT: &str = &"I"; - #[allow(unused)] fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { let tx = conn.transaction()?; // TODO: A better way to do this? tx.execute("PRAGMA foreign_keys = ON;", params![])?; + /* // Single row is enforced in this table according to https://stackoverflow.com/a/33104119 tx.execute( "CREATE TABLE funder( @@ -18,21 +15,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { );", params![], )?; - - tx.execute( - "CREATE TABLE token_channel_statuses( - status TEXT PRIMARY KEY - );", - params![], - )?; - - // Initialize token_channel_status table: - for value in &[TC_CONSISTENT_IN, TC_CONSISTENT_OUT, TC_INCONSISTENT] { - tx.execute( - "INSERT INTO token_channel_statuses VALUES (?1);", - params![value], - )?; - } + */ // TODO: Add index on primary key? tx.execute( @@ -48,45 +31,44 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { -- Do we allow connectivity with this friend? is_consistent BOOL NOT NULL, -- Is the channel with this friend consistent? - token_channel_status TEXT NOT NULL, - -- Current status of the token channel - FOREIGN KEY(token_channel_status) - REFERENCES token_channel_statuses(status) + token_channel_status TEXT NOT NULL );", params![], )?; - // TODO: Make sure that consistent and inconsistent channels tables are disjoint, but still - // refer to the friends table. Add constraints to make sure that when an item is removed from - // the consistent_channels table, active currencies will also be affected. - tx.execute( "CREATE TABLE consistent_channels( friend_public_key BLOB NOT NULL PRIMARY KEY, + is_consistent BOOL NOT NULL CHECK (is_consistent = true), is_incoming BOOL NOT NULL, - FOREIGN KEY(friend_public_key) - REFERENCES friends(friend_public_key) + FOREIGN KEY(friend_public_key, is_consistent) + REFERENCES friends(friend_public_key, is_consistent) + ON DELETE CASCADE );", params![], )?; tx.execute( "CREATE TABLE inconsistent_channels( - friend_public_key BLOB NOT NULL PRIMARY KEY, - is_incoming BOOL NOT NULL, - FOREIGN KEY(friend_public_key) - REFERENCES friends(friend_public_key) + friend_public_key BLOB NOT NULL PRIMARY KEY, + is_consistent BOOL NOT NULL CHECK (is_consistent = false), + opt_last_incoming_move_token BLOB, + local_reset_terms BLOB NOT NULL, + opt_remote_reset_terms BLOB, + FOREIGN KEY(friend_public_key, is_consistent) + REFERENCES friends(friend_public_key, is_consistent) + ON DELETE CASCADE );", params![], )?; // Should only exist if relevant token channel is alive tx.execute( - "CREATE TABLE local_active_currencies( + "CREATE TABLE local_currencies( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, FOREIGN KEY(friend_public_key) - REFERENCES friends(friend_public_key) + REFERENCES consistent_channels(friend_public_key) ON DELETE CASCADE, PRIMARY KEY(friend_public_key, currency) );", @@ -94,56 +76,79 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE TABLE remote_active_currencies( + "CREATE TABLE remote_currencies( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, FOREIGN KEY(friend_public_key) - REFERENCES friends(friend_public_key) + REFERENCES consistent_channels(friend_public_key) ON DELETE CASCADE, PRIMARY KEY(friend_public_key, currency) );", params![], )?; - // TODO: tx.execute( - "CREATE TABLE active_currencies( + "CREATE TABLE mutual_credits( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, + balance BLOB NOT NULL, + local_pending_debt BLOB NOT NULL, + remote_pending_debt BLOB NOT NULL, + PRIMARY KEY(friend_public_key, currency) FOREIGN KEY(friend_public_key, currency) - REFERENCES local_active_currencies(friend_public_key, currency) - ON DELETE RESTRICT + REFERENCES local_currencies(friend_public_key, currency) + ON DELETE CASCADE FOREIGN KEY(friend_public_key, currency) - REFERENCES remote_active_currencies(friend_public_key, currency) - ON DELETE RESTRICT + REFERENCES remote_currencies(friend_public_key, currency) + ON DELETE CASCADE );", params![], )?; - // TODO: + dbg!("4"); + tx.execute( "CREATE TABLE local_pending_transactions( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, + request_id BLOB NOT NULL, + route BLOB NOT NULL, + dest_payment BLOB NOT NULL, + total_dest_payment BLOB NOT NULL, + invoice_id BLOB NOT NULL, + left_fees BLOB NOT NULL, + src_hashed_lock BLOB NOT NULL, + transaction_stage BLOB NOT NULL, FOREIGN KEY(friend_public_key, currency) - REFERENCES active_currencies(friend_public_key, currency) + REFERENCES mutual_credits(friend_public_key, currency) ON DELETE CASCADE );", params![], )?; - // TODO: + dbg!("5"); + tx.execute( "CREATE TABLE remote_pending_transactions( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, + request_id BLOB NOT NULL, + route BLOB NOT NULL, + dest_payment BLOB NOT NULL, + total_dest_payment BLOB NOT NULL, + invoice_id BLOB NOT NULL, + left_fees BLOB NOT NULL, + src_hashed_lock BLOB NOT NULL, + transaction_stage BLOB NOT NULL, FOREIGN KEY(friend_public_key, currency) - REFERENCES active_currencies(friend_public_key, currency) + REFERENCES mutual_credits(friend_public_key, currency) ON DELETE CASCADE );", params![], )?; + dbg!("6"); + tx.execute( "CREATE TABLE currency_configs( friend_public_key BLOB NOT NULL PRIMARY KEY, @@ -158,16 +163,32 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // TODO: tx.execute( "CREATE TABLE pending_user_requests( - friend_public_key BLOB NOT NULL PRIMARY KEY + friend_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + FOREIGN KEY(friend_public_key) + REFERENCES active_currencies(friend_public_key) + ON DELETE CASCADE );", params![], )?; + dbg!("8"); + // TODO: tx.execute( "CREATE TABLE pending_requests( friend_public_key BLOB NOT NULL, - currency BLOB NOT NULL PRIMARY KEY + currency TEXT NOT NULL, + request_id BLOB NOT NULL, + src_hashed_lock BLOB NOT NULL, + route BLOB NOT NULL, + dest_payment BLOB NOT NULL, + total_dest_payment BLOB NOT NULL, + invoice_id BLOB NOT NULL, + left_fees BLOB NOT NULL, + FOREIGN KEY(friend_public_key, currency) + REFERENCES mutual_credits(friend_public_key, currency) + ON DELETE CASCADE );", params![], )?; @@ -175,7 +196,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // TODO: tx.execute( "CREATE TABLE pending_responses( - friend_public_key BLOB NOT NULL PRIMARY KEY + friend_public_key BLOB NOT NULL PRIMARY KEY, + currency TEXT NOT NULL, + FOREIGN KEY(friend_public_key, currency) + REFERENCES mutual_credits(friend_public_key, currency) + ON DELETE CASCADE );", params![], )?; @@ -207,14 +232,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - tx.execute( - "CREATE TABLE currencies( - friend_public_key BLOB NOT NULL PRIMARY KEY - - );", - params![], - )?; - // TODO: tx.execute( "CREATE TABLE payments( From ba43a9f5948f141be150694ff48dcf3f819eb84a Mon Sep 17 00:00:00 2001 From: real Date: Wed, 12 Aug 2020 12:55:10 +0300 Subject: [PATCH 007/478] db: TODO message --- components/database/src/db_check.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index c9d014d33..e59dceb2e 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -205,6 +205,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // TODO: Set up primary key? tx.execute( "CREATE TABLE friend_relays( friend_public_key BLOB NOT NULL, From 9dfaa4e16f401cd009ed5865e7cfe331213a288c Mon Sep 17 00:00:00 2001 From: real Date: Fri, 14 Aug 2020 11:16:16 +0300 Subject: [PATCH 008/478] Removed dbg statements --- components/database/src/db_check.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index e59dceb2e..f0f23d9fc 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -105,8 +105,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - dbg!("4"); - tx.execute( "CREATE TABLE local_pending_transactions( friend_public_key BLOB NOT NULL, @@ -126,8 +124,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - dbg!("5"); - tx.execute( "CREATE TABLE remote_pending_transactions( friend_public_key BLOB NOT NULL, @@ -147,8 +143,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - dbg!("6"); - tx.execute( "CREATE TABLE currency_configs( friend_public_key BLOB NOT NULL PRIMARY KEY, @@ -172,8 +166,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - dbg!("8"); - // TODO: tx.execute( "CREATE TABLE pending_requests( From a2a9516b6d164b099d8d62b04136ae6fd69a600d Mon Sep 17 00:00:00 2001 From: real Date: Fri, 14 Aug 2020 11:20:53 +0300 Subject: [PATCH 009/478] db: Updated pending_requests and pending_user_requests tables --- components/database/src/db_check.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index f0f23d9fc..b289d1030 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -154,24 +154,29 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: tx.execute( "CREATE TABLE pending_user_requests( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, - FOREIGN KEY(friend_public_key) - REFERENCES active_currencies(friend_public_key) + request_id BLOB NOT NULL PRIMARY KEY, + src_hashed_lock BLOB NOT NULL, + route BLOB NOT NULL, + dest_payment BLOB NOT NULL, + total_dest_payment BLOB NOT NULL, + invoice_id BLOB NOT NULL, + left_fees BLOB NOT NULL, + FOREIGN KEY(friend_public_key, currency) + REFERENCES mutual_credits(friend_public_key, currency) ON DELETE CASCADE );", params![], )?; - // TODO: tx.execute( "CREATE TABLE pending_requests( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, - request_id BLOB NOT NULL, + request_id BLOB NOT NULL PRIMARY KEY, src_hashed_lock BLOB NOT NULL, route BLOB NOT NULL, dest_payment BLOB NOT NULL, From 0bb528ab9c3fc45c950606e3c4106f7a1b60ddb4 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 14 Aug 2020 11:54:12 +0300 Subject: [PATCH 010/478] db: Some work on tables --- components/database/src/db_check.rs | 41 +++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index b289d1030..0c35f195f 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -6,7 +6,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // TODO: A better way to do this? tx.execute("PRAGMA foreign_keys = ON;", params![])?; - /* // Single row is enforced in this table according to https://stackoverflow.com/a/33104119 tx.execute( "CREATE TABLE funder( @@ -15,7 +14,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { );", params![], )?; - */ // TODO: Add index on primary key? tx.execute( @@ -190,13 +188,46 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: tx.execute( - "CREATE TABLE pending_responses( - friend_public_key BLOB NOT NULL PRIMARY KEY, + "CREATE TABLE pending_backwards( + friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, + request_id BLOB NOT NULL PRIMARY KEY, + backwards_type TEXT CHECK (backwards_type IN ('R', 'C')) NOT NULL, + -- R: Response, C: Cancel FOREIGN KEY(friend_public_key, currency) REFERENCES mutual_credits(friend_public_key, currency) + ON DELETE CASCADE, + FOREIGN KEY(request_id) + REFERENCES pending_requests(request_id) + ON DELETE CASCADE + );", + params![], + )?; + + // TODO: Fill in according to new response design: + tx.execute( + "CREATE TABLE pending_backwards_responses( + friend_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + request_id BLOB NOT NULL PRIMARY KEY, + backwards_type TEXT NOT NULL CHECK (backwards_type = 'R'), + -- TODO + FOREIGN KEY(friend_public_key, currency, request_id, backwards_type) + REFERENCES pending_backwards(friend_public_key, currency, request_id, backwards_type) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE TABLE pending_backwards_cancels( + friend_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + request_id BLOB NOT NULL PRIMARY KEY, + backwards_type TEXT NOT NULL CHECK (backwards_type = 'C'), + FOREIGN KEY(friend_public_key, currency, request_id, backwards_type) + REFERENCES pending_backwards(friend_public_key, currency, request_id, backwards_type) ON DELETE CASCADE );", params![], From c4b2e5a1d4926585b9b26b823fb4b9bd82e4d6ab Mon Sep 17 00:00:00 2001 From: real Date: Fri, 14 Aug 2020 12:00:00 +0300 Subject: [PATCH 011/478] Set up primary key for friend_relays table --- components/database/src/db_check.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index 0c35f195f..744cb27fa 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -233,12 +233,15 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: Set up primary key? tx.execute( "CREATE TABLE friend_relays( friend_public_key BLOB NOT NULL, relay_public_key BLOB NOT NULL, - address TEXT + address TEXT, + PRIMARY KEY(friend_public_key, relay_public_key), + FOREIGN KEY(friend_public_key) + REFERENCES friends(friend_public_key) + ON DELETE CASCADE );", params![], )?; From 7690a8d7b116d9b958bbd5160b68b975563632c0 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 14 Aug 2020 12:00:10 +0300 Subject: [PATCH 012/478] TODO comments --- components/database/src/db_check.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index 744cb27fa..5be2bfbbb 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -103,6 +103,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // TODO: Update according to new request design: tx.execute( "CREATE TABLE local_pending_transactions( friend_public_key BLOB NOT NULL, @@ -122,6 +123,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // TODO: Update according to new request design: tx.execute( "CREATE TABLE remote_pending_transactions( friend_public_key BLOB NOT NULL, @@ -152,6 +154,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // TODO: Update according to new request design: tx.execute( "CREATE TABLE pending_user_requests( friend_public_key BLOB NOT NULL, @@ -170,6 +173,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // TODO: Update according to new request design: tx.execute( "CREATE TABLE pending_requests( friend_public_key BLOB NOT NULL, @@ -268,7 +272,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE payments( counter BLOB NOT NULL PRIMARY KEY - );", params![], )?; @@ -277,7 +280,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE invoices ( counter BLOB NOT NULL PRIMARY KEY - );", params![], )?; From 4e54124badf25f37957afe2b81e9d3983b21ba54 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 14 Aug 2020 16:48:13 +0300 Subject: [PATCH 013/478] db: Updated requests/responses tables --- components/database/src/db_check.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index 5be2bfbbb..574ada8c1 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -103,19 +103,18 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: Update according to new request design: tx.execute( "CREATE TABLE local_pending_transactions( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL, + src_hashed_lock BLOB NOT NULL, route BLOB NOT NULL, dest_payment BLOB NOT NULL, total_dest_payment BLOB NOT NULL, - invoice_id BLOB NOT NULL, + invoice_hash BLOB NOT NULL, + hmac BLOB NOT NULL, left_fees BLOB NOT NULL, - src_hashed_lock BLOB NOT NULL, - transaction_stage BLOB NOT NULL, FOREIGN KEY(friend_public_key, currency) REFERENCES mutual_credits(friend_public_key, currency) ON DELETE CASCADE @@ -123,19 +122,18 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: Update according to new request design: tx.execute( "CREATE TABLE remote_pending_transactions( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL, + src_hashed_lock BLOB NOT NULL, route BLOB NOT NULL, dest_payment BLOB NOT NULL, total_dest_payment BLOB NOT NULL, - invoice_id BLOB NOT NULL, + invoice_hash BLOB NOT NULL, + hmac BLOB NOT NULL, left_fees BLOB NOT NULL, - src_hashed_lock BLOB NOT NULL, - transaction_stage BLOB NOT NULL, FOREIGN KEY(friend_public_key, currency) REFERENCES mutual_credits(friend_public_key, currency) ON DELETE CASCADE @@ -154,7 +152,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: Update according to new request design: tx.execute( "CREATE TABLE pending_user_requests( friend_public_key BLOB NOT NULL, @@ -164,7 +161,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { route BLOB NOT NULL, dest_payment BLOB NOT NULL, total_dest_payment BLOB NOT NULL, - invoice_id BLOB NOT NULL, + invoice_hash BLOB NOT NULL, + hmac BLOB NOT NULL, left_fees BLOB NOT NULL, FOREIGN KEY(friend_public_key, currency) REFERENCES mutual_credits(friend_public_key, currency) @@ -173,7 +171,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: Update according to new request design: tx.execute( "CREATE TABLE pending_requests( friend_public_key BLOB NOT NULL, @@ -183,7 +180,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { route BLOB NOT NULL, dest_payment BLOB NOT NULL, total_dest_payment BLOB NOT NULL, - invoice_id BLOB NOT NULL, + invoice_hash BLOB NOT NULL, + hmac BLOB NOT NULL, left_fees BLOB NOT NULL, FOREIGN KEY(friend_public_key, currency) REFERENCES mutual_credits(friend_public_key, currency) @@ -209,14 +207,15 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: Fill in according to new response design: tx.execute( "CREATE TABLE pending_backwards_responses( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, backwards_type TEXT NOT NULL CHECK (backwards_type = 'R'), - -- TODO + src_hashed_lock BLOB NOT NULL, + serial_num BLOB NOT NULL, + signature BLOB NOT NULL, FOREIGN KEY(friend_public_key, currency, request_id, backwards_type) REFERENCES pending_backwards(friend_public_key, currency, request_id, backwards_type) ON DELETE CASCADE From 82ee69c68892f0f07a07dedfe0a1ec00393d1377 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 14 Aug 2020 17:33:22 +0300 Subject: [PATCH 014/478] db: Added table indices --- components/database/src/db_check.rs | 125 ++++++++++++++++++++++++---- 1 file changed, 111 insertions(+), 14 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index 574ada8c1..d341daabb 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -15,7 +15,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: Add index on primary key? tx.execute( "CREATE TABLE friends( friend_public_key BLOB NOT NULL PRIMARY KEY, @@ -23,17 +22,47 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { -- Last local relays we have sent to the friend remote_relays BLOB NOT NULL, -- Friend's relays - name TEXT NOT NULL, + name TEXT NOT NULL UNIQUE, -- Friend's name is_enabled BOOL NOT NULL, -- Do we allow connectivity with this friend? - is_consistent BOOL NOT NULL, + is_consistent BOOL NOT NULL -- Is the channel with this friend consistent? - token_channel_status TEXT NOT NULL );", params![], )?; + // friend public key index: + tx.execute( + "CREATE UNIQUE INDEX idx_friends_friend_public_key ON friends(friend_public_key);", + params![], + )?; + + // public name index: + tx.execute( + "CREATE UNIQUE INDEX idx_friends_name ON friends(name);", + params![], + )?; + + tx.execute( + "CREATE TABLE currency_configs( + friend_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + rate BLOB NOT NULL, + remote_max_debt BLOB NOT NULL, + is_open BOOL NOT NULL, + FOREIGN KEY(friend_public_key, currency) + REFERENCES friends(friend_public_key, currency) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_currency_configs ON currency_configs(friend_public_key, currency);", + params![], + )?; + tx.execute( "CREATE TABLE consistent_channels( friend_public_key BLOB NOT NULL PRIMARY KEY, @@ -46,6 +75,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // friend public key index: + tx.execute( + "CREATE UNIQUE INDEX idx_consistent_channels ON consistent_channels(friend_public_key);", + params![], + )?; + tx.execute( "CREATE TABLE inconsistent_channels( friend_public_key BLOB NOT NULL PRIMARY KEY, @@ -60,7 +95,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // Should only exist if relevant token channel is alive + // friend public key index: + tx.execute( + "CREATE UNIQUE INDEX idx_inconsistent_channels ON inconsistent_channels(friend_public_key);", + params![], + )?; + tx.execute( "CREATE TABLE local_currencies( friend_public_key BLOB NOT NULL, @@ -68,11 +108,19 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { FOREIGN KEY(friend_public_key) REFERENCES consistent_channels(friend_public_key) ON DELETE CASCADE, + FOREIGN KEY(friend_public_key, currency) + REFERENCES currency_configs(friend_public_key, currency) + ON DELETE CASCADE, PRIMARY KEY(friend_public_key, currency) );", params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_local_currencies ON local_currencies(friend_public_key, currency);", + params![], + )?; + tx.execute( "CREATE TABLE remote_currencies( friend_public_key BLOB NOT NULL, @@ -85,6 +133,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_remote_currencies ON remote_currencies(friend_public_key, currency);", + params![], + )?; + tx.execute( "CREATE TABLE mutual_credits( friend_public_key BLOB NOT NULL, @@ -103,11 +156,16 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_mutual_credits ON mutual_credits(friend_public_key, currency);", + params![], + )?; + tx.execute( "CREATE TABLE local_pending_transactions( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, - request_id BLOB NOT NULL, + request_id BLOB NOT NULL PRIMARY KEY, src_hashed_lock BLOB NOT NULL, route BLOB NOT NULL, dest_payment BLOB NOT NULL, @@ -122,11 +180,16 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_local_pending_transactions ON local_pending_transactions(request_id);", + params![], + )?; + tx.execute( "CREATE TABLE remote_pending_transactions( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, - request_id BLOB NOT NULL, + request_id BLOB NOT NULL PRIMARY KEY, src_hashed_lock BLOB NOT NULL, route BLOB NOT NULL, dest_payment BLOB NOT NULL, @@ -142,13 +205,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE TABLE currency_configs( - friend_public_key BLOB NOT NULL PRIMARY KEY, - currency TEXT NOT NULL, - rate BLOB NOT NULL, - remote_max_debt BLOB NOT NULL, - is_open BOOL NOT NULL - );", + "CREATE UNIQUE INDEX idx_remote_pending_transactions ON remote_pending_transactions(request_id);", params![], )?; @@ -171,6 +228,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_pending_user_requests ON pending_user_requests(request_id);", + params![], + )?; + tx.execute( "CREATE TABLE pending_requests( friend_public_key BLOB NOT NULL, @@ -190,6 +252,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_pending_requests ON pending_requests(request_id);", + params![], + )?; + tx.execute( "CREATE TABLE pending_backwards( friend_public_key BLOB NOT NULL, @@ -207,6 +274,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_pending_backwards ON pending_backwards(request_id);", + params![], + )?; + tx.execute( "CREATE TABLE pending_backwards_responses( friend_public_key BLOB NOT NULL, @@ -223,6 +295,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_pending_backwards_responses ON pending_backwards_responses(request_id);", + params![], + )?; + tx.execute( "CREATE TABLE pending_backwards_cancels( friend_public_key BLOB NOT NULL, @@ -236,6 +313,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_pending_backwards_cancels ON pending_backwards_cancels(request_id);", + params![], + )?; + tx.execute( "CREATE TABLE friend_relays( friend_public_key BLOB NOT NULL, @@ -249,6 +331,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_friend_relays ON friend_relays(friend_public_key, relay_public_key);", + params![], + )?; + tx.execute( "CREATE TABLE relays( relay_public_key BLOB NOT NULL PRIMARY KEY, @@ -258,6 +345,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_relays ON relays(relay_public_key);", + params![], + )?; + tx.execute( "CREATE TABLE index_servers( index_public_key BLOB NOT NULL PRIMARY KEY, @@ -267,6 +359,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_index_servers ON index_servers(index_public_key);", + params![], + )?; + // TODO: tx.execute( "CREATE TABLE payments( From bdbc717a8e54eced766c83e49afb015580950056 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 14 Aug 2020 17:49:15 +0300 Subject: [PATCH 015/478] db: Some thoughts about invoices and payments tables --- components/database/src/db_check.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index d341daabb..110abc7cd 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -365,17 +365,31 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; // TODO: + // - Reconsider primary key + // - Add a new table for pending requests? + // - Add indices tx.execute( "CREATE TABLE payments( - counter BLOB NOT NULL PRIMARY KEY + counter BLOB NOT NULL PRIMARY KEY, + payment_id BLOB NOT NULL, + amount BLOB NOT NULL );", params![], )?; // TODO: + // - Reconsider primary key + // - Add fields for total amount paid? + // - Add indices tx.execute( "CREATE TABLE invoices ( - counter BLOB NOT NULL PRIMARY KEY + counter BLOB NOT NULL PRIMARY KEY, + invoice_id BLOB NOT NULL, + currency TEXT NOT NULL, + amount BLOB NOT NULL, + -- TODO: Possibly pick a different name to 'summary' + summary TEXT NOT NULL, + status BLOB NOT NULL );", params![], )?; From edfdc98b206d58989ffcd6959926a444ad360f28 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 15 Aug 2020 12:35:02 +0300 Subject: [PATCH 016/478] db: Updated field name --- components/database/src/db_check.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index 110abc7cd..feee93152 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -387,8 +387,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { invoice_id BLOB NOT NULL, currency TEXT NOT NULL, amount BLOB NOT NULL, - -- TODO: Possibly pick a different name to 'summary' - summary TEXT NOT NULL, + desription TEXT NOT NULL, status BLOB NOT NULL );", params![], From 352a2bc8116957ba51919f837894eb7a2a054124 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 15 Aug 2020 13:08:35 +0300 Subject: [PATCH 017/478] db: Some tables updates --- components/database/src/db_check.rs | 53 ++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index feee93152..de6791f05 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -66,7 +66,9 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE consistent_channels( friend_public_key BLOB NOT NULL PRIMARY KEY, - is_consistent BOOL NOT NULL CHECK (is_consistent = true), + is_consistent BOOL NOT NULL + CHECK (is_consistent = true) + DEFAULT true, is_incoming BOOL NOT NULL, FOREIGN KEY(friend_public_key, is_consistent) REFERENCES friends(friend_public_key, is_consistent) @@ -84,7 +86,9 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE inconsistent_channels( friend_public_key BLOB NOT NULL PRIMARY KEY, - is_consistent BOOL NOT NULL CHECK (is_consistent = false), + is_consistent BOOL NOT NULL + CHECK (is_consistent = false) + DEFAULT false, opt_last_incoming_move_token BLOB, local_reset_terms BLOB NOT NULL, opt_remote_reset_terms BLOB, @@ -284,7 +288,9 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, - backwards_type TEXT NOT NULL CHECK (backwards_type = 'R'), + backwards_type TEXT NOT NULL + CHECK (backwards_type = 'R') + DEFAULT 'R', src_hashed_lock BLOB NOT NULL, serial_num BLOB NOT NULL, signature BLOB NOT NULL, @@ -305,7 +311,9 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, - backwards_type TEXT NOT NULL CHECK (backwards_type = 'C'), + backwards_type TEXT NOT NULL + CHECK (backwards_type = 'C') + DEFAULT 'C', FOREIGN KEY(friend_public_key, currency, request_id, backwards_type) REFERENCES pending_backwards(friend_public_key, currency, request_id, backwards_type) ON DELETE CASCADE @@ -364,31 +372,50 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // Chronological items table, allows total order on all items payments and invoices + tx.execute( + "CREATE TABLE chrono( + counter BLOB NOT NULL PRIMARY KEY, + chrono_type TEXT CHECK (chrono_type IN ('P', 'I')) NOT NULL + );", + params![], + )?; + // TODO: - // - Reconsider primary key // - Add a new table for pending requests? // - Add indices tx.execute( "CREATE TABLE payments( - counter BLOB NOT NULL PRIMARY KEY, - payment_id BLOB NOT NULL, - amount BLOB NOT NULL + counter BLOB NOT NULL, + chrono_type TEXT CHECK (chrono_type = 'P') + DEFAULT 'P' + NOT NULL, + payment_id BLOB NOT NULL PRIMARY KEY, + amount BLOB NOT NULL, + FOREIGN KEY(counter, chrono_type) + REFERENCES chrono(counter, chrono_type) + ON DELETE CASCADE );", params![], )?; // TODO: - // - Reconsider primary key // - Add fields for total amount paid? // - Add indices tx.execute( "CREATE TABLE invoices ( - counter BLOB NOT NULL PRIMARY KEY, - invoice_id BLOB NOT NULL, + counter BLOB NOT NULL, + chrono_type TEXT CHECK (chrono_type = 'I') + DEFAULT 'I' + NOT NULL, + invoice_id BLOB NOT NULL PRIMARY KEY, currency TEXT NOT NULL, amount BLOB NOT NULL, - desription TEXT NOT NULL, - status BLOB NOT NULL + description TEXT NOT NULL, + status BLOB NOT NULL, + FOREIGN KEY(counter, chrono_type) + REFERENCES chrono(counter, chrono_type) + ON DELETE CASCADE );", params![], )?; From 6a177dc721026d79adf3c339158dea2374e26ec8 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 15 Aug 2020 13:38:16 +0300 Subject: [PATCH 018/478] db: Added documents table --- components/database/src/db_check.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index de6791f05..79a7fb051 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -372,11 +372,13 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // Chronological items table, allows total order on all items payments and invoices + // Documents table, allowing total order on all items payments and invoices tx.execute( - "CREATE TABLE chrono( - counter BLOB NOT NULL PRIMARY KEY, - chrono_type TEXT CHECK (chrono_type IN ('P', 'I')) NOT NULL + "CREATE TABLE documents( + counter BLOB NOT NULL PRIMARY KEY, + time INTEGER NOT NULL, + doc_type TEXT CHECK (doc_type IN ('P', 'I')) NOT NULL + -- Document type: P: Payment, I: Invoice );", params![], )?; @@ -387,13 +389,13 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE payments( counter BLOB NOT NULL, - chrono_type TEXT CHECK (chrono_type = 'P') + doc_type TEXT CHECK (doc_type = 'P') DEFAULT 'P' NOT NULL, payment_id BLOB NOT NULL PRIMARY KEY, amount BLOB NOT NULL, - FOREIGN KEY(counter, chrono_type) - REFERENCES chrono(counter, chrono_type) + FOREIGN KEY(counter, doc_type) + REFERENCES documents(counter, doc_type) ON DELETE CASCADE );", params![], @@ -405,7 +407,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE invoices ( counter BLOB NOT NULL, - chrono_type TEXT CHECK (chrono_type = 'I') + doc_type TEXT CHECK (doc_type = 'I') DEFAULT 'I' NOT NULL, invoice_id BLOB NOT NULL PRIMARY KEY, @@ -413,8 +415,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { amount BLOB NOT NULL, description TEXT NOT NULL, status BLOB NOT NULL, - FOREIGN KEY(counter, chrono_type) - REFERENCES chrono(counter, chrono_type) + FOREIGN KEY(counter, doc_type) + REFERENCES documents(counter, doc_type) ON DELETE CASCADE );", params![], From 19b71fd1034cdd971efe5f1ecc305b9ba19d02a3 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 15 Aug 2020 13:43:15 +0300 Subject: [PATCH 019/478] db: documents: some ideas, not done yet --- components/database/src/db_check.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/components/database/src/db_check.rs b/components/database/src/db_check.rs index 79a7fb051..64f7e4b3a 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/db_check.rs @@ -386,14 +386,17 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // TODO: // - Add a new table for pending requests? // - Add indices + // More work needed here: tx.execute( "CREATE TABLE payments( - counter BLOB NOT NULL, - doc_type TEXT CHECK (doc_type = 'P') - DEFAULT 'P' - NOT NULL, - payment_id BLOB NOT NULL PRIMARY KEY, - amount BLOB NOT NULL, + counter BLOB NOT NULL, + doc_type TEXT CHECK (doc_type = 'P') + DEFAULT 'P' + NOT NULL, + payment_id BLOB NOT NULL PRIMARY KEY, + currency TEXT NOT NULL, + total_dest_payment BLOB NOT NULL, + amount BLOB NOT NULL, FOREIGN KEY(counter, doc_type) REFERENCES documents(counter, doc_type) ON DELETE CASCADE @@ -404,6 +407,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // TODO: // - Add fields for total amount paid? // - Add indices + // More work needed here: tx.execute( "CREATE TABLE invoices ( counter BLOB NOT NULL, From 959667c1ea47dbd98e291d814efa5bf852a9a64e Mon Sep 17 00:00:00 2001 From: real Date: Sat, 15 Aug 2020 16:55:38 +0300 Subject: [PATCH 020/478] db: Moved database creation code into create module --- .../database/src/{db_check.rs => create.rs} | 53 ++----------------- components/database/src/lib.rs | 3 +- 2 files changed, 6 insertions(+), 50 deletions(-) rename components/database/src/{db_check.rs => create.rs} (92%) diff --git a/components/database/src/db_check.rs b/components/database/src/create.rs similarity index 92% rename from components/database/src/db_check.rs rename to components/database/src/create.rs index 64f7e4b3a..6361b5537 100644 --- a/components/database/src/db_check.rs +++ b/components/database/src/create.rs @@ -1,6 +1,6 @@ use rusqlite::{self, params, Connection}; -#[allow(unused)] +/// Create a new Offset database fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { let tx = conn.transaction()?; // TODO: A better way to do this? @@ -432,55 +432,10 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { #[cfg(test)] mod tests { use super::*; - use rusqlite::{self, params}; - - #[derive(Debug)] - struct Person { - id: i32, - name: String, - data: Option>, - } - - fn inner_db_check() -> rusqlite::Result<()> { - let mut conn = Connection::open_in_memory()?; - - create_database(&mut conn).unwrap(); - - conn.execute( - "CREATE TABLE person ( - id INTEGER PRIMARY KEY, - name TEXT NOT NULL, - data BLOB - )", - params![], - )?; - let me = Person { - id: 0, - name: "Steven".to_string(), - data: None, - }; - conn.execute( - "INSERT INTO person (name, data) VALUES (?1, ?2)", - params![me.name, me.data], - )?; - - let mut stmt = conn.prepare("SELECT id, name, data FROM person")?; - let person_iter = stmt.query_map(params![], |row| { - Ok(Person { - id: row.get(0)?, - name: row.get(1)?, - data: row.get(2)?, - }) - })?; - - for person in person_iter { - println!("Found person {:?}", person.unwrap()); - } - Ok(()) - } #[test] - fn test_db_check() { - inner_db_check().unwrap(); + fn test_create_db() { + let mut conn = Connection::open_in_memory().unwrap(); + create_database(&mut conn).unwrap(); } } diff --git a/components/database/src/lib.rs b/components/database/src/lib.rs index 3e4fb1fae..3c953ddbc 100644 --- a/components/database/src/lib.rs +++ b/components/database/src/lib.rs @@ -13,8 +13,9 @@ extern crate serde; mod atomic_db; +#[allow(unused)] +mod create; mod database; -mod db_check; pub mod file_db; pub use self::atomic_db::AtomicDb; From 313577b6640dabddf1ff8d5c7a5defcf42ab65d2 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 15 Sep 2020 13:30:10 +0300 Subject: [PATCH 021/478] database: Added applications table --- components/database/src/create.rs | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 6361b5537..3d222aabe 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -6,6 +6,43 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // TODO: A better way to do this? tx.execute("PRAGMA foreign_keys = ON;", params![])?; + // This table serves as an "archive" table, containing active and non active applications. + // Some applications can not be removed from the database, because they might be still used in + // the documents table (As part of an invoice or payment document) + tx.execute( + "CREATE TABLE applications ( + app_public_key BLOB NOT NULL PRIMARY KEY, + name TEXT NOT NULL UNIQUE + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_applications ON applications(app_public_key, name);", + params![], + )?; + + tx.execute( + "CREATE TABLE active_applications ( + app_public_key BLOB NOT NULL PRIMARY KEY, + last_online INTEGER NOT NULL, + is_enabled BOOL NOT NULL, + + perm_info_docs BOOL NOT NULL, + perm_info_friends BOOL NOT NULL, + perm_routes BOOL NOT NULL, + perm_buy BOOL NOT NULL, + perm_sell BOOL NOT NULL, + perm_config_card BOOL NOT NULL, + perm_config_access BOOL NOT NULL, + + FOREIGN KEY(app_public_key) + REFERENCES applications(app_public_key) + ON DELETE CASCADE + );", + params![], + )?; + // Single row is enforced in this table according to https://stackoverflow.com/a/33104119 tx.execute( "CREATE TABLE funder( From cc7b7dffd94ef32aaec7d5c244fd1152476747f4 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 15 Sep 2020 13:53:45 +0300 Subject: [PATCH 022/478] database: Added balances documentation for every document --- components/database/src/create.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 3d222aabe..cd6f2577e 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -420,6 +420,28 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // Balances table, showing the exact balance for every document. + // The numbers shown represent the numbers right after the document occured. + tx.execute( + "CREATE TABLE documents_balances( + counter BLOB NOT NULL, + currency TEXT NOT NULL, + amount BLOB NOT NULL, + in_fees BLOB NOT NULL, + out_fees BLOB NOT NULL, + + PRIMARY KEY(counter, currency) + FOREIGN KEY(counter) + REFERENCES documents(counter) + ON DELETE CASCADE + );", + params![], + )?; + + // TODO: Add friend removal document? + // This is important for accounting purposes, + // because friend removal might suddenly change balances. + // TODO: // - Add a new table for pending requests? // - Add indices From c83bdf397c59b75014315508473ed23d15f2001a Mon Sep 17 00:00:00 2001 From: real Date: Tue, 15 Sep 2020 13:58:33 +0300 Subject: [PATCH 023/478] database: Added in_fees and out_fees fields to mutual_credits table --- components/database/src/create.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index cd6f2577e..0f91c042d 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -186,6 +186,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { balance BLOB NOT NULL, local_pending_debt BLOB NOT NULL, remote_pending_debt BLOB NOT NULL, + in_fees BLOB NOT NULL, + out_fees BLOB NOT NULL, PRIMARY KEY(friend_public_key, currency) FOREIGN KEY(friend_public_key, currency) REFERENCES local_currencies(friend_public_key, currency) From f4909d39de9f799c22b5eca98815f96257acbc72 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 15 Sep 2020 15:11:49 +0300 Subject: [PATCH 024/478] database: Added friend removal documents --- components/database/src/create.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 0f91c042d..3cc5ddaac 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -416,8 +416,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE documents( counter BLOB NOT NULL PRIMARY KEY, time INTEGER NOT NULL, - doc_type TEXT CHECK (doc_type IN ('P', 'I')) NOT NULL - -- Document type: P: Payment, I: Invoice + doc_type TEXT CHECK (doc_type IN ('P', 'I', 'R')) NOT NULL + -- Document type: P: Payment, I: Invoice, R: Friend removal );", params![], )?; @@ -440,10 +440,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: Add friend removal document? - // This is important for accounting purposes, - // because friend removal might suddenly change balances. - // TODO: // - Add a new table for pending requests? // - Add indices @@ -487,6 +483,19 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE TABLE friend_removals ( + counter BLOB NOT NULL, + doc_type TEXT CHECK (doc_type = 'R') + DEFAULT 'R' + NOT NULL, + FOREIGN KEY(counter, doc_type) + REFERENCES documents(counter, doc_type) + ON DELETE CASCADE + );", + params![], + )?; + tx.commit() } From d0ca5d0d45d4a27296b1bf623d0e57d63f583b48 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 15 Sep 2020 16:53:04 +0300 Subject: [PATCH 025/478] database: Added currencies table --- components/database/src/create.rs | 32 +++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 3cc5ddaac..818b1b6ee 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -22,6 +22,13 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE TABLE currencies ( + currency TEXT NOT NULL PRIMARY KEY + );", + params![], + )?; + tx.execute( "CREATE TABLE active_applications ( app_public_key BLOB NOT NULL PRIMARY KEY, @@ -88,9 +95,13 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { rate BLOB NOT NULL, remote_max_debt BLOB NOT NULL, is_open BOOL NOT NULL, - FOREIGN KEY(friend_public_key, currency) - REFERENCES friends(friend_public_key, currency) - ON DELETE CASCADE + PRIMARY KEY(friend_public_key, currency), + FOREIGN KEY(friend_public_key) + REFERENCES friends(friend_public_key) + ON DELETE CASCADE, + FOREIGN KEY(currency) + REFERENCES currencies(currency) + ON DELETE RESTRICT );", params![], )?; @@ -435,7 +446,10 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { PRIMARY KEY(counter, currency) FOREIGN KEY(counter) REFERENCES documents(counter) - ON DELETE CASCADE + ON DELETE CASCADE, + FOREIGN KEY(currency) + REFERENCES currencies(currency) + ON DELETE RESTRICT );", params![], )?; @@ -456,7 +470,10 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { amount BLOB NOT NULL, FOREIGN KEY(counter, doc_type) REFERENCES documents(counter, doc_type) - ON DELETE CASCADE + ON DELETE CASCADE, + FOREIGN KEY(currency) + REFERENCES currencies(currency) + ON DELETE RESTRICT );", params![], )?; @@ -478,7 +495,10 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { status BLOB NOT NULL, FOREIGN KEY(counter, doc_type) REFERENCES documents(counter, doc_type) - ON DELETE CASCADE + ON DELETE CASCADE, + FOREIGN KEY(currency) + REFERENCES currencies(currency) + ON DELETE RESTRICT );", params![], )?; From 0c46c47b09eb1a460683975e1114fb7efa7021a1 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 15 Sep 2020 17:12:20 +0300 Subject: [PATCH 026/478] Rename document -> event --- components/database/src/create.rs | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 818b1b6ee..39461f8ef 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -8,7 +8,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // This table serves as an "archive" table, containing active and non active applications. // Some applications can not be removed from the database, because they might be still used in - // the documents table (As part of an invoice or payment document) + // the events table (As part of an invoice or payment event) tx.execute( "CREATE TABLE applications ( app_public_key BLOB NOT NULL PRIMARY KEY, @@ -424,19 +424,19 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // Documents table, allowing total order on all items payments and invoices tx.execute( - "CREATE TABLE documents( + "CREATE TABLE events( counter BLOB NOT NULL PRIMARY KEY, time INTEGER NOT NULL, - doc_type TEXT CHECK (doc_type IN ('P', 'I', 'R')) NOT NULL - -- Document type: P: Payment, I: Invoice, R: Friend removal + event_type TEXT CHECK (event_type IN ('P', 'I', 'R')) NOT NULL + -- Event type: P: Payment, I: Invoice, R: Friend removal );", params![], )?; - // Balances table, showing the exact balance for every document. - // The numbers shown represent the numbers right after the document occured. + // Balances table, showing the exact balance for every event. + // The numbers shown represent the numbers right after the event occured. tx.execute( - "CREATE TABLE documents_balances( + "CREATE TABLE event_balances( counter BLOB NOT NULL, currency TEXT NOT NULL, amount BLOB NOT NULL, @@ -445,7 +445,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { PRIMARY KEY(counter, currency) FOREIGN KEY(counter) - REFERENCES documents(counter) + REFERENCES events(counter) ON DELETE CASCADE, FOREIGN KEY(currency) REFERENCES currencies(currency) @@ -461,15 +461,15 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE payments( counter BLOB NOT NULL, - doc_type TEXT CHECK (doc_type = 'P') + event_type TEXT CHECK (event_type = 'P') DEFAULT 'P' NOT NULL, payment_id BLOB NOT NULL PRIMARY KEY, currency TEXT NOT NULL, total_dest_payment BLOB NOT NULL, amount BLOB NOT NULL, - FOREIGN KEY(counter, doc_type) - REFERENCES documents(counter, doc_type) + FOREIGN KEY(counter, event_type) + REFERENCES events(counter, event_type) ON DELETE CASCADE, FOREIGN KEY(currency) REFERENCES currencies(currency) @@ -485,7 +485,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE invoices ( counter BLOB NOT NULL, - doc_type TEXT CHECK (doc_type = 'I') + event_type TEXT CHECK (event_type = 'I') DEFAULT 'I' NOT NULL, invoice_id BLOB NOT NULL PRIMARY KEY, @@ -493,8 +493,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { amount BLOB NOT NULL, description TEXT NOT NULL, status BLOB NOT NULL, - FOREIGN KEY(counter, doc_type) - REFERENCES documents(counter, doc_type) + FOREIGN KEY(counter, event_type) + REFERENCES events(counter, event_type) ON DELETE CASCADE, FOREIGN KEY(currency) REFERENCES currencies(currency) @@ -506,11 +506,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE friend_removals ( counter BLOB NOT NULL, - doc_type TEXT CHECK (doc_type = 'R') + event_type TEXT CHECK (event_type = 'R') DEFAULT 'R' NOT NULL, - FOREIGN KEY(counter, doc_type) - REFERENCES documents(counter, doc_type) + FOREIGN KEY(counter, event_type) + REFERENCES events(counter, event_type) ON DELETE CASCADE );", params![], From d38a0290ed72fcb5cb44c0383ab9f49c63cab730 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 18 Sep 2020 17:54:26 +0300 Subject: [PATCH 027/478] Removed currencies table --- components/database/src/create.rs | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 39461f8ef..91a91d336 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -22,13 +22,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - tx.execute( - "CREATE TABLE currencies ( - currency TEXT NOT NULL PRIMARY KEY - );", - params![], - )?; - tx.execute( "CREATE TABLE active_applications ( app_public_key BLOB NOT NULL PRIMARY KEY, @@ -98,10 +91,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { PRIMARY KEY(friend_public_key, currency), FOREIGN KEY(friend_public_key) REFERENCES friends(friend_public_key) - ON DELETE CASCADE, - FOREIGN KEY(currency) - REFERENCES currencies(currency) - ON DELETE RESTRICT + ON DELETE CASCADE );", params![], )?; @@ -173,6 +163,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // TODO: Where does the currency field here comes from? tx.execute( "CREATE TABLE remote_currencies( friend_public_key BLOB NOT NULL, @@ -446,10 +437,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { PRIMARY KEY(counter, currency) FOREIGN KEY(counter) REFERENCES events(counter) - ON DELETE CASCADE, - FOREIGN KEY(currency) - REFERENCES currencies(currency) - ON DELETE RESTRICT + ON DELETE CASCADE );", params![], )?; @@ -470,10 +458,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { amount BLOB NOT NULL, FOREIGN KEY(counter, event_type) REFERENCES events(counter, event_type) - ON DELETE CASCADE, - FOREIGN KEY(currency) - REFERENCES currencies(currency) - ON DELETE RESTRICT + ON DELETE CASCADE );", params![], )?; @@ -495,10 +480,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { status BLOB NOT NULL, FOREIGN KEY(counter, event_type) REFERENCES events(counter, event_type) - ON DELETE CASCADE, - FOREIGN KEY(currency) - REFERENCES currencies(currency) - ON DELETE RESTRICT + ON DELETE CASCADE );", params![], )?; From 485679f90a625a7b32d5de2763c3d9089b8d28b6 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 18 Sep 2020 17:57:07 +0300 Subject: [PATCH 028/478] Added database version --- components/database/src/create.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 91a91d336..ed833f2ee 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -47,6 +47,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE funder( id INTEGER PRIMARY KEY CHECK (id = 0), -- enforce single row + version INTEGER NOT NULL, -- Database version local_public_key BLOB NOT NULL );", params![], From 8edc4677211d2005959256a8fd7a43a676a20fb0 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 18 Sep 2020 18:27:18 +0300 Subject: [PATCH 029/478] Formatting --- components/database/src/create.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index ed833f2ee..6fdeea955 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -420,7 +420,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { counter BLOB NOT NULL PRIMARY KEY, time INTEGER NOT NULL, event_type TEXT CHECK (event_type IN ('P', 'I', 'R')) NOT NULL - -- Event type: P: Payment, I: Invoice, R: Friend removal + -- Event type: P: Payment, I: Invoice, R: Friend Removal );", params![], )?; @@ -450,7 +450,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE payments( counter BLOB NOT NULL, - event_type TEXT CHECK (event_type = 'P') + event_type TEXT CHECK (event_type = 'P') DEFAULT 'P' NOT NULL, payment_id BLOB NOT NULL PRIMARY KEY, @@ -471,7 +471,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE invoices ( counter BLOB NOT NULL, - event_type TEXT CHECK (event_type = 'I') + event_type TEXT CHECK (event_type = 'I') DEFAULT 'I' NOT NULL, invoice_id BLOB NOT NULL PRIMARY KEY, From 6bbe091eea24bac3cadee6e68a7e81b3b2657f4c Mon Sep 17 00:00:00 2001 From: real Date: Sat, 19 Sep 2020 10:55:00 +0300 Subject: [PATCH 030/478] database: Changed column name --- components/database/src/create.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 6fdeea955..ddf176c10 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -456,7 +456,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { payment_id BLOB NOT NULL PRIMARY KEY, currency TEXT NOT NULL, total_dest_payment BLOB NOT NULL, - amount BLOB NOT NULL, + dest_payment BLOB NOT NULL, FOREIGN KEY(counter, event_type) REFERENCES events(counter, event_type) ON DELETE CASCADE From a080bc4700a4929d52554fe0ff816589e352e22b Mon Sep 17 00:00:00 2001 From: real Date: Sat, 19 Sep 2020 13:01:29 +0300 Subject: [PATCH 031/478] database: Added generation to some tables, introducing order --- components/database/src/create.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index ddf176c10..b887b6cb2 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -260,6 +260,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, + generation BLOB NOT NULL UNIQUE, src_hashed_lock BLOB NOT NULL, route BLOB NOT NULL, dest_payment BLOB NOT NULL, @@ -275,7 +276,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_pending_user_requests ON pending_user_requests(request_id);", + "CREATE UNIQUE INDEX idx_pending_user_requests_request_id ON pending_user_requests(request_id);", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_pending_user_requests_generation ON pending_user_requests(generation);", params![], )?; @@ -284,6 +290,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, + generation BLOB NOT NULL UNIQUE, src_hashed_lock BLOB NOT NULL, route BLOB NOT NULL, dest_payment BLOB NOT NULL, @@ -299,7 +306,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_pending_requests ON pending_requests(request_id);", + "CREATE UNIQUE INDEX idx_pending_requests_request_id ON pending_requests(request_id);", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_pending_requests_generation ON pending_requests(generation);", params![], )?; @@ -308,6 +320,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, + generation BLOB NOT NULL UNIQUE, backwards_type TEXT CHECK (backwards_type IN ('R', 'C')) NOT NULL, -- R: Response, C: Cancel FOREIGN KEY(friend_public_key, currency) @@ -321,7 +334,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_pending_backwards ON pending_backwards(request_id);", + "CREATE UNIQUE INDEX idx_pending_backwards_request_id ON pending_backwards(request_id);", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_pending_backwards_generation ON pending_backwards(generation);", params![], )?; From 91a0d2f9a1ceef4bb45d2a434175285b17f53f0b Mon Sep 17 00:00:00 2001 From: real Date: Sat, 19 Sep 2020 13:46:17 +0300 Subject: [PATCH 032/478] database: Removed old comment --- components/database/src/create.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index b887b6cb2..6d5e6ecef 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -164,7 +164,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: Where does the currency field here comes from? tx.execute( "CREATE TABLE remote_currencies( friend_public_key BLOB NOT NULL, From cb31d2b5a9f1bddc66b33b675f230c9704042eda Mon Sep 17 00:00:00 2001 From: real Date: Sat, 19 Sep 2020 13:46:50 +0300 Subject: [PATCH 033/478] database: Unite events and event_balances tables --- components/database/src/create.rs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 6d5e6ecef..f16074c41 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -436,26 +436,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE events( counter BLOB NOT NULL PRIMARY KEY, time INTEGER NOT NULL, - event_type TEXT CHECK (event_type IN ('P', 'I', 'R')) NOT NULL - -- Event type: P: Payment, I: Invoice, R: Friend Removal - );", - params![], - )?; - - // Balances table, showing the exact balance for every event. - // The numbers shown represent the numbers right after the event occured. - tx.execute( - "CREATE TABLE event_balances( - counter BLOB NOT NULL, - currency TEXT NOT NULL, amount BLOB NOT NULL, in_fees BLOB NOT NULL, out_fees BLOB NOT NULL, - - PRIMARY KEY(counter, currency) - FOREIGN KEY(counter) - REFERENCES events(counter) - ON DELETE CASCADE + event_type TEXT CHECK (event_type IN ('P', 'I', 'R')) NOT NULL + -- Event type: P: Payment, I: Invoice, R: Friend Removal );", params![], )?; From b5be331cdc45c546bdeb09f3ee024f95e84beee2 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 19 Sep 2020 13:47:02 +0300 Subject: [PATCH 034/478] database: renamed tables --- components/database/src/create.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index f16074c41..e08e0898e 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -450,7 +450,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // - Add indices // More work needed here: tx.execute( - "CREATE TABLE payments( + "CREATE TABLE payment_events( counter BLOB NOT NULL, event_type TEXT CHECK (event_type = 'P') DEFAULT 'P' @@ -471,7 +471,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // - Add indices // More work needed here: tx.execute( - "CREATE TABLE invoices ( + "CREATE TABLE invoice_events ( counter BLOB NOT NULL, event_type TEXT CHECK (event_type = 'I') DEFAULT 'I' @@ -489,7 +489,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE TABLE friend_removals ( + "CREATE TABLE friend_removal_events ( counter BLOB NOT NULL, event_type TEXT CHECK (event_type = 'R') DEFAULT 'R' From 752c6849e7f4e44b4fa8bb875f631949fa6d9d26 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 19 Sep 2020 14:15:08 +0300 Subject: [PATCH 035/478] database: Renamed tables --- components/database/src/create.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index e08e0898e..c066cb5b6 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -207,7 +207,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE TABLE local_pending_transactions( + "CREATE TABLE local_open_transactions( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, @@ -226,12 +226,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_local_pending_transactions ON local_pending_transactions(request_id);", + "CREATE UNIQUE INDEX idx_local_open_transactions ON local_open_transactions(request_id);", params![], )?; tx.execute( - "CREATE TABLE remote_pending_transactions( + "CREATE TABLE remote_open_transactions( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, @@ -250,7 +250,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_remote_pending_transactions ON remote_pending_transactions(request_id);", + "CREATE UNIQUE INDEX idx_remote_open_transactions ON remote_open_transactions(request_id);", params![], )?; From 8b12ab0e9b884ae670b6c751e5740b0b2a6f8840 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 19 Sep 2020 14:20:02 +0300 Subject: [PATCH 036/478] database: TODO comment --- components/database/src/create.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index c066cb5b6..974c046bb 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -102,6 +102,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // TODO: Add last incoming/outgoing move token? + // Maybe we should add to friends table directly? tx.execute( "CREATE TABLE consistent_channels( friend_public_key BLOB NOT NULL PRIMARY KEY, From e457c110c5fef21f5dece6e05b3f528ae92f6090 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 19 Sep 2020 18:37:54 +0300 Subject: [PATCH 037/478] database: Some work on event tables and related. --- components/database/src/create.rs | 96 ++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 33 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 974c046bb..4f9ff7c57 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -6,25 +6,10 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // TODO: A better way to do this? tx.execute("PRAGMA foreign_keys = ON;", params![])?; - // This table serves as an "archive" table, containing active and non active applications. - // Some applications can not be removed from the database, because they might be still used in - // the events table (As part of an invoice or payment event) tx.execute( "CREATE TABLE applications ( - app_public_key BLOB NOT NULL PRIMARY KEY, - name TEXT NOT NULL UNIQUE - );", - params![], - )?; - - tx.execute( - "CREATE UNIQUE INDEX idx_applications ON applications(app_public_key, name);", - params![], - )?; - - tx.execute( - "CREATE TABLE active_applications ( app_public_key BLOB NOT NULL PRIMARY KEY, + app_name TEXT NOT NULL UNIQUE, last_online INTEGER NOT NULL, is_enabled BOOL NOT NULL, @@ -43,6 +28,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_applications ON applications(app_public_key, app_name);", + params![], + )?; + // Single row is enforced in this table according to https://stackoverflow.com/a/33104119 tx.execute( "CREATE TABLE funder( @@ -60,7 +50,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { -- Last local relays we have sent to the friend remote_relays BLOB NOT NULL, -- Friend's relays - name TEXT NOT NULL UNIQUE, + friend_name TEXT NOT NULL UNIQUE, -- Friend's name is_enabled BOOL NOT NULL, -- Do we allow connectivity with this friend? @@ -78,7 +68,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // public name index: tx.execute( - "CREATE UNIQUE INDEX idx_friends_name ON friends(name);", + "CREATE UNIQUE INDEX idx_friends_name ON friends(friend_name);", params![], )?; @@ -409,7 +399,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE relays( relay_public_key BLOB NOT NULL PRIMARY KEY, address TEXT, - name TEXT + relay_name TEXT );", params![], )?; @@ -423,7 +413,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE index_servers( index_public_key BLOB NOT NULL PRIMARY KEY, address TEXT, - name TEXT + index_name TEXT );", params![], )?; @@ -438,26 +428,46 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE events( counter BLOB NOT NULL PRIMARY KEY, time INTEGER NOT NULL, - amount BLOB NOT NULL, - in_fees BLOB NOT NULL, - out_fees BLOB NOT NULL, - event_type TEXT CHECK (event_type IN ('P', 'I', 'R')) NOT NULL + event_type TEXT CHECK (event_type IN ('P', 'I', 'R')) NOT NULL, -- Event type: P: Payment, I: Invoice, R: Friend Removal + -- Information about the application that trigerred this event: + app_public_key BLOB NOT NULL, + app_name TEXT NOT NULL );", params![], )?; + // Balances table, showing the exact balance for every event. + // The numbers shown represent the numbers right after the event occurred. + tx.execute( + "CREATE TABLE event_balances( + counter BLOB NOT NULL, + currency TEXT NOT NULL, + amount BLOB NOT NULL, + in_fees BLOB NOT NULL, + out_fees BLOB NOT NULL, + event_type TEXT CHECK (event_type IN ('P', 'I', 'F')) NOT NULL, + -- Event type: P: Payment, I: Invoice, F: Friend inconsistency + + PRIMARY KEY(counter, currency) + FOREIGN KEY(counter) + REFERENCES events(counter) + ON DELETE CASCADE + );", + params![], + )?; + // TODO: // - Add a new table for pending requests? // - Add indices // More work needed here: tx.execute( "CREATE TABLE payment_events( - counter BLOB NOT NULL, + counter BLOB NOT NULL PRIMARY KEY, event_type TEXT CHECK (event_type = 'P') DEFAULT 'P' NOT NULL, - payment_id BLOB NOT NULL PRIMARY KEY, + payment_id BLOB NOT NULL UNIQUE, currency TEXT NOT NULL, total_dest_payment BLOB NOT NULL, dest_payment BLOB NOT NULL, @@ -474,11 +484,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // More work needed here: tx.execute( "CREATE TABLE invoice_events ( - counter BLOB NOT NULL, + counter BLOB NOT NULL PRIMARY KEY, event_type TEXT CHECK (event_type = 'I') DEFAULT 'I' NOT NULL, - invoice_id BLOB NOT NULL PRIMARY KEY, + invoice_id BLOB NOT NULL UNIQUE, currency TEXT NOT NULL, amount BLOB NOT NULL, description TEXT NOT NULL, @@ -491,11 +501,13 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE TABLE friend_removal_events ( - counter BLOB NOT NULL, - event_type TEXT CHECK (event_type = 'R') - DEFAULT 'R' - NOT NULL, + "CREATE TABLE friend_inconsistency_events ( + counter BLOB NOT NULL PRIMARY KEY, + event_type TEXT CHECK (event_type = 'F') + DEFAULT 'F' + NOT NULL, + friend_public_key BLOB NOT NULL, + friend_name TEXT NOT NULL, FOREIGN KEY(counter, event_type) REFERENCES events(counter, event_type) ON DELETE CASCADE @@ -503,6 +515,24 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE TABLE friend_inconsistency_event_balances ( + counter BLOB NOT NULL, + currency TEXT NOT NULL, + old_balance BLOB NOT NULL, + old_in_fees BLOB NOT NULL, + old_out_fees BLOB NOT NULL, + new_balance BLOB NOT NULL, + new_in_fees BLOB NOT NULL, + new_out_fees BLOB NOT NULL, + PRIMARY KEY(counter, currency), + FOREIGN KEY(counter) + REFERENCES friend_inconsistency_events(counter) + ON DELETE CASCADE + );", + params![], + )?; + tx.commit() } From 527566639bccd6d39599d9a19740ddb16e8ee54f Mon Sep 17 00:00:00 2001 From: real Date: Sat, 19 Sep 2020 18:39:21 +0300 Subject: [PATCH 038/478] database: Added TODO comment --- components/database/src/create.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 4f9ff7c57..512c48c6f 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -515,6 +515,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // TODO: What should we do in case of friend inconsistency resolve? + // Should we zero the in_fees and out_fees fields? tx.execute( "CREATE TABLE friend_inconsistency_event_balances ( counter BLOB NOT NULL, From 0d321e5f050ef5afd94165aead3ae4891bd0a9a6 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 19 Sep 2020 21:10:26 +0300 Subject: [PATCH 039/478] database: Added missing channels info. --- components/database/src/create.rs | 73 ++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 512c48c6f..8effc8157 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -100,7 +100,15 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { is_consistent BOOL NOT NULL CHECK (is_consistent = true) DEFAULT true, - is_incoming BOOL NOT NULL, + move_token_counter BLOB NOT NULL, + opt_move_token_out BLOB, + opt_move_token_in BLOB, + -- Two options: + -- 1. Incoming mode: No outgoing token, there is incoming token. + -- 2. Outgoing mode: We keep the last incoming token if exists, + -- and there is a pending outgoing token. + CHECK ((opt_move_token_out IS NULL AND opt_move_token_in IS NOT NULL) + OR (opt_move_token_out IS NOT NULL)), FOREIGN KEY(friend_public_key, is_consistent) REFERENCES friends(friend_public_key, is_consistent) ON DELETE CASCADE @@ -116,13 +124,15 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE inconsistent_channels( - friend_public_key BLOB NOT NULL PRIMARY KEY, - is_consistent BOOL NOT NULL - CHECK (is_consistent = false) - DEFAULT false, - opt_last_incoming_move_token BLOB, - local_reset_terms BLOB NOT NULL, - opt_remote_reset_terms BLOB, + friend_public_key BLOB NOT NULL PRIMARY KEY, + is_consistent BOOL NOT NULL + CHECK (is_consistent = false) + DEFAULT false, + -- Last seen incoming move token: + opt_move_token_in BLOB, + -- Local reset terms: + local_reset_token BLOB NOT NULL, + local_reset_move_token_counter BLOB NOT NULL, FOREIGN KEY(friend_public_key, is_consistent) REFERENCES friends(friend_public_key, is_consistent) ON DELETE CASCADE @@ -130,6 +140,49 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE TABLE local_reset_terms( + friend_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + balance BLOB NOT NULL, + in_fees BLOB NOT NULL, + out_fees BLOB NOT NULL, + PRIMARY KEY(friend_public_key, currency), + FOREIGN KEY(friend_public_key) + REFERENCES inconsistent_channels(friend_public_key) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE TABLE inconsistent_channels_with_remote( + friend_public_key BLOB NOT NULL PRIMARY KEY, + -- Remote reset terms: + remote_reset_token BLOB NOT NULL, + remote_reset_move_token_counter BLOB NOT NULL, + FOREIGN KEY(friend_public_key) + REFERENCES inconsistent_channels(friend_public_key) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE TABLE remote_reset_terms( + friend_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + balance BLOB NOT NULL, + in_fees BLOB NOT NULL, + out_fees BLOB NOT NULL, + PRIMARY KEY(friend_public_key, currency), + FOREIGN KEY(friend_public_key) + REFERENCES inconsistent_channels_with_remote(friend_public_key) + ON DELETE CASCADE + );", + params![], + )?; + // friend public key index: tx.execute( "CREATE UNIQUE INDEX idx_inconsistent_channels ON inconsistent_channels(friend_public_key);", @@ -500,6 +553,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // A case of friend inconsistency or friend removal tx.execute( "CREATE TABLE friend_inconsistency_events ( counter BLOB NOT NULL PRIMARY KEY, @@ -515,8 +569,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: What should we do in case of friend inconsistency resolve? - // Should we zero the in_fees and out_fees fields? + // Balances (per currency) in case of friend inconsistency event. tx.execute( "CREATE TABLE friend_inconsistency_event_balances ( counter BLOB NOT NULL, From 80b064d95efeddb548ef9ff75d2e346da98dc620 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 19 Sep 2020 21:14:35 +0300 Subject: [PATCH 040/478] database: Removed redundant comment --- components/database/src/create.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 8effc8157..548faa6fb 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -116,7 +116,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // friend public key index: tx.execute( "CREATE UNIQUE INDEX idx_consistent_channels ON consistent_channels(friend_public_key);", params![], From 1d8f3db2bc66b3a59904d92523477e67c1cacc75 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 19 Sep 2020 21:15:55 +0300 Subject: [PATCH 041/478] database: Added indexes --- components/database/src/create.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 548faa6fb..625f95c4e 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -139,6 +139,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX idx_inconsistent_channels ON inconsistent_channels(friend_public_key);", + params![], + )?; + tx.execute( "CREATE TABLE local_reset_terms( friend_public_key BLOB NOT NULL, @@ -154,6 +159,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX local_reset_terms_idx ON local_reset_terms(friend_public_key);", + params![], + )?; + tx.execute( "CREATE TABLE inconsistent_channels_with_remote( friend_public_key BLOB NOT NULL PRIMARY KEY, @@ -167,6 +177,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX inconsistent_channels_with_remote_idx ON + inconsistent_channels_with_remote(friend_public_key);", + params![], + )?; + tx.execute( "CREATE TABLE remote_reset_terms( friend_public_key BLOB NOT NULL, @@ -182,6 +198,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE UNIQUE INDEX remote_reset_terms_idx ON remote_reset_terms(friend_public_key);", + params![], + )?; + // friend public key index: tx.execute( "CREATE UNIQUE INDEX idx_inconsistent_channels ON inconsistent_channels(friend_public_key);", From 554dac6cd1bf56f31876c0bbe2bc0586d1b51a4b Mon Sep 17 00:00:00 2001 From: real Date: Sun, 20 Sep 2020 12:05:32 +0300 Subject: [PATCH 042/478] database: Removed TODO comment --- components/database/src/create.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 625f95c4e..7eab875b7 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -92,8 +92,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: Add last incoming/outgoing move token? - // Maybe we should add to friends table directly? tx.execute( "CREATE TABLE consistent_channels( friend_public_key BLOB NOT NULL PRIMARY KEY, From 9a4a6c8407cc00734be6acd5a7959cff96ff9f2e Mon Sep 17 00:00:00 2001 From: real Date: Sun, 20 Sep 2020 13:19:50 +0300 Subject: [PATCH 043/478] database: Added comment --- components/database/src/create.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 7eab875b7..f067515a4 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -162,6 +162,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // Inconsistent channels that contain remote reset terms. tx.execute( "CREATE TABLE inconsistent_channels_with_remote( friend_public_key BLOB NOT NULL PRIMARY KEY, From 1eab84121a2ba0cb19990ed76c33e5dc27fbe545 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 20 Sep 2020 13:22:56 +0300 Subject: [PATCH 044/478] database: Removed redundant index --- components/database/src/create.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index f067515a4..60af33343 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -202,12 +202,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // friend public key index: - tx.execute( - "CREATE UNIQUE INDEX idx_inconsistent_channels ON inconsistent_channels(friend_public_key);", - params![], - )?; - tx.execute( "CREATE TABLE local_currencies( friend_public_key BLOB NOT NULL, From 7461f62b834ea333361eabcc08118152d202518f Mon Sep 17 00:00:00 2001 From: real Date: Sun, 20 Sep 2020 15:29:19 +0300 Subject: [PATCH 045/478] database: comment --- components/database/src/create.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 60af33343..c59b56172 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -583,6 +583,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; // Balances (per currency) in case of friend inconsistency event. + // Friend inconsistency can be one of: 1. Channel reset, 2. Friend removal tx.execute( "CREATE TABLE friend_inconsistency_event_balances ( counter BLOB NOT NULL, From 6fb49301a6737d0a38cd8a1596ad44915c30bc42 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 20 Sep 2020 17:13:54 +0300 Subject: [PATCH 046/478] database: Some work on open invoices --- components/database/src/create.rs | 121 ++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 16 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index c59b56172..5045c2c99 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -158,7 +158,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX local_reset_terms_idx ON local_reset_terms(friend_public_key);", + "CREATE UNIQUE INDEX local_reset_terms_idx ON local_reset_terms(friend_public_key, currency);", params![], )?; @@ -198,7 +198,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX remote_reset_terms_idx ON remote_reset_terms(friend_public_key);", + "CREATE UNIQUE INDEX remote_reset_terms_idx ON remote_reset_terms(friend_public_key, currency);", params![], )?; @@ -465,7 +465,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE relays( relay_public_key BLOB NOT NULL PRIMARY KEY, address TEXT, - relay_name TEXT + relay_name TEXT );", params![], )?; @@ -479,7 +479,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE index_servers( index_public_key BLOB NOT NULL PRIMARY KEY, address TEXT, - index_name TEXT + index_name TEXT );", params![], )?; @@ -489,6 +489,103 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // Ongoing payments that were not yet finalized + tx.execute( + "CREATE TABLE open_payments( + payment_id BLOB NOT NULL PRIMARY KEY, + dest_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + amount BLOB NOT NULL, + description TEXT NOT NULL + -- TODO + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_open_payments ON open_payments(payment_id);", + params![], + )?; + + // TODO: + tx.execute( + "CREATE TABLE open_invoices( + invoice_id BLOB NOT NULL PRIMARY KEY, + description TEXT NOT NULL, + currency TEXT NOT NULL, + opt_amount BLOB + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_open_invoices ON open_invoices(invoice_id);", + params![], + )?; + + tx.execute( + "CREATE TABLE open_invoices_relays( + invoice_id BLOB NOT NULL, + relay_address TEXT NOT NULL, + relay_port BLOB NOT NULL, + PRIMARY KEY(invoice_id, relay_address), + FOREIGN KEY(invoice_id) + REFERENCES open_invoices(invoice_id) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_open_invoices_relays ON open_invoices_relays(invoice_id, relay_address);", + params![], + )?; + + tx.execute( + "CREATE TABLE invoice_instances( + invoice_id BLOB NOT NULL, + invoice_instance BLOB NOT NULL, + description TEXT NOT NULL, + payload_hash BLOB NOT NULL UNIQUE, + -- hash(invoice_instance, description, payload_hash) + invoice_hash BLOB NOT NULL UNIQUE, + opt_src_hashed_lock BLOB, + PRIMARY KEY(invoice_id, invoice_instance), + FOREIGN KEY(invoice_id) + REFERENCES open_invoices(invoice_id) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_invoice_instances ON invoice_instances(invoice_id, invoice_instance);", + params![], + )?; + + // TODO: Possibly add full request information here: + tx.execute( + "CREATE TABLE invoice_instances_requests( + invoice_id BLOB NOT NULL, + invoice_instance BLOB NOT NULL, + request_id BLOB NOT NULL PRIMARY KEY, + FOREIGN KEY(invoice_id, invoice_instance) + REFERENCES invoice_instances(invoice_id, invoice_instance) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE INDEX idx_instances_requests ON invoice_instances_requests(invoice_id, invoice_instance);", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_instances_requests_request_id ON invoice_instances_requests(request_id);", + params![], + )?; + // Documents table, allowing total order on all items payments and invoices tx.execute( "CREATE TABLE events( @@ -523,10 +620,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: - // - Add a new table for pending requests? - // - Add indices - // More work needed here: tx.execute( "CREATE TABLE payment_events( counter BLOB NOT NULL PRIMARY KEY, @@ -535,8 +628,9 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { NOT NULL, payment_id BLOB NOT NULL UNIQUE, currency TEXT NOT NULL, - total_dest_payment BLOB NOT NULL, - dest_payment BLOB NOT NULL, + total_amount BLOB NOT NULL, + amount BLOB NOT NULL, + description TEXT NOT NULL, FOREIGN KEY(counter, event_type) REFERENCES events(counter, event_type) ON DELETE CASCADE @@ -544,21 +638,16 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: - // - Add fields for total amount paid? - // - Add indices - // More work needed here: tx.execute( "CREATE TABLE invoice_events ( counter BLOB NOT NULL PRIMARY KEY, event_type TEXT CHECK (event_type = 'I') DEFAULT 'I' NOT NULL, - invoice_id BLOB NOT NULL UNIQUE, currency TEXT NOT NULL, amount BLOB NOT NULL, description TEXT NOT NULL, - status BLOB NOT NULL, + serial_num BLOB NOT NULL UNIQUE, FOREIGN KEY(counter, event_type) REFERENCES events(counter, event_type) ON DELETE CASCADE From 8dc0f7649742c4ba7217560c4e720a64f0deb708 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 20 Sep 2020 17:17:27 +0300 Subject: [PATCH 047/478] database: Updated comments --- components/database/src/create.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 5045c2c99..850101aa5 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -490,6 +490,9 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; // Ongoing payments that were not yet finalized + // TODO: Complete open payments information: + // - Pending requests/responses? + // - Stage information? (See state.rs in funder) tx.execute( "CREATE TABLE open_payments( payment_id BLOB NOT NULL PRIMARY KEY, @@ -497,7 +500,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { currency TEXT NOT NULL, amount BLOB NOT NULL, description TEXT NOT NULL - -- TODO );", params![], )?; @@ -507,7 +509,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: tx.execute( "CREATE TABLE open_invoices( invoice_id BLOB NOT NULL PRIMARY KEY, @@ -563,7 +564,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: Possibly add full request information here: tx.execute( "CREATE TABLE invoice_instances_requests( invoice_id BLOB NOT NULL, From 8673227826b4aab26ea9db2ff5bffb9e8c26bf4f Mon Sep 17 00:00:00 2001 From: real Date: Sun, 20 Sep 2020 17:44:54 +0300 Subject: [PATCH 048/478] database: Added src_plain_lock column to open_payments --- components/database/src/create.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 850101aa5..95a8682c3 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -499,7 +499,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { dest_public_key BLOB NOT NULL, currency TEXT NOT NULL, amount BLOB NOT NULL, - description TEXT NOT NULL + description TEXT NOT NULL, + src_plain_lock BLOB NOT NULL );", params![], )?; From 9db510e523e924f5fe5a479438779950b0974aea Mon Sep 17 00:00:00 2001 From: real Date: Sun, 20 Sep 2020 17:45:43 +0300 Subject: [PATCH 049/478] database: request_id now references remote_open_transactions --- components/database/src/create.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 95a8682c3..323ac2a9b 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -570,6 +570,9 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { invoice_id BLOB NOT NULL, invoice_instance BLOB NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, + FOREIGN KEY(request_id) + REFERENCES remote_open_transactions(request_id) + ON DELETE RESTRICT, FOREIGN KEY(invoice_id, invoice_instance) REFERENCES invoice_instances(invoice_id, invoice_instance) ON DELETE CASCADE From 9eb0add4b84fb3baf06e4b12fe96c23529aadb3a Mon Sep 17 00:00:00 2001 From: real Date: Mon, 21 Sep 2020 21:11:10 +0300 Subject: [PATCH 050/478] database: Comment --- components/database/src/create.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 323ac2a9b..0a2d41e88 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -551,6 +551,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { payload_hash BLOB NOT NULL UNIQUE, -- hash(invoice_instance, description, payload_hash) invoice_hash BLOB NOT NULL UNIQUE, + -- src_hashed_lock is provided by the buyer/payer during the commitment. opt_src_hashed_lock BLOB, PRIMARY KEY(invoice_id, invoice_instance), FOREIGN KEY(invoice_id) From 8c22ba615a047d5dd6d6bcfb2645ac0d622c33eb Mon Sep 17 00:00:00 2001 From: real Date: Tue, 29 Sep 2020 12:22:02 +0300 Subject: [PATCH 051/478] database: Removed routes permissions (Removed from interface) --- components/database/src/create.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 0a2d41e88..9e3083506 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -15,7 +15,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { perm_info_docs BOOL NOT NULL, perm_info_friends BOOL NOT NULL, - perm_routes BOOL NOT NULL, perm_buy BOOL NOT NULL, perm_sell BOOL NOT NULL, perm_config_card BOOL NOT NULL, From a3d2ce2032efd0a552a096f4e78ca98ffed3eee3 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 29 Sep 2020 12:26:43 +0300 Subject: [PATCH 052/478] database: Updated comment --- components/database/src/create.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 9e3083506..5f98e0b07 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -676,7 +676,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; // Balances (per currency) in case of friend inconsistency event. - // Friend inconsistency can be one of: 1. Channel reset, 2. Friend removal + // Friend inconsistency can be one of: 1. Channel reset, 2. Friend removal, 3. currency removal tx.execute( "CREATE TABLE friend_inconsistency_event_balances ( counter BLOB NOT NULL, From 6430221c99412d97115ab32b0b6b256a841629a2 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 3 Oct 2020 13:44:44 +0300 Subject: [PATCH 053/478] Updated rust toolchain to 1.46.0 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 372cf402c..0a3db35b2 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.44.0 +1.46.0 From 1cc6d7bbf661dabfbcc3b0638aa312e47f7b6c3a Mon Sep 17 00:00:00 2001 From: real Date: Sat, 3 Oct 2020 13:50:18 +0300 Subject: [PATCH 054/478] funder: Commented out everything, left mutual_credit --- components/funder/src/lib.rs | 28 +++++++++---------- .../funder/src/mutual_credit/incoming.rs | 1 + .../funder/src/mutual_credit/outgoing.rs | 3 ++ components/funder/src/mutual_credit/types.rs | 3 ++ 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 3218fe01e..d9f3b4c41 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -9,8 +9,8 @@ clippy::new_without_default )] -#[macro_use] -extern crate log; +// #[macro_use] +// extern crate log; #[macro_use] extern crate serde; @@ -18,19 +18,19 @@ extern crate serde; #[macro_use] extern crate quickcheck_derive; -mod ephemeral; -mod friend; -mod funder; -mod handler; -mod liveness; +// mod ephemeral; +// mod friend; +// mod funder; +// mod handler; +// mod liveness; mod mutual_credit; -pub mod report; -mod state; -mod token_channel; +// pub mod report; +// mod state; +// mod token_channel; pub mod types; -#[cfg(test)] -mod tests; +// #[cfg(test)] +// mod tests; -pub use self::funder::{funder_loop, FunderError}; -pub use self::state::{FunderMutation, FunderState}; +// pub use self::funder::{funder_loop, FunderError}; +// pub use self::state::{FunderMutation, FunderState}; diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index b8bb68dc0..65c4a3a9f 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -67,6 +67,7 @@ pub struct ProcessTransListError { process_trans_error: ProcessOperationError, } +#[allow(unused)] pub fn process_operations_list( mutual_credit: &mut MutualCredit, operations: Vec, diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 403c121ad..9763a4b16 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + use crypto::hash_lock::HashLock; use crypto::identity::verify_signature; @@ -36,6 +38,7 @@ pub enum QueueOperationError { DestPaymentExceedsTotal, } +#[allow(unused)] /// A wrapper over a token channel, accumulating operations to be sent as one transaction. impl OutgoingMc { // TODO: Take MutualCredit instead of &MutualCredit? diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index ae0514388..8647e2c2b 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + use std::collections::HashMap as ImHashMap; use common::safe_arithmetic::SafeSignedArithmetic; @@ -119,6 +121,7 @@ impl MutualCredit { } } + #[allow(unused)] /// Calculate required balance for reset. /// This would be current balance plus additional future profits. pub fn balance_for_reset(&self) -> i128 { From 36287b745afaf1ca3bc3beb7b67c249aa96f9df9 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 3 Oct 2020 13:51:05 +0300 Subject: [PATCH 055/478] Removed unnecessary unused hint --- components/funder/src/mutual_credit/outgoing.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 9763a4b16..752646365 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -38,7 +38,6 @@ pub enum QueueOperationError { DestPaymentExceedsTotal, } -#[allow(unused)] /// A wrapper over a token channel, accumulating operations to be sent as one transaction. impl OutgoingMc { // TODO: Take MutualCredit instead of &MutualCredit? From 568f64f415fc6a1faa179995d93f96141e085848 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 3 Oct 2020 14:18:31 +0300 Subject: [PATCH 056/478] crypto: Initial work on hmac implementation --- Cargo.lock | 21 +++++++++++++++++ components/crypto/Cargo.toml | 1 + components/crypto/src/hmac.rs | 29 ++++++++++++++++++++++++ components/crypto/src/lib.rs | 1 + components/proto/src/crypto/mod.rs | 6 +++++ components/proto/src/schema/common.capnp | 8 +++++++ 6 files changed, 66 insertions(+) create mode 100644 components/crypto/src/hmac.rs diff --git a/Cargo.lock b/Cargo.lock index 9ca554f55..0342596d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -357,6 +357,15 @@ dependencies = [ "subtle 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crypto-mac" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "csv" version = "1.1.3" @@ -708,6 +717,15 @@ dependencies = [ "digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hmac" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crypto-mac 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "humantime" version = "1.3.0" @@ -1000,6 +1018,7 @@ dependencies = [ "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", "ed25519-dalek 1.0.0-pre.3 (registry+https://github.com/rust-lang/crates.io-index)", "hkdf 0.9.0-alpha.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "offset-common 0.1.0", "offset-proto 0.1.0", "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2237,6 +2256,7 @@ dependencies = [ "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum crypto-mac 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +"checksum crypto-mac 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58bcd97a54c7ca5ce2f6eb16f6bede5b0ab5f0055fedc17d2f0b4466e21671ca" "checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" "checksum csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" "checksum curve25519-dalek 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d85653f070353a16313d0046f173f70d1aadd5b42600a14de626f0dfb3473a5" @@ -2276,6 +2296,7 @@ dependencies = [ "checksum hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" "checksum hkdf 0.9.0-alpha.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e551da9a76291df932270bc2b100d0571588eaa9ef77af7bceee80dba9ace3ad" "checksum hmac 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b87b580bd66811cc2324a27f3587de707cacf7525b96dca8122f7493e6cce0da" +"checksum hmac 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "deae6d9dbb35ec2c502d62b8f7b1c000a0822c3b0794ba36b3149c0a1c840dff" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum im 14.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "696059c87b83c5a258817ecd67c3af915e3ed141891fc35a1e79908801cf0ce7" "checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" diff --git a/components/crypto/Cargo.toml b/components/crypto/Cargo.toml index c6dad3e8a..d14f6fd19 100644 --- a/components/crypto/Cargo.toml +++ b/components/crypto/Cargo.toml @@ -16,6 +16,7 @@ ed25519-dalek = "1.0.0-pre.3" sha2 = "0.9.0" hkdf = "0.9.0-alpha.0" chacha20poly1305 = "0.5.1" +hmac = "0.9.0" serde = {version = "1.0.104", features = ["derive"]} diff --git a/components/crypto/src/hmac.rs b/components/crypto/src/hmac.rs new file mode 100644 index 000000000..846e2e68c --- /dev/null +++ b/components/crypto/src/hmac.rs @@ -0,0 +1,29 @@ +use hmac::{Hmac, Mac, NewMac}; +use proto::crypto::{HmacKey, HmacResult}; +use sha2::Sha512Trunc256; + +// Create alias for HMAC-SHA512-256 +type HmacSha512Trunc256 = Hmac; + +pub fn create_hmac(data: &[u8], hmac_key: &HmacKey) -> HmacResult { + let mut mac = HmacSha512Trunc256::new_varkey(&*hmac_key).expect("Invalid key length"); + mac.update(data); + let digest_res = mac.finalize().into_bytes(); + + let mut inner = [0x00; HmacResult::len()]; + inner.copy_from_slice(digest_res.as_ref()); + + HmacResult::from(inner) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_hmac_basic() { + let my_data = b"This is my data"; + let my_key = HmacKey::from([1u8; 32]); + let _hmac_result = create_hmac(&my_data[..], &my_key); + } +} diff --git a/components/crypto/src/lib.rs b/components/crypto/src/lib.rs index d1bea9334..3d2296ccd 100644 --- a/components/crypto/src/lib.rs +++ b/components/crypto/src/lib.rs @@ -16,6 +16,7 @@ pub mod dh; pub mod error; pub mod hash; pub mod hash_lock; +pub mod hmac; pub mod identity; // pub mod nonce_window; pub mod rand; diff --git a/components/proto/src/crypto/mod.rs b/components/proto/src/crypto/mod.rs index ae6702834..9ff43bdb9 100644 --- a/components/proto/src/crypto/mod.rs +++ b/components/proto/src/crypto/mod.rs @@ -15,6 +15,12 @@ use crate::common_capnp; mod serialize; // use self::serialize::{type_capnp_serde128, type_capnp_serde256, type_capnp_serde512}; +// +define_fixed_bytes!(HmacResult, 32); +type_capnp_serde!(HmacResult, common_capnp::hmac_result, (x0, x1, x2, x3)); + +define_fixed_bytes!(HmacKey, 32); +type_capnp_serde!(HmacKey, common_capnp::hmac_key, (x0, x1, x2, x3)); define_fixed_bytes!(HashResult, 32); type_capnp_serde!(HashResult, common_capnp::hash_result, (x0, x1, x2, x3)); diff --git a/components/proto/src/schema/common.capnp b/components/proto/src/schema/common.capnp index 4254349ed..62f222106 100644 --- a/components/proto/src/schema/common.capnp +++ b/components/proto/src/schema/common.capnp @@ -57,6 +57,14 @@ struct HashResult { inner @0: Buffer256; } +struct HmacResult { + inner @0: Buffer256; +} + +struct HmacKey { + inner @0: Buffer256; +} + struct InvoiceId { inner @0: Buffer256; } From 12822294f6c37e5cc76f466e09a5f7679f64e652 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 3 Oct 2020 14:28:48 +0300 Subject: [PATCH 057/478] crypto: TODO comment --- components/crypto/src/hash.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/crypto/src/hash.rs b/components/crypto/src/hash.rs index d3ace45c9..19959e7ca 100644 --- a/components/crypto/src/hash.rs +++ b/components/crypto/src/hash.rs @@ -1,6 +1,7 @@ use proto::crypto::HashResult; use sha2::{Digest, Sha512Trunc256}; +// TODO: Possibly choose a more generic name, to allow changes in the future? /// Calculate SHA512/256 over the given data. pub fn sha_512_256(data: &[u8]) -> HashResult { let mut hasher = Sha512Trunc256::new(); From b37dad6dee8cfaf8a926e8f5a1acbb200fb683d0 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 3 Oct 2020 14:29:07 +0300 Subject: [PATCH 058/478] crypto: Added initial hmac implementation --- components/crypto/src/hmac.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/components/crypto/src/hmac.rs b/components/crypto/src/hmac.rs index 846e2e68c..87dcb43c5 100644 --- a/components/crypto/src/hmac.rs +++ b/components/crypto/src/hmac.rs @@ -1,3 +1,5 @@ +//! Hash based message authentication + use hmac::{Hmac, Mac, NewMac}; use proto::crypto::{HmacKey, HmacResult}; use sha2::Sha512Trunc256; @@ -16,6 +18,12 @@ pub fn create_hmac(data: &[u8], hmac_key: &HmacKey) -> HmacResult { HmacResult::from(inner) } +pub fn verify_hmac(data: &[u8], hmac_key: &HmacKey, hmac_result: &HmacResult) -> bool { + let mut mac = HmacSha512Trunc256::new_varkey(&*hmac_key).expect("Invalid key length"); + mac.update(data); + mac.verify(&hmac_result).is_ok() +} + #[cfg(test)] mod tests { use super::*; @@ -23,7 +31,17 @@ mod tests { #[test] fn test_hmac_basic() { let my_data = b"This is my data"; - let my_key = HmacKey::from([1u8; 32]); - let _hmac_result = create_hmac(&my_data[..], &my_key); + + let my_key1 = HmacKey::from([1u8; 32]); + let hmac_result1 = create_hmac(&my_data[..], &my_key1); + + let my_key2 = HmacKey::from([2u8; 32]); + let hmac_result2 = create_hmac(&my_data[..], &my_key2); + + assert!(verify_hmac(my_data, &my_key1, &hmac_result1)); + assert!(verify_hmac(my_data, &my_key2, &hmac_result2)); + + assert!(!verify_hmac(my_data, &my_key1, &hmac_result2)); + assert!(!verify_hmac(my_data, &my_key2, &hmac_result1)); } } From 82607287f2a532c0e2a90b199e99e1b60697aef9 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 3 Oct 2020 14:30:06 +0300 Subject: [PATCH 059/478] crypto: TODO comment --- components/crypto/src/hmac.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/crypto/src/hmac.rs b/components/crypto/src/hmac.rs index 87dcb43c5..1fa155c93 100644 --- a/components/crypto/src/hmac.rs +++ b/components/crypto/src/hmac.rs @@ -7,6 +7,9 @@ use sha2::Sha512Trunc256; // Create alias for HMAC-SHA512-256 type HmacSha512Trunc256 = Hmac; +// TODO: Possibly add a more efficient version, with a struct and update() method. +// This might allow us to save allocation in the rest of the code. + pub fn create_hmac(data: &[u8], hmac_key: &HmacKey) -> HmacResult { let mut mac = HmacSha512Trunc256::new_varkey(&*hmac_key).expect("Invalid key length"); mac.update(data); From 069b90d509434f67f1f7c3a3e97b02220268b8c3 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 3 Oct 2020 20:05:39 +0300 Subject: [PATCH 060/478] funder: Updated funder's protocol messages --- components/proto/src/funder/messages.rs | 39 ++++++++------------- components/proto/src/schema/funder.capnp | 43 +++++++++++------------- 2 files changed, 33 insertions(+), 49 deletions(-) diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 0a5fd7cc5..a12fd667b 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -16,7 +16,8 @@ use num_traits::cast::ToPrimitive; use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; use crate::crypto::{ - HashResult, HashedLock, InvoiceId, PaymentId, PlainLock, PublicKey, RandValue, Signature, Uid, + HashResult, HashedLock, HmacResult, InvoiceId, PaymentId, PlainLock, PublicKey, RandValue, + Signature, Uid, }; use crate::app_server::messages::{NamedRelayAddress, RelayAddress}; @@ -89,7 +90,9 @@ pub struct RequestSendFundsOp { #[serde(with = "ser_string")] pub total_dest_payment: u128, #[serde(with = "ser_b64")] - pub invoice_id: InvoiceId, + pub invoice_hash: HashResult, + #[serde(with = "ser_b64")] + pub hmac: HmacResult, #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub left_fees: u128, @@ -101,10 +104,10 @@ pub struct ResponseSendFundsOp { #[serde(with = "ser_b64")] pub request_id: Uid, #[serde(with = "ser_b64")] - pub dest_hashed_lock: HashedLock, - pub is_complete: bool, - #[serde(with = "ser_b64")] - pub rand_nonce: RandValue, + pub src_plain_lock: PlainLock, + #[capnp_conv(with = Wrapper)] + #[serde(with = "ser_string")] + pub serial_num: u128, #[serde(with = "ser_b64")] pub signature: Signature, } @@ -114,10 +117,9 @@ pub struct UnsignedResponseSendFundsOp { #[serde(with = "ser_b64")] pub request_id: Uid, #[serde(with = "ser_b64")] - pub dest_hashed_lock: HashedLock, - pub is_complete: bool, - #[serde(with = "ser_b64")] - pub rand_nonce: RandValue, + pub src_plain_lock: PlainLock, + #[serde(with = "ser_string")] + pub serial_num: u128, } #[capnp_conv(crate::funder_capnp::cancel_send_funds_op)] @@ -151,24 +153,12 @@ pub struct Commit { pub signature: Signature, } -#[capnp_conv(crate::funder_capnp::collect_send_funds_op)] -#[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] -pub struct CollectSendFundsOp { - #[serde(with = "ser_b64")] - pub request_id: Uid, - #[serde(with = "ser_b64")] - pub src_plain_lock: PlainLock, - #[serde(with = "ser_b64")] - pub dest_plain_lock: PlainLock, -} - #[capnp_conv(crate::funder_capnp::friend_tc_op)] #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub enum FriendTcOp { RequestSendFunds(RequestSendFundsOp), ResponseSendFunds(ResponseSendFundsOp), CancelSendFunds(CancelSendFundsOp), - CollectSendFunds(CollectSendFundsOp), } #[capnp_conv(crate::funder_capnp::move_token::opt_local_relays)] @@ -190,9 +180,8 @@ impl Into for ResponseSendFundsOp { fn into(self) -> UnsignedResponseSendFundsOp { UnsignedResponseSendFundsOp { request_id: self.request_id, - dest_hashed_lock: self.dest_hashed_lock, - is_complete: self.is_complete, - rand_nonce: self.rand_nonce, + src_plain_lock: self.src_plain_lock, + serial_num: self.serial_num, } } } diff --git a/components/proto/src/schema/funder.capnp b/components/proto/src/schema/funder.capnp index b421f8d41..bd829558b 100644 --- a/components/proto/src/schema/funder.capnp +++ b/components/proto/src/schema/funder.capnp @@ -11,6 +11,7 @@ using import "common.capnp".RelayAddress; using import "common.capnp".HashedLock; using import "common.capnp".PlainLock; using import "common.capnp".HashResult; +using import "common.capnp".HmacResult; using import "common.capnp".Currency; @@ -107,9 +108,15 @@ struct RequestSendFundsOp { route @2: FriendsRoute; destPayment @3: CustomUInt128; totalDestPayment @4: CustomUInt128; - invoiceId @5: InvoiceId; - # Id number of the invoice we are attempting to pay - leftFees @6: CustomUInt128; + invoiceHash @5: HashResult; + # A hash of the contents of the invoice (Including text etc) + # Possibly a hash over a random invoiceId, and text hash + hmac @6: HmacResult; + # An HMAC signature over the whole message, not including "leftFees" + # and "route" (as they change when the message is passed). + # The shared secret for the HMAC algorithm was received through + # "direct" relay communication with the seller. + leftFees @7: CustomUInt128; # Amount of fees left to give to mediators # Every mediator takes the amount of fees he wants and subtracts this # value accordingly. @@ -117,23 +124,18 @@ struct RequestSendFundsOp { struct ResponseSendFundsOp { requestId @0: Uid; - destHashedLock @1: HashedLock; - isComplete @2: Bool; - # Has the destination received all the funds he asked for at the invoice? - # Mostly meaningful in the case of multi-path payments. - # isComplete == True means that no more requests should be sent. - # The isComplete field is crucial for the construction of a Commit message. - randNonce @3: RandValue; - signature @4: Signature; + srcPlainLock @1: PlainLock; + serialNum @2: CustomUInt128; + # Serial number used for this collection of invoice money. + # This should be a u128 counter, increased by 1 for every collected + # invoice. + signature @3: Signature; # Signature{key=destinationKey}( # sha512/256("FUNDS_RESPONSE") || - # sha512/256(requestId || randNonce) || - # srcHashedLock || - # destHashedLock || - # isComplete || - # destPayment || + # sha512/256(requestId || hmac || srcPlainLock || destPayment) + # serialNum || # totalDestPayment || - # invoiceId || + # invoiceHash || # currency [Implicitly known by the mutual credit] # ) } @@ -142,18 +144,11 @@ struct CancelSendFundsOp { requestId @0: Uid; } -struct CollectSendFundsOp { - requestId @0: Uid; - srcPlainLock @1: PlainLock; - destPlainLock @2: PlainLock; -} - struct FriendTcOp { union { requestSendFunds @0: RequestSendFundsOp; responseSendFunds @1: ResponseSendFundsOp; cancelSendFunds @2: CancelSendFundsOp; - collectSendFunds @3: CollectSendFundsOp; } } From 474f8bf6c23967ea9e8de7a13d6858b80d4f24c1 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 3 Oct 2020 20:20:52 +0300 Subject: [PATCH 061/478] proto: Updated PendingTransaction struct --- components/proto/src/funder/messages.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index a12fd667b..db7fdffb6 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -480,18 +480,18 @@ pub enum TransactionStage { pub struct PendingTransaction { #[serde(with = "ser_b64")] pub request_id: Uid, + #[serde(with = "ser_b64")] + pub src_hashed_lock: HashedLock, pub route: FriendsRoute, - #[serde(with = "ser_string")] pub dest_payment: u128, #[serde(with = "ser_string")] pub total_dest_payment: u128, #[serde(with = "ser_b64")] - pub invoice_id: InvoiceId, + pub invoice_hash: HashResult, + #[serde(with = "ser_b64")] + pub hmac: HmacResult, #[serde(with = "ser_string")] pub left_fees: u128, - #[serde(with = "ser_b64")] - pub src_hashed_lock: HashedLock, - pub stage: TransactionStage, } // ================================================================== From 6baf65f3a911facd6a858433523faa5cc5524692 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 3 Oct 2020 20:21:11 +0300 Subject: [PATCH 062/478] signature: Updated to match new funder messages --- components/signature/src/canonical.rs | 28 ++++++---------------- components/signature/src/signature_buff.rs | 24 ++++++++++++++----- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/components/signature/src/canonical.rs b/components/signature/src/canonical.rs index ae82c7951..6e04ab9bb 100644 --- a/components/signature/src/canonical.rs +++ b/components/signature/src/canonical.rs @@ -3,9 +3,9 @@ use byteorder::{BigEndian, WriteBytesExt}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ - BalanceInfo, CancelSendFundsOp, CollectSendFundsOp, CountersInfo, Currency, - CurrencyBalanceInfo, CurrencyOperations, FriendTcOp, FriendsRoute, McInfo, OptLocalRelays, - Receipt, RequestSendFundsOp, ResponseSendFundsOp, TokenInfo, + BalanceInfo, CancelSendFundsOp, CountersInfo, Currency, CurrencyBalanceInfo, + CurrencyOperations, FriendTcOp, FriendsRoute, McInfo, OptLocalRelays, Receipt, + RequestSendFundsOp, ResponseSendFundsOp, TokenInfo, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -165,7 +165,8 @@ impl CanonicalSerialize for RequestSendFundsOp { res_bytes .write_u128::(self.total_dest_payment) .unwrap(); - res_bytes.extend_from_slice(&self.invoice_id); + res_bytes.extend_from_slice(&self.invoice_hash); + res_bytes.extend_from_slice(&self.hmac); res_bytes.write_u128::(self.left_fees).unwrap(); res_bytes } @@ -175,9 +176,8 @@ impl CanonicalSerialize for ResponseSendFundsOp { fn canonical_serialize(&self) -> Vec { let mut res_bytes = Vec::new(); res_bytes.extend_from_slice(&self.request_id); - res_bytes.extend_from_slice(&self.dest_hashed_lock); - res_bytes.extend_from_slice(&self.is_complete.canonical_serialize()); - res_bytes.extend_from_slice(&self.rand_nonce); + res_bytes.extend_from_slice(&self.src_plain_lock); + res_bytes.write_u128::(self.serial_num).unwrap(); res_bytes.extend_from_slice(&self.signature); res_bytes } @@ -191,16 +191,6 @@ impl CanonicalSerialize for CancelSendFundsOp { } } -impl CanonicalSerialize for CollectSendFundsOp { - fn canonical_serialize(&self) -> Vec { - let mut res_bytes = Vec::new(); - res_bytes.extend_from_slice(&self.request_id); - res_bytes.extend_from_slice(&self.src_plain_lock); - res_bytes.extend_from_slice(&self.dest_plain_lock); - res_bytes - } -} - impl CanonicalSerialize for FriendTcOp { fn canonical_serialize(&self) -> Vec { let mut res_bytes = Vec::new(); @@ -217,10 +207,6 @@ impl CanonicalSerialize for FriendTcOp { res_bytes.push(2u8); res_bytes.append(&mut cancel_send_funds.canonical_serialize()) } - FriendTcOp::CollectSendFunds(commit_send_funds) => { - res_bytes.push(3u8); - res_bytes.append(&mut commit_send_funds.canonical_serialize()) - } } res_bytes } diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index c7df95f47..5a7411010 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -27,6 +27,17 @@ pub fn create_response_signature_buffer( where RSF: Into, { + /* + # Signature{key=destinationKey}( + # sha512/256("FUNDS_RESPONSE") || + # sha512/256(requestId || hmac || srcPlainLock || destPayment) + # serialNum || + # totalDestPayment || + # invoiceHash || + # currency [Implicitly known by the mutual credit] + # ) + */ + let response_send_funds: UnsignedResponseSendFundsOp = response_send_funds.into(); let mut sbuffer = Vec::new(); @@ -34,19 +45,20 @@ where let mut inner_blob = Vec::new(); inner_blob.extend_from_slice(&pending_transaction.request_id); - inner_blob.extend_from_slice(&response_send_funds.rand_nonce); + inner_blob.extend_from_slice(&pending_transaction.hmac); + inner_blob.extend_from_slice(&response_send_funds.src_plain_lock); + inner_blob + .write_u128::(pending_transaction.dest_payment) + .unwrap(); sbuffer.extend_from_slice(&hash::sha_512_256(&inner_blob)); - sbuffer.extend_from_slice(&pending_transaction.src_hashed_lock); - sbuffer.extend_from_slice(&response_send_funds.dest_hashed_lock); - sbuffer.extend_from_slice(&response_send_funds.is_complete.canonical_serialize()); sbuffer - .write_u128::(pending_transaction.dest_payment) + .write_u128::(response_send_funds.serial_num) .unwrap(); sbuffer .write_u128::(pending_transaction.total_dest_payment) .unwrap(); - sbuffer.extend_from_slice(&pending_transaction.invoice_id); + sbuffer.extend_from_slice(&pending_transaction.invoice_hash); sbuffer.extend_from_slice(¤cy.canonical_serialize()); sbuffer From 1558076013eb2ad595f5c1c827af29027064dcd9 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 3 Oct 2020 20:26:24 +0300 Subject: [PATCH 063/478] funder: Initial adjustment of mutual credit to v2. --- components/funder/src/mutual_credit/mod.rs | 8 +++--- components/funder/src/mutual_credit/types.rs | 26 -------------------- components/funder/src/types.rs | 14 ++++++++--- 3 files changed, 14 insertions(+), 34 deletions(-) diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index a3521f69d..7881f514c 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -1,5 +1,5 @@ -pub mod incoming; -pub mod outgoing; -#[cfg(test)] -mod tests; +// pub mod incoming; +// pub mod outgoing; +// #[cfg(test)] +// mod tests; pub mod types; diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 8647e2c2b..997c0ae6d 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -92,10 +92,8 @@ pub enum McMutation { SetBalance(i128), InsertLocalPendingTransaction(PendingTransaction), RemoveLocalPendingTransaction(Uid), - SetLocalPendingTransactionStage((Uid, TransactionStage)), InsertRemotePendingTransaction(PendingTransaction), RemoveRemotePendingTransaction(Uid), - SetRemotePendingTransactionStage((Uid, TransactionStage)), SetLocalPendingDebt(u128), SetRemotePendingDebt(u128), } @@ -149,18 +147,12 @@ impl MutualCredit { McMutation::RemoveLocalPendingTransaction(request_id) => { self.remove_local_pending_transaction(request_id) } - McMutation::SetLocalPendingTransactionStage((request_id, stage)) => { - self.set_local_pending_transaction_stage(&request_id, stage.clone()) - } McMutation::InsertRemotePendingTransaction(pending_friend_request) => { self.insert_remote_pending_transaction(pending_friend_request) } McMutation::RemoveRemotePendingTransaction(request_id) => { self.remove_remote_pending_transaction(request_id) } - McMutation::SetRemotePendingTransactionStage((request_id, stage)) => { - self.set_remote_pending_transaction_stage(&request_id, stage.clone()) - } McMutation::SetLocalPendingDebt(local_pending_debt) => { self.set_local_pending_debt(*local_pending_debt) } @@ -203,22 +195,4 @@ impl MutualCredit { fn set_local_pending_debt(&mut self, local_pending_debt: u128) { self.state.balance.local_pending_debt = local_pending_debt; } - - fn set_local_pending_transaction_stage(&mut self, request_id: &Uid, stage: TransactionStage) { - self.state - .pending_transactions - .local - .get_mut(&request_id) - .unwrap() - .stage = stage; - } - - fn set_remote_pending_transaction_stage(&mut self, request_id: &Uid, stage: TransactionStage) { - self.state - .pending_transactions - .remote - .get_mut(&request_id) - .unwrap() - .stage = stage; - } } diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 83dc516f9..64c293e23 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -1,3 +1,6 @@ +// TODO: Remove this hint: +#![allow(unused)] + use signature::canonical::CanonicalSerialize; use common::ser_utils::ser_b64; @@ -8,7 +11,7 @@ use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ CancelSendFundsOp, ChannelerUpdateFriend, Currency, CurrencyOperations, FriendMessage, FunderIncomingControl, FunderOutgoingControl, MoveToken, PendingTransaction, - RequestSendFundsOp, ResponseSendFundsOp, TokenInfo, TransactionStage, UnsignedMoveToken, + RequestSendFundsOp, ResponseSendFundsOp, TokenInfo, UnsignedMoveToken, UnsignedResponseSendFundsOp, }; @@ -50,6 +53,8 @@ pub async fn create_response_send_funds<'a>( rand_nonce: RandValue, identity_client: &'a mut IdentityClient, ) -> ResponseSendFundsOp { + unimplemented!(); + /* let u_response_send_funds = UnsignedResponseSendFundsOp { request_id: pending_transaction.request_id.clone(), dest_hashed_lock, @@ -74,6 +79,7 @@ pub async fn create_response_send_funds<'a>( rand_nonce: u_response_send_funds.rand_nonce, signature, } + */ } pub fn create_cancel_send_funds(request_id: Uid) -> CancelSendFundsOp { @@ -83,13 +89,13 @@ pub fn create_cancel_send_funds(request_id: Uid) -> CancelSendFundsOp { pub fn create_pending_transaction(request_send_funds: &RequestSendFundsOp) -> PendingTransaction { PendingTransaction { request_id: request_send_funds.request_id.clone(), + src_hashed_lock: request_send_funds.src_hashed_lock.clone(), route: request_send_funds.route.clone(), dest_payment: request_send_funds.dest_payment, total_dest_payment: request_send_funds.total_dest_payment, - invoice_id: request_send_funds.invoice_id.clone(), + invoice_hash: request_send_funds.invoice_hash.clone(), + hmac: request_send_funds.hmac.clone(), left_fees: request_send_funds.left_fees, - src_hashed_lock: request_send_funds.src_hashed_lock.clone(), - stage: TransactionStage::Request, } } From a63b1f71cb5d9d30dceba5d54d8552c5653c0e43 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 3 Oct 2020 20:29:48 +0300 Subject: [PATCH 064/478] funder: reimplemented create_response_send_funds() --- components/funder/src/types.rs | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 64c293e23..80b1db270 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -1,11 +1,8 @@ -// TODO: Remove this hint: -#![allow(unused)] - use signature::canonical::CanonicalSerialize; use common::ser_utils::ser_b64; -use proto::crypto::{HashResult, HashedLock, PublicKey, RandValue, Signature, Uid}; +use proto::crypto::{HashResult, PlainLock, PublicKey, RandValue, Signature, Uid}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ @@ -48,18 +45,14 @@ where pub async fn create_response_send_funds<'a>( currency: &Currency, pending_transaction: &'a PendingTransaction, - dest_hashed_lock: HashedLock, - is_complete: bool, - rand_nonce: RandValue, + src_plain_lock: PlainLock, + serial_num: u128, identity_client: &'a mut IdentityClient, ) -> ResponseSendFundsOp { - unimplemented!(); - /* let u_response_send_funds = UnsignedResponseSendFundsOp { request_id: pending_transaction.request_id.clone(), - dest_hashed_lock, - is_complete, - rand_nonce, + src_plain_lock: src_plain_lock.clone(), + serial_num, }; let signature_buff = create_response_signature_buffer( @@ -74,12 +67,10 @@ pub async fn create_response_send_funds<'a>( ResponseSendFundsOp { request_id: u_response_send_funds.request_id, - dest_hashed_lock: u_response_send_funds.dest_hashed_lock, - is_complete: u_response_send_funds.is_complete, - rand_nonce: u_response_send_funds.rand_nonce, + src_plain_lock, + serial_num, signature, } - */ } pub fn create_cancel_send_funds(request_id: Uid) -> CancelSendFundsOp { From ec5b4d1112ab1e1bb2ba39b7eb00d92cc14217be Mon Sep 17 00:00:00 2001 From: real Date: Sun, 4 Oct 2020 11:50:18 +0300 Subject: [PATCH 065/478] funder: Updated mutual_credit incoming impl --- .../funder/src/mutual_credit/incoming.rs | 155 +++++------------- components/funder/src/mutual_credit/mod.rs | 2 +- .../funder/src/mutual_credit/outgoing.rs | 2 - components/funder/src/mutual_credit/types.rs | 2 +- components/proto/src/funder/messages.rs | 6 - 5 files changed, 41 insertions(+), 126 deletions(-) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 65c4a3a9f..26cd6a740 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -4,8 +4,7 @@ use crypto::identity::verify_signature; use common::safe_arithmetic::SafeSignedArithmetic; use proto::funder::messages::{ - CancelSendFundsOp, CollectSendFundsOp, FriendTcOp, PendingTransaction, RequestSendFundsOp, - ResponseSendFundsOp, TransactionStage, + CancelSendFundsOp, FriendTcOp, PendingTransaction, RequestSendFundsOp, ResponseSendFundsOp, }; use signature::signature_buff::create_response_signature_buffer; @@ -25,19 +24,12 @@ pub struct IncomingCancelSendFundsOp { pub incoming_cancel: CancelSendFundsOp, } -#[derive(Debug)] -pub struct IncomingCollectSendFundsOp { - pub pending_transaction: PendingTransaction, - pub incoming_collect: CollectSendFundsOp, -} - #[derive(Debug)] pub enum IncomingMessage { Request(RequestSendFundsOp), RequestCancel(RequestSendFundsOp), Response(IncomingResponseSendFundsOp), Cancel(IncomingCancelSendFundsOp), - Collect(IncomingCollectSendFundsOp), } /// Resulting tasks to perform after processing an incoming operation. @@ -54,10 +46,7 @@ pub enum ProcessOperationError { RequestAlreadyExists, RequestDoesNotExist, InvalidResponseSignature, - NotExpectingResponse, InvalidSrcPlainLock, - InvalidDestPlainLock, - NotExpectingCollect, DestPaymentExceedsTotal, } @@ -109,9 +98,6 @@ pub fn process_operation( FriendTcOp::CancelSendFunds(cancel_send_funds) => { process_cancel_send_funds(mutual_credit, cancel_send_funds) } - FriendTcOp::CollectSendFunds(collect_send_funds) => { - process_collect_send_funds(mutual_credit, collect_send_funds) - } } } @@ -129,13 +115,6 @@ fn process_request_send_funds( return Err(ProcessOperationError::DestPaymentExceedsTotal); } - /* - // Make sure that we are open to requests: - if !mutual_credit.state().requests_status.local.is_open() { - return Err(ProcessOperationError::LocalRequestsClosed); - } - */ - // Make sure that we don't have this request as a pending request already: let p_remote_requests = &mutual_credit.state().pending_transactions.remote; if p_remote_requests.contains_key(&request_send_funds.request_id) { @@ -176,8 +155,6 @@ fn process_request_send_funds( // Add pending transaction: let pending_transaction = create_pending_transaction(&request_send_funds); - // let pending_friend_request = create_pending_transaction(&request_send_funds); - let mut op_output = ProcessOperationOutput { incoming_message: Some(incoming_message), mc_mutations: Vec::new(), @@ -210,6 +187,11 @@ fn process_response_send_funds( .ok_or(ProcessOperationError::RequestDoesNotExist)? .clone(); + // Verify src_plain_lock and dest_plain_lock: + if response_send_funds.src_plain_lock.hash_lock() != pending_transaction.src_hashed_lock { + return Err(ProcessOperationError::InvalidSrcPlainLock); + } + let dest_public_key = if pending_transaction.route.public_keys.is_empty() { &mutual_credit.state().idents.remote_public_key } else { @@ -231,22 +213,42 @@ fn process_response_send_funds( return Err(ProcessOperationError::InvalidResponseSignature); } - // We expect that the current stage is Request: - if let TransactionStage::Request = pending_transaction.stage { - } else { - return Err(ProcessOperationError::NotExpectingResponse); - } + // Calculate amount of credits that were frozen: + let freeze_credits = pending_transaction + .dest_payment + .checked_add(pending_transaction.left_fees) + .unwrap(); + // Note: The unwrap() above should never fail, because this was already checked during the + // request message processing. let mut mc_mutations = Vec::new(); - // Set the stage to Response, and remember dest_hashed_lock: - let mc_mutation = McMutation::SetLocalPendingTransactionStage(( - response_send_funds.request_id.clone(), - TransactionStage::Response( - response_send_funds.dest_hashed_lock.clone(), - response_send_funds.is_complete, - ), - )); + // Remove entry from local_pending hashmap: + let mc_mutation = + McMutation::RemoveLocalPendingTransaction(response_send_funds.request_id.clone()); + mutual_credit.mutate(&mc_mutation); + mc_mutations.push(mc_mutation); + + // Decrease frozen credits and decrease balance: + let new_local_pending_debt = mutual_credit + .state() + .balance + .local_pending_debt + .checked_sub(freeze_credits) + .unwrap(); + + let mc_mutation = McMutation::SetLocalPendingDebt(new_local_pending_debt); + mutual_credit.mutate(&mc_mutation); + mc_mutations.push(mc_mutation); + + let new_balance = mutual_credit + .state() + .balance + .balance + .checked_sub_unsigned(freeze_credits) + .unwrap(); + + let mc_mutation = McMutation::SetBalance(new_balance); mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); @@ -312,82 +314,3 @@ fn process_cancel_send_funds( mc_mutations, }) } - -fn process_collect_send_funds( - mutual_credit: &mut MutualCredit, - collect_send_funds: CollectSendFundsOp, -) -> Result { - // Make sure that id exists in local_pending hashmap, - // and access saved request details. - let local_pending_transactions = &mutual_credit.state().pending_transactions.local; - - // Obtain pending request: - // TODO: Possibly get rid of clone() here for optimization later - let pending_transaction = local_pending_transactions - .get(&collect_send_funds.request_id) - .ok_or(ProcessOperationError::RequestDoesNotExist)? - .clone(); - - let dest_hashed_lock = match &pending_transaction.stage { - TransactionStage::Response(dest_hashed_lock, _is_complete) => dest_hashed_lock, - _ => return Err(ProcessOperationError::NotExpectingCollect), - }; - - // Verify src_plain_lock and dest_plain_lock: - if collect_send_funds.src_plain_lock.hash_lock() != pending_transaction.src_hashed_lock { - return Err(ProcessOperationError::InvalidSrcPlainLock); - } - - if collect_send_funds.dest_plain_lock.hash_lock() != *dest_hashed_lock { - return Err(ProcessOperationError::InvalidDestPlainLock); - } - - // Calculate amount of credits that were frozen: - let freeze_credits = pending_transaction - .dest_payment - .checked_add(pending_transaction.left_fees) - .unwrap(); - // Note: The unwrap() above should never fail, because this was already checked during the - // request message processing. - - let mut mc_mutations = Vec::new(); - - // Remove entry from local_pending hashmap: - let mc_mutation = - McMutation::RemoveLocalPendingTransaction(collect_send_funds.request_id.clone()); - mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); - - // Decrease frozen credits and decrease balance: - let new_local_pending_debt = mutual_credit - .state() - .balance - .local_pending_debt - .checked_sub(freeze_credits) - .unwrap(); - - let mc_mutation = McMutation::SetLocalPendingDebt(new_local_pending_debt); - mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); - - let new_balance = mutual_credit - .state() - .balance - .balance - .checked_sub_unsigned(freeze_credits) - .unwrap(); - - let mc_mutation = McMutation::SetBalance(new_balance); - mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); - - let incoming_message = Some(IncomingMessage::Collect(IncomingCollectSendFundsOp { - pending_transaction, - incoming_collect: collect_send_funds, - })); - - Ok(ProcessOperationOutput { - incoming_message, - mc_mutations, - }) -} diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index 7881f514c..2409707f4 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -1,4 +1,4 @@ -// pub mod incoming; +pub mod incoming; // pub mod outgoing; // #[cfg(test)] // mod tests; diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 752646365..403c121ad 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -1,5 +1,3 @@ -#![allow(unused)] - use crypto::hash_lock::HashLock; use crypto::identity::verify_signature; diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 997c0ae6d..995d36e2e 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -6,7 +6,7 @@ use common::safe_arithmetic::SafeSignedArithmetic; use common::ser_utils::{ser_b64, ser_map_b64_any, ser_string}; use proto::crypto::{PublicKey, Uid}; -use proto::funder::messages::{Currency, PendingTransaction, TransactionStage}; +use proto::funder::messages::{Currency, PendingTransaction}; /* // TODO: Where do we need to check this value? diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index db7fdffb6..f9d8f6da8 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -470,12 +470,6 @@ pub struct Receipt { */ } -#[derive(Arbitrary, Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] -pub enum TransactionStage { - Request, - Response(#[serde(with = "ser_b64")] HashedLock, bool), // inner: (dest_hashed_lock, is_complete) -} - #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct PendingTransaction { #[serde(with = "ser_b64")] From bf2523da7580a244d95d232b467148f9ff91fe4c Mon Sep 17 00:00:00 2001 From: real Date: Sun, 4 Oct 2020 12:00:47 +0300 Subject: [PATCH 066/478] funder: mutual credit: Updated outgoing impl --- components/funder/src/mutual_credit/mod.rs | 2 +- .../funder/src/mutual_credit/outgoing.rs | 135 +++++------------- 2 files changed, 40 insertions(+), 97 deletions(-) diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index 2409707f4..14e993f35 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -1,5 +1,5 @@ pub mod incoming; -// pub mod outgoing; +pub mod outgoing; // #[cfg(test)] // mod tests; pub mod types; diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 403c121ad..84de38d17 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -4,8 +4,7 @@ use crypto::identity::verify_signature; use common::safe_arithmetic::SafeSignedArithmetic; use proto::funder::messages::{ - CancelSendFundsOp, CollectSendFundsOp, FriendTcOp, RequestSendFundsOp, ResponseSendFundsOp, - TransactionStage, + CancelSendFundsOp, FriendTcOp, RequestSendFundsOp, ResponseSendFundsOp, }; use signature::signature_buff::create_response_signature_buffer; @@ -22,20 +21,19 @@ pub struct OutgoingMc { #[derive(Debug)] pub enum QueueOperationError { - RemoteMaxDebtTooLarge, + // RemoteMaxDebtTooLarge, InvalidRoute, - PkPairNotInRoute, + // PkPairNotInRoute, CreditsCalcOverflow, RequestAlreadyExists, RequestDoesNotExist, InvalidResponseSignature, - NotExpectingResponse, - NotExpectingCollect, InvalidSrcPlainLock, - InvalidDestPlainLock, DestPaymentExceedsTotal, } +// TODO: Remove unused hint here: +#[allow(unused)] /// A wrapper over a token channel, accumulating operations to be sent as one transaction. impl OutgoingMc { // TODO: Take MutualCredit instead of &MutualCredit? @@ -60,9 +58,6 @@ impl OutgoingMc { FriendTcOp::CancelSendFunds(cancel_send_funds) => { self.queue_cancel_send_funds(cancel_send_funds) } - FriendTcOp::CollectSendFunds(collect_send_funds) => { - self.queue_collect_send_funds(collect_send_funds) - } } } @@ -78,13 +73,6 @@ impl OutgoingMc { return Err(QueueOperationError::DestPaymentExceedsTotal); } - /* - // Make sure that remote side is open to requests: - if !self.mutual_credit.state().requests_status.remote.is_open() { - return Err(QueueOperationError::RemoteRequestsClosed); - } - */ - // Calculate amount of credits to freeze let own_freeze_credits = request_send_funds .dest_payment @@ -137,6 +125,11 @@ impl OutgoingMc { .clone(); // TODO: Possibly get rid of clone() here for optimization later + // Verify src_plain_lock and dest_plain_lock: + if response_send_funds.src_plain_lock.hash_lock() != pending_transaction.src_hashed_lock { + return Err(QueueOperationError::InvalidSrcPlainLock); + } + // verify signature: let response_signature_buffer = create_response_signature_buffer( &self.mutual_credit.state().currency, @@ -159,54 +152,20 @@ impl OutgoingMc { return Err(QueueOperationError::InvalidResponseSignature); } - // We expect that the current stage is Request: - if let TransactionStage::Request = pending_transaction.stage { - } else { - return Err(QueueOperationError::NotExpectingResponse); - } - - let mut mc_mutations = Vec::new(); - - // Set the stage to Response, and remember dest_hashed_lock: - let mc_mutation = McMutation::SetRemotePendingTransactionStage(( - response_send_funds.request_id, - TransactionStage::Response( - response_send_funds.dest_hashed_lock.clone(), - response_send_funds.is_complete, - ), - )); - self.mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); - - Ok(mc_mutations) - } - - fn queue_cancel_send_funds( - &mut self, - cancel_send_funds: CancelSendFundsOp, - ) -> Result, QueueOperationError> { - // Make sure that id exists in remote_pending hashmap, - // and access saved request details. - let remote_pending_transactions = &self.mutual_credit.state().pending_transactions.remote; - - // Obtain pending request: - let pending_transaction = remote_pending_transactions - .get(&cancel_send_funds.request_id) - .ok_or(QueueOperationError::RequestDoesNotExist)?; - + // Calculate amount of credits that were frozen: let freeze_credits = pending_transaction .dest_payment .checked_add(pending_transaction.left_fees) .unwrap(); - // Remove entry from remote hashmap: + // Remove entry from remote_pending hashmap: let mut mc_mutations = Vec::new(); - - let mc_mutation = McMutation::RemoveRemotePendingTransaction(cancel_send_funds.request_id); + let mc_mutation = + McMutation::RemoveRemotePendingTransaction(response_send_funds.request_id); self.mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); - // Decrease frozen credits: + // Decrease frozen credits and increase balance: let new_remote_pending_debt = self .mutual_credit .state() @@ -214,17 +173,33 @@ impl OutgoingMc { .remote_pending_debt .checked_sub(freeze_credits) .unwrap(); + // Above unwrap() should never fail. This was already checked when a request message was + // received. let mc_mutation = McMutation::SetRemotePendingDebt(new_remote_pending_debt); self.mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); + let new_balance = self + .mutual_credit + .state() + .balance + .balance + .checked_add_unsigned(freeze_credits) + .unwrap(); + // Above unwrap() should never fail. This was already checked when a request message was + // received. + + let mc_mutation = McMutation::SetBalance(new_balance); + self.mutual_credit.mutate(&mc_mutation); + mc_mutations.push(mc_mutation); + Ok(mc_mutations) } - fn queue_collect_send_funds( + fn queue_cancel_send_funds( &mut self, - collect_send_funds: CollectSendFundsOp, + cancel_send_funds: CancelSendFundsOp, ) -> Result, QueueOperationError> { // Make sure that id exists in remote_pending hashmap, // and access saved request details. @@ -232,38 +207,22 @@ impl OutgoingMc { // Obtain pending request: let pending_transaction = remote_pending_transactions - .get(&collect_send_funds.request_id) - .ok_or(QueueOperationError::RequestDoesNotExist)? - .clone(); - // TODO: Possibly get rid of clone() here for optimization later - - let dest_hashed_lock = match &pending_transaction.stage { - TransactionStage::Response(dest_hashed_lock, _is_complete) => dest_hashed_lock, - _ => return Err(QueueOperationError::NotExpectingCollect), - }; - - // Verify src_plain_lock and dest_plain_lock: - if collect_send_funds.src_plain_lock.hash_lock() != pending_transaction.src_hashed_lock { - return Err(QueueOperationError::InvalidSrcPlainLock); - } - - if collect_send_funds.dest_plain_lock.hash_lock() != *dest_hashed_lock { - return Err(QueueOperationError::InvalidDestPlainLock); - } + .get(&cancel_send_funds.request_id) + .ok_or(QueueOperationError::RequestDoesNotExist)?; - // Calculate amount of credits that were frozen: let freeze_credits = pending_transaction .dest_payment .checked_add(pending_transaction.left_fees) .unwrap(); - // Remove entry from remote_pending hashmap: + // Remove entry from remote hashmap: let mut mc_mutations = Vec::new(); - let mc_mutation = McMutation::RemoveRemotePendingTransaction(collect_send_funds.request_id); + + let mc_mutation = McMutation::RemoveRemotePendingTransaction(cancel_send_funds.request_id); self.mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); - // Decrease frozen credits and increase balance: + // Decrease frozen credits: let new_remote_pending_debt = self .mutual_credit .state() @@ -271,27 +230,11 @@ impl OutgoingMc { .remote_pending_debt .checked_sub(freeze_credits) .unwrap(); - // Above unwrap() should never fail. This was already checked when a request message was - // received. let mc_mutation = McMutation::SetRemotePendingDebt(new_remote_pending_debt); self.mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); - let new_balance = self - .mutual_credit - .state() - .balance - .balance - .checked_add_unsigned(freeze_credits) - .unwrap(); - // Above unwrap() should never fail. This was already checked when a request message was - // received. - - let mc_mutation = McMutation::SetBalance(new_balance); - self.mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); - Ok(mc_mutations) } } From 176a09175aeb02fe59c46cc0cd8ac0940b8eada9 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 4 Oct 2020 12:07:55 +0300 Subject: [PATCH 067/478] funder: mutual credit: Restored one test --- components/funder/src/mutual_credit/mod.rs | 5 +- components/funder/src/mutual_credit/tests.rs | 51 +++++++------------- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index 14e993f35..1a1950f14 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -1,5 +1,6 @@ pub mod incoming; pub mod outgoing; -// #[cfg(test)] -// mod tests; +#[allow(unused)] +#[cfg(test)] +mod tests; pub mod types; diff --git a/components/funder/src/mutual_credit/tests.rs b/components/funder/src/mutual_credit/tests.rs index 580dbe7dd..815e4500a 100644 --- a/components/funder/src/mutual_credit/tests.rs +++ b/components/funder/src/mutual_credit/tests.rs @@ -5,10 +5,11 @@ use crypto::identity::{Identity, SoftwareEd25519Identity}; use crypto::rand::RandGen; use crypto::test_utils::DummyRandom; -use proto::crypto::{InvoiceId, PlainLock, PrivateKey, PublicKey, RandValue, Signature, Uid}; +use proto::crypto::{ + HashResult, HmacResult, InvoiceId, PlainLock, PrivateKey, PublicKey, RandValue, Signature, Uid, +}; use proto::funder::messages::{ - CancelSendFundsOp, CollectSendFundsOp, Currency, FriendTcOp, FriendsRoute, RequestSendFundsOp, - ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendTcOp, FriendsRoute, RequestSendFundsOp, ResponseSendFundsOp, }; use signature::signature_buff::create_response_signature_buffer; @@ -44,8 +45,8 @@ fn apply_incoming( } #[test] -fn test_request_response_collect_send_funds() { - let currency = Currency::try_from("OFFSET".to_owned()).unwrap(); +fn test_request_response_send_funds() { + let currency = Currency::try_from("FST".to_owned()).unwrap(); let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); let remote_public_key = PublicKey::from(&[0xbb; PublicKey::len()]); @@ -68,8 +69,9 @@ fn test_request_response_collect_send_funds() { public_key_c.clone(), ], }; - let invoice_id = InvoiceId::from(&[0; InvoiceId::len()]); + let invoice_hash = HashResult::from(&[0; HashResult::len()]); let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); + let hmac = HmacResult::from(&[2; HmacResult::len()]); let request_send_funds = RequestSendFundsOp { request_id: request_id.clone(), @@ -77,7 +79,8 @@ fn test_request_response_collect_send_funds() { route, dest_payment: 10, total_dest_payment: 10, - invoice_id, + invoice_hash, + hmac, left_fees: 5, }; @@ -96,12 +99,12 @@ fn test_request_response_collect_send_funds() { // -------------------------------- let rand_nonce = RandValue::from(&[5; RandValue::len()]); let dest_plain_lock = PlainLock::from(&[2; PlainLock::len()]); + let serial_num: u128 = 0; let mut response_send_funds = ResponseSendFundsOp { request_id: request_id.clone(), - dest_hashed_lock: dest_plain_lock.hash_lock(), - is_complete: false, - rand_nonce: rand_nonce.clone(), + src_plain_lock: src_plain_lock.clone(), + serial_num, signature: Signature::from(&[0; Signature::len()]), }; @@ -119,35 +122,16 @@ fn test_request_response_collect_send_funds() { ) .unwrap(); - // We expect that no changes to balance happened yet: - assert_eq!(mutual_credit.state().balance.balance, 0); - assert_eq!(mutual_credit.state().balance.local_pending_debt, 10 + 5); - assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); - - // -----[CollectSendFunds]-------- - // -------------------------------- - let collect_send_funds = CollectSendFundsOp { - request_id, - src_plain_lock, - dest_plain_lock, - }; - - apply_incoming( - &mut mutual_credit, - FriendTcOp::CollectSendFunds(collect_send_funds), - 100, - ) - .unwrap(); - - // We expect that no changes to balance happened yet: + // We expect that the balance has updated: assert_eq!(mutual_credit.state().balance.balance, -15); assert_eq!(mutual_credit.state().balance.local_pending_debt, 0); assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); } +/* #[test] fn test_request_cancel_send_funds() { - let currency = Currency::try_from("OFFSET".to_owned()).unwrap(); + let currency = Currency::try_from("FST".to_owned()).unwrap(); let mut rng = DummyRandom::new(&[1u8]); let private_key = PrivateKey::rand_gen(&mut rng); @@ -211,7 +195,7 @@ fn test_request_cancel_send_funds() { #[test] fn test_request_response_cancel_send_funds() { - let currency = Currency::try_from("OFFSET".to_owned()).unwrap(); + let currency = Currency::try_from("FST".to_owned()).unwrap(); let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); let remote_public_key = PublicKey::from(&[0xbb; PublicKey::len()]); @@ -305,3 +289,4 @@ fn test_request_response_cancel_send_funds() { assert_eq!(mutual_credit.state().balance.local_pending_debt, 0); assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); } +*/ From c7f0e92acba44f68bc1e7f324ed31a8c60ad1b8f Mon Sep 17 00:00:00 2001 From: real Date: Sun, 4 Oct 2020 12:10:08 +0300 Subject: [PATCH 068/478] funder: Restored test_request_cancel_send_funds() --- components/funder/src/mutual_credit/tests.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/funder/src/mutual_credit/tests.rs b/components/funder/src/mutual_credit/tests.rs index 815e4500a..e922b8b4d 100644 --- a/components/funder/src/mutual_credit/tests.rs +++ b/components/funder/src/mutual_credit/tests.rs @@ -128,7 +128,6 @@ fn test_request_response_send_funds() { assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); } -/* #[test] fn test_request_cancel_send_funds() { let currency = Currency::try_from("FST".to_owned()).unwrap(); @@ -154,8 +153,9 @@ fn test_request_cancel_send_funds() { PublicKey::from(&[0xcc; PublicKey::len()]), ], }; - let invoice_id = InvoiceId::from(&[0; InvoiceId::len()]); + let invoice_hash = HashResult::from(&[0; HashResult::len()]); let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); + let hmac = HmacResult::from(&[2; HmacResult::len()]); let request_send_funds = RequestSendFundsOp { request_id: request_id.clone(), @@ -163,7 +163,8 @@ fn test_request_cancel_send_funds() { route, dest_payment: 10, total_dest_payment: 10, - invoice_id, + invoice_hash, + hmac, left_fees: 5, }; @@ -193,6 +194,7 @@ fn test_request_cancel_send_funds() { assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); } +/* #[test] fn test_request_response_cancel_send_funds() { let currency = Currency::try_from("FST".to_owned()).unwrap(); From fd612eaa9cb455a76f70b6f78a1501a3917ac561 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 4 Oct 2020 12:12:45 +0300 Subject: [PATCH 069/478] funder: Removed nonrelevant test --- components/funder/src/mutual_credit/tests.rs | 99 -------------------- 1 file changed, 99 deletions(-) diff --git a/components/funder/src/mutual_credit/tests.rs b/components/funder/src/mutual_credit/tests.rs index e922b8b4d..6da01cb41 100644 --- a/components/funder/src/mutual_credit/tests.rs +++ b/components/funder/src/mutual_credit/tests.rs @@ -193,102 +193,3 @@ fn test_request_cancel_send_funds() { assert_eq!(mutual_credit.state().balance.local_pending_debt, 0); assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); } - -/* -#[test] -fn test_request_response_cancel_send_funds() { - let currency = Currency::try_from("FST".to_owned()).unwrap(); - - let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); - let remote_public_key = PublicKey::from(&[0xbb; PublicKey::len()]); - let balance = 0; - let mut mutual_credit = - MutualCredit::new(&local_public_key, &remote_public_key, ¤cy, balance); - - // -----[RequestSendFunds]-------- - // ----------------------------- - let mut rng = DummyRandom::new(&[1u8]); - let private_key = PrivateKey::rand_gen(&mut rng); - let identity = SoftwareEd25519Identity::from_private_key(&private_key).unwrap(); - let public_key_c = identity.get_public_key(); - - let request_id = Uid::from(&[3; Uid::len()]); - let route = FriendsRoute { - public_keys: vec![ - PublicKey::from(&[0xaa; PublicKey::len()]), - PublicKey::from(&[0xbb; PublicKey::len()]), - public_key_c.clone(), - ], - }; - let invoice_id = InvoiceId::from(&[0; InvoiceId::len()]); - let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); - - let request_send_funds = RequestSendFundsOp { - request_id: request_id.clone(), - src_hashed_lock: src_plain_lock.hash_lock(), - route, - dest_payment: 10, - total_dest_payment: 10, - invoice_id, - left_fees: 5, - }; - - let pending_transaction = create_pending_transaction(&request_send_funds); - apply_outgoing( - &mut mutual_credit, - &FriendTcOp::RequestSendFunds(request_send_funds), - ) - .unwrap(); - - assert_eq!(mutual_credit.state().balance.balance, 0); - assert_eq!(mutual_credit.state().balance.local_pending_debt, 10 + 5); - assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); - - // -----[ResponseSendFunds]-------- - // -------------------------------- - let rand_nonce = RandValue::from(&[5; RandValue::len()]); - let dest_plain_lock = PlainLock::from(&[2; PlainLock::len()]); - - let mut response_send_funds = ResponseSendFundsOp { - request_id: request_id.clone(), - dest_hashed_lock: dest_plain_lock.hash_lock(), - is_complete: true, - rand_nonce: rand_nonce.clone(), - signature: Signature::from(&[0; Signature::len()]), - }; - - let sign_buffer = create_response_signature_buffer( - ¤cy, - response_send_funds.clone(), - &pending_transaction, - ); - response_send_funds.signature = identity.sign(&sign_buffer); - - apply_incoming( - &mut mutual_credit, - FriendTcOp::ResponseSendFunds(response_send_funds), - 100, - ) - .unwrap(); - - // We expect that no changes to balance happened yet: - assert_eq!(mutual_credit.state().balance.balance, 0); - assert_eq!(mutual_credit.state().balance.local_pending_debt, 10 + 5); - assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); - - // -----[CancelSendFunds]-------- - // ------------------------------ - let cancel_send_funds = CancelSendFundsOp { request_id }; - - apply_incoming( - &mut mutual_credit, - FriendTcOp::CancelSendFunds(cancel_send_funds), - 100, - ) - .unwrap(); - - assert_eq!(mutual_credit.state().balance.balance, 0); - assert_eq!(mutual_credit.state().balance.local_pending_debt, 0); - assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); -} -*/ From 215f921eebcefaff6ea10c52aef3c2f436950517 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 4 Oct 2020 12:16:59 +0300 Subject: [PATCH 070/478] funder: Removed some unused hints and unused imports --- components/funder/src/mutual_credit/mod.rs | 1 - components/funder/src/mutual_credit/tests.rs | 6 +----- components/funder/src/mutual_credit/types.rs | 6 ++++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index 1a1950f14..a3521f69d 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -1,6 +1,5 @@ pub mod incoming; pub mod outgoing; -#[allow(unused)] #[cfg(test)] mod tests; pub mod types; diff --git a/components/funder/src/mutual_credit/tests.rs b/components/funder/src/mutual_credit/tests.rs index 6da01cb41..033a7e9d7 100644 --- a/components/funder/src/mutual_credit/tests.rs +++ b/components/funder/src/mutual_credit/tests.rs @@ -5,9 +5,7 @@ use crypto::identity::{Identity, SoftwareEd25519Identity}; use crypto::rand::RandGen; use crypto::test_utils::DummyRandom; -use proto::crypto::{ - HashResult, HmacResult, InvoiceId, PlainLock, PrivateKey, PublicKey, RandValue, Signature, Uid, -}; +use proto::crypto::{HashResult, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid}; use proto::funder::messages::{ CancelSendFundsOp, Currency, FriendTcOp, FriendsRoute, RequestSendFundsOp, ResponseSendFundsOp, }; @@ -97,8 +95,6 @@ fn test_request_response_send_funds() { // -----[ResponseSendFunds]-------- // -------------------------------- - let rand_nonce = RandValue::from(&[5; RandValue::len()]); - let dest_plain_lock = PlainLock::from(&[2; PlainLock::len()]); let serial_num: u128 = 0; let mut response_send_funds = ResponseSendFundsOp { diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 995d36e2e..6f8be78a9 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -1,5 +1,3 @@ -#![allow(unused)] - use std::collections::HashMap as ImHashMap; use common::safe_arithmetic::SafeSignedArithmetic; @@ -42,6 +40,8 @@ pub struct McBalance { } impl McBalance { + // TODO: Remove unused hint + #[allow(unused)] fn new(balance: i128) -> McBalance { McBalance { balance, @@ -99,6 +99,8 @@ pub enum McMutation { } impl MutualCredit { + // TODO: Remove unused hint + #[allow(unused)] pub fn new( // TODO: Should we move instead of take a reference here? local_public_key: &PublicKey, From 87ff77e1978afa83db416bab514c9972ad829c59 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 4 Oct 2020 16:30:43 +0300 Subject: [PATCH 071/478] funder: Restored token_channel module --- components/funder/src/lib.rs | 3 ++- components/funder/src/mutual_credit/incoming.rs | 1 - components/funder/src/mutual_credit/outgoing.rs | 2 -- components/funder/src/mutual_credit/types.rs | 3 +-- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index d9f3b4c41..84fde2fcc 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -26,7 +26,8 @@ extern crate quickcheck_derive; mod mutual_credit; // pub mod report; // mod state; -// mod token_channel; +#[allow(unused)] +mod token_channel; pub mod types; // #[cfg(test)] diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 26cd6a740..7ec9d98bc 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -56,7 +56,6 @@ pub struct ProcessTransListError { process_trans_error: ProcessOperationError, } -#[allow(unused)] pub fn process_operations_list( mutual_credit: &mut MutualCredit, operations: Vec, diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 84de38d17..74a2f9749 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -32,8 +32,6 @@ pub enum QueueOperationError { DestPaymentExceedsTotal, } -// TODO: Remove unused hint here: -#[allow(unused)] /// A wrapper over a token channel, accumulating operations to be sent as one transaction. impl OutgoingMc { // TODO: Take MutualCredit instead of &MutualCredit? diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 6f8be78a9..a9b2f9d45 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -99,8 +99,6 @@ pub enum McMutation { } impl MutualCredit { - // TODO: Remove unused hint - #[allow(unused)] pub fn new( // TODO: Should we move instead of take a reference here? local_public_key: &PublicKey, @@ -121,6 +119,7 @@ impl MutualCredit { } } + // TODO: Remove unused hint #[allow(unused)] /// Calculate required balance for reset. /// This would be current balance plus additional future profits. From 7f69b46bd10dcd5794c1beced7827ac5695c1e91 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 4 Oct 2020 16:41:18 +0300 Subject: [PATCH 072/478] database: Renamed funder -> node --- components/database/src/create.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 5f98e0b07..1dc9c6a1f 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -34,7 +34,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // Single row is enforced in this table according to https://stackoverflow.com/a/33104119 tx.execute( - "CREATE TABLE funder( + "CREATE TABLE node( id INTEGER PRIMARY KEY CHECK (id = 0), -- enforce single row version INTEGER NOT NULL, -- Database version local_public_key BLOB NOT NULL From a5bfd465a3442c993831cb4df72c67dff9580d29 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 4 Oct 2020 17:33:58 +0300 Subject: [PATCH 073/478] database: Some ideas for funder interface. WIP --- Cargo.lock | 1 + components/database/Cargo.toml | 1 + components/database/src/interfaces/funder.rs | 69 ++++++++++++++++++++ components/database/src/interfaces/mod.rs | 1 + components/database/src/lib.rs | 1 + 5 files changed, 73 insertions(+) create mode 100644 components/database/src/interfaces/funder.rs create mode 100644 components/database/src/interfaces/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 0342596d9..fef5f708d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1040,6 +1040,7 @@ dependencies = [ "im 14.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "offset-common 0.1.0", + "offset-proto 0.1.0", "rusqlite 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/database/Cargo.toml b/components/database/Cargo.toml index 9f87e1633..d6ab988d7 100644 --- a/components/database/Cargo.toml +++ b/components/database/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [dependencies] common = { path = "../common", version = "0.1.0", package = "offset-common" } +proto = { path = "../proto", version = "0.1.0", package = "offset-proto" } log = "0.4" futures = "0.3.1" diff --git a/components/database/src/interfaces/funder.rs b/components/database/src/interfaces/funder.rs new file mode 100644 index 000000000..aae153ed3 --- /dev/null +++ b/components/database/src/interfaces/funder.rs @@ -0,0 +1,69 @@ +use serde::{Deserialize, Serialize}; + +use proto::app_server::messages::{NamedRelayAddress, RelayAddress}; +use proto::crypto::PublicKey; +use proto::funder::messages::{Currency, Rate}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub enum SentLocalRelays { + NeverSent, + Transition(Vec>, Vec>), // (last sent, before last sent) + LastSent(Vec>), +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CurrencyConfig { + /// Rate of forwarding transactions that arrived from this friend to any other friend + /// for a certain currency. + pub rate: Rate, + /// Credit frame for the remote side (Set by the user of this node) + /// The remote side does not know this value. + pub remote_max_debt: u128, + /// Can new requests be sent through the mutual credit with this friend? + pub is_open: bool, +} + +pub enum FunderDbError {} + +// TODO: Remove unused hint: +#[allow(unused)] +pub type FunderDbResult = Result; + +pub trait FunderDb { + fn local_public_key() -> PublicKey; + fn get_friend_remote_relays( + friend_public_key: PublicKey, + ) -> FunderDbResult>>; + fn set_friend_remote_relays( + friend_public_key: PublicKey, + remote_relays: Vec>, + ) -> FunderDbResult<()>; + fn get_friend_sent_local_relays( + friend_public_key: PublicKey, + ) -> FunderDbResult>; + fn set_friend_sent_local_relays( + friend_public_key: PublicKey, + sent_local_relays: SentLocalRelays, + ) -> FunderDbResult<()>; + fn get_friend_name(friend_public_key: PublicKey) -> FunderDbResult; + fn set_friend_name(friend_public_key: PublicKey, name: String) -> FunderDbResult<()>; + fn get_friend_currency_config( + friend_public_key: PublicKey, + currency: Currency, + ) -> FunderDbResult; + fn set_friend_currency_rate( + friend_public_key: PublicKey, + currency: Currency, + rate: Rate, + ) -> FunderDbResult<()>; + fn set_friend_currency_remote_max_debt( + friend_public_key: PublicKey, + currency: Currency, + remote_max_debt: u128, + ) -> FunderDbResult<()>; + fn set_friend_currency_is_open( + friend_public_key: PublicKey, + currency: Currency, + is_open: bool, + ) -> FunderDbResult<()>; +} diff --git a/components/database/src/interfaces/mod.rs b/components/database/src/interfaces/mod.rs new file mode 100644 index 000000000..e353d1275 --- /dev/null +++ b/components/database/src/interfaces/mod.rs @@ -0,0 +1 @@ +mod funder; diff --git a/components/database/src/lib.rs b/components/database/src/lib.rs index 3c953ddbc..26d7f5a10 100644 --- a/components/database/src/lib.rs +++ b/components/database/src/lib.rs @@ -17,6 +17,7 @@ mod atomic_db; mod create; mod database; pub mod file_db; +mod interfaces; pub use self::atomic_db::AtomicDb; pub use self::database::{database_loop, DatabaseClient, DatabaseClientError, DatabaseRequest}; From c1939c79615cc608a30ea7512ffc153d452ee6e9 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 8 Oct 2020 12:59:39 +0300 Subject: [PATCH 074/478] database: Some design work on FunderDbClient --- components/database/src/interfaces/funder.rs | 94 +++++++++++++++----- 1 file changed, 72 insertions(+), 22 deletions(-) diff --git a/components/database/src/interfaces/funder.rs b/components/database/src/interfaces/funder.rs index aae153ed3..afca5f002 100644 --- a/components/database/src/interfaces/funder.rs +++ b/components/database/src/interfaces/funder.rs @@ -4,6 +4,8 @@ use proto::app_server::messages::{NamedRelayAddress, RelayAddress}; use proto::crypto::PublicKey; use proto::funder::messages::{Currency, Rate}; +use futures::channel::{mpsc, oneshot}; + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub enum SentLocalRelays { NeverSent, @@ -25,45 +27,93 @@ pub struct CurrencyConfig { pub enum FunderDbError {} -// TODO: Remove unused hint: -#[allow(unused)] pub type FunderDbResult = Result; +pub type SenderResult = oneshot::Sender>; + +// TODO: Remove this unused hint later: +#[allow(unused)] +pub enum FunderDbOp { + GetLocalPublicKey(oneshot::Sender>), + GetFriendIsEnabled(PublicKey, SenderResult), + SetFriendIsEnabled(PublicKey, bool, SenderResult<()>), + GetFriendRemoteRelays(PublicKey, SenderResult>>), + SetFriendRemoteRelays(PublicKey, Vec>, SenderResult<()>), + GetFriendSentLocalRelays(PublicKey, SenderResult>>), + SetFriendSentLocalRelays(PublicKey, Vec>, SenderResult<()>), + GetFriendName(PublicKey, SenderResult), + SetFriendName(PublicKey, String, SenderResult<()>), + GetCurrencyConfig(PublicKey, SenderResult), + SetFriendCurrencyRate(PublicKey, Currency, Rate, SenderResult<()>), + SetFriendCurrencyRemoteMaxDebt(PublicKey, Currency, u128, SenderResult<()>), + SetFriendCurrencyIsOpen(PublicKey, Currency, bool, SenderResult<()>), +} -pub trait FunderDb { - fn local_public_key() -> PublicKey; - fn get_friend_remote_relays( +// TODO: Remove this unused hint later: +#[allow(unused)] +pub struct FunderDbClient { + sender: mpsc::Sender>, +} + +// TODO: Remove this unused hint later: +#[allow(unused)] +impl FunderDbClient { + pub async fn local_public_key() -> PublicKey { + unimplemented!(); + } + pub async fn get_friend_remote_relays( friend_public_key: PublicKey, - ) -> FunderDbResult>>; - fn set_friend_remote_relays( + ) -> FunderDbResult>> { + unimplemented!(); + } + pub async fn set_friend_remote_relays( friend_public_key: PublicKey, remote_relays: Vec>, - ) -> FunderDbResult<()>; - fn get_friend_sent_local_relays( + ) -> FunderDbResult<()> { + unimplemented!(); + } + pub async fn get_friend_sent_local_relays( friend_public_key: PublicKey, - ) -> FunderDbResult>; - fn set_friend_sent_local_relays( + ) -> FunderDbResult> { + unimplemented!(); + } + pub async fn set_friend_sent_local_relays( friend_public_key: PublicKey, sent_local_relays: SentLocalRelays, - ) -> FunderDbResult<()>; - fn get_friend_name(friend_public_key: PublicKey) -> FunderDbResult; - fn set_friend_name(friend_public_key: PublicKey, name: String) -> FunderDbResult<()>; - fn get_friend_currency_config( + ) -> FunderDbResult<()> { + unimplemented!(); + } + pub async fn get_friend_name(friend_public_key: PublicKey) -> FunderDbResult { + unimplemented!(); + } + pub async fn set_friend_name(friend_public_key: PublicKey, name: String) -> FunderDbResult<()> { + unimplemented!(); + } + pub async fn get_friend_currency_config( friend_public_key: PublicKey, currency: Currency, - ) -> FunderDbResult; - fn set_friend_currency_rate( + ) -> FunderDbResult { + unimplemented!(); + } + pub async fn set_friend_currency_rate( friend_public_key: PublicKey, currency: Currency, rate: Rate, - ) -> FunderDbResult<()>; - fn set_friend_currency_remote_max_debt( + ) -> FunderDbResult<()> { + unimplemented!(); + } + pub async fn set_friend_currency_remote_max_debt( friend_public_key: PublicKey, currency: Currency, remote_max_debt: u128, - ) -> FunderDbResult<()>; - fn set_friend_currency_is_open( + ) -> FunderDbResult<()> { + unimplemented!(); + } + + async fn set_friend_currency_is_open( friend_public_key: PublicKey, currency: Currency, is_open: bool, - ) -> FunderDbResult<()>; + ) -> FunderDbResult<()> { + unimplemented!(); + } } From ccc817200f98d013e4dddd4c00d1035f4d4e142e Mon Sep 17 00:00:00 2001 From: real Date: Thu, 8 Oct 2020 14:31:56 +0300 Subject: [PATCH 075/478] funder + database: Some work on mutual credit db interface --- components/database/src/interfaces/funder.rs | 55 +++--- components/database/src/interfaces/mod.rs | 1 + components/database/src/interfaces/types.rs | 10 ++ .../funder/src/mutual_credit/incoming.rs | 18 +- .../funder/src/mutual_credit/outgoing.rs | 25 +-- components/funder/src/mutual_credit/types.rs | 170 +++++++++++++++++- components/funder/src/token_channel.rs | 4 +- 7 files changed, 222 insertions(+), 61 deletions(-) create mode 100644 components/database/src/interfaces/types.rs diff --git a/components/database/src/interfaces/funder.rs b/components/database/src/interfaces/funder.rs index afca5f002..b732b5310 100644 --- a/components/database/src/interfaces/funder.rs +++ b/components/database/src/interfaces/funder.rs @@ -4,7 +4,9 @@ use proto::app_server::messages::{NamedRelayAddress, RelayAddress}; use proto::crypto::PublicKey; use proto::funder::messages::{Currency, Rate}; -use futures::channel::{mpsc, oneshot}; +use crate::interfaces::types::{DbOpResult, DbOpSenderResult}; + +use futures::channel::mpsc; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub enum SentLocalRelays { @@ -25,27 +27,22 @@ pub struct CurrencyConfig { pub is_open: bool, } -pub enum FunderDbError {} - -pub type FunderDbResult = Result; -pub type SenderResult = oneshot::Sender>; - // TODO: Remove this unused hint later: #[allow(unused)] pub enum FunderDbOp { - GetLocalPublicKey(oneshot::Sender>), - GetFriendIsEnabled(PublicKey, SenderResult), - SetFriendIsEnabled(PublicKey, bool, SenderResult<()>), - GetFriendRemoteRelays(PublicKey, SenderResult>>), - SetFriendRemoteRelays(PublicKey, Vec>, SenderResult<()>), - GetFriendSentLocalRelays(PublicKey, SenderResult>>), - SetFriendSentLocalRelays(PublicKey, Vec>, SenderResult<()>), - GetFriendName(PublicKey, SenderResult), - SetFriendName(PublicKey, String, SenderResult<()>), - GetCurrencyConfig(PublicKey, SenderResult), - SetFriendCurrencyRate(PublicKey, Currency, Rate, SenderResult<()>), - SetFriendCurrencyRemoteMaxDebt(PublicKey, Currency, u128, SenderResult<()>), - SetFriendCurrencyIsOpen(PublicKey, Currency, bool, SenderResult<()>), + GetLocalPublicKey(DbOpSenderResult), + GetFriendIsEnabled(PublicKey, DbOpSenderResult), + SetFriendIsEnabled(PublicKey, bool, DbOpSenderResult<()>), + GetFriendRemoteRelays(PublicKey, DbOpSenderResult>>), + SetFriendRemoteRelays(PublicKey, Vec>, DbOpSenderResult<()>), + GetFriendSentLocalRelays(PublicKey, DbOpSenderResult>>), + SetFriendSentLocalRelays(PublicKey, Vec>, DbOpSenderResult<()>), + GetFriendName(PublicKey, DbOpSenderResult), + SetFriendName(PublicKey, String, DbOpSenderResult<()>), + GetCurrencyConfig(PublicKey, DbOpSenderResult), + SetFriendCurrencyRate(PublicKey, Currency, Rate, DbOpSenderResult<()>), + SetFriendCurrencyRemoteMaxDebt(PublicKey, Currency, u128, DbOpSenderResult<()>), + SetFriendCurrencyIsOpen(PublicKey, Currency, bool, DbOpSenderResult<()>), } // TODO: Remove this unused hint later: @@ -62,50 +59,50 @@ impl FunderDbClient { } pub async fn get_friend_remote_relays( friend_public_key: PublicKey, - ) -> FunderDbResult>> { + ) -> DbOpResult>> { unimplemented!(); } pub async fn set_friend_remote_relays( friend_public_key: PublicKey, remote_relays: Vec>, - ) -> FunderDbResult<()> { + ) -> DbOpResult<()> { unimplemented!(); } pub async fn get_friend_sent_local_relays( friend_public_key: PublicKey, - ) -> FunderDbResult> { + ) -> DbOpResult> { unimplemented!(); } pub async fn set_friend_sent_local_relays( friend_public_key: PublicKey, sent_local_relays: SentLocalRelays, - ) -> FunderDbResult<()> { + ) -> DbOpResult<()> { unimplemented!(); } - pub async fn get_friend_name(friend_public_key: PublicKey) -> FunderDbResult { + pub async fn get_friend_name(friend_public_key: PublicKey) -> DbOpResult { unimplemented!(); } - pub async fn set_friend_name(friend_public_key: PublicKey, name: String) -> FunderDbResult<()> { + pub async fn set_friend_name(friend_public_key: PublicKey, name: String) -> DbOpResult<()> { unimplemented!(); } pub async fn get_friend_currency_config( friend_public_key: PublicKey, currency: Currency, - ) -> FunderDbResult { + ) -> DbOpResult { unimplemented!(); } pub async fn set_friend_currency_rate( friend_public_key: PublicKey, currency: Currency, rate: Rate, - ) -> FunderDbResult<()> { + ) -> DbOpResult<()> { unimplemented!(); } pub async fn set_friend_currency_remote_max_debt( friend_public_key: PublicKey, currency: Currency, remote_max_debt: u128, - ) -> FunderDbResult<()> { + ) -> DbOpResult<()> { unimplemented!(); } @@ -113,7 +110,7 @@ impl FunderDbClient { friend_public_key: PublicKey, currency: Currency, is_open: bool, - ) -> FunderDbResult<()> { + ) -> DbOpResult<()> { unimplemented!(); } } diff --git a/components/database/src/interfaces/mod.rs b/components/database/src/interfaces/mod.rs index e353d1275..c5bbadd4b 100644 --- a/components/database/src/interfaces/mod.rs +++ b/components/database/src/interfaces/mod.rs @@ -1 +1,2 @@ mod funder; +mod types; diff --git a/components/database/src/interfaces/types.rs b/components/database/src/interfaces/types.rs new file mode 100644 index 000000000..f33dc4686 --- /dev/null +++ b/components/database/src/interfaces/types.rs @@ -0,0 +1,10 @@ +use futures::channel::oneshot; + +#[derive(Debug)] +pub enum DbOpError { + // SendOpFailed, +// ResponseOpFailed(oneshot::Canceled), +} + +pub type DbOpResult = Result; +pub type DbOpSenderResult = oneshot::Sender>; diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 7ec9d98bc..6758da3ae 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -10,7 +10,7 @@ use signature::signature_buff::create_response_signature_buffer; use crate::types::create_pending_transaction; -use super::types::{McMutation, MutualCredit}; +use super::types::{McMutationOld, MutualCredit}; #[derive(Debug)] pub struct IncomingResponseSendFundsOp { @@ -35,7 +35,7 @@ pub enum IncomingMessage { /// Resulting tasks to perform after processing an incoming operation. pub struct ProcessOperationOutput { pub incoming_message: Option, - pub mc_mutations: Vec, + pub mc_mutations: Vec, } #[derive(Debug)] @@ -159,12 +159,12 @@ fn process_request_send_funds( mc_mutations: Vec::new(), }; - let mc_mutation = McMutation::InsertRemotePendingTransaction(pending_transaction); + let mc_mutation = McMutationOld::InsertRemotePendingTransaction(pending_transaction); mutual_credit.mutate(&mc_mutation); op_output.mc_mutations.push(mc_mutation); // If we are here, we can freeze the credits: - let mc_mutation = McMutation::SetRemotePendingDebt(new_remote_pending_debt); + let mc_mutation = McMutationOld::SetRemotePendingDebt(new_remote_pending_debt); mutual_credit.mutate(&mc_mutation); op_output.mc_mutations.push(mc_mutation); @@ -224,7 +224,7 @@ fn process_response_send_funds( // Remove entry from local_pending hashmap: let mc_mutation = - McMutation::RemoveLocalPendingTransaction(response_send_funds.request_id.clone()); + McMutationOld::RemoveLocalPendingTransaction(response_send_funds.request_id.clone()); mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); @@ -236,7 +236,7 @@ fn process_response_send_funds( .checked_sub(freeze_credits) .unwrap(); - let mc_mutation = McMutation::SetLocalPendingDebt(new_local_pending_debt); + let mc_mutation = McMutationOld::SetLocalPendingDebt(new_local_pending_debt); mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); @@ -247,7 +247,7 @@ fn process_response_send_funds( .checked_sub_unsigned(freeze_credits) .unwrap(); - let mc_mutation = McMutation::SetBalance(new_balance); + let mc_mutation = McMutationOld::SetBalance(new_balance); mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); @@ -281,7 +281,7 @@ fn process_cancel_send_funds( // Remove entry from local_pending hashmap: let mc_mutation = - McMutation::RemoveLocalPendingTransaction(cancel_send_funds.request_id.clone()); + McMutationOld::RemoveLocalPendingTransaction(cancel_send_funds.request_id.clone()); mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); @@ -298,7 +298,7 @@ fn process_cancel_send_funds( .checked_sub(freeze_credits) .unwrap(); - let mc_mutation = McMutation::SetLocalPendingDebt(new_local_pending_debt); + let mc_mutation = McMutationOld::SetLocalPendingDebt(new_local_pending_debt); mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 74a2f9749..1bd0f5cfa 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -10,7 +10,7 @@ use signature::signature_buff::create_response_signature_buffer; use crate::types::create_pending_transaction; -use super::types::{McMutation, MutualCredit}; +use super::types::{McMutationOld, MutualCredit}; /// Processes outgoing funds for a token channel. /// Used to batch as many funds as possible. @@ -44,7 +44,7 @@ impl OutgoingMc { pub fn queue_operation( &mut self, operation: &FriendTcOp, - ) -> Result, QueueOperationError> { + ) -> Result, QueueOperationError> { // TODO: Maybe remove clone from here later: match operation.clone() { FriendTcOp::RequestSendFunds(request_send_funds) => { @@ -62,7 +62,7 @@ impl OutgoingMc { fn queue_request_send_funds( &mut self, request_send_funds: RequestSendFundsOp, - ) -> Result, QueueOperationError> { + ) -> Result, QueueOperationError> { if !request_send_funds.route.is_part_valid() { return Err(QueueOperationError::InvalidRoute); } @@ -96,12 +96,12 @@ impl OutgoingMc { let pending_transaction = create_pending_transaction(&request_send_funds); let mut mc_mutations = Vec::new(); - let mc_mutation = McMutation::InsertLocalPendingTransaction(pending_transaction); + let mc_mutation = McMutationOld::InsertLocalPendingTransaction(pending_transaction); self.mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); // If we are here, we can freeze the credits: - let mc_mutation = McMutation::SetLocalPendingDebt(new_local_pending_debt); + let mc_mutation = McMutationOld::SetLocalPendingDebt(new_local_pending_debt); self.mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); @@ -111,7 +111,7 @@ impl OutgoingMc { fn queue_response_send_funds( &mut self, response_send_funds: ResponseSendFundsOp, - ) -> Result, QueueOperationError> { + ) -> Result, QueueOperationError> { // Make sure that id exists in remote_pending hashmap, // and access saved request details. let remote_pending_transactions = &self.mutual_credit.state().pending_transactions.remote; @@ -159,7 +159,7 @@ impl OutgoingMc { // Remove entry from remote_pending hashmap: let mut mc_mutations = Vec::new(); let mc_mutation = - McMutation::RemoveRemotePendingTransaction(response_send_funds.request_id); + McMutationOld::RemoveRemotePendingTransaction(response_send_funds.request_id); self.mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); @@ -174,7 +174,7 @@ impl OutgoingMc { // Above unwrap() should never fail. This was already checked when a request message was // received. - let mc_mutation = McMutation::SetRemotePendingDebt(new_remote_pending_debt); + let mc_mutation = McMutationOld::SetRemotePendingDebt(new_remote_pending_debt); self.mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); @@ -188,7 +188,7 @@ impl OutgoingMc { // Above unwrap() should never fail. This was already checked when a request message was // received. - let mc_mutation = McMutation::SetBalance(new_balance); + let mc_mutation = McMutationOld::SetBalance(new_balance); self.mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); @@ -198,7 +198,7 @@ impl OutgoingMc { fn queue_cancel_send_funds( &mut self, cancel_send_funds: CancelSendFundsOp, - ) -> Result, QueueOperationError> { + ) -> Result, QueueOperationError> { // Make sure that id exists in remote_pending hashmap, // and access saved request details. let remote_pending_transactions = &self.mutual_credit.state().pending_transactions.remote; @@ -216,7 +216,8 @@ impl OutgoingMc { // Remove entry from remote hashmap: let mut mc_mutations = Vec::new(); - let mc_mutation = McMutation::RemoveRemotePendingTransaction(cancel_send_funds.request_id); + let mc_mutation = + McMutationOld::RemoveRemotePendingTransaction(cancel_send_funds.request_id); self.mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); @@ -229,7 +230,7 @@ impl OutgoingMc { .checked_sub(freeze_credits) .unwrap(); - let mc_mutation = McMutation::SetRemotePendingDebt(new_remote_pending_debt); + let mc_mutation = McMutationOld::SetRemotePendingDebt(new_remote_pending_debt); self.mutual_credit.mutate(&mc_mutation); mc_mutations.push(mc_mutation); diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index a9b2f9d45..9952f5b84 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -6,6 +6,9 @@ use common::ser_utils::{ser_b64, ser_map_b64_any, ser_string}; use proto::crypto::{PublicKey, Uid}; use proto::funder::messages::{Currency, PendingTransaction}; +use futures::channel::{mpsc, oneshot}; +use futures::SinkExt; + /* // TODO: Where do we need to check this value? /// The maximum possible funder debt. @@ -88,7 +91,7 @@ pub struct MutualCredit { } #[derive(Arbitrary, Eq, PartialEq, Debug, Clone)] -pub enum McMutation { +pub enum McMutationOld { SetBalance(i128), InsertLocalPendingTransaction(PendingTransaction), RemoveLocalPendingTransaction(Uid), @@ -98,6 +101,155 @@ pub enum McMutation { SetRemotePendingDebt(u128), } +#[derive(Debug)] +pub enum McOpError { + SendOpFailed, + ResponseOpFailed(oneshot::Canceled), +} + +pub type McOpResult = Result; +pub type McOpSenderResult = oneshot::Sender>; + +#[derive(Debug)] +pub enum McOp { + GetBalance(McOpSenderResult), + SetBalance(i128, McOpSenderResult<()>), + SetLocalPendingDebt(u128, McOpSenderResult<()>), + SetRemotePendingDebt(u128, McOpSenderResult<()>), + GetLocalPendingTransaction(Uid, McOpSenderResult>), + InsertLocalPendingTransaction(PendingTransaction, McOpSenderResult<()>), + RemoveLocalPendingTransaction(Uid, McOpSenderResult<()>), + GetRemotePendingTransaction(Uid, McOpSenderResult>), + InsertRemotePendingTransaction(PendingTransaction, McOpSenderResult<()>), + RemoveRemotePendingTransaction(Uid, McOpSenderResult<()>), + // Commit(McOpSenderResult<()>), +} + +// TODO: Remove: +#[allow(unused)] +struct McTransaction { + sender: mpsc::Sender, +} + +// TODO: Remove: +#[allow(unused)] +impl McTransaction { + async fn get_balance(&mut self) -> McOpResult { + let (op_sender, op_receiver) = oneshot::channel(); + let op = McOp::GetBalance(op_sender); + self.sender + .send(op) + .await + .map_err(|_| McOpError::SendOpFailed)?; + op_receiver.await.map_err(McOpError::ResponseOpFailed)? + } + async fn set_balance(&mut self, balance: i128) -> McOpResult<()> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = McOp::SetBalance(balance, op_sender); + self.sender + .send(op) + .await + .map_err(|_| McOpError::SendOpFailed)?; + op_receiver.await.map_err(McOpError::ResponseOpFailed)? + } + async fn set_local_pending_debt(&mut self, local_pending_debt: u128) -> McOpResult<()> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = McOp::SetLocalPendingDebt(local_pending_debt, op_sender); + self.sender + .send(op) + .await + .map_err(|_| McOpError::SendOpFailed)?; + op_receiver.await.map_err(McOpError::ResponseOpFailed)? + } + async fn set_remote_pending_debt(&mut self, remote_pending_debt: u128) -> McOpResult<()> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = McOp::SetRemotePendingDebt(remote_pending_debt, op_sender); + self.sender + .send(op) + .await + .map_err(|_| McOpError::SendOpFailed)?; + op_receiver.await.map_err(McOpError::ResponseOpFailed)? + } + async fn get_local_pending_transaction( + &mut self, + request_id: Uid, + ) -> McOpResult> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = McOp::GetLocalPendingTransaction(request_id, op_sender); + self.sender + .send(op) + .await + .map_err(|_| McOpError::SendOpFailed)?; + op_receiver.await.map_err(McOpError::ResponseOpFailed)? + } + async fn insert_local_pending_transaction( + &mut self, + pending_transaction: PendingTransaction, + ) -> McOpResult<()> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = McOp::InsertLocalPendingTransaction(pending_transaction, op_sender); + self.sender + .send(op) + .await + .map_err(|_| McOpError::SendOpFailed)?; + op_receiver.await.map_err(McOpError::ResponseOpFailed)? + } + async fn remove_local_pending_transaction(&mut self, request_id: Uid) -> McOpResult<()> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = McOp::RemoveLocalPendingTransaction(request_id, op_sender); + self.sender + .send(op) + .await + .map_err(|_| McOpError::SendOpFailed)?; + op_receiver.await.map_err(McOpError::ResponseOpFailed)? + } + async fn get_remote_pending_transaction( + &mut self, + request_id: Uid, + ) -> McOpResult> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = McOp::GetRemotePendingTransaction(request_id, op_sender); + self.sender + .send(op) + .await + .map_err(|_| McOpError::SendOpFailed)?; + op_receiver.await.map_err(McOpError::ResponseOpFailed)? + } + async fn insert_remote_pending_transaction( + &mut self, + pending_transaction: PendingTransaction, + ) -> McOpResult<()> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = McOp::InsertRemotePendingTransaction(pending_transaction, op_sender); + self.sender + .send(op) + .await + .map_err(|_| McOpError::SendOpFailed)?; + op_receiver.await.map_err(McOpError::ResponseOpFailed)? + } + async fn remove_remote_pending_transaction(&mut self, request_id: Uid) -> McOpResult<()> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = McOp::RemoveRemotePendingTransaction(request_id, op_sender); + self.sender + .send(op) + .await + .map_err(|_| McOpError::SendOpFailed)?; + op_receiver.await.map_err(McOpError::ResponseOpFailed)? + } + + /* + async fn commit(mut self) -> McOpResult<()> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = McOp::Commit(op_sender); + self.sender + .send(op) + .await + .map_err(|_| McOpError::SendOpFailed)?; + op_receiver.await.map_err(McOpError::ResponseOpFailed)? + } + */ +} + impl MutualCredit { pub fn new( // TODO: Should we move instead of take a reference here? @@ -139,25 +291,25 @@ impl MutualCredit { &self.state } - pub fn mutate(&mut self, mc_mutation: &McMutation) { + pub fn mutate(&mut self, mc_mutation: &McMutationOld) { match mc_mutation { - McMutation::SetBalance(balance) => self.set_balance(*balance), - McMutation::InsertLocalPendingTransaction(pending_friend_request) => { + McMutationOld::SetBalance(balance) => self.set_balance(*balance), + McMutationOld::InsertLocalPendingTransaction(pending_friend_request) => { self.insert_local_pending_transaction(pending_friend_request) } - McMutation::RemoveLocalPendingTransaction(request_id) => { + McMutationOld::RemoveLocalPendingTransaction(request_id) => { self.remove_local_pending_transaction(request_id) } - McMutation::InsertRemotePendingTransaction(pending_friend_request) => { + McMutationOld::InsertRemotePendingTransaction(pending_friend_request) => { self.insert_remote_pending_transaction(pending_friend_request) } - McMutation::RemoveRemotePendingTransaction(request_id) => { + McMutationOld::RemoveRemotePendingTransaction(request_id) => { self.remove_remote_pending_transaction(request_id) } - McMutation::SetLocalPendingDebt(local_pending_debt) => { + McMutationOld::SetLocalPendingDebt(local_pending_debt) => { self.set_local_pending_debt(*local_pending_debt) } - McMutation::SetRemotePendingDebt(remote_pending_debt) => { + McMutationOld::SetRemotePendingDebt(remote_pending_debt) => { self.set_remote_pending_debt(*remote_pending_debt) } } diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 13c08c3aa..a6eb74a71 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -25,7 +25,7 @@ use crate::mutual_credit::incoming::{ process_operations_list, IncomingMessage, ProcessOperationOutput, ProcessTransListError, }; use crate::mutual_credit::outgoing::OutgoingMc; -use crate::mutual_credit::types::{McMutation, MutualCredit}; +use crate::mutual_credit::types::{McMutationOld, MutualCredit}; use crate::types::{create_hashed, create_unsigned_move_token, MoveTokenHashed}; @@ -38,7 +38,7 @@ pub enum SetDirection { #[allow(clippy::large_enum_variant)] #[derive(Arbitrary, Debug, Clone)] pub enum TcMutation { - McMutation((Currency, McMutation)), + McMutation((Currency, McMutationOld)), SetLocalActiveCurrencies(Vec), SetRemoteActiveCurrencies(Vec), AddMutualCredit(Currency), From 8c4b1c3ea2493f74e51ee7a163dd18a13fa2f02f Mon Sep 17 00:00:00 2001 From: real Date: Thu, 8 Oct 2020 14:35:37 +0300 Subject: [PATCH 076/478] funder: mutual_credit (incoming): Changing all func signatures to async --- components/funder/src/lib.rs | 4 ++-- .../funder/src/mutual_credit/incoming.rs | 18 +++++++++--------- components/funder/src/mutual_credit/mod.rs | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 84fde2fcc..6cf45cd2c 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -23,11 +23,11 @@ extern crate quickcheck_derive; // mod funder; // mod handler; // mod liveness; +#[allow(unused)] mod mutual_credit; // pub mod report; // mod state; -#[allow(unused)] -mod token_channel; +// mod token_channel; pub mod types; // #[cfg(test)] diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 6758da3ae..81107ac39 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -56,7 +56,7 @@ pub struct ProcessTransListError { process_trans_error: ProcessOperationError, } -pub fn process_operations_list( +pub async fn process_operations_list( mutual_credit: &mut MutualCredit, operations: Vec, remote_max_debt: u128, @@ -69,7 +69,7 @@ pub fn process_operations_list( // (specifically, HashMaps). for (index, friend_tc_op) in operations.into_iter().enumerate() { - match process_operation(mutual_credit, friend_tc_op, remote_max_debt) { + match process_operation(mutual_credit, friend_tc_op, remote_max_debt).await { Err(e) => { return Err(ProcessTransListError { index, @@ -82,26 +82,26 @@ pub fn process_operations_list( Ok(outputs) } -pub fn process_operation( +pub async fn process_operation( mutual_credit: &mut MutualCredit, friend_tc_op: FriendTcOp, remote_max_debt: u128, ) -> Result { match friend_tc_op { FriendTcOp::RequestSendFunds(request_send_funds) => { - process_request_send_funds(mutual_credit, request_send_funds, remote_max_debt) + process_request_send_funds(mutual_credit, request_send_funds, remote_max_debt).await } FriendTcOp::ResponseSendFunds(response_send_funds) => { - process_response_send_funds(mutual_credit, response_send_funds) + process_response_send_funds(mutual_credit, response_send_funds).await } FriendTcOp::CancelSendFunds(cancel_send_funds) => { - process_cancel_send_funds(mutual_credit, cancel_send_funds) + process_cancel_send_funds(mutual_credit, cancel_send_funds).await } } } /// Process an incoming RequestSendFundsOp -fn process_request_send_funds( +async fn process_request_send_funds( mutual_credit: &mut MutualCredit, request_send_funds: RequestSendFundsOp, remote_max_debt: u128, @@ -171,7 +171,7 @@ fn process_request_send_funds( Ok(op_output) } -fn process_response_send_funds( +async fn process_response_send_funds( mutual_credit: &mut MutualCredit, response_send_funds: ResponseSendFundsOp, ) -> Result { @@ -262,7 +262,7 @@ fn process_response_send_funds( }) } -fn process_cancel_send_funds( +async fn process_cancel_send_funds( mutual_credit: &mut MutualCredit, cancel_send_funds: CancelSendFundsOp, ) -> Result { diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index a3521f69d..14e993f35 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -1,5 +1,5 @@ pub mod incoming; pub mod outgoing; -#[cfg(test)] -mod tests; +// #[cfg(test)] +// mod tests; pub mod types; From f9380a26df83d7c46057401d25913e00dd6f9d07 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 8 Oct 2020 15:13:40 +0300 Subject: [PATCH 077/478] funder: mutual_credit(incoming): Reimplemented with McTransaction --- Cargo.lock | 1 + components/funder/Cargo.toml | 1 + .../funder/src/mutual_credit/incoming.rs | 189 ++++++++---------- components/funder/src/mutual_credit/types.rs | 25 ++- 4 files changed, 95 insertions(+), 121 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fef5f708d..33d9ae638 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1053,6 +1053,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "im 14.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/funder/Cargo.toml b/components/funder/Cargo.toml index 5804c7f74..1bf69f902 100644 --- a/components/funder/Cargo.toml +++ b/components/funder/Cargo.toml @@ -17,6 +17,7 @@ database = { path = "../database", version = "0.1.0", package = "offset-database log = "0.4" pretty_env_logger = "0.2" +derive_more = "0.15.0" bytes = "0.5.4" futures = "0.3.1" diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 81107ac39..6c7f6f48c 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -1,16 +1,21 @@ +use derive_more::From; + use crypto::hash_lock::HashLock; use crypto::identity::verify_signature; use common::safe_arithmetic::SafeSignedArithmetic; +use proto::crypto::PublicKey; use proto::funder::messages::{ - CancelSendFundsOp, FriendTcOp, PendingTransaction, RequestSendFundsOp, ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendTcOp, PendingTransaction, RequestSendFundsOp, + ResponseSendFundsOp, }; + use signature::signature_buff::create_response_signature_buffer; use crate::types::create_pending_transaction; -use super::types::{McMutationOld, MutualCredit}; +use super::types::{McMutationOld, McOpError, McTransaction}; #[derive(Debug)] pub struct IncomingResponseSendFundsOp { @@ -32,13 +37,7 @@ pub enum IncomingMessage { Cancel(IncomingCancelSendFundsOp), } -/// Resulting tasks to perform after processing an incoming operation. -pub struct ProcessOperationOutput { - pub incoming_message: Option, - pub mc_mutations: Vec, -} - -#[derive(Debug)] +#[derive(Debug, From)] pub enum ProcessOperationError { /// The Route contains some public key twice. InvalidRoute, @@ -48,6 +47,7 @@ pub enum ProcessOperationError { InvalidResponseSignature, InvalidSrcPlainLock, DestPaymentExceedsTotal, + McOpError(McOpError), } #[derive(Debug)] @@ -57,55 +57,62 @@ pub struct ProcessTransListError { } pub async fn process_operations_list( - mutual_credit: &mut MutualCredit, + mc: &mut McTransaction, operations: Vec, + currency: &Currency, + remote_public_key: &PublicKey, remote_max_debt: u128, -) -> Result, ProcessTransListError> { +) -> Result, ProcessTransListError> { let mut outputs = Vec::new(); - // We do not change the original MutualCredit. - // Instead, we are operating over a clone: - // This operation is not very expensive, because we are using immutable data structures - // (specifically, HashMaps). - for (index, friend_tc_op) in operations.into_iter().enumerate() { - match process_operation(mutual_credit, friend_tc_op, remote_max_debt).await { + match process_operation( + mc, + friend_tc_op, + currency, + remote_public_key, + remote_max_debt, + ) + .await + { Err(e) => { return Err(ProcessTransListError { index, process_trans_error: e, }) } - Ok(trans_output) => outputs.push(trans_output), + Ok(incoming_message) => outputs.push(incoming_message), } } Ok(outputs) } pub async fn process_operation( - mutual_credit: &mut MutualCredit, + mc: &mut McTransaction, friend_tc_op: FriendTcOp, + currency: &Currency, + remote_public_key: &PublicKey, remote_max_debt: u128, -) -> Result { +) -> Result { match friend_tc_op { FriendTcOp::RequestSendFunds(request_send_funds) => { - process_request_send_funds(mutual_credit, request_send_funds, remote_max_debt).await + process_request_send_funds(mc, request_send_funds, remote_max_debt).await } FriendTcOp::ResponseSendFunds(response_send_funds) => { - process_response_send_funds(mutual_credit, response_send_funds).await + process_response_send_funds(mc, response_send_funds, currency, remote_public_key).await } FriendTcOp::CancelSendFunds(cancel_send_funds) => { - process_cancel_send_funds(mutual_credit, cancel_send_funds).await + process_cancel_send_funds(mc, cancel_send_funds).await } } } /// Process an incoming RequestSendFundsOp async fn process_request_send_funds( - mutual_credit: &mut MutualCredit, + mc: &mut McTransaction, request_send_funds: RequestSendFundsOp, remote_max_debt: u128, -) -> Result { +) -> Result { if !request_send_funds.route.is_part_valid() { return Err(ProcessOperationError::InvalidRoute); } @@ -115,8 +122,10 @@ async fn process_request_send_funds( } // Make sure that we don't have this request as a pending request already: - let p_remote_requests = &mutual_credit.state().pending_transactions.remote; - if p_remote_requests.contains_key(&request_send_funds.request_id) { + let opt_remote_pending_transaction = mc + .get_remote_pending_transaction(request_send_funds.request_id.clone()) + .await?; + if opt_remote_pending_transaction.is_some() { return Err(ProcessOperationError::RequestAlreadyExists); } @@ -127,15 +136,15 @@ async fn process_request_send_funds( .ok_or(ProcessOperationError::CreditsCalcOverflow)?; // Make sure we can freeze the credits - let balance = &mutual_credit.state().balance; + let mc_balance = mc.get_balance().await?; - let new_remote_pending_debt = balance + let new_remote_pending_debt = mc_balance .remote_pending_debt .checked_add(own_freeze_credits) .ok_or(ProcessOperationError::CreditsCalcOverflow)?; // Check that local_pending_debt - balance <= local_max_debt: - let add = balance + let add = mc_balance .balance .checked_add_unsigned(new_remote_pending_debt) .ok_or(ProcessOperationError::CreditsCalcOverflow)?; @@ -154,37 +163,28 @@ async fn process_request_send_funds( // Add pending transaction: let pending_transaction = create_pending_transaction(&request_send_funds); - let mut op_output = ProcessOperationOutput { - incoming_message: Some(incoming_message), - mc_mutations: Vec::new(), - }; - - let mc_mutation = McMutationOld::InsertRemotePendingTransaction(pending_transaction); - mutual_credit.mutate(&mc_mutation); - op_output.mc_mutations.push(mc_mutation); - + mc.insert_remote_pending_transaction(pending_transaction) + .await?; // If we are here, we can freeze the credits: - let mc_mutation = McMutationOld::SetRemotePendingDebt(new_remote_pending_debt); - mutual_credit.mutate(&mc_mutation); - op_output.mc_mutations.push(mc_mutation); + mc.set_remote_pending_debt(new_remote_pending_debt).await?; - Ok(op_output) + Ok(incoming_message) } async fn process_response_send_funds( - mutual_credit: &mut MutualCredit, + mc: &mut McTransaction, response_send_funds: ResponseSendFundsOp, -) -> Result { + currency: &Currency, + remote_public_key: &PublicKey, +) -> Result { // Make sure that id exists in local_pending hashmap, // and access saved request details. - let local_pending_transactions = &mutual_credit.state().pending_transactions.local; // Obtain pending request: - // TODO: Possibly get rid of clone() here for optimization later - let pending_transaction = local_pending_transactions - .get(&response_send_funds.request_id) - .ok_or(ProcessOperationError::RequestDoesNotExist)? - .clone(); + let pending_transaction = mc + .get_local_pending_transaction(response_send_funds.request_id.clone()) + .await? + .ok_or(ProcessOperationError::RequestDoesNotExist)?; // Verify src_plain_lock and dest_plain_lock: if response_send_funds.src_plain_lock.hash_lock() != pending_transaction.src_hashed_lock { @@ -192,13 +192,13 @@ async fn process_response_send_funds( } let dest_public_key = if pending_transaction.route.public_keys.is_empty() { - &mutual_credit.state().idents.remote_public_key + remote_public_key } else { pending_transaction.route.public_keys.last().unwrap() }; let response_signature_buffer = create_response_signature_buffer( - &mutual_credit.state().currency, + currency, response_send_funds.clone(), &pending_transaction, ); @@ -220,96 +220,65 @@ async fn process_response_send_funds( // Note: The unwrap() above should never fail, because this was already checked during the // request message processing. - let mut mc_mutations = Vec::new(); - // Remove entry from local_pending hashmap: - let mc_mutation = - McMutationOld::RemoveLocalPendingTransaction(response_send_funds.request_id.clone()); - mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); - - // Decrease frozen credits and decrease balance: - let new_local_pending_debt = mutual_credit - .state() - .balance + mc.remove_local_pending_transaction(response_send_funds.request_id.clone()) + .await?; + + // Decrease frozen credits: + let mc_balance = mc.get_balance().await?; + let new_local_pending_debt = mc_balance .local_pending_debt .checked_sub(freeze_credits) .unwrap(); + mc.set_local_pending_debt(new_local_pending_debt).await?; - let mc_mutation = McMutationOld::SetLocalPendingDebt(new_local_pending_debt); - mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); - - let new_balance = mutual_credit - .state() - .balance + // Decrease balance: + let mc_balance = mc.get_balance().await?; + let new_balance = mc_balance .balance .checked_sub_unsigned(freeze_credits) .unwrap(); + mc.set_balance(new_balance).await?; - let mc_mutation = McMutationOld::SetBalance(new_balance); - mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); - - let incoming_message = Some(IncomingMessage::Response(IncomingResponseSendFundsOp { + Ok(IncomingMessage::Response(IncomingResponseSendFundsOp { pending_transaction, incoming_response: response_send_funds, - })); - - Ok(ProcessOperationOutput { - incoming_message, - mc_mutations, - }) + })) } async fn process_cancel_send_funds( - mutual_credit: &mut MutualCredit, + mc: &mut McTransaction, cancel_send_funds: CancelSendFundsOp, -) -> Result { +) -> Result { // Make sure that id exists in local_pending hashmap, // and access saved request details. - let local_pending_transactions = &mutual_credit.state().pending_transactions.local; // Obtain pending request: - let pending_transaction = local_pending_transactions - .get(&cancel_send_funds.request_id) - .ok_or(ProcessOperationError::RequestDoesNotExist)? - .clone(); - // TODO: Possibly get rid of clone() here for optimization later - - let mut mc_mutations = Vec::new(); + let pending_transaction = mc + .get_local_pending_transaction(cancel_send_funds.request_id.clone()) + .await? + .ok_or(ProcessOperationError::RequestDoesNotExist)?; - // Remove entry from local_pending hashmap: - let mc_mutation = - McMutationOld::RemoveLocalPendingTransaction(cancel_send_funds.request_id.clone()); - mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); + mc.remove_local_pending_transaction(cancel_send_funds.request_id.clone()) + .await?; let freeze_credits = pending_transaction .dest_payment .checked_add(pending_transaction.left_fees) .unwrap(); + let mc_balance = mc.get_balance().await?; // Decrease frozen credits: - let new_local_pending_debt = mutual_credit - .state() - .balance + let new_local_pending_debt = mc_balance .local_pending_debt .checked_sub(freeze_credits) .unwrap(); - let mc_mutation = McMutationOld::SetLocalPendingDebt(new_local_pending_debt); - mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); + mc.set_local_pending_debt(new_local_pending_debt).await?; // Return cancel_send_funds: - let incoming_message = Some(IncomingMessage::Cancel(IncomingCancelSendFundsOp { + Ok(IncomingMessage::Cancel(IncomingCancelSendFundsOp { pending_transaction, incoming_cancel: cancel_send_funds, - })); - - Ok(ProcessOperationOutput { - incoming_message, - mc_mutations, - }) + })) } diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 9952f5b84..f1cbb56f6 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -127,14 +127,17 @@ pub enum McOp { // TODO: Remove: #[allow(unused)] -struct McTransaction { +pub struct McTransaction { sender: mpsc::Sender, } // TODO: Remove: #[allow(unused)] impl McTransaction { - async fn get_balance(&mut self) -> McOpResult { + pub fn new(sender: mpsc::Sender) -> Self { + Self { sender } + } + pub async fn get_balance(&mut self) -> McOpResult { let (op_sender, op_receiver) = oneshot::channel(); let op = McOp::GetBalance(op_sender); self.sender @@ -143,7 +146,7 @@ impl McTransaction { .map_err(|_| McOpError::SendOpFailed)?; op_receiver.await.map_err(McOpError::ResponseOpFailed)? } - async fn set_balance(&mut self, balance: i128) -> McOpResult<()> { + pub async fn set_balance(&mut self, balance: i128) -> McOpResult<()> { let (op_sender, op_receiver) = oneshot::channel(); let op = McOp::SetBalance(balance, op_sender); self.sender @@ -152,7 +155,7 @@ impl McTransaction { .map_err(|_| McOpError::SendOpFailed)?; op_receiver.await.map_err(McOpError::ResponseOpFailed)? } - async fn set_local_pending_debt(&mut self, local_pending_debt: u128) -> McOpResult<()> { + pub async fn set_local_pending_debt(&mut self, local_pending_debt: u128) -> McOpResult<()> { let (op_sender, op_receiver) = oneshot::channel(); let op = McOp::SetLocalPendingDebt(local_pending_debt, op_sender); self.sender @@ -161,7 +164,7 @@ impl McTransaction { .map_err(|_| McOpError::SendOpFailed)?; op_receiver.await.map_err(McOpError::ResponseOpFailed)? } - async fn set_remote_pending_debt(&mut self, remote_pending_debt: u128) -> McOpResult<()> { + pub async fn set_remote_pending_debt(&mut self, remote_pending_debt: u128) -> McOpResult<()> { let (op_sender, op_receiver) = oneshot::channel(); let op = McOp::SetRemotePendingDebt(remote_pending_debt, op_sender); self.sender @@ -170,7 +173,7 @@ impl McTransaction { .map_err(|_| McOpError::SendOpFailed)?; op_receiver.await.map_err(McOpError::ResponseOpFailed)? } - async fn get_local_pending_transaction( + pub async fn get_local_pending_transaction( &mut self, request_id: Uid, ) -> McOpResult> { @@ -182,7 +185,7 @@ impl McTransaction { .map_err(|_| McOpError::SendOpFailed)?; op_receiver.await.map_err(McOpError::ResponseOpFailed)? } - async fn insert_local_pending_transaction( + pub async fn insert_local_pending_transaction( &mut self, pending_transaction: PendingTransaction, ) -> McOpResult<()> { @@ -194,7 +197,7 @@ impl McTransaction { .map_err(|_| McOpError::SendOpFailed)?; op_receiver.await.map_err(McOpError::ResponseOpFailed)? } - async fn remove_local_pending_transaction(&mut self, request_id: Uid) -> McOpResult<()> { + pub async fn remove_local_pending_transaction(&mut self, request_id: Uid) -> McOpResult<()> { let (op_sender, op_receiver) = oneshot::channel(); let op = McOp::RemoveLocalPendingTransaction(request_id, op_sender); self.sender @@ -203,7 +206,7 @@ impl McTransaction { .map_err(|_| McOpError::SendOpFailed)?; op_receiver.await.map_err(McOpError::ResponseOpFailed)? } - async fn get_remote_pending_transaction( + pub async fn get_remote_pending_transaction( &mut self, request_id: Uid, ) -> McOpResult> { @@ -215,7 +218,7 @@ impl McTransaction { .map_err(|_| McOpError::SendOpFailed)?; op_receiver.await.map_err(McOpError::ResponseOpFailed)? } - async fn insert_remote_pending_transaction( + pub async fn insert_remote_pending_transaction( &mut self, pending_transaction: PendingTransaction, ) -> McOpResult<()> { @@ -227,7 +230,7 @@ impl McTransaction { .map_err(|_| McOpError::SendOpFailed)?; op_receiver.await.map_err(McOpError::ResponseOpFailed)? } - async fn remove_remote_pending_transaction(&mut self, request_id: Uid) -> McOpResult<()> { + pub async fn remove_remote_pending_transaction(&mut self, request_id: Uid) -> McOpResult<()> { let (op_sender, op_receiver) = oneshot::channel(); let op = McOp::RemoveRemotePendingTransaction(request_id, op_sender); self.sender From a2646fda3d1a492addcebabc8dba26281fd5aba4 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 8 Oct 2020 17:57:51 +0300 Subject: [PATCH 078/478] funder: mutual_credit(outgoing): Ported to use McTransaction --- .../funder/src/mutual_credit/incoming.rs | 2 +- .../funder/src/mutual_credit/outgoing.rs | 152 +++++++++--------- components/funder/src/mutual_credit/types.rs | 1 + 3 files changed, 77 insertions(+), 78 deletions(-) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 6c7f6f48c..40ed07808 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -15,7 +15,7 @@ use signature::signature_buff::create_response_signature_buffer; use crate::types::create_pending_transaction; -use super::types::{McMutationOld, McOpError, McTransaction}; +use super::types::{McOpError, McTransaction}; #[derive(Debug)] pub struct IncomingResponseSendFundsOp { diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 1bd0f5cfa..7c0005062 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -1,25 +1,30 @@ +use derive_more::From; + use crypto::hash_lock::HashLock; use crypto::identity::verify_signature; use common::safe_arithmetic::SafeSignedArithmetic; +use proto::crypto::PublicKey; use proto::funder::messages::{ - CancelSendFundsOp, FriendTcOp, RequestSendFundsOp, ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendTcOp, RequestSendFundsOp, ResponseSendFundsOp, }; use signature::signature_buff::create_response_signature_buffer; use crate::types::create_pending_transaction; -use super::types::{McMutationOld, MutualCredit}; +use super::types::{McOpError, McTransaction}; /// Processes outgoing funds for a token channel. /// Used to batch as many funds as possible. #[derive(Debug)] pub struct OutgoingMc { - mutual_credit: MutualCredit, + mc: McTransaction, + currency: Currency, + local_public_key: PublicKey, } -#[derive(Debug)] +#[derive(Debug, From)] pub enum QueueOperationError { // RemoteMaxDebtTooLarge, InvalidRoute, @@ -30,39 +35,42 @@ pub enum QueueOperationError { InvalidResponseSignature, InvalidSrcPlainLock, DestPaymentExceedsTotal, + McOpError(McOpError), } /// A wrapper over a token channel, accumulating operations to be sent as one transaction. impl OutgoingMc { // TODO: Take MutualCredit instead of &MutualCredit? - pub fn new(mutual_credit: &MutualCredit) -> OutgoingMc { + pub fn new(mc: McTransaction, currency: Currency, local_public_key: PublicKey) -> OutgoingMc { OutgoingMc { - mutual_credit: mutual_credit.clone(), + mc, + currency, + local_public_key, } } - pub fn queue_operation( + pub async fn queue_operation( &mut self, operation: &FriendTcOp, - ) -> Result, QueueOperationError> { + ) -> Result<(), QueueOperationError> { // TODO: Maybe remove clone from here later: match operation.clone() { FriendTcOp::RequestSendFunds(request_send_funds) => { - self.queue_request_send_funds(request_send_funds) + self.queue_request_send_funds(request_send_funds).await } FriendTcOp::ResponseSendFunds(response_send_funds) => { - self.queue_response_send_funds(response_send_funds) + self.queue_response_send_funds(response_send_funds).await } FriendTcOp::CancelSendFunds(cancel_send_funds) => { - self.queue_cancel_send_funds(cancel_send_funds) + self.queue_cancel_send_funds(cancel_send_funds).await } } } - fn queue_request_send_funds( + async fn queue_request_send_funds( &mut self, request_send_funds: RequestSendFundsOp, - ) -> Result, QueueOperationError> { + ) -> Result<(), QueueOperationError> { if !request_send_funds.route.is_part_valid() { return Err(QueueOperationError::InvalidRoute); } @@ -77,50 +85,51 @@ impl OutgoingMc { .checked_add(request_send_funds.left_fees) .ok_or(QueueOperationError::CreditsCalcOverflow)?; - let balance = &self.mutual_credit.state().balance; + let mc_balance = self.mc.get_balance().await?; // Make sure we can freeze the credits - let new_local_pending_debt = balance + let new_local_pending_debt = mc_balance .local_pending_debt .checked_add(own_freeze_credits) .ok_or(QueueOperationError::CreditsCalcOverflow)?; - let p_local_requests = &self.mutual_credit.state().pending_transactions.local; - // Make sure that we don't have this request as a pending request already: - if p_local_requests.contains_key(&request_send_funds.request_id) { + if self + .mc + .get_local_pending_transaction(request_send_funds.request_id.clone()) + .await? + .is_some() + { return Err(QueueOperationError::RequestAlreadyExists); } // Add pending transaction: let pending_transaction = create_pending_transaction(&request_send_funds); - - let mut mc_mutations = Vec::new(); - let mc_mutation = McMutationOld::InsertLocalPendingTransaction(pending_transaction); - self.mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); + self.mc + .insert_local_pending_transaction(pending_transaction) + .await?; // If we are here, we can freeze the credits: - let mc_mutation = McMutationOld::SetLocalPendingDebt(new_local_pending_debt); - self.mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); + self.mc + .set_local_pending_debt(new_local_pending_debt) + .await?; - Ok(mc_mutations) + Ok(()) } - fn queue_response_send_funds( + async fn queue_response_send_funds( &mut self, response_send_funds: ResponseSendFundsOp, - ) -> Result, QueueOperationError> { + ) -> Result<(), QueueOperationError> { // Make sure that id exists in remote_pending hashmap, // and access saved request details. - let remote_pending_transactions = &self.mutual_credit.state().pending_transactions.remote; // Obtain pending request: - let pending_transaction = remote_pending_transactions - .get(&response_send_funds.request_id) - .ok_or(QueueOperationError::RequestDoesNotExist)? - .clone(); + let pending_transaction = self + .mc + .get_remote_pending_transaction(response_send_funds.request_id.clone()) + .await? + .ok_or(QueueOperationError::RequestDoesNotExist)?; // TODO: Possibly get rid of clone() here for optimization later // Verify src_plain_lock and dest_plain_lock: @@ -130,13 +139,13 @@ impl OutgoingMc { // verify signature: let response_signature_buffer = create_response_signature_buffer( - &self.mutual_credit.state().currency, + &self.currency, response_send_funds.clone(), &pending_transaction, ); // The response was signed by the destination node: let dest_public_key = if pending_transaction.route.public_keys.is_empty() { - &self.mutual_credit.state().idents.local_public_key + &self.local_public_key } else { pending_transaction.route.public_keys.last().unwrap() }; @@ -157,55 +166,49 @@ impl OutgoingMc { .unwrap(); // Remove entry from remote_pending hashmap: - let mut mc_mutations = Vec::new(); - let mc_mutation = - McMutationOld::RemoveRemotePendingTransaction(response_send_funds.request_id); - self.mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); - - // Decrease frozen credits and increase balance: - let new_remote_pending_debt = self - .mutual_credit - .state() - .balance + self.mc + .remove_remote_pending_transaction(response_send_funds.request_id) + .await?; + + // Decrease frozen credits + let mc_balance = self.mc.get_balance().await?; + let new_remote_pending_debt = mc_balance .remote_pending_debt .checked_sub(freeze_credits) .unwrap(); // Above unwrap() should never fail. This was already checked when a request message was // received. - let mc_mutation = McMutationOld::SetRemotePendingDebt(new_remote_pending_debt); - self.mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); + self.mc + .set_remote_pending_debt(new_remote_pending_debt) + .await?; - let new_balance = self - .mutual_credit - .state() - .balance + // Increase balance: + let mc_balance = self.mc.get_balance().await?; + let new_balance = mc_balance .balance .checked_add_unsigned(freeze_credits) .unwrap(); // Above unwrap() should never fail. This was already checked when a request message was // received. - let mc_mutation = McMutationOld::SetBalance(new_balance); - self.mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); + self.mc.set_balance(new_balance).await?; - Ok(mc_mutations) + Ok(()) } - fn queue_cancel_send_funds( + async fn queue_cancel_send_funds( &mut self, cancel_send_funds: CancelSendFundsOp, - ) -> Result, QueueOperationError> { + ) -> Result<(), QueueOperationError> { // Make sure that id exists in remote_pending hashmap, // and access saved request details. - let remote_pending_transactions = &self.mutual_credit.state().pending_transactions.remote; // Obtain pending request: - let pending_transaction = remote_pending_transactions - .get(&cancel_send_funds.request_id) + let pending_transaction = self + .mc + .get_remote_pending_transaction(cancel_send_funds.request_id.clone()) + .await? .ok_or(QueueOperationError::RequestDoesNotExist)?; let freeze_credits = pending_transaction @@ -214,26 +217,21 @@ impl OutgoingMc { .unwrap(); // Remove entry from remote hashmap: - let mut mc_mutations = Vec::new(); - - let mc_mutation = - McMutationOld::RemoveRemotePendingTransaction(cancel_send_funds.request_id); - self.mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); + self.mc + .remove_remote_pending_transaction(cancel_send_funds.request_id.clone()) + .await?; // Decrease frozen credits: - let new_remote_pending_debt = self - .mutual_credit - .state() - .balance + let mc_balance = self.mc.get_balance().await?; + let new_remote_pending_debt = mc_balance .remote_pending_debt .checked_sub(freeze_credits) .unwrap(); - let mc_mutation = McMutationOld::SetRemotePendingDebt(new_remote_pending_debt); - self.mutual_credit.mutate(&mc_mutation); - mc_mutations.push(mc_mutation); + self.mc + .set_remote_pending_debt(new_remote_pending_debt) + .await?; - Ok(mc_mutations) + Ok(()) } } diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index f1cbb56f6..c7b3052e8 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -127,6 +127,7 @@ pub enum McOp { // TODO: Remove: #[allow(unused)] +#[derive(Debug)] pub struct McTransaction { sender: mpsc::Sender, } From f5b0bc40d24f6b0250419b23e290cabd2b7a7b65 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 8 Oct 2020 18:03:03 +0300 Subject: [PATCH 079/478] funder: Moved around some 'unused' hints. Not done yet. --- components/funder/src/lib.rs | 1 - components/funder/src/mutual_credit/incoming.rs | 2 ++ components/funder/src/mutual_credit/mod.rs | 3 +++ components/funder/src/mutual_credit/outgoing.rs | 6 +++++- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 6cf45cd2c..d9f3b4c41 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -23,7 +23,6 @@ extern crate quickcheck_derive; // mod funder; // mod handler; // mod liveness; -#[allow(unused)] mod mutual_credit; // pub mod report; // mod state; diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 40ed07808..710802d09 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -56,6 +56,8 @@ pub struct ProcessTransListError { process_trans_error: ProcessOperationError, } +// TODO: Remove later: +#[allow(unused)] pub async fn process_operations_list( mc: &mut McTransaction, operations: Vec, diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index 14e993f35..b49fd06ce 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -1,5 +1,8 @@ +#[allow(unused)] pub mod incoming; +#[allow(unused)] pub mod outgoing; // #[cfg(test)] // mod tests; +#[allow(unused)] pub mod types; diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 7c0005062..3e47cff75 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -38,9 +38,11 @@ pub enum QueueOperationError { McOpError(McOpError), } +#[allow(unused)] /// A wrapper over a token channel, accumulating operations to be sent as one transaction. impl OutgoingMc { - // TODO: Take MutualCredit instead of &MutualCredit? + // TODO: Remove later: + #[allow(unused)] pub fn new(mc: McTransaction, currency: Currency, local_public_key: PublicKey) -> OutgoingMc { OutgoingMc { mc, @@ -49,6 +51,8 @@ impl OutgoingMc { } } + // TODO: Remove later: + #[allow(unused)] pub async fn queue_operation( &mut self, operation: &FriendTcOp, From 0fbce1bf061ab745d1698e8c6872a4e26bad1609 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 13:55:32 +0300 Subject: [PATCH 080/478] funder: mutual_credit: Initial refactoring of tests --- components/funder/src/mutual_credit/mod.rs | 4 +- components/funder/src/mutual_credit/tests.rs | 191 ------------------ .../funder/src/mutual_credit/tests/mod.rs | 4 + .../tests/request_cancel_send_funds.rs | 65 ++++++ .../tests/request_response_send_funds.rs | 81 ++++++++ .../funder/src/mutual_credit/tests/utils.rs | 125 ++++++++++++ components/funder/src/mutual_credit/types.rs | 172 ++-------------- 7 files changed, 289 insertions(+), 353 deletions(-) delete mode 100644 components/funder/src/mutual_credit/tests.rs create mode 100644 components/funder/src/mutual_credit/tests/mod.rs create mode 100644 components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs create mode 100644 components/funder/src/mutual_credit/tests/request_response_send_funds.rs create mode 100644 components/funder/src/mutual_credit/tests/utils.rs diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index b49fd06ce..e7843dde5 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -2,7 +2,7 @@ pub mod incoming; #[allow(unused)] pub mod outgoing; -// #[cfg(test)] -// mod tests; +#[cfg(test)] +mod tests; #[allow(unused)] pub mod types; diff --git a/components/funder/src/mutual_credit/tests.rs b/components/funder/src/mutual_credit/tests.rs deleted file mode 100644 index 033a7e9d7..000000000 --- a/components/funder/src/mutual_credit/tests.rs +++ /dev/null @@ -1,191 +0,0 @@ -use std::convert::TryFrom; - -use crypto::hash_lock::HashLock; -use crypto::identity::{Identity, SoftwareEd25519Identity}; -use crypto::rand::RandGen; -use crypto::test_utils::DummyRandom; - -use proto::crypto::{HashResult, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid}; -use proto::funder::messages::{ - CancelSendFundsOp, Currency, FriendTcOp, FriendsRoute, RequestSendFundsOp, ResponseSendFundsOp, -}; -use signature::signature_buff::create_response_signature_buffer; - -use crate::types::create_pending_transaction; - -use crate::mutual_credit::incoming::{ - process_operation, ProcessOperationError, ProcessOperationOutput, -}; -use crate::mutual_credit::outgoing::{OutgoingMc, QueueOperationError}; -use crate::mutual_credit::types::MutualCredit; - -/// Helper function for applying an outgoing operation over a token channel. -fn apply_outgoing( - mutual_credit: &mut MutualCredit, - friend_tc_op: &FriendTcOp, -) -> Result<(), QueueOperationError> { - let mut outgoing = OutgoingMc::new(mutual_credit); - let mutations = outgoing.queue_operation(friend_tc_op)?; - - for mutation in mutations { - mutual_credit.mutate(&mutation); - } - Ok(()) -} - -/// Helper function for applying an incoming operation over a token channel. -fn apply_incoming( - mut mutual_credit: &mut MutualCredit, - friend_tc_op: FriendTcOp, - remote_max_debt: u128, -) -> Result { - process_operation(&mut mutual_credit, friend_tc_op, remote_max_debt) -} - -#[test] -fn test_request_response_send_funds() { - let currency = Currency::try_from("FST".to_owned()).unwrap(); - - let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); - let remote_public_key = PublicKey::from(&[0xbb; PublicKey::len()]); - let balance = 0; - let mut mutual_credit = - MutualCredit::new(&local_public_key, &remote_public_key, ¤cy, balance); - - // -----[RequestSendFunds]-------- - // ----------------------------- - let mut rng = DummyRandom::new(&[1u8]); - let private_key = PrivateKey::rand_gen(&mut rng); - let identity = SoftwareEd25519Identity::from_private_key(&private_key).unwrap(); - let public_key_c = identity.get_public_key(); - - let request_id = Uid::from(&[3; Uid::len()]); - let route = FriendsRoute { - public_keys: vec![ - PublicKey::from(&[0xaa; PublicKey::len()]), - PublicKey::from(&[0xbb; PublicKey::len()]), - public_key_c.clone(), - ], - }; - let invoice_hash = HashResult::from(&[0; HashResult::len()]); - let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); - let hmac = HmacResult::from(&[2; HmacResult::len()]); - - let request_send_funds = RequestSendFundsOp { - request_id: request_id.clone(), - src_hashed_lock: src_plain_lock.hash_lock(), - route, - dest_payment: 10, - total_dest_payment: 10, - invoice_hash, - hmac, - left_fees: 5, - }; - - let pending_transaction = create_pending_transaction(&request_send_funds); - apply_outgoing( - &mut mutual_credit, - &FriendTcOp::RequestSendFunds(request_send_funds), - ) - .unwrap(); - - assert_eq!(mutual_credit.state().balance.balance, 0); - assert_eq!(mutual_credit.state().balance.local_pending_debt, 10 + 5); - assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); - - // -----[ResponseSendFunds]-------- - // -------------------------------- - let serial_num: u128 = 0; - - let mut response_send_funds = ResponseSendFundsOp { - request_id: request_id.clone(), - src_plain_lock: src_plain_lock.clone(), - serial_num, - signature: Signature::from(&[0; Signature::len()]), - }; - - let sign_buffer = create_response_signature_buffer( - ¤cy, - response_send_funds.clone(), - &pending_transaction, - ); - response_send_funds.signature = identity.sign(&sign_buffer); - - apply_incoming( - &mut mutual_credit, - FriendTcOp::ResponseSendFunds(response_send_funds), - 100, - ) - .unwrap(); - - // We expect that the balance has updated: - assert_eq!(mutual_credit.state().balance.balance, -15); - assert_eq!(mutual_credit.state().balance.local_pending_debt, 0); - assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); -} - -#[test] -fn test_request_cancel_send_funds() { - let currency = Currency::try_from("FST".to_owned()).unwrap(); - - let mut rng = DummyRandom::new(&[1u8]); - let private_key = PrivateKey::rand_gen(&mut rng); - let identity = SoftwareEd25519Identity::from_private_key(&private_key).unwrap(); - let public_key_b = identity.get_public_key(); - - let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); - let remote_public_key = public_key_b.clone(); - let balance = 0; - let mut mutual_credit = - MutualCredit::new(&local_public_key, &remote_public_key, ¤cy, balance); - - // -----[RequestSendFunds]-------- - // ----------------------------- - let request_id = Uid::from(&[3; Uid::len()]); - let route = FriendsRoute { - public_keys: vec![ - PublicKey::from(&[0xaa; PublicKey::len()]), - public_key_b.clone(), - PublicKey::from(&[0xcc; PublicKey::len()]), - ], - }; - let invoice_hash = HashResult::from(&[0; HashResult::len()]); - let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); - let hmac = HmacResult::from(&[2; HmacResult::len()]); - - let request_send_funds = RequestSendFundsOp { - request_id: request_id.clone(), - src_hashed_lock: src_plain_lock.hash_lock(), - route, - dest_payment: 10, - total_dest_payment: 10, - invoice_hash, - hmac, - left_fees: 5, - }; - - apply_outgoing( - &mut mutual_credit, - &FriendTcOp::RequestSendFunds(request_send_funds), - ) - .unwrap(); - - assert_eq!(mutual_credit.state().balance.balance, 0); - assert_eq!(mutual_credit.state().balance.local_pending_debt, 10 + 5); - assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); - - // -----[CancelSendFunds]-------- - // ------------------------------ - let cancel_send_funds = CancelSendFundsOp { request_id }; - - apply_incoming( - &mut mutual_credit, - FriendTcOp::CancelSendFunds(cancel_send_funds), - 100, - ) - .unwrap(); - - assert_eq!(mutual_credit.state().balance.balance, 0); - assert_eq!(mutual_credit.state().balance.local_pending_debt, 0); - assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); -} diff --git a/components/funder/src/mutual_credit/tests/mod.rs b/components/funder/src/mutual_credit/tests/mod.rs new file mode 100644 index 000000000..5bf793f12 --- /dev/null +++ b/components/funder/src/mutual_credit/tests/mod.rs @@ -0,0 +1,4 @@ +// mod request_cancel_send_funds; +// mod request_response_send_funds; +#[allow(unused)] +mod utils; diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs new file mode 100644 index 000000000..a5930a85f --- /dev/null +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -0,0 +1,65 @@ +#[test] +fn test_request_cancel_send_funds() { + let currency = Currency::try_from("FST".to_owned()).unwrap(); + + let mut rng = DummyRandom::new(&[1u8]); + let private_key = PrivateKey::rand_gen(&mut rng); + let identity = SoftwareEd25519Identity::from_private_key(&private_key).unwrap(); + let public_key_b = identity.get_public_key(); + + let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); + let remote_public_key = public_key_b.clone(); + let balance = 0; + let mut mutual_credit = + MutualCredit::new(&local_public_key, &remote_public_key, ¤cy, balance); + + // -----[RequestSendFunds]-------- + // ----------------------------- + let request_id = Uid::from(&[3; Uid::len()]); + let route = FriendsRoute { + public_keys: vec![ + PublicKey::from(&[0xaa; PublicKey::len()]), + public_key_b.clone(), + PublicKey::from(&[0xcc; PublicKey::len()]), + ], + }; + let invoice_hash = HashResult::from(&[0; HashResult::len()]); + let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); + let hmac = HmacResult::from(&[2; HmacResult::len()]); + + let request_send_funds = RequestSendFundsOp { + request_id: request_id.clone(), + src_hashed_lock: src_plain_lock.hash_lock(), + route, + dest_payment: 10, + total_dest_payment: 10, + invoice_hash, + hmac, + left_fees: 5, + }; + + apply_outgoing( + &mut mutual_credit, + &FriendTcOp::RequestSendFunds(request_send_funds), + ) + .unwrap(); + + assert_eq!(mutual_credit.state().balance.balance, 0); + assert_eq!(mutual_credit.state().balance.local_pending_debt, 10 + 5); + assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); + + // -----[CancelSendFunds]-------- + // ------------------------------ + let cancel_send_funds = CancelSendFundsOp { request_id }; + + apply_incoming( + &mut mutual_credit, + FriendTcOp::CancelSendFunds(cancel_send_funds), + 100, + ) + .unwrap(); + + assert_eq!(mutual_credit.state().balance.balance, 0); + assert_eq!(mutual_credit.state().balance.local_pending_debt, 0); + assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); +} diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs new file mode 100644 index 000000000..4636ed598 --- /dev/null +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -0,0 +1,81 @@ +#[test] +fn test_request_response_send_funds() { + let currency = Currency::try_from("FST".to_owned()).unwrap(); + + let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); + let remote_public_key = PublicKey::from(&[0xbb; PublicKey::len()]); + let balance = 0; + let mut mutual_credit = + MutualCredit::new(&local_public_key, &remote_public_key, ¤cy, balance); + + // -----[RequestSendFunds]-------- + // ----------------------------- + let mut rng = DummyRandom::new(&[1u8]); + let private_key = PrivateKey::rand_gen(&mut rng); + let identity = SoftwareEd25519Identity::from_private_key(&private_key).unwrap(); + let public_key_c = identity.get_public_key(); + + let request_id = Uid::from(&[3; Uid::len()]); + let route = FriendsRoute { + public_keys: vec![ + PublicKey::from(&[0xaa; PublicKey::len()]), + PublicKey::from(&[0xbb; PublicKey::len()]), + public_key_c.clone(), + ], + }; + let invoice_hash = HashResult::from(&[0; HashResult::len()]); + let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); + let hmac = HmacResult::from(&[2; HmacResult::len()]); + + let request_send_funds = RequestSendFundsOp { + request_id: request_id.clone(), + src_hashed_lock: src_plain_lock.hash_lock(), + route, + dest_payment: 10, + total_dest_payment: 10, + invoice_hash, + hmac, + left_fees: 5, + }; + + let pending_transaction = create_pending_transaction(&request_send_funds); + apply_outgoing( + &mut mutual_credit, + &FriendTcOp::RequestSendFunds(request_send_funds), + ) + .unwrap(); + + assert_eq!(mutual_credit.state().balance.balance, 0); + assert_eq!(mutual_credit.state().balance.local_pending_debt, 10 + 5); + assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); + + // -----[ResponseSendFunds]-------- + // -------------------------------- + let serial_num: u128 = 0; + + let mut response_send_funds = ResponseSendFundsOp { + request_id: request_id.clone(), + src_plain_lock: src_plain_lock.clone(), + serial_num, + signature: Signature::from(&[0; Signature::len()]), + }; + + let sign_buffer = create_response_signature_buffer( + ¤cy, + response_send_funds.clone(), + &pending_transaction, + ); + response_send_funds.signature = identity.sign(&sign_buffer); + + apply_incoming( + &mut mutual_credit, + FriendTcOp::ResponseSendFunds(response_send_funds), + 100, + ) + .unwrap(); + + // We expect that the balance has updated: + assert_eq!(mutual_credit.state().balance.balance, -15); + assert_eq!(mutual_credit.state().balance.local_pending_debt, 0); + assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); +} diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs new file mode 100644 index 000000000..4ede31f3c --- /dev/null +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -0,0 +1,125 @@ +// use std::convert::TryFrom; + +use std::collections::HashMap; + +use crypto::hash_lock::HashLock; +use crypto::identity::{Identity, SoftwareEd25519Identity}; +use crypto::rand::RandGen; +use crypto::test_utils::DummyRandom; + +use proto::crypto::{HashResult, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid}; +use proto::funder::messages::{ + CancelSendFundsOp, Currency, FriendTcOp, FriendsRoute, PendingTransaction, RequestSendFundsOp, + ResponseSendFundsOp, +}; +use signature::signature_buff::create_response_signature_buffer; + +use crate::types::create_pending_transaction; + +use crate::mutual_credit::incoming::{ + process_operation, ProcessOperationError, /*ProcessOperationOutput,*/ +}; +use crate::mutual_credit::outgoing::{OutgoingMc, QueueOperationError}; +use crate::mutual_credit::types::{McBalance, McOp}; + +/* +/// Helper function for applying an outgoing operation over a token channel. +fn apply_outgoing( + mutual_credit: &mut MutualCredit, + friend_tc_op: &FriendTcOp, +) -> Result<(), QueueOperationError> { + let mut outgoing = OutgoingMc::new(mutual_credit); + let mutations = outgoing.queue_operation(friend_tc_op)?; + + for mutation in mutations { + mutual_credit.mutate(&mutation); + } + Ok(()) +} + +/// Helper function for applying an incoming operation over a token channel. +fn apply_incoming( + mut mutual_credit: &mut MutualCredit, + friend_tc_op: FriendTcOp, + remote_max_debt: u128, +) -> Result { + process_operation(&mut mutual_credit, friend_tc_op, remote_max_debt) +} +*/ + +#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] +pub struct McPendingTransactions { + /// Pending transactions that were opened locally and not yet completed + pub local: HashMap, + /// Pending transactions that were opened remotely and not yet completed + pub remote: HashMap, +} + +impl McPendingTransactions { + fn new() -> McPendingTransactions { + McPendingTransactions { + local: HashMap::new(), + remote: HashMap::new(), + } + } +} + +#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] +pub struct MutualCredit { + /// Currency in use (How much is one credit worth?) + pub currency: Currency, + /// Current credit balance with respect to remote side + pub balance: McBalance, + /// Requests in progress + pub pending_transactions: McPendingTransactions, +} + +impl MutualCredit { + pub fn new( + // TODO: Should we move instead of take a reference here? + local_public_key: &PublicKey, + remote_public_key: &PublicKey, + currency: &Currency, + balance: i128, + ) -> MutualCredit { + MutualCredit { + currency: currency.clone(), + balance: McBalance::new(balance), + pending_transactions: McPendingTransactions::new(), + } + } + + fn set_balance(&mut self, balance: i128) { + self.balance.balance = balance; + } + + fn insert_remote_pending_transaction(&mut self, pending_friend_request: &PendingTransaction) { + self.pending_transactions.remote.insert( + pending_friend_request.request_id.clone(), + pending_friend_request.clone(), + ); + } + + fn remove_remote_pending_transaction(&mut self, request_id: &Uid) { + let _ = self.pending_transactions.remote.remove(request_id); + } + + fn insert_local_pending_transaction(&mut self, pending_friend_request: &PendingTransaction) { + self.pending_transactions.local.insert( + pending_friend_request.request_id.clone(), + pending_friend_request.clone(), + ); + } + + fn remove_local_pending_transaction(&mut self, request_id: &Uid) { + let _ = self.pending_transactions.local.remove(request_id); + } + + fn set_remote_pending_debt(&mut self, remote_pending_debt: u128) { + self.balance.remote_pending_debt = remote_pending_debt; + } + + fn set_local_pending_debt(&mut self, local_pending_debt: u128) { + self.balance.local_pending_debt = local_pending_debt; + } +} diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index c7b3052e8..b283198f4 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -9,25 +9,15 @@ use proto::funder::messages::{Currency, PendingTransaction}; use futures::channel::{mpsc, oneshot}; use futures::SinkExt; -/* -// TODO: Where do we need to check this value? -/// The maximum possible funder debt. -/// We don't use the full u128 because i128 can not go beyond this value. -pub const MAX_FUNDER_DEBT: u128 = (1 << 127) - 1; -*/ - -// TODO: Rename this to McIdents -#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] -pub struct McIdents { - /// My public key - #[serde(with = "ser_b64")] - pub local_public_key: PublicKey, - /// Friend's public key - #[serde(with = "ser_b64")] - pub remote_public_key: PublicKey, +#[derive(Debug)] +pub enum McOpError { + SendOpFailed, + ResponseOpFailed(oneshot::Canceled), } -// TODO: Rename this to McBalance +pub type McOpResult = Result; +pub type McOpSenderResult = oneshot::Sender>; + #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct McBalance { /// Amount of credits this side has against the remote side. @@ -45,7 +35,7 @@ pub struct McBalance { impl McBalance { // TODO: Remove unused hint #[allow(unused)] - fn new(balance: i128) -> McBalance { + pub fn new(balance: i128) -> McBalance { McBalance { balance, local_pending_debt: 0, @@ -54,62 +44,6 @@ impl McBalance { } } -#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] -pub struct McPendingTransactions { - /// Pending transactions that were opened locally and not yet completed - #[serde(with = "ser_map_b64_any")] - pub local: ImHashMap, - /// Pending transactions that were opened remotely and not yet completed - #[serde(with = "ser_map_b64_any")] - pub remote: ImHashMap, -} - -impl McPendingTransactions { - fn new() -> McPendingTransactions { - McPendingTransactions { - local: ImHashMap::new(), - remote: ImHashMap::new(), - } - } -} - -#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] -pub struct MutualCreditState { - /// Public identities of local and remote side - pub idents: McIdents, - /// Currency in use (How much is one credit worth?) - pub currency: Currency, - /// Current credit balance with respect to remote side - pub balance: McBalance, - /// Requests in progress - pub pending_transactions: McPendingTransactions, -} - -#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] -pub struct MutualCredit { - state: MutualCreditState, -} - -#[derive(Arbitrary, Eq, PartialEq, Debug, Clone)] -pub enum McMutationOld { - SetBalance(i128), - InsertLocalPendingTransaction(PendingTransaction), - RemoveLocalPendingTransaction(Uid), - InsertRemotePendingTransaction(PendingTransaction), - RemoveRemotePendingTransaction(Uid), - SetLocalPendingDebt(u128), - SetRemotePendingDebt(u128), -} - -#[derive(Debug)] -pub enum McOpError { - SendOpFailed, - ResponseOpFailed(oneshot::Canceled), -} - -pub type McOpResult = Result; -pub type McOpSenderResult = oneshot::Sender>; - #[derive(Debug)] pub enum McOp { GetBalance(McOpSenderResult), @@ -125,14 +59,14 @@ pub enum McOp { // Commit(McOpSenderResult<()>), } -// TODO: Remove: +// TODO: Remove unused hint: #[allow(unused)] #[derive(Debug)] pub struct McTransaction { sender: mpsc::Sender, } -// TODO: Remove: +// TODO: Remove unused hint: #[allow(unused)] impl McTransaction { pub fn new(sender: mpsc::Sender) -> Self { @@ -254,27 +188,7 @@ impl McTransaction { */ } -impl MutualCredit { - pub fn new( - // TODO: Should we move instead of take a reference here? - local_public_key: &PublicKey, - remote_public_key: &PublicKey, - currency: &Currency, - balance: i128, - ) -> MutualCredit { - MutualCredit { - state: MutualCreditState { - idents: McIdents { - local_public_key: local_public_key.clone(), - remote_public_key: remote_public_key.clone(), - }, - currency: currency.clone(), - balance: McBalance::new(balance), - pending_transactions: McPendingTransactions::new(), - }, - } - } - +/* // TODO: Remove unused hint #[allow(unused)] /// Calculate required balance for reset. @@ -290,66 +204,4 @@ impl MutualCredit { // * balance // * balance + remote_pending_debt - local_pending_debt } - - pub fn state(&self) -> &MutualCreditState { - &self.state - } - - pub fn mutate(&mut self, mc_mutation: &McMutationOld) { - match mc_mutation { - McMutationOld::SetBalance(balance) => self.set_balance(*balance), - McMutationOld::InsertLocalPendingTransaction(pending_friend_request) => { - self.insert_local_pending_transaction(pending_friend_request) - } - McMutationOld::RemoveLocalPendingTransaction(request_id) => { - self.remove_local_pending_transaction(request_id) - } - McMutationOld::InsertRemotePendingTransaction(pending_friend_request) => { - self.insert_remote_pending_transaction(pending_friend_request) - } - McMutationOld::RemoveRemotePendingTransaction(request_id) => { - self.remove_remote_pending_transaction(request_id) - } - McMutationOld::SetLocalPendingDebt(local_pending_debt) => { - self.set_local_pending_debt(*local_pending_debt) - } - McMutationOld::SetRemotePendingDebt(remote_pending_debt) => { - self.set_remote_pending_debt(*remote_pending_debt) - } - } - } - - fn set_balance(&mut self, balance: i128) { - self.state.balance.balance = balance; - } - - fn insert_remote_pending_transaction(&mut self, pending_friend_request: &PendingTransaction) { - self.state.pending_transactions.remote.insert( - pending_friend_request.request_id.clone(), - pending_friend_request.clone(), - ); - } - - fn remove_remote_pending_transaction(&mut self, request_id: &Uid) { - let _ = self.state.pending_transactions.remote.remove(request_id); - } - - fn insert_local_pending_transaction(&mut self, pending_friend_request: &PendingTransaction) { - self.state.pending_transactions.local.insert( - pending_friend_request.request_id.clone(), - pending_friend_request.clone(), - ); - } - - fn remove_local_pending_transaction(&mut self, request_id: &Uid) { - let _ = self.state.pending_transactions.local.remove(request_id); - } - - fn set_remote_pending_debt(&mut self, remote_pending_debt: u128) { - self.state.balance.remote_pending_debt = remote_pending_debt; - } - - fn set_local_pending_debt(&mut self, local_pending_debt: u128) { - self.state.balance.local_pending_debt = local_pending_debt; - } -} +*/ From ff1b21008f978bc44dd568d315d9b36979b06fea Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 14:32:43 +0300 Subject: [PATCH 081/478] funder: Renaming --- .../funder/src/mutual_credit/incoming.rs | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 710802d09..548614a8f 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -59,7 +59,7 @@ pub struct ProcessTransListError { // TODO: Remove later: #[allow(unused)] pub async fn process_operations_list( - mc: &mut McTransaction, + mc_transaction: &mut McTransaction, operations: Vec, currency: &Currency, remote_public_key: &PublicKey, @@ -69,7 +69,7 @@ pub async fn process_operations_list( for (index, friend_tc_op) in operations.into_iter().enumerate() { match process_operation( - mc, + mc_transaction, friend_tc_op, currency, remote_public_key, @@ -90,7 +90,7 @@ pub async fn process_operations_list( } pub async fn process_operation( - mc: &mut McTransaction, + mc_transaction: &mut McTransaction, friend_tc_op: FriendTcOp, currency: &Currency, remote_public_key: &PublicKey, @@ -98,20 +98,26 @@ pub async fn process_operation( ) -> Result { match friend_tc_op { FriendTcOp::RequestSendFunds(request_send_funds) => { - process_request_send_funds(mc, request_send_funds, remote_max_debt).await + process_request_send_funds(mc_transaction, request_send_funds, remote_max_debt).await } FriendTcOp::ResponseSendFunds(response_send_funds) => { - process_response_send_funds(mc, response_send_funds, currency, remote_public_key).await + process_response_send_funds( + mc_transaction, + response_send_funds, + currency, + remote_public_key, + ) + .await } FriendTcOp::CancelSendFunds(cancel_send_funds) => { - process_cancel_send_funds(mc, cancel_send_funds).await + process_cancel_send_funds(mc_transaction, cancel_send_funds).await } } } /// Process an incoming RequestSendFundsOp async fn process_request_send_funds( - mc: &mut McTransaction, + mc_transaction: &mut McTransaction, request_send_funds: RequestSendFundsOp, remote_max_debt: u128, ) -> Result { @@ -124,7 +130,7 @@ async fn process_request_send_funds( } // Make sure that we don't have this request as a pending request already: - let opt_remote_pending_transaction = mc + let opt_remote_pending_transaction = mc_transaction .get_remote_pending_transaction(request_send_funds.request_id.clone()) .await?; if opt_remote_pending_transaction.is_some() { @@ -138,7 +144,7 @@ async fn process_request_send_funds( .ok_or(ProcessOperationError::CreditsCalcOverflow)?; // Make sure we can freeze the credits - let mc_balance = mc.get_balance().await?; + let mc_balance = mc_transaction.get_balance().await?; let new_remote_pending_debt = mc_balance .remote_pending_debt @@ -165,16 +171,19 @@ async fn process_request_send_funds( // Add pending transaction: let pending_transaction = create_pending_transaction(&request_send_funds); - mc.insert_remote_pending_transaction(pending_transaction) + mc_transaction + .insert_remote_pending_transaction(pending_transaction) .await?; // If we are here, we can freeze the credits: - mc.set_remote_pending_debt(new_remote_pending_debt).await?; + mc_transaction + .set_remote_pending_debt(new_remote_pending_debt) + .await?; Ok(incoming_message) } async fn process_response_send_funds( - mc: &mut McTransaction, + mc_transaction: &mut McTransaction, response_send_funds: ResponseSendFundsOp, currency: &Currency, remote_public_key: &PublicKey, @@ -183,7 +192,7 @@ async fn process_response_send_funds( // and access saved request details. // Obtain pending request: - let pending_transaction = mc + let pending_transaction = mc_transaction .get_local_pending_transaction(response_send_funds.request_id.clone()) .await? .ok_or(ProcessOperationError::RequestDoesNotExist)?; @@ -223,24 +232,27 @@ async fn process_response_send_funds( // request message processing. // Remove entry from local_pending hashmap: - mc.remove_local_pending_transaction(response_send_funds.request_id.clone()) + mc_transaction + .remove_local_pending_transaction(response_send_funds.request_id.clone()) .await?; // Decrease frozen credits: - let mc_balance = mc.get_balance().await?; + let mc_balance = mc_transaction.get_balance().await?; let new_local_pending_debt = mc_balance .local_pending_debt .checked_sub(freeze_credits) .unwrap(); - mc.set_local_pending_debt(new_local_pending_debt).await?; + mc_transaction + .set_local_pending_debt(new_local_pending_debt) + .await?; // Decrease balance: - let mc_balance = mc.get_balance().await?; + let mc_balance = mc_transaction.get_balance().await?; let new_balance = mc_balance .balance .checked_sub_unsigned(freeze_credits) .unwrap(); - mc.set_balance(new_balance).await?; + mc_transaction.set_balance(new_balance).await?; Ok(IncomingMessage::Response(IncomingResponseSendFundsOp { pending_transaction, @@ -249,19 +261,20 @@ async fn process_response_send_funds( } async fn process_cancel_send_funds( - mc: &mut McTransaction, + mc_transaction: &mut McTransaction, cancel_send_funds: CancelSendFundsOp, ) -> Result { // Make sure that id exists in local_pending hashmap, // and access saved request details. // Obtain pending request: - let pending_transaction = mc + let pending_transaction = mc_transaction .get_local_pending_transaction(cancel_send_funds.request_id.clone()) .await? .ok_or(ProcessOperationError::RequestDoesNotExist)?; - mc.remove_local_pending_transaction(cancel_send_funds.request_id.clone()) + mc_transaction + .remove_local_pending_transaction(cancel_send_funds.request_id.clone()) .await?; let freeze_credits = pending_transaction @@ -269,14 +282,16 @@ async fn process_cancel_send_funds( .checked_add(pending_transaction.left_fees) .unwrap(); - let mc_balance = mc.get_balance().await?; + let mc_balance = mc_transaction.get_balance().await?; // Decrease frozen credits: let new_local_pending_debt = mc_balance .local_pending_debt .checked_sub(freeze_credits) .unwrap(); - mc.set_local_pending_debt(new_local_pending_debt).await?; + mc_transaction + .set_local_pending_debt(new_local_pending_debt) + .await?; // Return cancel_send_funds: Ok(IncomingMessage::Cancel(IncomingCancelSendFundsOp { From ac8eb17d6831f58bd174dd5143f98c3e2ea098e7 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 14:33:18 +0300 Subject: [PATCH 082/478] funder: mutual_credit(outgoing): Changed to functional style --- .../funder/src/mutual_credit/outgoing.rs | 369 +++++++++--------- 1 file changed, 181 insertions(+), 188 deletions(-) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 3e47cff75..69a91b77c 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -11,15 +11,14 @@ use proto::funder::messages::{ }; use signature::signature_buff::create_response_signature_buffer; +use crate::mutual_credit::types::{McOpError, McTransaction}; use crate::types::create_pending_transaction; -use super::types::{McOpError, McTransaction}; - /// Processes outgoing funds for a token channel. /// Used to batch as many funds as possible. #[derive(Debug)] pub struct OutgoingMc { - mc: McTransaction, + mc_transaction: McTransaction, currency: Currency, local_public_key: PublicKey, } @@ -38,204 +37,198 @@ pub enum QueueOperationError { McOpError(McOpError), } -#[allow(unused)] /// A wrapper over a token channel, accumulating operations to be sent as one transaction. -impl OutgoingMc { - // TODO: Remove later: - #[allow(unused)] - pub fn new(mc: McTransaction, currency: Currency, local_public_key: PublicKey) -> OutgoingMc { - OutgoingMc { - mc, - currency, - local_public_key, +// TODO: Remove later: +#[allow(unused)] +pub async fn queue_operation( + mc_transaction: &mut McTransaction, + operation: &FriendTcOp, + currency: &Currency, + local_public_key: &PublicKey, +) -> Result<(), QueueOperationError> { + // TODO: Maybe remove clone from here later: + match operation.clone() { + FriendTcOp::RequestSendFunds(request_send_funds) => { + queue_request_send_funds(mc_transaction, request_send_funds).await + } + FriendTcOp::ResponseSendFunds(response_send_funds) => { + queue_response_send_funds( + mc_transaction, + response_send_funds, + currency, + local_public_key, + ) + .await + } + FriendTcOp::CancelSendFunds(cancel_send_funds) => { + queue_cancel_send_funds(mc_transaction, cancel_send_funds).await } } +} - // TODO: Remove later: - #[allow(unused)] - pub async fn queue_operation( - &mut self, - operation: &FriendTcOp, - ) -> Result<(), QueueOperationError> { - // TODO: Maybe remove clone from here later: - match operation.clone() { - FriendTcOp::RequestSendFunds(request_send_funds) => { - self.queue_request_send_funds(request_send_funds).await - } - FriendTcOp::ResponseSendFunds(response_send_funds) => { - self.queue_response_send_funds(response_send_funds).await - } - FriendTcOp::CancelSendFunds(cancel_send_funds) => { - self.queue_cancel_send_funds(cancel_send_funds).await - } - } +async fn queue_request_send_funds( + mc_transaction: &mut McTransaction, + request_send_funds: RequestSendFundsOp, +) -> Result<(), QueueOperationError> { + if !request_send_funds.route.is_part_valid() { + return Err(QueueOperationError::InvalidRoute); } - async fn queue_request_send_funds( - &mut self, - request_send_funds: RequestSendFundsOp, - ) -> Result<(), QueueOperationError> { - if !request_send_funds.route.is_part_valid() { - return Err(QueueOperationError::InvalidRoute); - } + if request_send_funds.dest_payment > request_send_funds.total_dest_payment { + return Err(QueueOperationError::DestPaymentExceedsTotal); + } - if request_send_funds.dest_payment > request_send_funds.total_dest_payment { - return Err(QueueOperationError::DestPaymentExceedsTotal); - } + // Calculate amount of credits to freeze + let own_freeze_credits = request_send_funds + .dest_payment + .checked_add(request_send_funds.left_fees) + .ok_or(QueueOperationError::CreditsCalcOverflow)?; + + let mc_balance = mc_transaction.get_balance().await?; + + // Make sure we can freeze the credits + let new_local_pending_debt = mc_balance + .local_pending_debt + .checked_add(own_freeze_credits) + .ok_or(QueueOperationError::CreditsCalcOverflow)?; + + // Make sure that we don't have this request as a pending request already: + if mc_transaction + .get_local_pending_transaction(request_send_funds.request_id.clone()) + .await? + .is_some() + { + return Err(QueueOperationError::RequestAlreadyExists); + } - // Calculate amount of credits to freeze - let own_freeze_credits = request_send_funds - .dest_payment - .checked_add(request_send_funds.left_fees) - .ok_or(QueueOperationError::CreditsCalcOverflow)?; - - let mc_balance = self.mc.get_balance().await?; - - // Make sure we can freeze the credits - let new_local_pending_debt = mc_balance - .local_pending_debt - .checked_add(own_freeze_credits) - .ok_or(QueueOperationError::CreditsCalcOverflow)?; - - // Make sure that we don't have this request as a pending request already: - if self - .mc - .get_local_pending_transaction(request_send_funds.request_id.clone()) - .await? - .is_some() - { - return Err(QueueOperationError::RequestAlreadyExists); - } + // Add pending transaction: + let pending_transaction = create_pending_transaction(&request_send_funds); + mc_transaction + .insert_local_pending_transaction(pending_transaction) + .await?; - // Add pending transaction: - let pending_transaction = create_pending_transaction(&request_send_funds); - self.mc - .insert_local_pending_transaction(pending_transaction) - .await?; + // If we are here, we can freeze the credits: + mc_transaction + .set_local_pending_debt(new_local_pending_debt) + .await?; - // If we are here, we can freeze the credits: - self.mc - .set_local_pending_debt(new_local_pending_debt) - .await?; + Ok(()) +} - Ok(()) +async fn queue_response_send_funds( + mc_transaction: &mut McTransaction, + response_send_funds: ResponseSendFundsOp, + currency: &Currency, + local_public_key: &PublicKey, +) -> Result<(), QueueOperationError> { + // Make sure that id exists in remote_pending hashmap, + // and access saved request details. + + // Obtain pending request: + let pending_transaction = mc_transaction + .get_remote_pending_transaction(response_send_funds.request_id.clone()) + .await? + .ok_or(QueueOperationError::RequestDoesNotExist)?; + // TODO: Possibly get rid of clone() here for optimization later + + // Verify src_plain_lock and dest_plain_lock: + if response_send_funds.src_plain_lock.hash_lock() != pending_transaction.src_hashed_lock { + return Err(QueueOperationError::InvalidSrcPlainLock); } - async fn queue_response_send_funds( - &mut self, - response_send_funds: ResponseSendFundsOp, - ) -> Result<(), QueueOperationError> { - // Make sure that id exists in remote_pending hashmap, - // and access saved request details. - - // Obtain pending request: - let pending_transaction = self - .mc - .get_remote_pending_transaction(response_send_funds.request_id.clone()) - .await? - .ok_or(QueueOperationError::RequestDoesNotExist)?; - // TODO: Possibly get rid of clone() here for optimization later - - // Verify src_plain_lock and dest_plain_lock: - if response_send_funds.src_plain_lock.hash_lock() != pending_transaction.src_hashed_lock { - return Err(QueueOperationError::InvalidSrcPlainLock); - } - - // verify signature: - let response_signature_buffer = create_response_signature_buffer( - &self.currency, - response_send_funds.clone(), - &pending_transaction, - ); - // The response was signed by the destination node: - let dest_public_key = if pending_transaction.route.public_keys.is_empty() { - &self.local_public_key - } else { - pending_transaction.route.public_keys.last().unwrap() - }; - - // Verify response funds signature: - if !verify_signature( - &response_signature_buffer, - dest_public_key, - &response_send_funds.signature, - ) { - return Err(QueueOperationError::InvalidResponseSignature); - } - - // Calculate amount of credits that were frozen: - let freeze_credits = pending_transaction - .dest_payment - .checked_add(pending_transaction.left_fees) - .unwrap(); - - // Remove entry from remote_pending hashmap: - self.mc - .remove_remote_pending_transaction(response_send_funds.request_id) - .await?; - - // Decrease frozen credits - let mc_balance = self.mc.get_balance().await?; - let new_remote_pending_debt = mc_balance - .remote_pending_debt - .checked_sub(freeze_credits) - .unwrap(); - // Above unwrap() should never fail. This was already checked when a request message was - // received. - - self.mc - .set_remote_pending_debt(new_remote_pending_debt) - .await?; - - // Increase balance: - let mc_balance = self.mc.get_balance().await?; - let new_balance = mc_balance - .balance - .checked_add_unsigned(freeze_credits) - .unwrap(); - // Above unwrap() should never fail. This was already checked when a request message was - // received. - - self.mc.set_balance(new_balance).await?; - - Ok(()) + // verify signature: + let response_signature_buffer = create_response_signature_buffer( + currency, + response_send_funds.clone(), + &pending_transaction, + ); + // The response was signed by the destination node: + let dest_public_key = if pending_transaction.route.public_keys.is_empty() { + local_public_key + } else { + pending_transaction.route.public_keys.last().unwrap() + }; + + // Verify response funds signature: + if !verify_signature( + &response_signature_buffer, + dest_public_key, + &response_send_funds.signature, + ) { + return Err(QueueOperationError::InvalidResponseSignature); } - async fn queue_cancel_send_funds( - &mut self, - cancel_send_funds: CancelSendFundsOp, - ) -> Result<(), QueueOperationError> { - // Make sure that id exists in remote_pending hashmap, - // and access saved request details. - - // Obtain pending request: - let pending_transaction = self - .mc - .get_remote_pending_transaction(cancel_send_funds.request_id.clone()) - .await? - .ok_or(QueueOperationError::RequestDoesNotExist)?; - - let freeze_credits = pending_transaction - .dest_payment - .checked_add(pending_transaction.left_fees) - .unwrap(); - - // Remove entry from remote hashmap: - self.mc - .remove_remote_pending_transaction(cancel_send_funds.request_id.clone()) - .await?; - - // Decrease frozen credits: - let mc_balance = self.mc.get_balance().await?; - let new_remote_pending_debt = mc_balance - .remote_pending_debt - .checked_sub(freeze_credits) - .unwrap(); - - self.mc - .set_remote_pending_debt(new_remote_pending_debt) - .await?; - - Ok(()) - } + // Calculate amount of credits that were frozen: + let freeze_credits = pending_transaction + .dest_payment + .checked_add(pending_transaction.left_fees) + .unwrap(); + + // Remove entry from remote_pending hashmap: + mc_transaction + .remove_remote_pending_transaction(response_send_funds.request_id) + .await?; + + // Decrease frozen credits + let mc_balance = mc_transaction.get_balance().await?; + let new_remote_pending_debt = mc_balance + .remote_pending_debt + .checked_sub(freeze_credits) + .unwrap(); + // Above unwrap() should never fail. This was already checked when a request message was + // received. + + mc_transaction + .set_remote_pending_debt(new_remote_pending_debt) + .await?; + + // Increase balance: + let mc_balance = mc_transaction.get_balance().await?; + let new_balance = mc_balance + .balance + .checked_add_unsigned(freeze_credits) + .unwrap(); + // Above unwrap() should never fail. This was already checked when a request message was + // received. + + mc_transaction.set_balance(new_balance).await?; + + Ok(()) +} + +async fn queue_cancel_send_funds( + mc_transaction: &mut McTransaction, + cancel_send_funds: CancelSendFundsOp, +) -> Result<(), QueueOperationError> { + // Make sure that id exists in remote_pending hashmap, + // and access saved request details. + + // Obtain pending request: + let pending_transaction = mc_transaction + .get_remote_pending_transaction(cancel_send_funds.request_id.clone()) + .await? + .ok_or(QueueOperationError::RequestDoesNotExist)?; + + let freeze_credits = pending_transaction + .dest_payment + .checked_add(pending_transaction.left_fees) + .unwrap(); + + // Remove entry from remote hashmap: + mc_transaction + .remove_remote_pending_transaction(cancel_send_funds.request_id.clone()) + .await?; + + // Decrease frozen credits: + let mc_balance = mc_transaction.get_balance().await?; + let new_remote_pending_debt = mc_balance + .remote_pending_debt + .checked_sub(freeze_credits) + .unwrap(); + + mc_transaction + .set_remote_pending_debt(new_remote_pending_debt) + .await?; + + Ok(()) } From 887f3c2548a463e306b1a245a0498a3c1c97b545 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 14:35:35 +0300 Subject: [PATCH 083/478] funder: mutual_credit: Some work on test utils --- .../funder/src/mutual_credit/tests/utils.rs | 78 +++++++++++++++---- 1 file changed, 65 insertions(+), 13 deletions(-) diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index 4ede31f3c..ced884a48 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -1,7 +1,9 @@ // use std::convert::TryFrom; - use std::collections::HashMap; +use futures::channel::mpsc; +use futures::StreamExt; + use crypto::hash_lock::HashLock; use crypto::identity::{Identity, SoftwareEd25519Identity}; use crypto::rand::RandGen; @@ -20,12 +22,12 @@ use crate::mutual_credit::incoming::{ process_operation, ProcessOperationError, /*ProcessOperationOutput,*/ }; use crate::mutual_credit::outgoing::{OutgoingMc, QueueOperationError}; -use crate::mutual_credit::types::{McBalance, McOp}; +use crate::mutual_credit::types::{McBalance, McOp, McOpResult, McTransaction}; /* /// Helper function for applying an outgoing operation over a token channel. fn apply_outgoing( - mutual_credit: &mut MutualCredit, + mc_transaction: &mut McTransaction, friend_tc_op: &FriendTcOp, ) -> Result<(), QueueOperationError> { let mut outgoing = OutgoingMc::new(mutual_credit); @@ -93,22 +95,20 @@ impl MutualCredit { self.balance.balance = balance; } - fn insert_remote_pending_transaction(&mut self, pending_friend_request: &PendingTransaction) { - self.pending_transactions.remote.insert( - pending_friend_request.request_id.clone(), - pending_friend_request.clone(), - ); + fn insert_remote_pending_transaction(&mut self, pending_transaction: PendingTransaction) { + self.pending_transactions + .remote + .insert(pending_transaction.request_id.clone(), pending_transaction); } fn remove_remote_pending_transaction(&mut self, request_id: &Uid) { let _ = self.pending_transactions.remote.remove(request_id); } - fn insert_local_pending_transaction(&mut self, pending_friend_request: &PendingTransaction) { - self.pending_transactions.local.insert( - pending_friend_request.request_id.clone(), - pending_friend_request.clone(), - ); + fn insert_local_pending_transaction(&mut self, pending_transaction: PendingTransaction) { + self.pending_transactions + .local + .insert(pending_transaction.request_id.clone(), pending_transaction); } fn remove_local_pending_transaction(&mut self, request_id: &Uid) { @@ -123,3 +123,55 @@ impl MutualCredit { self.balance.local_pending_debt = local_pending_debt; } } + +async fn mc_server(mut mc: MutualCredit, mut incoming_ops: mpsc::Receiver) { + while let Some(mc_op) = incoming_ops.next().await { + match mc_op { + McOp::GetBalance(mc_balance_sender) => { + mc_balance_sender.send(Ok(mc.balance.clone())).unwrap(); + } + McOp::SetBalance(new_balance, sender) => { + mc.set_balance(new_balance); + sender.send(Ok(())).unwrap(); + } + McOp::SetLocalPendingDebt(new_pending_debt, sender) => { + mc.set_local_pending_debt(new_pending_debt); + sender.send(Ok(())).unwrap(); + } + McOp::SetRemotePendingDebt(new_pending_debt, sender) => { + mc.set_remote_pending_debt(new_pending_debt); + sender.send(Ok(())).unwrap(); + } + McOp::GetLocalPendingTransaction(request_id, pending_transaction_sender) => { + let opt_pending_transaction = + mc.pending_transactions.local.get(&request_id).cloned(); + pending_transaction_sender + .send(Ok(opt_pending_transaction)) + .unwrap(); + } + McOp::InsertLocalPendingTransaction(pending_transaction, sender) => { + mc.insert_local_pending_transaction(pending_transaction); + sender.send(Ok(())).unwrap(); + } + McOp::RemoveLocalPendingTransaction(request_id, sender) => { + mc.remove_local_pending_transaction(&request_id); + sender.send(Ok(())).unwrap(); + } + McOp::GetRemotePendingTransaction(request_id, pending_transaction_sender) => { + let opt_pending_transaction = + mc.pending_transactions.remote.get(&request_id).cloned(); + pending_transaction_sender + .send(Ok(opt_pending_transaction)) + .unwrap(); + } + McOp::InsertRemotePendingTransaction(pending_transaction, sender) => { + mc.insert_remote_pending_transaction(pending_transaction); + sender.send(Ok(())).unwrap(); + } + McOp::RemoveRemotePendingTransaction(request_id, sender) => { + mc.remove_remote_pending_transaction(&request_id); + sender.send(Ok(())).unwrap(); + } + } + } +} From ce671176ff5abbb24173c3c34587662dc4d17e89 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 15:03:35 +0300 Subject: [PATCH 084/478] funder: mutual_credit: mc_server() returns error instead of panic --- .../funder/src/mutual_credit/tests/utils.rs | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index ced884a48..d888c84f0 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -124,54 +124,65 @@ impl MutualCredit { } } -async fn mc_server(mut mc: MutualCredit, mut incoming_ops: mpsc::Receiver) { +#[derive(Debug)] +pub enum McServerError { + SendError, +} + +pub async fn mc_server( + mut mc: MutualCredit, + mut incoming_ops: mpsc::Receiver, +) -> Result<(), McServerError> { while let Some(mc_op) = incoming_ops.next().await { match mc_op { McOp::GetBalance(mc_balance_sender) => { - mc_balance_sender.send(Ok(mc.balance.clone())).unwrap(); + mc_balance_sender + .send(Ok(mc.balance.clone())) + .map_err(|_| McServerError::SendError)?; } McOp::SetBalance(new_balance, sender) => { mc.set_balance(new_balance); - sender.send(Ok(())).unwrap(); + sender.send(Ok(())).map_err(|_| McServerError::SendError)?; } McOp::SetLocalPendingDebt(new_pending_debt, sender) => { mc.set_local_pending_debt(new_pending_debt); - sender.send(Ok(())).unwrap(); + sender.send(Ok(())).map_err(|_| McServerError::SendError)?; } McOp::SetRemotePendingDebt(new_pending_debt, sender) => { mc.set_remote_pending_debt(new_pending_debt); - sender.send(Ok(())).unwrap(); + sender.send(Ok(())).map_err(|_| McServerError::SendError)?; } McOp::GetLocalPendingTransaction(request_id, pending_transaction_sender) => { let opt_pending_transaction = mc.pending_transactions.local.get(&request_id).cloned(); pending_transaction_sender .send(Ok(opt_pending_transaction)) - .unwrap(); + .map_err(|_| McServerError::SendError)?; } McOp::InsertLocalPendingTransaction(pending_transaction, sender) => { mc.insert_local_pending_transaction(pending_transaction); - sender.send(Ok(())).unwrap(); + sender.send(Ok(())).map_err(|_| McServerError::SendError)?; } McOp::RemoveLocalPendingTransaction(request_id, sender) => { mc.remove_local_pending_transaction(&request_id); - sender.send(Ok(())).unwrap(); + sender.send(Ok(())).map_err(|_| McServerError::SendError)?; } McOp::GetRemotePendingTransaction(request_id, pending_transaction_sender) => { let opt_pending_transaction = mc.pending_transactions.remote.get(&request_id).cloned(); pending_transaction_sender .send(Ok(opt_pending_transaction)) - .unwrap(); + .map_err(|_| McServerError::SendError)?; } McOp::InsertRemotePendingTransaction(pending_transaction, sender) => { mc.insert_remote_pending_transaction(pending_transaction); - sender.send(Ok(())).unwrap(); + sender.send(Ok(())).map_err(|_| McServerError::SendError)?; } McOp::RemoveRemotePendingTransaction(request_id, sender) => { mc.remove_remote_pending_transaction(&request_id); - sender.send(Ok(())).unwrap(); + sender.send(Ok(())).map_err(|_| McServerError::SendError)?; } } } + Ok(()) } From c57636243b4236185655bdc70107fdadc9a17f49 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 15:04:11 +0300 Subject: [PATCH 085/478] funder: Take ownership instead of cloning internally --- components/funder/src/mutual_credit/outgoing.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 69a91b77c..e40c59bcb 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -42,12 +42,12 @@ pub enum QueueOperationError { #[allow(unused)] pub async fn queue_operation( mc_transaction: &mut McTransaction, - operation: &FriendTcOp, + operation: FriendTcOp, currency: &Currency, local_public_key: &PublicKey, ) -> Result<(), QueueOperationError> { // TODO: Maybe remove clone from here later: - match operation.clone() { + match operation { FriendTcOp::RequestSendFunds(request_send_funds) => { queue_request_send_funds(mc_transaction, request_send_funds).await } From 9a23a6d393b6c5d7b6d38c284aa1f68c8344b307 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 15:04:42 +0300 Subject: [PATCH 086/478] funder: mutual_credit: Restore request_response_send_funds() test --- components/funder/src/lib.rs | 5 +- .../funder/src/mutual_credit/tests/mod.rs | 2 +- .../tests/request_response_send_funds.rs | 82 +++++++++++++++---- 3 files changed, 71 insertions(+), 18 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index d9f3b4c41..e3713dfda 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -9,8 +9,9 @@ clippy::new_without_default )] -// #[macro_use] -// extern crate log; +#[allow(unused)] +#[macro_use] +extern crate log; #[macro_use] extern crate serde; diff --git a/components/funder/src/mutual_credit/tests/mod.rs b/components/funder/src/mutual_credit/tests/mod.rs index 5bf793f12..1074aa24c 100644 --- a/components/funder/src/mutual_credit/tests/mod.rs +++ b/components/funder/src/mutual_credit/tests/mod.rs @@ -1,4 +1,4 @@ // mod request_cancel_send_funds; -// mod request_response_send_funds; +mod request_response_send_funds; #[allow(unused)] mod utils; diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index 4636ed598..6804bdb9f 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -1,12 +1,49 @@ -#[test] -fn test_request_response_send_funds() { +use std::convert::TryFrom; + +use futures::channel::mpsc; +use futures::task::SpawnExt; +use futures::{FutureExt, TryFutureExt}; + +use common::test_executor::TestExecutor; + +use crypto::hash_lock::HashLock; +use crypto::identity::{Identity, SoftwareEd25519Identity}; +use crypto::rand::RandGen; +use crypto::test_utils::DummyRandom; + +use proto::crypto::{HashResult, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid}; +use proto::funder::messages::{ + Currency, FriendTcOp, FriendsRoute, RequestSendFundsOp, ResponseSendFundsOp, +}; +use signature::signature_buff::create_response_signature_buffer; + +use crate::mutual_credit::tests::utils::{mc_server, MutualCredit}; +use crate::mutual_credit::types::McTransaction; +use crate::types::create_pending_transaction; + +use crate::mutual_credit::incoming::process_operations_list; +use crate::mutual_credit::outgoing::queue_operation; +// use crate::mutual_credit::types::{McBalance, McOp, McOpResult, McTransaction}; + +async fn task_request_response_send_funds(test_executor: TestExecutor) { let currency = Currency::try_from("FST".to_owned()).unwrap(); let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); let remote_public_key = PublicKey::from(&[0xbb; PublicKey::len()]); let balance = 0; - let mut mutual_credit = + let (sender, receiver) = mpsc::channel(0); + + let mutual_credit = MutualCredit::new(&local_public_key, &remote_public_key, ¤cy, balance); + test_executor + .spawn( + mc_server(mutual_credit, receiver) + .map_err(|e| warn!("mc_server closed with error: {:?}", e)) + .map(|_| ()), + ) + .unwrap(); + + let mut mc_transaction = McTransaction::new(sender); // -----[RequestSendFunds]-------- // ----------------------------- @@ -39,15 +76,19 @@ fn test_request_response_send_funds() { }; let pending_transaction = create_pending_transaction(&request_send_funds); - apply_outgoing( - &mut mutual_credit, - &FriendTcOp::RequestSendFunds(request_send_funds), + queue_operation( + &mut mc_transaction, + FriendTcOp::RequestSendFunds(request_send_funds), + ¤cy, + &local_public_key, ) + .await .unwrap(); - assert_eq!(mutual_credit.state().balance.balance, 0); - assert_eq!(mutual_credit.state().balance.local_pending_debt, 10 + 5); - assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); + let mc_balance = mc_transaction.get_balance().await.unwrap(); + assert_eq!(mc_balance.balance, 0); + assert_eq!(mc_balance.local_pending_debt, 10 + 5); + assert_eq!(mc_balance.remote_pending_debt, 0); // -----[ResponseSendFunds]-------- // -------------------------------- @@ -67,15 +108,26 @@ fn test_request_response_send_funds() { ); response_send_funds.signature = identity.sign(&sign_buffer); - apply_incoming( - &mut mutual_credit, - FriendTcOp::ResponseSendFunds(response_send_funds), + process_operations_list( + &mut mc_transaction, + vec![FriendTcOp::ResponseSendFunds(response_send_funds)], + ¤cy, + &remote_public_key, 100, ) + .await .unwrap(); // We expect that the balance has updated: - assert_eq!(mutual_credit.state().balance.balance, -15); - assert_eq!(mutual_credit.state().balance.local_pending_debt, 0); - assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); + let mc_balance = mc_transaction.get_balance().await.unwrap(); + assert_eq!(mc_balance.balance, -15); + assert_eq!(mc_balance.local_pending_debt, 0); + assert_eq!(mc_balance.remote_pending_debt, 0); +} + +#[test] +fn test_request_response_send_funds() { + let test_executor = TestExecutor::new(); + let res = test_executor.run(task_request_response_send_funds(test_executor.clone())); + assert!(res.is_output()); } From d53aefbceb3e685963aa0ad93a06b447d924f8ee Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 15:11:10 +0300 Subject: [PATCH 087/478] funder: formatting --- .../src/mutual_credit/tests/request_response_send_funds.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index 6804bdb9f..62d3ec6cd 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -23,7 +23,6 @@ use crate::types::create_pending_transaction; use crate::mutual_credit::incoming::process_operations_list; use crate::mutual_credit::outgoing::queue_operation; -// use crate::mutual_credit::types::{McBalance, McOp, McOpResult, McTransaction}; async fn task_request_response_send_funds(test_executor: TestExecutor) { let currency = Currency::try_from("FST".to_owned()).unwrap(); @@ -31,8 +30,8 @@ async fn task_request_response_send_funds(test_executor: TestExecutor) { let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); let remote_public_key = PublicKey::from(&[0xbb; PublicKey::len()]); let balance = 0; - let (sender, receiver) = mpsc::channel(0); + let (sender, receiver) = mpsc::channel(0); let mutual_credit = MutualCredit::new(&local_public_key, &remote_public_key, ¤cy, balance); test_executor @@ -42,7 +41,6 @@ async fn task_request_response_send_funds(test_executor: TestExecutor) { .map(|_| ()), ) .unwrap(); - let mut mc_transaction = McTransaction::new(sender); // -----[RequestSendFunds]-------- From 982474f45e96018900845c6a71554874a4dadbf9 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 15:11:34 +0300 Subject: [PATCH 088/478] funder: mutual_credit: Restored tesT_request_cancel_send_funds() --- .../funder/src/mutual_credit/tests/mod.rs | 2 +- .../tests/request_cancel_send_funds.rs | 78 +++++++++++++++---- 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/components/funder/src/mutual_credit/tests/mod.rs b/components/funder/src/mutual_credit/tests/mod.rs index 1074aa24c..ac97e1172 100644 --- a/components/funder/src/mutual_credit/tests/mod.rs +++ b/components/funder/src/mutual_credit/tests/mod.rs @@ -1,4 +1,4 @@ -// mod request_cancel_send_funds; +mod request_cancel_send_funds; mod request_response_send_funds; #[allow(unused)] mod utils; diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index a5930a85f..b4103c253 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -1,5 +1,28 @@ -#[test] -fn test_request_cancel_send_funds() { +use std::convert::TryFrom; + +use futures::channel::mpsc; +use futures::task::SpawnExt; +use futures::{FutureExt, TryFutureExt}; + +use common::test_executor::TestExecutor; + +use crypto::hash_lock::HashLock; +use crypto::identity::{Identity, SoftwareEd25519Identity}; +use crypto::rand::RandGen; +use crypto::test_utils::DummyRandom; + +use proto::crypto::{HashResult, HmacResult, PlainLock, PrivateKey, PublicKey, Uid}; +use proto::funder::messages::{ + CancelSendFundsOp, Currency, FriendTcOp, FriendsRoute, RequestSendFundsOp, +}; + +use crate::mutual_credit::tests::utils::{mc_server, MutualCredit}; +use crate::mutual_credit::types::McTransaction; + +use crate::mutual_credit::incoming::process_operations_list; +use crate::mutual_credit::outgoing::queue_operation; + +async fn task_request_cancel_send_funds(test_executor: TestExecutor) { let currency = Currency::try_from("FST".to_owned()).unwrap(); let mut rng = DummyRandom::new(&[1u8]); @@ -10,8 +33,18 @@ fn test_request_cancel_send_funds() { let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); let remote_public_key = public_key_b.clone(); let balance = 0; - let mut mutual_credit = + + let mutual_credit = MutualCredit::new(&local_public_key, &remote_public_key, ¤cy, balance); + let (sender, receiver) = mpsc::channel(0); + test_executor + .spawn( + mc_server(mutual_credit, receiver) + .map_err(|e| warn!("mc_server closed with error: {:?}", e)) + .map(|_| ()), + ) + .unwrap(); + let mut mc_transaction = McTransaction::new(sender); // -----[RequestSendFunds]-------- // ----------------------------- @@ -38,28 +71,43 @@ fn test_request_cancel_send_funds() { left_fees: 5, }; - apply_outgoing( - &mut mutual_credit, - &FriendTcOp::RequestSendFunds(request_send_funds), + queue_operation( + &mut mc_transaction, + FriendTcOp::RequestSendFunds(request_send_funds), + ¤cy, + &local_public_key, ) + .await .unwrap(); - assert_eq!(mutual_credit.state().balance.balance, 0); - assert_eq!(mutual_credit.state().balance.local_pending_debt, 10 + 5); - assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); + let mc_balance = mc_transaction.get_balance().await.unwrap(); + assert_eq!(mc_balance.balance, 0); + assert_eq!(mc_balance.local_pending_debt, 10 + 5); + assert_eq!(mc_balance.remote_pending_debt, 0); // -----[CancelSendFunds]-------- // ------------------------------ let cancel_send_funds = CancelSendFundsOp { request_id }; - apply_incoming( - &mut mutual_credit, - FriendTcOp::CancelSendFunds(cancel_send_funds), + process_operations_list( + &mut mc_transaction, + vec![FriendTcOp::CancelSendFunds(cancel_send_funds)], + ¤cy, + &remote_public_key, 100, ) + .await .unwrap(); - assert_eq!(mutual_credit.state().balance.balance, 0); - assert_eq!(mutual_credit.state().balance.local_pending_debt, 0); - assert_eq!(mutual_credit.state().balance.remote_pending_debt, 0); + let mc_balance = mc_transaction.get_balance().await.unwrap(); + assert_eq!(mc_balance.balance, 0); + assert_eq!(mc_balance.local_pending_debt, 0); + assert_eq!(mc_balance.remote_pending_debt, 0); +} + +#[test] +fn test_request_cancel_send_funds() { + let test_executor = TestExecutor::new(); + let res = test_executor.run(task_request_cancel_send_funds(test_executor.clone())); + assert!(res.is_output()); } From a6e5fdccb6fc5ef0af5f4c1eaedb9544a29d9287 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 15:13:49 +0300 Subject: [PATCH 089/478] funder: Removed unused imports --- .../funder/src/mutual_credit/tests/utils.rs | 46 ++----------------- 1 file changed, 3 insertions(+), 43 deletions(-) diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index d888c84f0..ecaa675f9 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -4,50 +4,10 @@ use std::collections::HashMap; use futures::channel::mpsc; use futures::StreamExt; -use crypto::hash_lock::HashLock; -use crypto::identity::{Identity, SoftwareEd25519Identity}; -use crypto::rand::RandGen; -use crypto::test_utils::DummyRandom; - -use proto::crypto::{HashResult, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid}; -use proto::funder::messages::{ - CancelSendFundsOp, Currency, FriendTcOp, FriendsRoute, PendingTransaction, RequestSendFundsOp, - ResponseSendFundsOp, -}; -use signature::signature_buff::create_response_signature_buffer; - -use crate::types::create_pending_transaction; - -use crate::mutual_credit::incoming::{ - process_operation, ProcessOperationError, /*ProcessOperationOutput,*/ -}; -use crate::mutual_credit::outgoing::{OutgoingMc, QueueOperationError}; -use crate::mutual_credit::types::{McBalance, McOp, McOpResult, McTransaction}; - -/* -/// Helper function for applying an outgoing operation over a token channel. -fn apply_outgoing( - mc_transaction: &mut McTransaction, - friend_tc_op: &FriendTcOp, -) -> Result<(), QueueOperationError> { - let mut outgoing = OutgoingMc::new(mutual_credit); - let mutations = outgoing.queue_operation(friend_tc_op)?; - - for mutation in mutations { - mutual_credit.mutate(&mutation); - } - Ok(()) -} +use proto::crypto::{PublicKey, Uid}; +use proto::funder::messages::{Currency, PendingTransaction}; -/// Helper function for applying an incoming operation over a token channel. -fn apply_incoming( - mut mutual_credit: &mut MutualCredit, - friend_tc_op: FriendTcOp, - remote_max_debt: u128, -) -> Result { - process_operation(&mut mutual_credit, friend_tc_op, remote_max_debt) -} -*/ +use crate::mutual_credit::types::{McBalance, McOp}; #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct McPendingTransactions { From 2113028f88be193370f54e67c0ed2ce94e14f159 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 15:14:49 +0300 Subject: [PATCH 090/478] funder: MutualCredit test util: Removed redundant fields --- components/funder/src/mutual_credit/tests/mod.rs | 1 - .../src/mutual_credit/tests/request_cancel_send_funds.rs | 3 +-- .../src/mutual_credit/tests/request_response_send_funds.rs | 3 +-- components/funder/src/mutual_credit/tests/utils.rs | 4 +--- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/components/funder/src/mutual_credit/tests/mod.rs b/components/funder/src/mutual_credit/tests/mod.rs index ac97e1172..0a9c0128f 100644 --- a/components/funder/src/mutual_credit/tests/mod.rs +++ b/components/funder/src/mutual_credit/tests/mod.rs @@ -1,4 +1,3 @@ mod request_cancel_send_funds; mod request_response_send_funds; -#[allow(unused)] mod utils; diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index b4103c253..aa8f4b671 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -34,8 +34,7 @@ async fn task_request_cancel_send_funds(test_executor: TestExecutor) { let remote_public_key = public_key_b.clone(); let balance = 0; - let mutual_credit = - MutualCredit::new(&local_public_key, &remote_public_key, ¤cy, balance); + let mutual_credit = MutualCredit::new(¤cy, balance); let (sender, receiver) = mpsc::channel(0); test_executor .spawn( diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index 62d3ec6cd..3ff9dc07a 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -32,8 +32,7 @@ async fn task_request_response_send_funds(test_executor: TestExecutor) { let balance = 0; let (sender, receiver) = mpsc::channel(0); - let mutual_credit = - MutualCredit::new(&local_public_key, &remote_public_key, ¤cy, balance); + let mutual_credit = MutualCredit::new(¤cy, balance); test_executor .spawn( mc_server(mutual_credit, receiver) diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index ecaa675f9..4e8c0bec2 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use futures::channel::mpsc; use futures::StreamExt; -use proto::crypto::{PublicKey, Uid}; +use proto::crypto::Uid; use proto::funder::messages::{Currency, PendingTransaction}; use crate::mutual_credit::types::{McBalance, McOp}; @@ -39,8 +39,6 @@ pub struct MutualCredit { impl MutualCredit { pub fn new( // TODO: Should we move instead of take a reference here? - local_public_key: &PublicKey, - remote_public_key: &PublicKey, currency: &Currency, balance: i128, ) -> MutualCredit { From 0a83a403ec27dc58d8fc72186694092ff5284309 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 15:23:03 +0300 Subject: [PATCH 091/478] funder: mutual_credit: Removed some unused hints --- components/funder/src/mutual_credit/mod.rs | 3 --- components/funder/src/mutual_credit/tests/utils.rs | 1 - components/funder/src/mutual_credit/types.rs | 10 ++++------ 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index e7843dde5..a3521f69d 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -1,8 +1,5 @@ -#[allow(unused)] pub mod incoming; -#[allow(unused)] pub mod outgoing; #[cfg(test)] mod tests; -#[allow(unused)] pub mod types; diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index 4e8c0bec2..570abf0ae 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -1,4 +1,3 @@ -// use std::convert::TryFrom; use std::collections::HashMap; use futures::channel::mpsc; diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index b283198f4..7ed28a65f 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -1,10 +1,8 @@ -use std::collections::HashMap as ImHashMap; +// use common::safe_arithmetic::SafeSignedArithmetic; +use common::ser_utils::ser_string; -use common::safe_arithmetic::SafeSignedArithmetic; -use common::ser_utils::{ser_b64, ser_map_b64_any, ser_string}; - -use proto::crypto::{PublicKey, Uid}; -use proto::funder::messages::{Currency, PendingTransaction}; +use proto::crypto::Uid; +use proto::funder::messages::PendingTransaction; use futures::channel::{mpsc, oneshot}; use futures::SinkExt; From b7ed238d7879b95ce85d1b52148012f0e0730969 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 17:37:43 +0300 Subject: [PATCH 092/478] funder: Removed unused struct --- components/funder/src/mutual_credit/outgoing.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index e40c59bcb..5a498cc97 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -14,15 +14,6 @@ use signature::signature_buff::create_response_signature_buffer; use crate::mutual_credit::types::{McOpError, McTransaction}; use crate::types::create_pending_transaction; -/// Processes outgoing funds for a token channel. -/// Used to batch as many funds as possible. -#[derive(Debug)] -pub struct OutgoingMc { - mc_transaction: McTransaction, - currency: Currency, - local_public_key: PublicKey, -} - #[derive(Debug, From)] pub enum QueueOperationError { // RemoteMaxDebtTooLarge, From 240ee5d687fb1440f054222772358e3047a5d731 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 13 Oct 2020 20:46:10 +0300 Subject: [PATCH 093/478] funder: Some work on macros for transactions interfaces --- components/funder/src/lib.rs | 6 + components/funder/src/token_channel.rs | 135 +++++++++++++++++-- components/funder/src/token_channel_macro.rs | 103 ++++++++++++++ 3 files changed, 231 insertions(+), 13 deletions(-) create mode 100644 components/funder/src/token_channel_macro.rs diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index e3713dfda..19672f1e3 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -27,7 +27,13 @@ extern crate quickcheck_derive; mod mutual_credit; // pub mod report; // mod state; +// #[allow(unused)] // mod token_channel; +// +// For testing: +#[allow(dead_code)] +mod token_channel_macro; + pub mod types; // #[cfg(test)] diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index a6eb74a71..a9b0c4eac 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -1,10 +1,12 @@ use std::cmp::Ordering; use std::convert::TryFrom; +use futures::channel::{mpsc, oneshot}; + use im::hashset::HashSet as ImHashSet; use std::collections::HashMap as ImHashMap; -use common::ser_utils::ser_map_str_any; +// use common::ser_utils::ser_map_str_any; use signature::canonical::CanonicalSerialize; @@ -22,27 +24,134 @@ use signature::signature_buff::hash_token_info; use signature::verify::verify_move_token; use crate::mutual_credit::incoming::{ - process_operations_list, IncomingMessage, ProcessOperationOutput, ProcessTransListError, + process_operations_list, IncomingMessage, ProcessTransListError, }; -use crate::mutual_credit::outgoing::OutgoingMc; -use crate::mutual_credit::types::{McMutationOld, MutualCredit}; +use crate::mutual_credit::outgoing::queue_operation; +use crate::mutual_credit::types::{McOp, McTransaction}; use crate::types::{create_hashed, create_unsigned_move_token, MoveTokenHashed}; +/* #[derive(Arbitrary, Debug, Clone, Serialize, Deserialize)] pub enum SetDirection { Incoming(MoveTokenHashed), Outgoing((MoveToken, TokenInfo)), } +*/ + +#[derive(Debug)] +pub enum TcOpError { + SendOpFailed, + ResponseOpFailed(oneshot::Canceled), +} + +pub type TcOpResult = Result; +pub type TcOpSenderResult = oneshot::Sender>; #[allow(clippy::large_enum_variant)] -#[derive(Arbitrary, Debug, Clone)] -pub enum TcMutation { - McMutation((Currency, McMutationOld)), - SetLocalActiveCurrencies(Vec), - SetRemoteActiveCurrencies(Vec), - AddMutualCredit(Currency), - SetDirection(SetDirection), +#[derive(Debug, Clone)] +pub enum TcOp { + // Internal mutual credit operations: + McGetBalance(Currency, TcOpSenderResult), + McSetBalance(Currency, i128, TcOpSenderResult<()>), + McSetLocalPendingDebt(Currency, u128, TcOpSenderResult<()>), + McSetRemotePendingDebt(Currency, u128, TcOpSenderResult<()>), + McGetLocalPendingTransaction(Currency, Uid, TcOpSenderResult>), + McInsertLocalPendingTransaction(Currency, PendingTransaction, TcOpSenderResult<()>), + McRemoveLocalPendingTransaction(Currency, Uid, TcOpSenderResult<()>), + McGetRemotePendingTransaction(Currency, Uid, TcOpSenderResult>), + McInsertRemotePendingTransaction(Currency, PendingTransaction, TcOpSenderResult<()>), + McRemoveRemotePendingTransaction(Currency, Uid, TcOpSenderResult<()>), + + // Token channel operations: + SetLocalActiveCurrencies(Vec, TcOpSenderResult<()>), + SetRemoteActiveCurrencies(Vec, TcOpSenderResult<()>), + AddMutualCredit(Currency, TcOpSenderResult<()>), + SetDirectionIncoming(MoveTokenHashed, TcOpSenderResult<()>), + SetDirectionOutgoing(MoveToken, TokenInfo, TcOpSenderResult<()>), +} + +macro_rules! ops_enum { + (($op_enum:ident <$($ty:ident),*>, $op_error:ident, $transaction:ident), + $( + { + ($variant_camel:ident, $variant_snake:ident), + ($(($arg_name:ident, $arg_type:ident)),*), + $ret_type:ident + } + ),* + + ) => { + /// Enum for all possible operations + pub enum $op_enum<$(ty),*> { + $( + $variant_camel($($arg_type),* , oneshot::Sender>) + )* + } + + + /// A transaction client + pub struct $transaction { + sender: mpsc::Sender<$op_enum<$(ty),*>, + } + + impl<$(ty),*> $transaction<$(ty),*> { + $( + async fn $variant_snake($($arg_name: $arg_type),*) -> Result<$ret_type, $op_error> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = $op_enum::$variant_camel($($arg_name),*, op_sender); + self.sender + .send(op) + .await + .map_err(|_| TcOpError::SendOpFailed)?; + op_receiver.await.map_err(TcOpError::ResponseOpFailed)? + } + )* + } + }; +} + +ops_enum!((TcOp, TcOpError, TcTransaction), +{ + (McGetBalance, mc_get_balance), + (currency, Currency), + McBalance +}); + +pub struct TcTransaction { + sender: mpsc::Sender>, +} + +impl TcTransaction { + async fn mc_get_balance(currency: Currency) -> TcOpResult { + let (op_sender, op_receiver) = oneshot::channel(); + let op = TcOp::McGetBalance(balance, op_sender); + self.sender + .send(op) + .await + .map_err(|_| TcOpError::SendOpFailed)?; + op_receiver.await.map_err(TcOpError::ResponseOpFailed)? + } + + async fn set_local_active_currencies(currencies: Vec) { + todo!(); + } + + async fn set_remote_active_currencies(currencies: Vec) { + todo!(); + } + + async fn add_mutual_credit(currency: Currency) { + todo!(); + } + + async fn set_direction_incoming(move_token_hashed: MoveTokenHashed) { + todo!(); + } + + async fn set_direction_outgoing(move_token: MoveToken, token_info: TokenInfo) { + todo!(); + } } /// The currencies set to be active by two sides of the token channel. @@ -107,10 +216,9 @@ pub enum TcDirectionBorrow<'a, B> { Out(TcOutBorrow<'a, B>), } -#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct TokenChannel { direction: TcDirection, - #[serde(with = "ser_map_str_any")] mutual_credits: ImHashMap, active_currencies: ActiveCurrencies, } @@ -1228,3 +1336,4 @@ mod tests { // TODO: Add more tests. // - Test behaviour of Duplicate, ChainInconsistency } +} diff --git a/components/funder/src/token_channel_macro.rs b/components/funder/src/token_channel_macro.rs new file mode 100644 index 000000000..b90d4a40f --- /dev/null +++ b/components/funder/src/token_channel_macro.rs @@ -0,0 +1,103 @@ +use futures::channel::{mpsc, oneshot}; +use futures::SinkExt; + +#[derive(Debug)] +pub enum OpError { + SendOpFailed, + ResponseOpFailed(oneshot::Canceled), +} + +macro_rules! ops_enum { + // Enum without type arguments: + (($op_enum:ident, $transaction:ident), + $( + { + ($variant_camel:ident, $variant_snake:ident), + ($(($arg_name:ident, $arg_type:path)),*), + $ret_type:ident + } + ),* + + ) => { + /// Enum for all possible operations + pub enum $op_enum { + $( + $variant_camel($($arg_type),* , oneshot::Sender>) + )* + } + + + /// A transaction client + pub struct $transaction { + sender: mpsc::Sender<$op_enum>, + } + + impl $transaction { + $( + async fn $variant_snake(&mut self, $($arg_name: $arg_type),*) -> Result<$ret_type, OpError> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = $op_enum::$variant_camel($($arg_name),*, op_sender); + self.sender + .send(op) + .await + .map_err(|_| OpError::SendOpFailed)?; + op_receiver.await.map_err(OpError::ResponseOpFailed)? + } + )* + } + }; + + // Enum with type arguments: + (($op_enum:ident <$($ty:ident),*>, $transaction:ident), + $( + { + ($variant_camel:ident, $variant_snake:ident), + ($(($arg_name:ident, $arg_type:path)),*), + $ret_type:ident + } + ),* + + ) => { + /// Enum for all possible operations + pub enum $op_enum<$($ty),*> { + $( + $variant_camel($($arg_type),* , oneshot::Sender>) + )* + } + + + /// A transaction client + pub struct $transaction<$($ty),*> { + sender: mpsc::Sender<$op_enum<$($ty),*>>, + } + + impl<$($ty),*> $transaction<$($ty),*> { + $( + async fn $variant_snake(&mut self, $($arg_name: $arg_type),*) -> Result<$ret_type, OpError> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = $op_enum::$variant_camel($($arg_name),*, op_sender); + self.sender + .send(op) + .await + .map_err(|_| OpError::SendOpFailed)?; + op_receiver.await.map_err(OpError::ResponseOpFailed)? + } + )* + } + }; + +} + +ops_enum!((TcOp, TcTransaction), +{ + (McGetBalance, mc_get_balance), + ((hello, Option::)), + u32 +}); + +ops_enum!((TcOp2, TcTransaction2), +{ + (McGetBalance, mc_get_balance), + ((hello, String)), + u32 +}); From e02d9d72250c67b45197eaeee175056189df2f64 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 11:06:02 +0300 Subject: [PATCH 094/478] funder: mutual_credit: macro syntax enhancements --- components/funder/src/token_channel_macro.rs | 44 +++++++------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/components/funder/src/token_channel_macro.rs b/components/funder/src/token_channel_macro.rs index b90d4a40f..747a2c537 100644 --- a/components/funder/src/token_channel_macro.rs +++ b/components/funder/src/token_channel_macro.rs @@ -8,18 +8,14 @@ pub enum OpError { } macro_rules! ops_enum { - // Enum without type arguments: - (($op_enum:ident, $transaction:ident), + // Enum with type arguments: + ({$op_enum:ident, $transaction:ident}, $( - { - ($variant_camel:ident, $variant_snake:ident), - ($(($arg_name:ident, $arg_type:path)),*), - $ret_type:ident - } + $variant_snake:ident, $variant_camel:ident($($arg_name:ident: $arg_type:path),*) -> $ret_type:ident ),* ) => { - /// Enum for all possible operations + // Enum for all possible operations pub enum $op_enum { $( $variant_camel($($arg_type),* , oneshot::Sender>) @@ -27,7 +23,7 @@ macro_rules! ops_enum { } - /// A transaction client + // A transaction client pub struct $transaction { sender: mpsc::Sender<$op_enum>, } @@ -48,17 +44,13 @@ macro_rules! ops_enum { }; // Enum with type arguments: - (($op_enum:ident <$($ty:ident),*>, $transaction:ident), + ({$op_enum:ident <$($ty:ident),*>, $transaction:ident}, $( - { - ($variant_camel:ident, $variant_snake:ident), - ($(($arg_name:ident, $arg_type:path)),*), - $ret_type:ident - } + $variant_snake:ident, $variant_camel:ident($($arg_name:ident: $arg_type:path),*) -> $ret_type:ident ),* ) => { - /// Enum for all possible operations + // Enum for all possible operations pub enum $op_enum<$($ty),*> { $( $variant_camel($($arg_type),* , oneshot::Sender>) @@ -66,7 +58,7 @@ macro_rules! ops_enum { } - /// A transaction client + // A transaction client pub struct $transaction<$($ty),*> { sender: mpsc::Sender<$op_enum<$($ty),*>>, } @@ -88,16 +80,10 @@ macro_rules! ops_enum { } -ops_enum!((TcOp, TcTransaction), -{ - (McGetBalance, mc_get_balance), - ((hello, Option::)), - u32 -}); +ops_enum!({TcOp, TcTransaction}, + mc_get_balance, McGetBalance(hello: Option::) -> u32 +); -ops_enum!((TcOp2, TcTransaction2), -{ - (McGetBalance, mc_get_balance), - ((hello, String)), - u32 -}); +ops_enum!({TcOp2, TcTransaction2}, + mc_get_balance, McGetBalance(hello: String) -> u32 +); From 1ad8c5d6180809213c0a3d38591e3f4e8f1429c8 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 11:55:16 +0300 Subject: [PATCH 095/478] common: Added ops_enum macro --- Cargo.lock | 7 +++ components/common/Cargo.toml | 2 +- components/common/src/lib.rs | 3 ++ components/common/src/ops_enum.rs | 72 +++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 components/common/src/ops_enum.rs diff --git a/Cargo.lock b/Cargo.lock index 33d9ae638..490f0627d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -984,6 +984,7 @@ dependencies = [ "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "paste 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1394,6 +1395,11 @@ dependencies = [ "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "paste" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "paste-impl" version = "0.1.16" @@ -2321,6 +2327,7 @@ dependencies = [ "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum parking 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c4029bc3504a62d92e42f30b9095fdef73b8a0b2a06aa41ce2935143b05a1a06" "checksum paste 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "d508492eeb1e5c38ee696371bf7b9fc33c83d46a7d451606b96458fbbbdc2dec" +"checksum paste 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0520af26d4cf99643dbbe093a61507922b57232d9978d8491fdc8f7b44573c8c" "checksum paste-impl 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "84f328a6a63192b333fce5fbb4be79db6758a4d518dfac6d54412f1492f72d32" "checksum pin-project 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e75373ff9037d112bb19bc61333a06a159eaeb217660dcfbea7d88e1db823919" "checksum pin-project-internal 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "10b4b44893d3c370407a1d6a5cfde7c41ae0478e31c516c85f67eb3adc51be6d" diff --git a/components/common/Cargo.toml b/components/common/Cargo.toml index 708f0314b..3e6d2dc26 100644 --- a/components/common/Cargo.toml +++ b/components/common/Cargo.toml @@ -8,7 +8,6 @@ edition = "2018" [dependencies] log = "0.4" - bytes = "0.5.4" futures = "0.3.1" @@ -21,3 +20,4 @@ base64 = "0.10.1" [dev-dependencies] serde = {version = "1.0.104", features = ["derive"]} +paste = "1.0.1" diff --git a/components/common/src/lib.rs b/components/common/src/lib.rs index b7040b044..953781f0c 100644 --- a/components/common/src/lib.rs +++ b/components/common/src/lib.rs @@ -16,7 +16,10 @@ extern crate serde; pub mod int_convert; pub mod never; +pub mod ops_enum; pub mod safe_arithmetic; + +// TODO: Big array might not be needed: #[macro_use] pub mod big_array; #[macro_use] diff --git a/components/common/src/ops_enum.rs b/components/common/src/ops_enum.rs new file mode 100644 index 000000000..9e7056cf7 --- /dev/null +++ b/components/common/src/ops_enum.rs @@ -0,0 +1,72 @@ +use futures::channel::oneshot; + +#[derive(Debug)] +pub enum OpError { + SendOpFailed, + ResponseOpFailed(oneshot::Canceled), +} + +/// Create an async interface for request/response messages +/// Generates an enum of all possible RPC messages, and an async interface that knows how to send +/// those RPC messages. +#[macro_export] +macro_rules! ops_enum { + (($op_enum:ident $(<$($ty:ident),*>)?, $transaction:ident) => { + $( + $variant_snake:ident ($($arg_name:ident: $arg_type:path),*) -> $ret_type:path + );* + // Possibly an extra semicolon: + $(;)? + }) => { + paste! { + // Enum for all possible operations + pub enum $op_enum$(<$($ty),*>)? { + $( + [<$variant_snake:camel>]($($arg_type),* , oneshot::Sender>) + ),* + } + } + + // A transaction client + pub struct $transaction$(<$($ty),*>)? { + sender: mpsc::Sender<$op_enum$(<$($ty),*>)?>, + } + + paste! { + impl$(<$($ty),*>)? $transaction$(<$($ty),*>)? { + $( + async fn $variant_snake(&mut self, $($arg_name: $arg_type),*) -> Result<$ret_type, OpError> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = $op_enum::[<$variant_snake:camel>]($($arg_name),*, op_sender); + self.sender + .send(op) + .await + .map_err(|_| OpError::SendOpFailed)?; + op_receiver.await.map_err(OpError::ResponseOpFailed)? + } + )* + } + } + }; + +} + +#[allow(dead_code)] +#[cfg(test)] +mod tests { + use super::*; + + use futures::channel::mpsc; + use futures::SinkExt; + use paste::paste; + + ops_enum!((TcOp1, TcTransaction1) => { + func1(hello: Option) -> u32; + func2(world: u64) -> u32; + }); + + ops_enum!((TcOp2, TcTransaction2) => { + func1(hello: String) -> Result; + func2(world: String) -> u32 + }); +} From ded5f295f2b9c6715ef2334783fbf94ff88b406a Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 11:56:16 +0300 Subject: [PATCH 096/478] funder: Removed draft macro --- components/funder/src/lib.rs | 2 - components/funder/src/token_channel_macro.rs | 89 -------------------- 2 files changed, 91 deletions(-) delete mode 100644 components/funder/src/token_channel_macro.rs diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 19672f1e3..f9cbafb90 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -31,8 +31,6 @@ mod mutual_credit; // mod token_channel; // // For testing: -#[allow(dead_code)] -mod token_channel_macro; pub mod types; diff --git a/components/funder/src/token_channel_macro.rs b/components/funder/src/token_channel_macro.rs deleted file mode 100644 index 747a2c537..000000000 --- a/components/funder/src/token_channel_macro.rs +++ /dev/null @@ -1,89 +0,0 @@ -use futures::channel::{mpsc, oneshot}; -use futures::SinkExt; - -#[derive(Debug)] -pub enum OpError { - SendOpFailed, - ResponseOpFailed(oneshot::Canceled), -} - -macro_rules! ops_enum { - // Enum with type arguments: - ({$op_enum:ident, $transaction:ident}, - $( - $variant_snake:ident, $variant_camel:ident($($arg_name:ident: $arg_type:path),*) -> $ret_type:ident - ),* - - ) => { - // Enum for all possible operations - pub enum $op_enum { - $( - $variant_camel($($arg_type),* , oneshot::Sender>) - )* - } - - - // A transaction client - pub struct $transaction { - sender: mpsc::Sender<$op_enum>, - } - - impl $transaction { - $( - async fn $variant_snake(&mut self, $($arg_name: $arg_type),*) -> Result<$ret_type, OpError> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = $op_enum::$variant_camel($($arg_name),*, op_sender); - self.sender - .send(op) - .await - .map_err(|_| OpError::SendOpFailed)?; - op_receiver.await.map_err(OpError::ResponseOpFailed)? - } - )* - } - }; - - // Enum with type arguments: - ({$op_enum:ident <$($ty:ident),*>, $transaction:ident}, - $( - $variant_snake:ident, $variant_camel:ident($($arg_name:ident: $arg_type:path),*) -> $ret_type:ident - ),* - - ) => { - // Enum for all possible operations - pub enum $op_enum<$($ty),*> { - $( - $variant_camel($($arg_type),* , oneshot::Sender>) - )* - } - - - // A transaction client - pub struct $transaction<$($ty),*> { - sender: mpsc::Sender<$op_enum<$($ty),*>>, - } - - impl<$($ty),*> $transaction<$($ty),*> { - $( - async fn $variant_snake(&mut self, $($arg_name: $arg_type),*) -> Result<$ret_type, OpError> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = $op_enum::$variant_camel($($arg_name),*, op_sender); - self.sender - .send(op) - .await - .map_err(|_| OpError::SendOpFailed)?; - op_receiver.await.map_err(OpError::ResponseOpFailed)? - } - )* - } - }; - -} - -ops_enum!({TcOp, TcTransaction}, - mc_get_balance, McGetBalance(hello: Option::) -> u32 -); - -ops_enum!({TcOp2, TcTransaction2}, - mc_get_balance, McGetBalance(hello: String) -> u32 -); From 0600a324b2275c040a92673c387888014f96ae71 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 12:39:57 +0300 Subject: [PATCH 097/478] common: async_rpc: Allowing unit return type --- components/common/src/async_rpc.rs | 120 +++++++++++++++++++++++++++++ components/common/src/lib.rs | 2 +- components/common/src/ops_enum.rs | 72 ----------------- 3 files changed, 121 insertions(+), 73 deletions(-) create mode 100644 components/common/src/async_rpc.rs delete mode 100644 components/common/src/ops_enum.rs diff --git a/components/common/src/async_rpc.rs b/components/common/src/async_rpc.rs new file mode 100644 index 000000000..8a2e1b671 --- /dev/null +++ b/components/common/src/async_rpc.rs @@ -0,0 +1,120 @@ +use futures::channel::oneshot; + +#[derive(Debug)] +pub enum OpError { + SendOpFailed, + ResponseOpFailed(oneshot::Canceled), +} + +/* +macro_rules! ops_enum_func { + ($variant_snake:ident($($arg_name: $arg_type),*) -> $ret_type) => { + paste! { + async fn $variant_snake(&mut self, $($arg_name: $arg_type),*) -> Result<$ret_type, OpError> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = $op_enum::[<$variant_snake:camel>]($($arg_name),*, op_sender); + self.sender + .send(op) + .await + .map_err(|_| OpError::SendOpFailed)?; + op_receiver.await.map_err(OpError::ResponseOpFailed)? + } + } + }; + + ($variant_snake:ident($($arg_name: $arg_type),*)) => { + paste! { + async fn $variant_snake(&mut self, $($arg_name: $arg_type),*) { + let (op_sender, op_receiver) = oneshot::channel(); + let op = $op_enum::[<$variant_snake:camel>]($($arg_name),*, op_sender); + self.sender + .send(op) + .await + .map_err(|_| OpError::SendOpFailed)?; + op_receiver.await.map_err(OpError::ResponseOpFailed)? + } + } + }; +} +*/ + +// A helper macro, allowing to have functions with unit "()" return value. +#[doc(hidden)] +#[macro_export] +macro_rules! get_out_type { + ($ret_type:path) => { + $ret_type + }; + () => { + () + }; +} + +#[macro_export] +/// Create an async interface for request/response messages +/// Generates an enum of all possible RPC messages, and an async interface that knows how to send +/// those RPC messages. +macro_rules! ops_enum { + (($op_enum:ident $(<$($ty:ident),*>)?, $transaction:ident) => { + $( + $variant_snake:ident ($($arg_name:ident: $arg_type:path),*) $(-> $ret_type:path)? + );* + // Possibly an extra semicolon: + $(;)? + }) => { + paste! { + // Enum for all possible operations + pub enum $op_enum$(<$($ty),*>)? { + $( + [<$variant_snake:camel>]($($arg_type),* , oneshot::Sender>) + ),* + } + } + + // A transaction client + pub struct $transaction$(<$($ty),*>)? { + sender: mpsc::Sender<$op_enum$(<$($ty),*>)?>, + } + + impl$(<$($ty),*>)? $transaction$(<$($ty),*>)? { + $( + paste! { + async fn $variant_snake(&mut self, $($arg_name: $arg_type),*) -> Result< get_out_type!($($ret_type)?) , OpError> { + let (op_sender, op_receiver) = oneshot::channel(); + let op = $op_enum::[<$variant_snake:camel>]($($arg_name),*, op_sender); + self.sender + .send(op) + .await + .map_err(|_| OpError::SendOpFailed)?; + op_receiver.await.map_err(OpError::ResponseOpFailed)? + } + } + )* + } + }; + +} + +#[allow(dead_code)] +#[cfg(test)] +mod tests { + use super::*; + + use futures::channel::mpsc; + use futures::SinkExt; + use paste::paste; + + #[test] + fn test_rpc_enums() { + ops_enum!((TcOp1, TcTransaction1) => { + func1(hello: Option) -> u32; + func2(world: u64) -> u32; + func3(world: u64); + }); + + ops_enum!((TcOp2, TcTransaction2) => { + func1(hello: String) -> Result; + func2(world: String) -> u32 + }); + } +} diff --git a/components/common/src/lib.rs b/components/common/src/lib.rs index 953781f0c..e27693593 100644 --- a/components/common/src/lib.rs +++ b/components/common/src/lib.rs @@ -14,9 +14,9 @@ extern crate log; #[cfg(test)] extern crate serde; +pub mod async_rpc; pub mod int_convert; pub mod never; -pub mod ops_enum; pub mod safe_arithmetic; // TODO: Big array might not be needed: diff --git a/components/common/src/ops_enum.rs b/components/common/src/ops_enum.rs deleted file mode 100644 index 9e7056cf7..000000000 --- a/components/common/src/ops_enum.rs +++ /dev/null @@ -1,72 +0,0 @@ -use futures::channel::oneshot; - -#[derive(Debug)] -pub enum OpError { - SendOpFailed, - ResponseOpFailed(oneshot::Canceled), -} - -/// Create an async interface for request/response messages -/// Generates an enum of all possible RPC messages, and an async interface that knows how to send -/// those RPC messages. -#[macro_export] -macro_rules! ops_enum { - (($op_enum:ident $(<$($ty:ident),*>)?, $transaction:ident) => { - $( - $variant_snake:ident ($($arg_name:ident: $arg_type:path),*) -> $ret_type:path - );* - // Possibly an extra semicolon: - $(;)? - }) => { - paste! { - // Enum for all possible operations - pub enum $op_enum$(<$($ty),*>)? { - $( - [<$variant_snake:camel>]($($arg_type),* , oneshot::Sender>) - ),* - } - } - - // A transaction client - pub struct $transaction$(<$($ty),*>)? { - sender: mpsc::Sender<$op_enum$(<$($ty),*>)?>, - } - - paste! { - impl$(<$($ty),*>)? $transaction$(<$($ty),*>)? { - $( - async fn $variant_snake(&mut self, $($arg_name: $arg_type),*) -> Result<$ret_type, OpError> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = $op_enum::[<$variant_snake:camel>]($($arg_name),*, op_sender); - self.sender - .send(op) - .await - .map_err(|_| OpError::SendOpFailed)?; - op_receiver.await.map_err(OpError::ResponseOpFailed)? - } - )* - } - } - }; - -} - -#[allow(dead_code)] -#[cfg(test)] -mod tests { - use super::*; - - use futures::channel::mpsc; - use futures::SinkExt; - use paste::paste; - - ops_enum!((TcOp1, TcTransaction1) => { - func1(hello: Option) -> u32; - func2(world: u64) -> u32; - }); - - ops_enum!((TcOp2, TcTransaction2) => { - func1(hello: String) -> Result; - func2(world: String) -> u32 - }); -} From 06269a3d8b5ed5dcac37b2ae3d9c8e09d23bfd56 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 12:48:36 +0300 Subject: [PATCH 098/478] common: async_rpc: Dealing with case of empty arguments list --- components/common/src/async_rpc.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/components/common/src/async_rpc.rs b/components/common/src/async_rpc.rs index 8a2e1b671..6aadece8b 100644 --- a/components/common/src/async_rpc.rs +++ b/components/common/src/async_rpc.rs @@ -57,7 +57,7 @@ macro_rules! get_out_type { macro_rules! ops_enum { (($op_enum:ident $(<$($ty:ident),*>)?, $transaction:ident) => { $( - $variant_snake:ident ($($arg_name:ident: $arg_type:path),*) $(-> $ret_type:path)? + $variant_snake:ident ($($($arg_name:ident: $arg_type:path),+)?) $(-> $ret_type:path)? );* // Possibly an extra semicolon: $(;)? @@ -66,7 +66,7 @@ macro_rules! ops_enum { // Enum for all possible operations pub enum $op_enum$(<$($ty),*>)? { $( - [<$variant_snake:camel>]($($arg_type),* , oneshot::Sender>) + [<$variant_snake:camel>]($($($arg_type),+ ,)? oneshot::Sender>) ),* } } @@ -79,9 +79,9 @@ macro_rules! ops_enum { impl$(<$($ty),*>)? $transaction$(<$($ty),*>)? { $( paste! { - async fn $variant_snake(&mut self, $($arg_name: $arg_type),*) -> Result< get_out_type!($($ret_type)?) , OpError> { + async fn $variant_snake(&mut self $(, $($arg_name: $arg_type),+)?) -> Result< get_out_type!($($ret_type)?) , OpError> { let (op_sender, op_receiver) = oneshot::channel(); - let op = $op_enum::[<$variant_snake:camel>]($($arg_name),*, op_sender); + let op = $op_enum::[<$variant_snake:camel>]($($($arg_name),+,)? op_sender); self.sender .send(op) .await @@ -108,8 +108,10 @@ mod tests { fn test_rpc_enums() { ops_enum!((TcOp1, TcTransaction1) => { func1(hello: Option) -> u32; - func2(world: u64) -> u32; - func3(world: u64); + func2() -> u8; + func3(); + func4(world: u64) -> u32; + func5(world: u64); }); ops_enum!((TcOp2, TcTransaction2) => { From 248c883c0d7c253807996563a5b7a67819ce42c9 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 12:57:13 +0300 Subject: [PATCH 099/478] common: async_rpc: Added transaction constructor --- components/common/src/async_rpc.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/common/src/async_rpc.rs b/components/common/src/async_rpc.rs index 6aadece8b..5370fb4bf 100644 --- a/components/common/src/async_rpc.rs +++ b/components/common/src/async_rpc.rs @@ -77,6 +77,9 @@ macro_rules! ops_enum { } impl$(<$($ty),*>)? $transaction$(<$($ty),*>)? { + pub fn new(sender: mpsc::Sender<$op_enum$(<$($ty),*>)?>) -> Self { + Self { sender } + } $( paste! { async fn $variant_snake(&mut self $(, $($arg_name: $arg_type),+)?) -> Result< get_out_type!($($ret_type)?) , OpError> { From bf95c641ed65d883ef5d61accdf3b9bfee55e90d Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 12:57:38 +0300 Subject: [PATCH 100/478] common: async_rpc: Changed async methods to be public --- components/common/src/async_rpc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/common/src/async_rpc.rs b/components/common/src/async_rpc.rs index 5370fb4bf..df9635f36 100644 --- a/components/common/src/async_rpc.rs +++ b/components/common/src/async_rpc.rs @@ -82,7 +82,7 @@ macro_rules! ops_enum { } $( paste! { - async fn $variant_snake(&mut self $(, $($arg_name: $arg_type),+)?) -> Result< get_out_type!($($ret_type)?) , OpError> { + pub async fn $variant_snake(&mut self $(, $($arg_name: $arg_type),+)?) -> Result< get_out_type!($($ret_type)?) , OpError> { let (op_sender, op_receiver) = oneshot::channel(); let op = $op_enum::[<$variant_snake:camel>]($($($arg_name),+,)? op_sender); self.sender From 0de65cb0554344363bf04aff659904eab3c95852 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 12:58:14 +0300 Subject: [PATCH 101/478] funder: mutual_credit: Using ops_enum! instead of manual methods --- Cargo.lock | 1 + components/funder/Cargo.toml | 2 + .../funder/src/mutual_credit/incoming.rs | 5 +- .../funder/src/mutual_credit/outgoing.rs | 5 +- components/funder/src/mutual_credit/types.rs | 188 ++---------------- 5 files changed, 27 insertions(+), 174 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 490f0627d..2ad01c2a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1064,6 +1064,7 @@ dependencies = [ "offset-identity 0.1.0", "offset-proto 0.1.0", "offset-signature 0.1.0", + "paste 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_env_logger 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "quickcheck_derive 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/funder/Cargo.toml b/components/funder/Cargo.toml index 1bf69f902..96bec8b7b 100644 --- a/components/funder/Cargo.toml +++ b/components/funder/Cargo.toml @@ -34,6 +34,8 @@ quickcheck_macros = {version = "0.8"} quickcheck_derive = {version = "0.2.1"} rand = {version = "0.7.2"} +paste = "1.0.1" + [dev-dependencies] futures = {version = "0.3.1", features = ["thread-pool"]} diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 548614a8f..bd69f0aef 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -3,6 +3,7 @@ use derive_more::From; use crypto::hash_lock::HashLock; use crypto::identity::verify_signature; +use common::async_rpc::OpError; use common::safe_arithmetic::SafeSignedArithmetic; use proto::crypto::PublicKey; @@ -15,7 +16,7 @@ use signature::signature_buff::create_response_signature_buffer; use crate::types::create_pending_transaction; -use super::types::{McOpError, McTransaction}; +use super::types::McTransaction; #[derive(Debug)] pub struct IncomingResponseSendFundsOp { @@ -47,7 +48,7 @@ pub enum ProcessOperationError { InvalidResponseSignature, InvalidSrcPlainLock, DestPaymentExceedsTotal, - McOpError(McOpError), + OpError(OpError), } #[derive(Debug)] diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 5a498cc97..26faa4584 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -3,6 +3,7 @@ use derive_more::From; use crypto::hash_lock::HashLock; use crypto::identity::verify_signature; +use common::async_rpc::OpError; use common::safe_arithmetic::SafeSignedArithmetic; use proto::crypto::PublicKey; @@ -11,7 +12,7 @@ use proto::funder::messages::{ }; use signature::signature_buff::create_response_signature_buffer; -use crate::mutual_credit::types::{McOpError, McTransaction}; +use crate::mutual_credit::types::McTransaction; use crate::types::create_pending_transaction; #[derive(Debug, From)] @@ -25,7 +26,7 @@ pub enum QueueOperationError { InvalidResponseSignature, InvalidSrcPlainLock, DestPaymentExceedsTotal, - McOpError(McOpError), + OpError(OpError), } /// A wrapper over a token channel, accumulating operations to be sent as one transaction. diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 7ed28a65f..b3ab2f7ae 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -1,5 +1,11 @@ // use common::safe_arithmetic::SafeSignedArithmetic; + +// Used for macros: +use paste::paste; + +use common::async_rpc::OpError; use common::ser_utils::ser_string; +use common::{get_out_type, ops_enum}; use proto::crypto::Uid; use proto::funder::messages::PendingTransaction; @@ -7,15 +13,6 @@ use proto::funder::messages::PendingTransaction; use futures::channel::{mpsc, oneshot}; use futures::SinkExt; -#[derive(Debug)] -pub enum McOpError { - SendOpFailed, - ResponseOpFailed(oneshot::Canceled), -} - -pub type McOpResult = Result; -pub type McOpSenderResult = oneshot::Sender>; - #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct McBalance { /// Amount of credits this side has against the remote side. @@ -42,164 +39,15 @@ impl McBalance { } } -#[derive(Debug)] -pub enum McOp { - GetBalance(McOpSenderResult), - SetBalance(i128, McOpSenderResult<()>), - SetLocalPendingDebt(u128, McOpSenderResult<()>), - SetRemotePendingDebt(u128, McOpSenderResult<()>), - GetLocalPendingTransaction(Uid, McOpSenderResult>), - InsertLocalPendingTransaction(PendingTransaction, McOpSenderResult<()>), - RemoveLocalPendingTransaction(Uid, McOpSenderResult<()>), - GetRemotePendingTransaction(Uid, McOpSenderResult>), - InsertRemotePendingTransaction(PendingTransaction, McOpSenderResult<()>), - RemoveRemotePendingTransaction(Uid, McOpSenderResult<()>), - // Commit(McOpSenderResult<()>), -} - -// TODO: Remove unused hint: -#[allow(unused)] -#[derive(Debug)] -pub struct McTransaction { - sender: mpsc::Sender, -} - -// TODO: Remove unused hint: -#[allow(unused)] -impl McTransaction { - pub fn new(sender: mpsc::Sender) -> Self { - Self { sender } - } - pub async fn get_balance(&mut self) -> McOpResult { - let (op_sender, op_receiver) = oneshot::channel(); - let op = McOp::GetBalance(op_sender); - self.sender - .send(op) - .await - .map_err(|_| McOpError::SendOpFailed)?; - op_receiver.await.map_err(McOpError::ResponseOpFailed)? - } - pub async fn set_balance(&mut self, balance: i128) -> McOpResult<()> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = McOp::SetBalance(balance, op_sender); - self.sender - .send(op) - .await - .map_err(|_| McOpError::SendOpFailed)?; - op_receiver.await.map_err(McOpError::ResponseOpFailed)? - } - pub async fn set_local_pending_debt(&mut self, local_pending_debt: u128) -> McOpResult<()> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = McOp::SetLocalPendingDebt(local_pending_debt, op_sender); - self.sender - .send(op) - .await - .map_err(|_| McOpError::SendOpFailed)?; - op_receiver.await.map_err(McOpError::ResponseOpFailed)? - } - pub async fn set_remote_pending_debt(&mut self, remote_pending_debt: u128) -> McOpResult<()> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = McOp::SetRemotePendingDebt(remote_pending_debt, op_sender); - self.sender - .send(op) - .await - .map_err(|_| McOpError::SendOpFailed)?; - op_receiver.await.map_err(McOpError::ResponseOpFailed)? - } - pub async fn get_local_pending_transaction( - &mut self, - request_id: Uid, - ) -> McOpResult> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = McOp::GetLocalPendingTransaction(request_id, op_sender); - self.sender - .send(op) - .await - .map_err(|_| McOpError::SendOpFailed)?; - op_receiver.await.map_err(McOpError::ResponseOpFailed)? - } - pub async fn insert_local_pending_transaction( - &mut self, - pending_transaction: PendingTransaction, - ) -> McOpResult<()> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = McOp::InsertLocalPendingTransaction(pending_transaction, op_sender); - self.sender - .send(op) - .await - .map_err(|_| McOpError::SendOpFailed)?; - op_receiver.await.map_err(McOpError::ResponseOpFailed)? - } - pub async fn remove_local_pending_transaction(&mut self, request_id: Uid) -> McOpResult<()> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = McOp::RemoveLocalPendingTransaction(request_id, op_sender); - self.sender - .send(op) - .await - .map_err(|_| McOpError::SendOpFailed)?; - op_receiver.await.map_err(McOpError::ResponseOpFailed)? - } - pub async fn get_remote_pending_transaction( - &mut self, - request_id: Uid, - ) -> McOpResult> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = McOp::GetRemotePendingTransaction(request_id, op_sender); - self.sender - .send(op) - .await - .map_err(|_| McOpError::SendOpFailed)?; - op_receiver.await.map_err(McOpError::ResponseOpFailed)? - } - pub async fn insert_remote_pending_transaction( - &mut self, - pending_transaction: PendingTransaction, - ) -> McOpResult<()> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = McOp::InsertRemotePendingTransaction(pending_transaction, op_sender); - self.sender - .send(op) - .await - .map_err(|_| McOpError::SendOpFailed)?; - op_receiver.await.map_err(McOpError::ResponseOpFailed)? - } - pub async fn remove_remote_pending_transaction(&mut self, request_id: Uid) -> McOpResult<()> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = McOp::RemoveRemotePendingTransaction(request_id, op_sender); - self.sender - .send(op) - .await - .map_err(|_| McOpError::SendOpFailed)?; - op_receiver.await.map_err(McOpError::ResponseOpFailed)? - } - - /* - async fn commit(mut self) -> McOpResult<()> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = McOp::Commit(op_sender); - self.sender - .send(op) - .await - .map_err(|_| McOpError::SendOpFailed)?; - op_receiver.await.map_err(McOpError::ResponseOpFailed)? - } - */ -} - -/* - // TODO: Remove unused hint - #[allow(unused)] - /// Calculate required balance for reset. - /// This would be current balance plus additional future profits. - pub fn balance_for_reset(&self) -> i128 { - self.state - .balance - .balance - .checked_add_unsigned(self.state.balance.remote_pending_debt) - .expect("Overflow when calculating balance_for_reset") - // TODO: Is this the correct formula? - // Other options: - // * balance - // * balance + remote_pending_debt - local_pending_debt - } -*/ +ops_enum!((McOp, McTransaction) => { + get_balance() -> McBalance; + set_balance(balance: i128); + set_local_pending_debt(debt: u128); + set_remote_pending_debt(debt: u128); + get_local_pending_transaction(request_id: Uid) -> Option; + insert_local_pending_transaction(pending_transaction: PendingTransaction); + remove_local_pending_transaction(request_id: Uid); + get_remote_pending_transaction(request_id: Uid) -> Option; + insert_remote_pending_transaction(pending_transaction: PendingTransaction); + remove_remote_pending_transaction(request_id: Uid); +}); From 008d4259905c78b6e4a5487d2b93b74b9ba6c5aa Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 13:13:06 +0300 Subject: [PATCH 102/478] funder: Initial work on token_channel. Not compiling --- components/funder/src/lib.rs | 4 +- components/funder/src/token_channel.rs | 134 +++++-------------------- 2 files changed, 28 insertions(+), 110 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index f9cbafb90..368c370ac 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -27,8 +27,8 @@ extern crate quickcheck_derive; mod mutual_credit; // pub mod report; // mod state; -// #[allow(unused)] -// mod token_channel; +#[allow(unused)] +mod token_channel; // // For testing: diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index a9b0c4eac..76f12a93c 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -1,7 +1,13 @@ use std::cmp::Ordering; use std::convert::TryFrom; +use paste::paste; + +use common::async_rpc::OpError; +use common::{get_out_type, ops_enum}; + use futures::channel::{mpsc, oneshot}; +use futures::SinkExt; use im::hashset::HashSet as ImHashSet; use std::collections::HashMap as ImHashMap; @@ -13,12 +19,12 @@ use signature::canonical::CanonicalSerialize; use crypto::hash::sha_512_256; use crypto::identity::compare_public_key; -use proto::crypto::{PublicKey, RandValue, Signature}; +use proto::crypto::{PublicKey, RandValue, Signature, Uid}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ BalanceInfo, CountersInfo, Currency, CurrencyBalanceInfo, CurrencyOperations, McInfo, - MoveToken, TokenInfo, UnsignedMoveToken, + MoveToken, PendingTransaction, TokenInfo, UnsignedMoveToken, }; use signature::signature_buff::hash_token_info; use signature::verify::verify_move_token; @@ -27,7 +33,7 @@ use crate::mutual_credit::incoming::{ process_operations_list, IncomingMessage, ProcessTransListError, }; use crate::mutual_credit::outgoing::queue_operation; -use crate::mutual_credit::types::{McOp, McTransaction}; +use crate::mutual_credit::types::{McBalance, McOp, McTransaction}; use crate::types::{create_hashed, create_unsigned_move_token, MoveTokenHashed}; @@ -48,112 +54,25 @@ pub enum TcOpError { pub type TcOpResult = Result; pub type TcOpSenderResult = oneshot::Sender>; -#[allow(clippy::large_enum_variant)] -#[derive(Debug, Clone)] -pub enum TcOp { - // Internal mutual credit operations: - McGetBalance(Currency, TcOpSenderResult), - McSetBalance(Currency, i128, TcOpSenderResult<()>), - McSetLocalPendingDebt(Currency, u128, TcOpSenderResult<()>), - McSetRemotePendingDebt(Currency, u128, TcOpSenderResult<()>), - McGetLocalPendingTransaction(Currency, Uid, TcOpSenderResult>), - McInsertLocalPendingTransaction(Currency, PendingTransaction, TcOpSenderResult<()>), - McRemoveLocalPendingTransaction(Currency, Uid, TcOpSenderResult<()>), - McGetRemotePendingTransaction(Currency, Uid, TcOpSenderResult>), - McInsertRemotePendingTransaction(Currency, PendingTransaction, TcOpSenderResult<()>), - McRemoveRemotePendingTransaction(Currency, Uid, TcOpSenderResult<()>), - - // Token channel operations: - SetLocalActiveCurrencies(Vec, TcOpSenderResult<()>), - SetRemoteActiveCurrencies(Vec, TcOpSenderResult<()>), - AddMutualCredit(Currency, TcOpSenderResult<()>), - SetDirectionIncoming(MoveTokenHashed, TcOpSenderResult<()>), - SetDirectionOutgoing(MoveToken, TokenInfo, TcOpSenderResult<()>), -} - -macro_rules! ops_enum { - (($op_enum:ident <$($ty:ident),*>, $op_error:ident, $transaction:ident), - $( - { - ($variant_camel:ident, $variant_snake:ident), - ($(($arg_name:ident, $arg_type:ident)),*), - $ret_type:ident - } - ),* - - ) => { - /// Enum for all possible operations - pub enum $op_enum<$(ty),*> { - $( - $variant_camel($($arg_type),* , oneshot::Sender>) - )* - } - - - /// A transaction client - pub struct $transaction { - sender: mpsc::Sender<$op_enum<$(ty),*>, - } - - impl<$(ty),*> $transaction<$(ty),*> { - $( - async fn $variant_snake($($arg_name: $arg_type),*) -> Result<$ret_type, $op_error> { - let (op_sender, op_receiver) = oneshot::channel(); - let op = $op_enum::$variant_camel($($arg_name),*, op_sender); - self.sender - .send(op) - .await - .map_err(|_| TcOpError::SendOpFailed)?; - op_receiver.await.map_err(TcOpError::ResponseOpFailed)? - } - )* - } - }; -} - -ops_enum!((TcOp, TcOpError, TcTransaction), -{ - (McGetBalance, mc_get_balance), - (currency, Currency), - McBalance +ops_enum!((TcOp, TcTransaction) => { + mc_get_balance(currency: Currency) -> McBalance; + mc_set_balance(currency: Currency, balance: i128); + mc_set_local_pending_debt(currency: Currency, debt: u128); + mc_set_remote_pending_debt(currency: Currency, debt: u128); + mc_get_local_pending_transaction(currency: Currency, request_id: Uid) -> Option; + mc_insert_local_pending_transaction(currency: Currency, pending_transaction: PendingTransaction); + mc_remove_local_pending_transaction(currency: Currency, request_id: Uid); + mc_get_remote_pending_transaction(currency: Currency, request_id: Uid) -> Option; + mc_insert_remote_pending_transaction(currency: Currency, pending_transaction: PendingTransaction); + mc_remove_remote_pending_transaction(currency: Currency, request_id: Uid); + + set_local_active_currencies(currencies: Vec); + set_remote_active_currencies(currencies: Vec); + add_mutual_credit(currency: Currency); + set_direction_incoming(move_token_hashed: MoveTokenHashed); + set_direction_outgoing(move_token: MoveToken); }); -pub struct TcTransaction { - sender: mpsc::Sender>, -} - -impl TcTransaction { - async fn mc_get_balance(currency: Currency) -> TcOpResult { - let (op_sender, op_receiver) = oneshot::channel(); - let op = TcOp::McGetBalance(balance, op_sender); - self.sender - .send(op) - .await - .map_err(|_| TcOpError::SendOpFailed)?; - op_receiver.await.map_err(TcOpError::ResponseOpFailed)? - } - - async fn set_local_active_currencies(currencies: Vec) { - todo!(); - } - - async fn set_remote_active_currencies(currencies: Vec) { - todo!(); - } - - async fn add_mutual_credit(currency: Currency) { - todo!(); - } - - async fn set_direction_incoming(move_token_hashed: MoveTokenHashed) { - todo!(); - } - - async fn set_direction_outgoing(move_token: MoveToken, token_info: TokenInfo) { - todo!(); - } -} - /// The currencies set to be active by two sides of the token channel. /// Only currencies that are active on both sides (Intersection) can be used for trading. #[derive(Arbitrary, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] @@ -1336,4 +1255,3 @@ mod tests { // TODO: Add more tests. // - Test behaviour of Duplicate, ChainInconsistency } -} From fa0b33e84cf69ed31ac96e95d061a4677bfacffb Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 16:20:06 +0300 Subject: [PATCH 103/478] funder: Some work on token_channel. Not done yet. --- components/funder/src/lib.rs | 4 +- components/funder/src/token_channel.rs | 479 +++++++++++++++---------- 2 files changed, 282 insertions(+), 201 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 368c370ac..f9cbafb90 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -27,8 +27,8 @@ extern crate quickcheck_derive; mod mutual_credit; // pub mod report; // mod state; -#[allow(unused)] -mod token_channel; +// #[allow(unused)] +// mod token_channel; // // For testing: diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 76f12a93c..eda95685c 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -1,6 +1,8 @@ use std::cmp::Ordering; use std::convert::TryFrom; +use derive_more::From; + use paste::paste; use common::async_rpc::OpError; @@ -54,6 +56,12 @@ pub enum TcOpError { pub type TcOpResult = Result; pub type TcOpSenderResult = oneshot::Sender>; +pub enum TcStatus { + ConsistentIn, + ConsistentOut, + Inconsistent, +} + ops_enum!((TcOp, TcTransaction) => { mc_get_balance(currency: Currency) -> McBalance; mc_set_balance(currency: Currency, balance: i128); @@ -66,8 +74,17 @@ ops_enum!((TcOp, TcTransaction) => { mc_insert_remote_pending_transaction(currency: Currency, pending_transaction: PendingTransaction); mc_remove_remote_pending_transaction(currency: Currency, request_id: Uid); + get_remote_public_key() -> PublicKey; + get_tc_status() -> TcStatus; + get_move_token_in() -> Option; + get_move_token_out() -> Option>; + + get_local_active_currencies() -> Option>; set_local_active_currencies(currencies: Vec); + + // get_remote_active_currencies() -> set_remote_active_currencies(currencies: Vec); + add_mutual_credit(currency: Currency); set_direction_incoming(move_token_hashed: MoveTokenHashed); set_direction_outgoing(move_token: MoveToken); @@ -115,6 +132,7 @@ pub enum TcDirection { Outgoing(TcOutgoing), } +/* #[derive(Clone, Debug)] pub struct TcInBorrow<'a> { pub tc_incoming: &'a TcIncoming, @@ -134,15 +152,19 @@ pub enum TcDirectionBorrow<'a, B> { In(TcInBorrow<'a>), Out(TcOutBorrow<'a, B>), } +*/ +/* #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct TokenChannel { - direction: TcDirection, - mutual_credits: ImHashMap, - active_currencies: ActiveCurrencies, + // direction: TcDirection, + tc_transaction: TcTransaction, + // mutual_credits: ImHashMap, + // active_currencies: ActiveCurrencies, } +*/ -#[derive(Debug)] +#[derive(Debug, From)] pub enum ReceiveMoveTokenError { ChainInconsistency, InvalidTransaction(ProcessTransListError), @@ -155,6 +177,8 @@ pub enum ReceiveMoveTokenError { InvalidCurrency, InvalidAddActiveCurrencies, CanNotRemoveCurrencyInUse, + InvalidState, + OpError(OpError), } #[derive(Debug)] @@ -165,7 +189,7 @@ pub struct MoveTokenReceivedCurrency { #[derive(Debug)] pub struct MoveTokenReceived { - pub mutations: Vec>, + // pub mutations: Vec>, pub currencies: Vec, pub opt_local_relays: Option>>, } @@ -182,7 +206,7 @@ pub enum ReceiveMoveTokenOutput { #[derive(Debug)] pub struct SendMoveTokenOutput { pub unsigned_move_token: UnsignedMoveToken, - pub mutations: Vec>, + // pub mutations: Vec>, pub token_info: TokenInfo, } @@ -251,6 +275,253 @@ fn initial_move_token( (move_token, token_info) } +async fn handle_in_move_token( + tc_transaction: &mut TcTransaction, + new_move_token: MoveToken, + remote_public_key: &PublicKey, +) -> Result, ReceiveMoveTokenError> +where + B: CanonicalSerialize + Clone, +{ + match tc_transaction.get_tc_status().await? { + TcStatus::ConsistentIn => handle_in_move_token_dir_in(tc_transaction, new_move_token).await, + TcStatus::ConsistentOut => { + handle_in_move_token_dir_out(tc_transaction, new_move_token, remote_public_key).await + } + TcStatus::Inconsistent => unreachable!(), + } +} + +async fn handle_in_move_token_dir_in( + tc_transaction: &mut TcTransaction, + new_move_token: MoveToken, +) -> Result, ReceiveMoveTokenError> +where + B: CanonicalSerialize + Clone, +{ + let move_token_in = tc_transaction.get_move_token_in().await?.unwrap(); + + if move_token_in == create_hashed(&new_move_token, &move_token_in.token_info) { + // Duplicate + Ok(ReceiveMoveTokenOutput::Duplicate) + } else { + // Inconsistency + Err(ReceiveMoveTokenError::ChainInconsistency) + } +} + +async fn handle_in_move_token_dir_out( + tc_transaction: &mut TcTransaction, + new_move_token: MoveToken, + remote_public_key: &PublicKey, +) -> Result, ReceiveMoveTokenError> +where + B: Clone + CanonicalSerialize, +{ + let move_token_out = tc_transaction.get_move_token_out().await?.unwrap(); + + if new_move_token.old_token == move_token_out.new_token { + Ok(ReceiveMoveTokenOutput::Received( + handle_incoming_token_match(tc_transaction, new_move_token, remote_public_key).await?, + )) + // self.outgoing_to_incoming(friend_move_token, new_move_token) + } else if move_token_out.old_token == new_move_token.new_token { + // We should retransmit our move token message to the remote side. + Ok(ReceiveMoveTokenOutput::RetransmitOutgoing( + move_token_out.clone(), + )) + } else { + Err(ReceiveMoveTokenError::ChainInconsistency) + } +} + +async fn handle_incoming_token_match( + tc_transaction: &mut TcTransaction, + new_move_token: MoveToken, // remote_max_debts: &ImHashMap, + remote_public_key: &PublicKey, +) -> Result, ReceiveMoveTokenError> +where + B: Clone + CanonicalSerialize, +{ + // We create a clone `token_channel` on which we are going to apply all the mutations. + // Eventually this cloned TokenChannel is discarded, and we only output the applied mutations. + // let tc_out_borrow = token_channel.get_outgoing().unwrap(); + + let move_token_out = tc_transaction.get_move_token_out().await?.unwrap(); + + // Verify signature: + // Note that we only verify the signature here, and not at the Incoming part. + // This allows the genesis move token to occur smoothly, even though its signature + // is not correct. + let remote_public_key = tc_transaction.get_remote_public_key().await?; + if !verify_move_token(new_move_token.clone(), &remote_public_key) { + return Err(ReceiveMoveTokenError::InvalidSignature); + } + + // Aggregate results for every currency: + let mut move_token_received = MoveTokenReceived { + currencies: Vec::new(), + opt_local_relays: new_move_token.opt_local_relays.clone(), + }; + + // Handle active_currencies: + if let Some(active_currencies) = new_move_token.opt_active_currencies.as_ref() { + for mutual_credit_currency in tc_out_borrow.mutual_credits.keys() { + if !active_currencies.contains(&mutual_credit_currency) { + return Err(ReceiveMoveTokenError::CanNotRemoveCurrencyInUse); + } + } + + let mutation = TcMutation::SetRemoteActiveCurrencies(active_currencies.clone()); + token_channel.mutate(&mutation); + move_token_received.mutations.push(mutation); + + let tc_out_borrow = token_channel.get_outgoing().unwrap(); + let active_currencies = &tc_out_borrow.active_currencies; + + // Find the new currencies we need to initialize. + // Calculate: + // (local ^ remote) \ mutual_credit_currencies: + let intersection = active_currencies + .remote + .clone() + .intersection(active_currencies.local.clone()); + + let mutual_credit_currencies: ImHashSet<_> = + tc_out_borrow.mutual_credits.keys().cloned().collect(); + + let new_currencies = intersection.relative_complement(mutual_credit_currencies); + + for new_currency in new_currencies { + let mutation = TcMutation::AddMutualCredit(new_currency.clone()); + token_channel.mutate(&mutation); + move_token_received.mutations.push(mutation); + } + } + + // Attempt to apply operations for every currency: + for currency_operations in &new_move_token.currencies_operations { + let tc_out_borrow = token_channel.get_outgoing().unwrap(); + let mut mutual_credit = tc_out_borrow + .mutual_credits + .get(¤cy_operations.currency) + .ok_or(ReceiveMoveTokenError::InvalidCurrency)? + .clone(); + + let remote_max_debt = remote_max_debts + .get(¤cy_operations.currency) + .cloned() + .unwrap_or(0); + + let outputs = process_operations_list( + &mut mutual_credit, + currency_operations.operations.clone(), + remote_max_debt, + ) + .map_err(ReceiveMoveTokenError::InvalidTransaction)?; + + let mut incoming_messages = Vec::new(); + + // We apply mutations on this token channel, to verify stated balance values + // let mut check_mutual_credit = mutual_credit.clone(); + + for output in outputs { + let ProcessOperationOutput { + incoming_message, + mc_mutations, + } = output; + + if let Some(funds) = incoming_message { + incoming_messages.push(funds); + } + for mc_mutation in mc_mutations { + let mutation = TcMutation::McMutation(( + currency_operations.currency.clone(), + mc_mutation.clone(), + )); + token_channel.mutate(&mutation); + move_token_received.mutations.push(mutation); + } + } + + let move_token_received_currency = MoveTokenReceivedCurrency { + currency: currency_operations.currency.clone(), + incoming_messages, + }; + + move_token_received + .currencies + .push(move_token_received_currency); + } + + // Create what we expect to be TokenInfo (From the point of view of remote side): + let tc_out_borrow = token_channel.get_outgoing().unwrap(); + let mut expected_balances: Vec<_> = tc_out_borrow + .mutual_credits + .iter() + .map(|(currency, mc)| CurrencyBalanceInfo { + currency: currency.clone(), + balance_info: BalanceInfo { + balance: mc.state().balance.balance, + local_pending_debt: mc.state().balance.local_pending_debt, + remote_pending_debt: mc.state().balance.remote_pending_debt, + }, + }) + .collect(); + + // Canonicalize: + expected_balances.sort_by(|cbi1, cbi2| cbi1.currency.cmp(&cbi2.currency)); + + let expected_token_info = TokenInfo { + mc: McInfo { + local_public_key: tc_out_borrow + .tc_outgoing + .token_info + .mc + .local_public_key + .clone(), + remote_public_key: tc_out_borrow + .tc_outgoing + .token_info + .mc + .remote_public_key + .clone(), + balances: expected_balances, + }, + counters: CountersInfo { + inconsistency_counter: tc_out_borrow + .tc_outgoing + .token_info + .counters + .inconsistency_counter, + move_token_counter: tc_out_borrow + .tc_outgoing + .token_info + .counters + .move_token_counter + .checked_add(1) + .ok_or(ReceiveMoveTokenError::MoveTokenCounterOverflow)?, + }, + } + .flip(); + + // Verify stated balances: + let info_hash = hash_token_info(&expected_token_info); + if new_move_token.info_hash != info_hash { + return Err(ReceiveMoveTokenError::InvalidTokenInfo); + } + + move_token_received + .mutations + .push(TcMutation::SetDirection(SetDirection::Incoming( + create_hashed(&new_move_token, &expected_token_info), + ))); + + Ok(move_token_received) +} + +fn handle_out_move_token(tc_transaction: &mut TcTransaction) {} + impl TokenChannel where B: Clone + CanonicalSerialize, @@ -373,17 +644,6 @@ where } } - /* - pub fn get_remote_max_debt(&self, currency: &Currency) -> u128 { - self.mutual_credits - .get(currency) - .unwrap() - .state() - .balance - .remote_max_debt - } - */ - pub fn get_direction(&self) -> TcDirectionBorrow<'_, B> { match &self.direction { TcDirection::Incoming(tc_incoming) => TcDirectionBorrow::In(TcInBorrow { @@ -707,193 +967,13 @@ where } } - fn handle_incoming_token_match( - &self, - new_move_token: MoveToken, - remote_max_debts: &ImHashMap, - ) -> Result, ReceiveMoveTokenError> { - // We create a clone `token_channel` on which we are going to apply all the mutations. - // Eventually this cloned TokenChannel is discarded, and we only output the applied mutations. - let mut token_channel = self.create_token_channel(); - let tc_out_borrow = token_channel.get_outgoing().unwrap(); - - // Verify signature: - // Note that we only verify the signature here, and not at the Incoming part. - // This allows the genesis move token to occur smoothly, even though its signature - // is not correct. - let remote_public_key = &tc_out_borrow.tc_outgoing.token_info.mc.remote_public_key; - if !verify_move_token(new_move_token.clone(), remote_public_key) { - return Err(ReceiveMoveTokenError::InvalidSignature); - } - - // Aggregate results for every currency: - let mut move_token_received = MoveTokenReceived { - mutations: Vec::new(), - currencies: Vec::new(), - opt_local_relays: new_move_token.opt_local_relays.clone(), - }; - - // Handle active_currencies: - if let Some(active_currencies) = new_move_token.opt_active_currencies.as_ref() { - for mutual_credit_currency in tc_out_borrow.mutual_credits.keys() { - if !active_currencies.contains(&mutual_credit_currency) { - return Err(ReceiveMoveTokenError::CanNotRemoveCurrencyInUse); - } - } - - let mutation = TcMutation::SetRemoteActiveCurrencies(active_currencies.clone()); - token_channel.mutate(&mutation); - move_token_received.mutations.push(mutation); - - let tc_out_borrow = token_channel.get_outgoing().unwrap(); - let active_currencies = &tc_out_borrow.active_currencies; - - // Find the new currencies we need to initialize. - // Calculate: - // (local ^ remote) \ mutual_credit_currencies: - let intersection = active_currencies - .remote - .clone() - .intersection(active_currencies.local.clone()); - - let mutual_credit_currencies: ImHashSet<_> = - tc_out_borrow.mutual_credits.keys().cloned().collect(); - - let new_currencies = intersection.relative_complement(mutual_credit_currencies); - - for new_currency in new_currencies { - let mutation = TcMutation::AddMutualCredit(new_currency.clone()); - token_channel.mutate(&mutation); - move_token_received.mutations.push(mutation); - } - } - - // Attempt to apply operations for every currency: - for currency_operations in &new_move_token.currencies_operations { - let tc_out_borrow = token_channel.get_outgoing().unwrap(); - let mut mutual_credit = tc_out_borrow - .mutual_credits - .get(¤cy_operations.currency) - .ok_or(ReceiveMoveTokenError::InvalidCurrency)? - .clone(); - - let remote_max_debt = remote_max_debts - .get(¤cy_operations.currency) - .cloned() - .unwrap_or(0); - - let outputs = process_operations_list( - &mut mutual_credit, - currency_operations.operations.clone(), - remote_max_debt, - ) - .map_err(ReceiveMoveTokenError::InvalidTransaction)?; - - let mut incoming_messages = Vec::new(); - - // We apply mutations on this token channel, to verify stated balance values - // let mut check_mutual_credit = mutual_credit.clone(); - - for output in outputs { - let ProcessOperationOutput { - incoming_message, - mc_mutations, - } = output; - - if let Some(funds) = incoming_message { - incoming_messages.push(funds); - } - for mc_mutation in mc_mutations { - let mutation = TcMutation::McMutation(( - currency_operations.currency.clone(), - mc_mutation.clone(), - )); - token_channel.mutate(&mutation); - move_token_received.mutations.push(mutation); - } - } - - let move_token_received_currency = MoveTokenReceivedCurrency { - currency: currency_operations.currency.clone(), - incoming_messages, - }; - - move_token_received - .currencies - .push(move_token_received_currency); - } - - // Create what we expect to be TokenInfo (From the point of view of remote side): - let tc_out_borrow = token_channel.get_outgoing().unwrap(); - let mut expected_balances: Vec<_> = tc_out_borrow - .mutual_credits - .iter() - .map(|(currency, mc)| CurrencyBalanceInfo { - currency: currency.clone(), - balance_info: BalanceInfo { - balance: mc.state().balance.balance, - local_pending_debt: mc.state().balance.local_pending_debt, - remote_pending_debt: mc.state().balance.remote_pending_debt, - }, - }) - .collect(); - - // Canonicalize: - expected_balances.sort_by(|cbi1, cbi2| cbi1.currency.cmp(&cbi2.currency)); - - let expected_token_info = TokenInfo { - mc: McInfo { - local_public_key: tc_out_borrow - .tc_outgoing - .token_info - .mc - .local_public_key - .clone(), - remote_public_key: tc_out_borrow - .tc_outgoing - .token_info - .mc - .remote_public_key - .clone(), - balances: expected_balances, - }, - counters: CountersInfo { - inconsistency_counter: tc_out_borrow - .tc_outgoing - .token_info - .counters - .inconsistency_counter, - move_token_counter: tc_out_borrow - .tc_outgoing - .token_info - .counters - .move_token_counter - .checked_add(1) - .ok_or(ReceiveMoveTokenError::MoveTokenCounterOverflow)?, - }, - } - .flip(); - - // Verify stated balances: - let info_hash = hash_token_info(&expected_token_info); - if new_move_token.info_hash != info_hash { - return Err(ReceiveMoveTokenError::InvalidTokenInfo); - } - - move_token_received - .mutations - .push(TcMutation::SetDirection(SetDirection::Incoming( - create_hashed(&new_move_token, &expected_token_info), - ))); - - Ok(move_token_received) - } - /// Get the current outgoing move token pub fn create_outgoing_move_token(&self) -> MoveToken { self.tc_outgoing.move_token_out.clone() } } +// TODO: Restore tests +/* #[cfg(test)] mod tests { @@ -1255,3 +1335,4 @@ mod tests { // TODO: Add more tests. // - Test behaviour of Duplicate, ChainInconsistency } +*/ From ac3a484b8f53cf39ca0be5db3f13b95d53bce606 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 17:03:55 +0300 Subject: [PATCH 104/478] proto: Some changes to MoveToken message --- components/proto/src/funder/messages.rs | 74 +++++------------------- components/proto/src/schema/funder.capnp | 35 ++++------- 2 files changed, 25 insertions(+), 84 deletions(-) diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index f9d8f6da8..a36b84d66 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -16,8 +16,7 @@ use num_traits::cast::ToPrimitive; use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; use crate::crypto::{ - HashResult, HashedLock, HmacResult, InvoiceId, PaymentId, PlainLock, PublicKey, RandValue, - Signature, Uid, + HashResult, HashedLock, HmacResult, InvoiceId, PaymentId, PlainLock, PublicKey, Signature, Uid, }; use crate::app_server::messages::{NamedRelayAddress, RelayAddress}; @@ -25,7 +24,7 @@ use crate::consts::{MAX_CURRENCY_LEN, MAX_ROUTE_LEN}; use crate::net::messages::NetAddress; use crate::report::messages::FunderReportMutations; -use common::ser_utils::{ser_b64, ser_seq_str, ser_string, ser_vec_b64}; +use common::ser_utils::{ser_b64, ser_string, ser_vec_b64}; use crate::wrapper::Wrapper; @@ -161,20 +160,14 @@ pub enum FriendTcOp { CancelSendFunds(CancelSendFundsOp), } +/* #[capnp_conv(crate::funder_capnp::move_token::opt_local_relays)] #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub enum OptLocalRelays { Empty, Relays(Vec>), } - -#[capnp_conv(crate::funder_capnp::move_token::opt_active_currencies)] -#[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] -pub enum OptActiveCurrencies { - Empty, - #[serde(with = "ser_seq_str")] - Currencies(Vec), -} +*/ impl Into for ResponseSendFundsOp { fn into(self) -> UnsignedResponseSendFundsOp { @@ -186,43 +179,6 @@ impl Into for ResponseSendFundsOp { } } -// TODO: Create a macro that does this: -impl From>>> for OptLocalRelays { - fn from(opt: Option>>) -> Self { - match opt { - Some(relays) => OptLocalRelays::Relays(relays), - None => OptLocalRelays::Empty, - } - } -} - -impl From> for Option>> { - fn from(opt: OptLocalRelays) -> Self { - match opt { - OptLocalRelays::Relays(relays) => Some(relays), - OptLocalRelays::Empty => None, - } - } -} - -impl From>> for OptActiveCurrencies { - fn from(opt: Option>) -> Self { - match opt { - Some(currencies) => OptActiveCurrencies::Currencies(currencies), - None => OptActiveCurrencies::Empty, - } - } -} - -impl From for Option> { - fn from(opt: OptActiveCurrencies) -> Self { - match opt { - OptActiveCurrencies::Currencies(currencies) => Some(currencies), - OptActiveCurrencies::Empty => None, - } - } -} - /// Balance information for a single currency #[capnp_conv(crate::report_capnp::balance_info)] #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] @@ -292,15 +248,12 @@ pub struct MoveToken { #[serde(with = "ser_b64")] pub old_token: Signature, pub currencies_operations: Vec, - #[capnp_conv(with = OptLocalRelays)] - pub opt_local_relays: Option>>, - #[capnp_conv(with = OptActiveCurrencies)] - pub opt_active_currencies: Option>, + pub remove_relays: Vec, + pub add_relays: Vec>, + pub currencies_diff: Vec, #[serde(with = "ser_b64")] pub info_hash: HashResult, #[serde(with = "ser_b64")] - pub rand_nonce: RandValue, - #[serde(with = "ser_b64")] pub new_token: Signature, } @@ -309,12 +262,11 @@ pub struct UnsignedMoveToken { #[serde(with = "ser_b64")] pub old_token: Signature, pub currencies_operations: Vec, - pub opt_local_relays: Option>>, - pub opt_active_currencies: Option>, + pub remove_relays: Vec, + pub add_relays: Vec>, + pub currencies_diff: Vec, #[serde(with = "ser_b64")] pub info_hash: HashResult, - #[serde(with = "ser_b64")] - pub rand_nonce: RandValue, } impl Into> for MoveToken { @@ -322,10 +274,10 @@ impl Into> for MoveToken { UnsignedMoveToken { old_token: self.old_token, currencies_operations: self.currencies_operations, - opt_local_relays: self.opt_local_relays, - opt_active_currencies: self.opt_active_currencies, + remove_relays: self.remove_relays, + add_relays: self.add_relays, + currencies_diff: self.currencies_diff, info_hash: self.info_hash, - rand_nonce: self.rand_nonce, } } } diff --git a/components/proto/src/schema/funder.capnp b/components/proto/src/schema/funder.capnp index bd829558b..5ff90e8d9 100644 --- a/components/proto/src/schema/funder.capnp +++ b/components/proto/src/schema/funder.capnp @@ -2,7 +2,6 @@ using import "common.capnp".Signature; using import "common.capnp".PublicKey; -using import "common.capnp".RandValue; using import "common.capnp".InvoiceId; using import "common.capnp".Uid; using import "common.capnp".CustomUInt128; @@ -35,29 +34,19 @@ struct MoveToken { # Operations that should be applied to various currencies. # For every currency, ordered batched operations are provided. # First operation should be applied first. - optLocalRelays: union { - empty @2: Void; - # Nothing has changed - relays @3: List(RelayAddress); - # Set this exact list to be the list of relays - } - # Set the relays used by the sender of this MoveToken message. - # (Empty means no change happens). - optActiveCurrencies: union { - empty @4: Void; - # Nothing has changed - currencies @5: List(Currency); - # Set this exact list to be the list of currencies - } - # Add a list of active currencies. (empty means that no change happens) - # Note that this field only allows to add new currencies. - infoHash @6: HashResult; + removeRelays @2: List(PublicKey); + # A list of relays to remove + addRelays @3: List(RelayAddress); + # A list of relays to add + # Should have no intersection with the removeRelays list. + # TODO: We might be able to have a similar xor based diff here if we use + # a map, mapping PublicKey to NetAddress. + currenciesDiff @4: List(Currency); + # Exclusive-Or difference of previous list of currencies and new list of currencies. + # Should be empty if nothing has changed. + infoHash @5: HashResult; # Current information about the channel that both sides implicitly agree upon. - randNonce @7: RandValue; - # A random nonce, generated by the sender. We have it because the - # sender is signing over this message, and we don't want him to be - # tricked into signing over something strange. - newToken @8 : Signature; + newToken @6 : Signature; # A signature over all the previous fields. } From 75bc266fc93156f36dbc88ff8980896cb91569a5 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 17:08:29 +0300 Subject: [PATCH 105/478] signature: Updated to new MoveToken design --- components/signature/src/canonical.rs | 21 ++------------------- components/signature/src/signature_buff.rs | 15 ++++++++++----- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/components/signature/src/canonical.rs b/components/signature/src/canonical.rs index 6e04ab9bb..4b31bacab 100644 --- a/components/signature/src/canonical.rs +++ b/components/signature/src/canonical.rs @@ -4,8 +4,8 @@ use byteorder::{BigEndian, WriteBytesExt}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ BalanceInfo, CancelSendFundsOp, CountersInfo, Currency, CurrencyBalanceInfo, - CurrencyOperations, FriendTcOp, FriendsRoute, McInfo, OptLocalRelays, Receipt, - RequestSendFundsOp, ResponseSendFundsOp, TokenInfo, + CurrencyOperations, FriendTcOp, FriendsRoute, McInfo, Receipt, RequestSendFundsOp, + ResponseSendFundsOp, TokenInfo, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -256,23 +256,6 @@ where } } -impl CanonicalSerialize for OptLocalRelays -where - B: CanonicalSerialize, -{ - fn canonical_serialize(&self) -> Vec { - let mut res_bytes = Vec::new(); - match self { - OptLocalRelays::Empty => res_bytes.push(0u8), - OptLocalRelays::Relays(relays) => { - res_bytes.push(1u8); - res_bytes.append(&mut relays.canonical_serialize()); - } - }; - res_bytes - } -} - impl CanonicalSerialize for UpdateFriendCurrency { fn canonical_serialize(&self) -> Vec { let mut res_bytes = Vec::new(); diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index 5a7411010..8d59ba637 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -68,6 +68,7 @@ where // NEXT is used for hashing for the next move token funds. pub const TOKEN_NEXT: &[u8] = b"NEXT"; +/* /// Combine all operations into one hash value. pub fn operations_hash(move_token: MT) -> HashResult where @@ -77,7 +78,9 @@ where let operations_data = move_token.currencies_operations.canonical_serialize(); sha_512_256(&operations_data) } +*/ +/* pub fn local_address_hash(move_token: MT) -> HashResult where B: CanonicalSerialize + Clone, @@ -86,11 +89,13 @@ where let move_token: UnsignedMoveToken = move_token.into(); sha_512_256(&move_token.opt_local_relays.canonical_serialize()) } +*/ pub fn hash_token_info(token_info: &TokenInfo) -> HashResult { sha_512_256(&token_info.canonical_serialize()) } +/* /// Hash operations and local_address: pub fn prefix_hash(move_token: MT) -> HashResult where @@ -101,12 +106,13 @@ where let mut hash_buff = Vec::new(); hash_buff.extend_from_slice(&move_token.old_token); - hash_buff.extend_from_slice(&move_token.currencies_operations.canonical_serialize()); - hash_buff.extend_from_slice(&move_token.opt_local_relays.canonical_serialize()); - hash_buff.extend_from_slice(&move_token.opt_active_currencies.canonical_serialize()); + // hash_buff.extend_from_slice(&move_token.currencies_operations.canonical_serialize()); + // hash_buff.extend_from_slice(&move_token.opt_local_relays.canonical_serialize()); + //hash_buff.extend_from_slice(&move_token.opt_active_currencies.canonical_serialize()); sha_512_256(&hash_buff) } +*/ pub fn move_token_signature_buff(move_token: MT) -> Vec where @@ -116,9 +122,8 @@ where let move_token: UnsignedMoveToken = move_token.into(); let mut sig_buffer = Vec::new(); sig_buffer.extend_from_slice(&sha_512_256(TOKEN_NEXT)); - sig_buffer.extend_from_slice(&prefix_hash(move_token.clone())); + sig_buffer.extend_from_slice(&move_token.old_token); sig_buffer.extend_from_slice(&move_token.info_hash); - sig_buffer.extend_from_slice(&move_token.rand_nonce); sig_buffer } From 6616ba9914b74b51ecb22ea253a09f5d28e4bc1a Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 17:14:38 +0300 Subject: [PATCH 106/478] funder: Updated to use new MoveToken --- components/funder/src/types.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 80b1db270..565e2d35e 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -2,7 +2,7 @@ use signature::canonical::CanonicalSerialize; use common::ser_utils::ser_b64; -use proto::crypto::{HashResult, PlainLock, PublicKey, RandValue, Signature, Uid}; +use proto::crypto::{PlainLock, PublicKey, Signature, Uid}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ @@ -13,7 +13,7 @@ use proto::funder::messages::{ }; use signature::signature_buff::{ - create_response_signature_buffer, hash_token_info, move_token_signature_buff, prefix_hash, + create_response_signature_buffer, hash_token_info, move_token_signature_buff, }; use identity::IdentityClient; @@ -34,10 +34,10 @@ where MoveToken { old_token: unsigned_move_token.old_token, currencies_operations: unsigned_move_token.currencies_operations, - opt_local_relays: unsigned_move_token.opt_local_relays, - opt_active_currencies: unsigned_move_token.opt_active_currencies, + remove_relays: unsigned_move_token.remove_relays, + add_relays: unsigned_move_token.add_relays, + currencies_diff: unsigned_move_token.currencies_diff, info_hash: unsigned_move_token.info_hash, - rand_nonce: unsigned_move_token.rand_nonce, new_token, } } @@ -108,29 +108,27 @@ pub enum UnsignedFriendTcOp { pub struct MoveTokenHashed { /// Hash of operations and local_relays #[serde(with = "ser_b64")] - pub prefix_hash: HashResult, + pub old_token: Signature, pub token_info: TokenInfo, #[serde(with = "ser_b64")] - pub rand_nonce: RandValue, - #[serde(with = "ser_b64")] pub new_token: Signature, } pub fn create_unsigned_move_token( currencies_operations: Vec, - opt_local_relays: Option>>, - opt_active_currencies: Option>, + remove_relays: Vec, + add_relays: Vec>, + currencies_diff: Vec, token_info: &TokenInfo, old_token: Signature, - rand_nonce: RandValue, ) -> UnsignedMoveToken { UnsignedMoveToken { old_token, currencies_operations, - opt_local_relays, - opt_active_currencies, + remove_relays, + add_relays, + currencies_diff, info_hash: hash_token_info(token_info), - rand_nonce, } } @@ -176,9 +174,8 @@ where B: CanonicalSerialize + Clone, { MoveTokenHashed { - prefix_hash: prefix_hash(move_token.clone()), + old_token: move_token.old_token.clone(), token_info: token_info.clone(), - rand_nonce: move_token.rand_nonce.clone(), new_token: move_token.new_token.clone(), } } From 6034837db1b01bdb9f1dd8d4a983c34f4e9c7ee5 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 18:51:31 +0300 Subject: [PATCH 107/478] proto: Updated MoveToken --- components/funder/src/token_channel.rs | 8 ++++++-- components/funder/src/types.rs | 9 +++------ components/proto/src/app_server/messages.rs | 8 +++++++- components/proto/src/file.rs | 2 ++ components/proto/src/funder/messages.rs | 9 +++------ components/proto/src/schema/common.capnp | 1 + components/proto/src/schema/funder.capnp | 20 +++++++++----------- 7 files changed, 31 insertions(+), 26 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index eda95685c..b58caa6ce 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -191,7 +191,7 @@ pub struct MoveTokenReceivedCurrency { pub struct MoveTokenReceived { // pub mutations: Vec>, pub currencies: Vec, - pub opt_local_relays: Option>>, + pub local_relays_diff: Option>>, } #[allow(clippy::large_enum_variant)] @@ -520,8 +520,11 @@ where Ok(move_token_received) } -fn handle_out_move_token(tc_transaction: &mut TcTransaction) {} +fn handle_out_move_token(tc_transaction: &mut TcTransaction) { + todo!(); +} +/* impl TokenChannel where B: Clone + CanonicalSerialize, @@ -773,6 +776,7 @@ where } } } +*/ impl<'a> TcInBorrow<'a> { /// Create a full TokenChannel (Incoming direction) diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 565e2d35e..6ca350926 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -34,8 +34,7 @@ where MoveToken { old_token: unsigned_move_token.old_token, currencies_operations: unsigned_move_token.currencies_operations, - remove_relays: unsigned_move_token.remove_relays, - add_relays: unsigned_move_token.add_relays, + relays_diff: unsigned_move_token.relays_diff, currencies_diff: unsigned_move_token.currencies_diff, info_hash: unsigned_move_token.info_hash, new_token, @@ -116,8 +115,7 @@ pub struct MoveTokenHashed { pub fn create_unsigned_move_token( currencies_operations: Vec, - remove_relays: Vec, - add_relays: Vec>, + relays_diff: Vec>, currencies_diff: Vec, token_info: &TokenInfo, old_token: Signature, @@ -125,8 +123,7 @@ pub fn create_unsigned_move_token( UnsignedMoveToken { old_token, currencies_operations, - remove_relays, - add_relays, + relays_diff, currencies_diff, info_hash: hash_token_info(token_info), } diff --git a/components/proto/src/app_server/messages.rs b/components/proto/src/app_server/messages.rs index 6b49a90a7..fc6a6f5c6 100644 --- a/components/proto/src/app_server/messages.rs +++ b/components/proto/src/app_server/messages.rs @@ -3,9 +3,10 @@ use serde::{Deserialize, Serialize}; use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; use common::mutable_state::MutableState; -use common::ser_utils::ser_b64; +use common::ser_utils::{ser_b64, ser_string}; use crate::crypto::{InvoiceId, PaymentId, PublicKey, Uid}; +use crate::wrapper::Wrapper; use crate::funder::messages::{ AckClosePayment, AddFriend, AddInvoice, Commit, CreatePayment, CreateTransaction, Currency, @@ -38,8 +39,12 @@ pub struct RelayAddress { #[serde(with = "ser_b64")] pub public_key: PublicKey, pub address: B, + #[capnp_conv(with = Wrapper)] + #[serde(with = "ser_string")] + pub port: u128, } +/* impl From> for RelayAddress { fn from(from: NamedRelayAddress) -> Self { RelayAddress { @@ -48,6 +53,7 @@ impl From> for RelayAddress { } } } +*/ #[capnp_conv(crate::report_capnp::node_report)] #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/components/proto/src/file.rs b/components/proto/src/file.rs index 020214b73..b7a681c79 100644 --- a/components/proto/src/file.rs +++ b/components/proto/src/file.rs @@ -35,6 +35,8 @@ pub struct RelayAddressFile { pub public_key: PublicKey, #[serde(with = "ser_string")] pub address: NetAddress, + #[serde(with = "ser_string")] + pub port: u128, } /// A helper structure for serialize and deserializing FriendAddress. diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index a36b84d66..d806a3d88 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -248,8 +248,7 @@ pub struct MoveToken { #[serde(with = "ser_b64")] pub old_token: Signature, pub currencies_operations: Vec, - pub remove_relays: Vec, - pub add_relays: Vec>, + pub relays_diff: Vec>, pub currencies_diff: Vec, #[serde(with = "ser_b64")] pub info_hash: HashResult, @@ -262,8 +261,7 @@ pub struct UnsignedMoveToken { #[serde(with = "ser_b64")] pub old_token: Signature, pub currencies_operations: Vec, - pub remove_relays: Vec, - pub add_relays: Vec>, + pub relays_diff: Vec>, pub currencies_diff: Vec, #[serde(with = "ser_b64")] pub info_hash: HashResult, @@ -274,8 +272,7 @@ impl Into> for MoveToken { UnsignedMoveToken { old_token: self.old_token, currencies_operations: self.currencies_operations, - remove_relays: self.remove_relays, - add_relays: self.add_relays, + relays_diff: self.relays_diff, currencies_diff: self.currencies_diff, info_hash: self.info_hash, } diff --git a/components/proto/src/schema/common.capnp b/components/proto/src/schema/common.capnp index 62f222106..8935a6ffb 100644 --- a/components/proto/src/schema/common.capnp +++ b/components/proto/src/schema/common.capnp @@ -111,6 +111,7 @@ struct Currency { struct RelayAddress { publicKey @0: PublicKey; address @1: NetAddress; + port @2: CustomUInt128; } # Authenticated named address of a Relay (Includes public key) diff --git a/components/proto/src/schema/funder.capnp b/components/proto/src/schema/funder.capnp index 5ff90e8d9..e03a965a9 100644 --- a/components/proto/src/schema/funder.capnp +++ b/components/proto/src/schema/funder.capnp @@ -34,19 +34,17 @@ struct MoveToken { # Operations that should be applied to various currencies. # For every currency, ordered batched operations are provided. # First operation should be applied first. - removeRelays @2: List(PublicKey); - # A list of relays to remove - addRelays @3: List(RelayAddress); - # A list of relays to add - # Should have no intersection with the removeRelays list. - # TODO: We might be able to have a similar xor based diff here if we use - # a map, mapping PublicKey to NetAddress. - currenciesDiff @4: List(Currency); - # Exclusive-Or difference of previous list of currencies and new list of currencies. + relaysDiff @2: List(RelayAddress); + # Exclusive-Or difference between previous list of relays and new list of relays. # Should be empty if nothing has changed. - infoHash @5: HashResult; + # TODO: We might be able to make this more efficient, as RelayAddress + # might be too much information for removing an entry. + currenciesDiff @3: List(Currency); + # Exclusive-Or difference between previous list of currencies and new list of currencies. + # Should be empty if nothing has changed. + infoHash @4: HashResult; # Current information about the channel that both sides implicitly agree upon. - newToken @6 : Signature; + newToken @5 : Signature; # A signature over all the previous fields. } From 4b22b4947619d8e56211e1b67146f94af4e6b2ae Mon Sep 17 00:00:00 2001 From: real Date: Wed, 14 Oct 2020 19:17:40 +0300 Subject: [PATCH 108/478] funder: Some work on token_channel. Not done yet --- components/funder/src/lib.rs | 2 +- components/funder/src/token_channel.rs | 87 ++++++++++++++++---------- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index f9cbafb90..586817f0c 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -28,7 +28,7 @@ mod mutual_credit; // pub mod report; // mod state; // #[allow(unused)] -// mod token_channel; +mod token_channel; // // For testing: diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index b58caa6ce..d2beb6d9b 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -79,11 +79,18 @@ ops_enum!((TcOp, TcTransaction) => { get_move_token_in() -> Option; get_move_token_out() -> Option>; - get_local_active_currencies() -> Option>; - set_local_active_currencies(currencies: Vec); + add_local_currency(currency: Currency); + // TODO: Possibly add boolean result here? And to other remove commands? + remove_local_currency(currency: Currency); + is_local_currency(currency: Currency) -> bool; + + add_remote_currency(currency: Currency); + remove_remote_currency(currency: Currency); + is_remote_currency(currency: Currency) -> bool; // get_remote_active_currencies() -> set_remote_active_currencies(currencies: Vec); + is_active_currency(currency: Currency) -> bool; add_mutual_credit(currency: Currency); set_direction_incoming(move_token_hashed: MoveTokenHashed); @@ -191,7 +198,7 @@ pub struct MoveTokenReceivedCurrency { pub struct MoveTokenReceived { // pub mutations: Vec>, pub currencies: Vec, - pub local_relays_diff: Option>>, + pub relays_diff: Vec>, } #[allow(clippy::large_enum_variant)] @@ -265,10 +272,9 @@ fn initial_move_token( let move_token = MoveToken { old_token: token_from_public_key(&low_public_key), currencies_operations: Vec::new(), - opt_local_relays: None, - opt_active_currencies: None, + relays_diff: Vec::new(), + currencies_diff: Vec::new(), info_hash: hash_token_info(&token_info), - rand_nonce: rand_nonce_from_public_key(&high_public_key), new_token: token_from_public_key(&high_public_key), }; @@ -361,41 +367,54 @@ where // Aggregate results for every currency: let mut move_token_received = MoveTokenReceived { currencies: Vec::new(), - opt_local_relays: new_move_token.opt_local_relays.clone(), + relays_diff: new_move_token.relays_diff.clone(), }; - // Handle active_currencies: - if let Some(active_currencies) = new_move_token.opt_active_currencies.as_ref() { - for mutual_credit_currency in tc_out_borrow.mutual_credits.keys() { - if !active_currencies.contains(&mutual_credit_currency) { - return Err(ReceiveMoveTokenError::CanNotRemoveCurrencyInUse); - } + // Handle active currencies: + + // First, make sure that nobody removed a currency that is already active: + // TODO: We might allow to do this in the future, in the special case of zero balance and zero + // pending debt? + + // TODO: Possibly unite this code with the code below: + for diff_currency in new_move_token.currencies_diff.as_ref() { + if tc_transaction.is_active_currency(diff_currency).await? { + return Err(ReceiveMoveTokenError::CanNotRemoveCurrencyInUse); } + } - let mutation = TcMutation::SetRemoteActiveCurrencies(active_currencies.clone()); - token_channel.mutate(&mutation); - move_token_received.mutations.push(mutation); + for diff_currency in new_move_token.currencies_diff.as_ref() { + if tc_transaction.is_remote_currency(diff_currency) { + // We need to remove this currency + // TODO: continue here. + // + let mutation = TcMutation::SetRemoteActiveCurrencies(active_currencies.clone()); + token_channel.mutate(&mutation); + move_token_received.mutations.push(mutation); - let tc_out_borrow = token_channel.get_outgoing().unwrap(); - let active_currencies = &tc_out_borrow.active_currencies; + let tc_out_borrow = token_channel.get_outgoing().unwrap(); + let active_currencies = &tc_out_borrow.active_currencies; - // Find the new currencies we need to initialize. - // Calculate: - // (local ^ remote) \ mutual_credit_currencies: - let intersection = active_currencies - .remote - .clone() - .intersection(active_currencies.local.clone()); + // Find the new currencies we need to initialize. + // Calculate: + // (local ^ remote) \ mutual_credit_currencies: + let intersection = active_currencies + .remote + .clone() + .intersection(active_currencies.local.clone()); - let mutual_credit_currencies: ImHashSet<_> = - tc_out_borrow.mutual_credits.keys().cloned().collect(); + let mutual_credit_currencies: ImHashSet<_> = + tc_out_borrow.mutual_credits.keys().cloned().collect(); - let new_currencies = intersection.relative_complement(mutual_credit_currencies); + let new_currencies = intersection.relative_complement(mutual_credit_currencies); - for new_currency in new_currencies { - let mutation = TcMutation::AddMutualCredit(new_currency.clone()); - token_channel.mutate(&mutation); - move_token_received.mutations.push(mutation); + for new_currency in new_currencies { + let mutation = TcMutation::AddMutualCredit(new_currency.clone()); + token_channel.mutate(&mutation); + move_token_received.mutations.push(mutation); + } + } else { + // TODO: Possibly add a new currency (If both remote and local have this currency): } } @@ -778,6 +797,8 @@ where } */ +/* +// TODO: Reimplement later impl<'a> TcInBorrow<'a> { /// Create a full TokenChannel (Incoming direction) fn create_token_channel(&self) -> TokenChannel { @@ -976,6 +997,8 @@ where self.tc_outgoing.move_token_out.clone() } } +*/ + // TODO: Restore tests /* From c9d5ca21b967fb0100d19c8a964cd912ea6573de Mon Sep 17 00:00:00 2001 From: real Date: Sun, 18 Oct 2020 18:14:00 +0300 Subject: [PATCH 109/478] common: ops_enum creates a trait instead of a struct --- components/common/src/async_rpc.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/components/common/src/async_rpc.rs b/components/common/src/async_rpc.rs index df9635f36..629810071 100644 --- a/components/common/src/async_rpc.rs +++ b/components/common/src/async_rpc.rs @@ -55,7 +55,7 @@ macro_rules! get_out_type { /// Generates an enum of all possible RPC messages, and an async interface that knows how to send /// those RPC messages. macro_rules! ops_enum { - (($op_enum:ident $(<$($ty:ident),*>)?, $transaction:ident) => { + (($op_enum:ident $(<$($ty:ident),*>)?, $transaction_trait:ident) => { $( $variant_snake:ident ($($($arg_name:ident: $arg_type:path),+)?) $(-> $ret_type:path)? );* @@ -72,11 +72,22 @@ macro_rules! ops_enum { } // A transaction client + /* pub struct $transaction$(<$($ty),*>)? { sender: mpsc::Sender<$op_enum$(<$($ty),*>)?>, } + */ - impl$(<$($ty),*>)? $transaction$(<$($ty),*>)? { + pub trait $transaction_trait$(<$($ty),*>)? { + $( + paste! { + fn $variant_snake(&mut self $(, $($arg_name: $arg_type),+)?) -> BoxFuture<'static, Result< get_out_type!($($ret_type)?) , OpError>>; + } + )* + } + + /* + impl$(<$($ty),*>)? $transaction_trait$(<$($ty),*>)? { pub fn new(sender: mpsc::Sender<$op_enum$(<$($ty),*>)?>) -> Self { Self { sender } } @@ -94,6 +105,7 @@ macro_rules! ops_enum { } )* } + */ }; } @@ -103,10 +115,12 @@ macro_rules! ops_enum { mod tests { use super::*; - use futures::channel::mpsc; - use futures::SinkExt; + // use futures::channel::mpsc; + // use futures::SinkExt; use paste::paste; + use crate::conn::BoxFuture; + #[test] fn test_rpc_enums() { ops_enum!((TcOp1, TcTransaction1) => { From bd2b48b393a289df2734b4f0eb7c53e2395a1fd8 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 18 Oct 2020 18:14:23 +0300 Subject: [PATCH 110/478] funder: Updated to use new ops_enum! macro --- components/funder/src/lib.rs | 2 +- .../funder/src/mutual_credit/incoming.rs | 10 +- .../funder/src/mutual_credit/outgoing.rs | 8 +- .../tests/request_cancel_send_funds.rs | 21 +-- .../tests/request_response_send_funds.rs | 21 +-- .../funder/src/mutual_credit/tests/utils.rs | 139 ++++++++---------- components/funder/src/mutual_credit/types.rs | 4 +- 7 files changed, 80 insertions(+), 125 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 586817f0c..f9cbafb90 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -28,7 +28,7 @@ mod mutual_credit; // pub mod report; // mod state; // #[allow(unused)] -mod token_channel; +// mod token_channel; // // For testing: diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index bd69f0aef..91412f9df 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -60,7 +60,7 @@ pub struct ProcessTransListError { // TODO: Remove later: #[allow(unused)] pub async fn process_operations_list( - mc_transaction: &mut McTransaction, + mc_transaction: &mut impl McTransaction, operations: Vec, currency: &Currency, remote_public_key: &PublicKey, @@ -91,7 +91,7 @@ pub async fn process_operations_list( } pub async fn process_operation( - mc_transaction: &mut McTransaction, + mc_transaction: &mut impl McTransaction, friend_tc_op: FriendTcOp, currency: &Currency, remote_public_key: &PublicKey, @@ -118,7 +118,7 @@ pub async fn process_operation( /// Process an incoming RequestSendFundsOp async fn process_request_send_funds( - mc_transaction: &mut McTransaction, + mc_transaction: &mut impl McTransaction, request_send_funds: RequestSendFundsOp, remote_max_debt: u128, ) -> Result { @@ -184,7 +184,7 @@ async fn process_request_send_funds( } async fn process_response_send_funds( - mc_transaction: &mut McTransaction, + mc_transaction: &mut impl McTransaction, response_send_funds: ResponseSendFundsOp, currency: &Currency, remote_public_key: &PublicKey, @@ -262,7 +262,7 @@ async fn process_response_send_funds( } async fn process_cancel_send_funds( - mc_transaction: &mut McTransaction, + mc_transaction: &mut impl McTransaction, cancel_send_funds: CancelSendFundsOp, ) -> Result { // Make sure that id exists in local_pending hashmap, diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 26faa4584..9edbecb0f 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -33,7 +33,7 @@ pub enum QueueOperationError { // TODO: Remove later: #[allow(unused)] pub async fn queue_operation( - mc_transaction: &mut McTransaction, + mc_transaction: &mut impl McTransaction, operation: FriendTcOp, currency: &Currency, local_public_key: &PublicKey, @@ -59,7 +59,7 @@ pub async fn queue_operation( } async fn queue_request_send_funds( - mc_transaction: &mut McTransaction, + mc_transaction: &mut impl McTransaction, request_send_funds: RequestSendFundsOp, ) -> Result<(), QueueOperationError> { if !request_send_funds.route.is_part_valid() { @@ -108,7 +108,7 @@ async fn queue_request_send_funds( } async fn queue_response_send_funds( - mc_transaction: &mut McTransaction, + mc_transaction: &mut impl McTransaction, response_send_funds: ResponseSendFundsOp, currency: &Currency, local_public_key: &PublicKey, @@ -189,7 +189,7 @@ async fn queue_response_send_funds( } async fn queue_cancel_send_funds( - mc_transaction: &mut McTransaction, + mc_transaction: &mut impl McTransaction, cancel_send_funds: CancelSendFundsOp, ) -> Result<(), QueueOperationError> { // Make sure that id exists in remote_pending hashmap, diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index aa8f4b671..ac37caf33 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -1,9 +1,5 @@ use std::convert::TryFrom; -use futures::channel::mpsc; -use futures::task::SpawnExt; -use futures::{FutureExt, TryFutureExt}; - use common::test_executor::TestExecutor; use crypto::hash_lock::HashLock; @@ -16,13 +12,13 @@ use proto::funder::messages::{ CancelSendFundsOp, Currency, FriendTcOp, FriendsRoute, RequestSendFundsOp, }; -use crate::mutual_credit::tests::utils::{mc_server, MutualCredit}; +use crate::mutual_credit::tests::utils::MutualCredit; use crate::mutual_credit::types::McTransaction; use crate::mutual_credit::incoming::process_operations_list; use crate::mutual_credit::outgoing::queue_operation; -async fn task_request_cancel_send_funds(test_executor: TestExecutor) { +async fn task_request_cancel_send_funds() { let currency = Currency::try_from("FST".to_owned()).unwrap(); let mut rng = DummyRandom::new(&[1u8]); @@ -34,16 +30,7 @@ async fn task_request_cancel_send_funds(test_executor: TestExecutor) { let remote_public_key = public_key_b.clone(); let balance = 0; - let mutual_credit = MutualCredit::new(¤cy, balance); - let (sender, receiver) = mpsc::channel(0); - test_executor - .spawn( - mc_server(mutual_credit, receiver) - .map_err(|e| warn!("mc_server closed with error: {:?}", e)) - .map(|_| ()), - ) - .unwrap(); - let mut mc_transaction = McTransaction::new(sender); + let mut mc_transaction = MutualCredit::new(¤cy, balance); // -----[RequestSendFunds]-------- // ----------------------------- @@ -107,6 +94,6 @@ async fn task_request_cancel_send_funds(test_executor: TestExecutor) { #[test] fn test_request_cancel_send_funds() { let test_executor = TestExecutor::new(); - let res = test_executor.run(task_request_cancel_send_funds(test_executor.clone())); + let res = test_executor.run(task_request_cancel_send_funds()); assert!(res.is_output()); } diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index 3ff9dc07a..572c008bf 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -1,9 +1,5 @@ use std::convert::TryFrom; -use futures::channel::mpsc; -use futures::task::SpawnExt; -use futures::{FutureExt, TryFutureExt}; - use common::test_executor::TestExecutor; use crypto::hash_lock::HashLock; @@ -17,30 +13,21 @@ use proto::funder::messages::{ }; use signature::signature_buff::create_response_signature_buffer; -use crate::mutual_credit::tests::utils::{mc_server, MutualCredit}; +use crate::mutual_credit::tests::utils::MutualCredit; use crate::mutual_credit::types::McTransaction; use crate::types::create_pending_transaction; use crate::mutual_credit::incoming::process_operations_list; use crate::mutual_credit::outgoing::queue_operation; -async fn task_request_response_send_funds(test_executor: TestExecutor) { +async fn task_request_response_send_funds() { let currency = Currency::try_from("FST".to_owned()).unwrap(); let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); let remote_public_key = PublicKey::from(&[0xbb; PublicKey::len()]); let balance = 0; - let (sender, receiver) = mpsc::channel(0); - let mutual_credit = MutualCredit::new(¤cy, balance); - test_executor - .spawn( - mc_server(mutual_credit, receiver) - .map_err(|e| warn!("mc_server closed with error: {:?}", e)) - .map(|_| ()), - ) - .unwrap(); - let mut mc_transaction = McTransaction::new(sender); + let mut mc_transaction = MutualCredit::new(¤cy, balance); // -----[RequestSendFunds]-------- // ----------------------------- @@ -125,6 +112,6 @@ async fn task_request_response_send_funds(test_executor: TestExecutor) { #[test] fn test_request_response_send_funds() { let test_executor = TestExecutor::new(); - let res = test_executor.run(task_request_response_send_funds(test_executor.clone())); + let res = test_executor.run(task_request_response_send_funds()); assert!(res.is_output()); } diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index 570abf0ae..98e9d52fc 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -1,12 +1,12 @@ use std::collections::HashMap; -use futures::channel::mpsc; -use futures::StreamExt; +use common::async_rpc::OpError; +use common::conn::BoxFuture; use proto::crypto::Uid; use proto::funder::messages::{Currency, PendingTransaction}; -use crate::mutual_credit::types::{McBalance, McOp}; +use crate::mutual_credit::types::{McBalance, McTransaction}; #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct McPendingTransactions { @@ -47,99 +47,80 @@ impl MutualCredit { pending_transactions: McPendingTransactions::new(), } } +} + +impl McTransaction for MutualCredit { + fn get_balance(&mut self) -> BoxFuture<'static, Result> { + let mc_balance = self.balance.clone(); + Box::pin(async move { Ok(mc_balance) }) + } - fn set_balance(&mut self, balance: i128) { + fn set_balance(&mut self, balance: i128) -> BoxFuture<'static, Result<(), OpError>> { self.balance.balance = balance; + Box::pin(async move { Ok(()) }) } - fn insert_remote_pending_transaction(&mut self, pending_transaction: PendingTransaction) { - self.pending_transactions - .remote - .insert(pending_transaction.request_id.clone(), pending_transaction); + fn set_local_pending_debt(&mut self, debt: u128) -> BoxFuture<'static, Result<(), OpError>> { + self.balance.local_pending_debt = debt; + Box::pin(async move { Ok(()) }) + } + + fn set_remote_pending_debt(&mut self, debt: u128) -> BoxFuture<'static, Result<(), OpError>> { + self.balance.remote_pending_debt = debt; + Box::pin(async move { Ok(()) }) } - fn remove_remote_pending_transaction(&mut self, request_id: &Uid) { - let _ = self.pending_transactions.remote.remove(request_id); + fn get_local_pending_transaction( + &mut self, + request_id: Uid, + ) -> BoxFuture<'static, Result, OpError>> { + let pending_transaction = self.pending_transactions.local.get(&request_id).cloned(); + Box::pin(async move { Ok(pending_transaction) }) } - fn insert_local_pending_transaction(&mut self, pending_transaction: PendingTransaction) { - self.pending_transactions + fn insert_local_pending_transaction( + &mut self, + pending_transaction: PendingTransaction, + ) -> BoxFuture<'static, Result<(), OpError>> { + let _ = self + .pending_transactions .local .insert(pending_transaction.request_id.clone(), pending_transaction); + Box::pin(async move { Ok(()) }) } - fn remove_local_pending_transaction(&mut self, request_id: &Uid) { - let _ = self.pending_transactions.local.remove(request_id); + fn remove_local_pending_transaction( + &mut self, + request_id: Uid, + ) -> BoxFuture<'static, Result<(), OpError>> { + let _ = self.pending_transactions.local.remove(&request_id); + Box::pin(async move { Ok(()) }) } - fn set_remote_pending_debt(&mut self, remote_pending_debt: u128) { - self.balance.remote_pending_debt = remote_pending_debt; + fn get_remote_pending_transaction( + &mut self, + request_id: Uid, + ) -> BoxFuture<'static, Result, OpError>> { + let pending_transaction = self.pending_transactions.remote.get(&request_id).cloned(); + Box::pin(async move { Ok(pending_transaction) }) } - fn set_local_pending_debt(&mut self, local_pending_debt: u128) { - self.balance.local_pending_debt = local_pending_debt; + fn insert_remote_pending_transaction( + &mut self, + pending_transaction: PendingTransaction, + ) -> BoxFuture<'static, Result<(), OpError>> { + let _ = self + .pending_transactions + .remote + .insert(pending_transaction.request_id.clone(), pending_transaction); + Box::pin(async move { Ok(()) }) } -} -#[derive(Debug)] -pub enum McServerError { - SendError, -} - -pub async fn mc_server( - mut mc: MutualCredit, - mut incoming_ops: mpsc::Receiver, -) -> Result<(), McServerError> { - while let Some(mc_op) = incoming_ops.next().await { - match mc_op { - McOp::GetBalance(mc_balance_sender) => { - mc_balance_sender - .send(Ok(mc.balance.clone())) - .map_err(|_| McServerError::SendError)?; - } - McOp::SetBalance(new_balance, sender) => { - mc.set_balance(new_balance); - sender.send(Ok(())).map_err(|_| McServerError::SendError)?; - } - McOp::SetLocalPendingDebt(new_pending_debt, sender) => { - mc.set_local_pending_debt(new_pending_debt); - sender.send(Ok(())).map_err(|_| McServerError::SendError)?; - } - McOp::SetRemotePendingDebt(new_pending_debt, sender) => { - mc.set_remote_pending_debt(new_pending_debt); - sender.send(Ok(())).map_err(|_| McServerError::SendError)?; - } - McOp::GetLocalPendingTransaction(request_id, pending_transaction_sender) => { - let opt_pending_transaction = - mc.pending_transactions.local.get(&request_id).cloned(); - pending_transaction_sender - .send(Ok(opt_pending_transaction)) - .map_err(|_| McServerError::SendError)?; - } - McOp::InsertLocalPendingTransaction(pending_transaction, sender) => { - mc.insert_local_pending_transaction(pending_transaction); - sender.send(Ok(())).map_err(|_| McServerError::SendError)?; - } - McOp::RemoveLocalPendingTransaction(request_id, sender) => { - mc.remove_local_pending_transaction(&request_id); - sender.send(Ok(())).map_err(|_| McServerError::SendError)?; - } - McOp::GetRemotePendingTransaction(request_id, pending_transaction_sender) => { - let opt_pending_transaction = - mc.pending_transactions.remote.get(&request_id).cloned(); - pending_transaction_sender - .send(Ok(opt_pending_transaction)) - .map_err(|_| McServerError::SendError)?; - } - McOp::InsertRemotePendingTransaction(pending_transaction, sender) => { - mc.insert_remote_pending_transaction(pending_transaction); - sender.send(Ok(())).map_err(|_| McServerError::SendError)?; - } - McOp::RemoveRemotePendingTransaction(request_id, sender) => { - mc.remove_remote_pending_transaction(&request_id); - sender.send(Ok(())).map_err(|_| McServerError::SendError)?; - } - } + fn remove_remote_pending_transaction( + &mut self, + request_id: Uid, + ) -> BoxFuture<'static, Result<(), OpError>> { + let _ = self.pending_transactions.remote.remove(&request_id); + Box::pin(async move { Ok(()) }) } - Ok(()) } diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index b3ab2f7ae..740419579 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -4,14 +4,14 @@ use paste::paste; use common::async_rpc::OpError; +use common::conn::BoxFuture; use common::ser_utils::ser_string; use common::{get_out_type, ops_enum}; use proto::crypto::Uid; use proto::funder::messages::PendingTransaction; -use futures::channel::{mpsc, oneshot}; -use futures::SinkExt; +use futures::channel::oneshot; #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct McBalance { From 5e99eb66fd5511e1c2c09f176ec17b304b6eb449 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 18 Oct 2020 20:05:30 +0300 Subject: [PATCH 111/478] funder: Some work on token_channel. Not done yet. --- components/funder/src/lib.rs | 2 +- components/funder/src/token_channel.rs | 111 ++++++++++++++----------- 2 files changed, 64 insertions(+), 49 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index f9cbafb90..586817f0c 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -28,7 +28,7 @@ mod mutual_credit; // pub mod report; // mod state; // #[allow(unused)] -// mod token_channel; +mod token_channel; // // For testing: diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index d2beb6d9b..70aca2c57 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -5,12 +5,13 @@ use derive_more::From; use paste::paste; -use common::async_rpc::OpError; -use common::{get_out_type, ops_enum}; - use futures::channel::{mpsc, oneshot}; use futures::SinkExt; +use common::async_rpc::OpError; +use common::conn::BoxFuture; +use common::{get_out_type, ops_enum}; + use im::hashset::HashSet as ImHashSet; use std::collections::HashMap as ImHashMap; @@ -282,7 +283,7 @@ fn initial_move_token( } async fn handle_in_move_token( - tc_transaction: &mut TcTransaction, + tc_transaction: &mut impl TcTransaction, new_move_token: MoveToken, remote_public_key: &PublicKey, ) -> Result, ReceiveMoveTokenError> @@ -299,7 +300,7 @@ where } async fn handle_in_move_token_dir_in( - tc_transaction: &mut TcTransaction, + tc_transaction: &mut impl TcTransaction, new_move_token: MoveToken, ) -> Result, ReceiveMoveTokenError> where @@ -317,7 +318,7 @@ where } async fn handle_in_move_token_dir_out( - tc_transaction: &mut TcTransaction, + tc_transaction: &mut impl TcTransaction, new_move_token: MoveToken, remote_public_key: &PublicKey, ) -> Result, ReceiveMoveTokenError> @@ -342,7 +343,7 @@ where } async fn handle_incoming_token_match( - tc_transaction: &mut TcTransaction, + tc_transaction: &mut impl TcTransaction, new_move_token: MoveToken, // remote_max_debts: &ImHashMap, remote_public_key: &PublicKey, ) -> Result, ReceiveMoveTokenError> @@ -372,49 +373,63 @@ where // Handle active currencies: - // First, make sure that nobody removed a currency that is already active: - // TODO: We might allow to do this in the future, in the special case of zero balance and zero - // pending debt? - - // TODO: Possibly unite this code with the code below: + // currencies_diff represents a "xor" between the previous set of currencies and the new set of + // currencies. + // + // TODO: + // - Add to remote currencies every currency that is in the xor set, but not in the current + // set. + // - Remove from remote currencies currencies that satisfy the following requirements: + // - (1) in the xor set. + // - (2) in the remote + // - (3) (Not in the local set) or (in the local set with balance zero and zero pending debts) for diff_currency in new_move_token.currencies_diff.as_ref() { - if tc_transaction.is_active_currency(diff_currency).await? { - return Err(ReceiveMoveTokenError::CanNotRemoveCurrencyInUse); - } - } - - for diff_currency in new_move_token.currencies_diff.as_ref() { - if tc_transaction.is_remote_currency(diff_currency) { - // We need to remove this currency - // TODO: continue here. - // - let mutation = TcMutation::SetRemoteActiveCurrencies(active_currencies.clone()); - token_channel.mutate(&mutation); - move_token_received.mutations.push(mutation); - - let tc_out_borrow = token_channel.get_outgoing().unwrap(); - let active_currencies = &tc_out_borrow.active_currencies; - - // Find the new currencies we need to initialize. - // Calculate: - // (local ^ remote) \ mutual_credit_currencies: - let intersection = active_currencies - .remote - .clone() - .intersection(active_currencies.local.clone()); - - let mutual_credit_currencies: ImHashSet<_> = - tc_out_borrow.mutual_credits.keys().cloned().collect(); - - let new_currencies = intersection.relative_complement(mutual_credit_currencies); - - for new_currency in new_currencies { - let mutation = TcMutation::AddMutualCredit(new_currency.clone()); - token_channel.mutate(&mutation); - move_token_received.mutations.push(mutation); + // Check if we need to add currency: + if !tc_transaction + .is_remote_currency(diff_currency.clone()) + .await? + { + // Add a new remote currency. + tc_transaction + .add_remote_currency(diff_currency.clone()) + .await?; + + // If we also have this currency as a local currency, add a new mutual credit: + if tc_transaction + .is_local_currency(diff_currency.clone()) + .await? + { + tc_transaction.add_mutual_credit(diff_currency.clone()); } } else { - // TODO: Possibly add a new currency (If both remote and local have this currency): + let is_local_currency = tc_transaction + .is_local_currency(diff_currency.clone()) + .await?; + if is_local_currency { + let mc_balance = tc_transaction.mc_get_balance(diff_currency.clone()).await?; + if mc_balance.balance == 0 + && mc_balance.remote_pending_debt == 0 + && mc_balance.local_pending_debt == 0 + { + // We may remove the currency if the balance and pending debts are exactly + // zero: + tc_transaction + .remove_remote_currency(diff_currency.clone()) + .await?; + // TODO: We need to report outside that we removed this currency somehow. + // TODO: Somehow unite all code for removing remote currencies. + todo!(); + } else { + // We are not allowed to remove this currency! + return Err(ReceiveMoveTokenError::CanNotRemoveCurrencyInUse); + } + } else { + tc_transaction + .remove_remote_currency(diff_currency.clone()) + .await?; + // TODO: We need to report outside that we removed this currency somehow. + todo!(); + } } } @@ -539,7 +554,7 @@ where Ok(move_token_received) } -fn handle_out_move_token(tc_transaction: &mut TcTransaction) { +fn handle_out_move_token(tc_transaction: &mut impl TcTransaction) { todo!(); } From b8ae12d3b030e04ef35b8765c77e1f87ad7a1a1c Mon Sep 17 00:00:00 2001 From: real Date: Mon, 19 Oct 2020 19:52:21 +0300 Subject: [PATCH 112/478] funder: Added comment --- components/funder/src/token_channel.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 70aca2c57..8c5fcc8f2 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -433,6 +433,9 @@ where } } + // TODO: How do we pass the new relay's information? Do we need to update anything related to + // the new relays? + // Attempt to apply operations for every currency: for currency_operations in &new_move_token.currencies_operations { let tc_out_borrow = token_channel.get_outgoing().unwrap(); From 27ea336e83f76aad8949fad2d5534df984c15319 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 21 Oct 2020 12:19:06 +0300 Subject: [PATCH 113/478] funder: Write trait manually instead of using a macro --- components/common/src/async_rpc.rs | 13 ++++-- .../src/{interfaces => interface}/funder.rs | 2 +- components/database/src/interface/mod.rs | 2 + .../src/{interfaces => interface}/types.rs | 0 components/database/src/interfaces/mod.rs | 2 - components/database/src/lib.rs | 2 +- components/funder/src/lib.rs | 2 +- components/funder/src/mutual_credit/types.rs | 45 ++++++++++--------- components/funder/src/token_channel.rs | 42 ++++++++++------- 9 files changed, 64 insertions(+), 46 deletions(-) rename components/database/src/{interfaces => interface}/funder.rs (98%) create mode 100644 components/database/src/interface/mod.rs rename components/database/src/{interfaces => interface}/types.rs (100%) delete mode 100644 components/database/src/interfaces/mod.rs diff --git a/components/common/src/async_rpc.rs b/components/common/src/async_rpc.rs index 629810071..f3e95dc21 100644 --- a/components/common/src/async_rpc.rs +++ b/components/common/src/async_rpc.rs @@ -1,3 +1,4 @@ +use crate::conn::BoxFuture; use futures::channel::oneshot; #[derive(Debug)] @@ -6,6 +7,8 @@ pub enum OpError { ResponseOpFailed(oneshot::Canceled), } +pub type AsyncOpResult = BoxFuture<'static, Result>; + /* macro_rules! ops_enum_func { ($variant_snake:ident($($arg_name: $arg_type),*) -> $ret_type) => { @@ -54,14 +57,15 @@ macro_rules! get_out_type { /// Create an async interface for request/response messages /// Generates an enum of all possible RPC messages, and an async interface that knows how to send /// those RPC messages. -macro_rules! ops_enum { - (($op_enum:ident $(<$($ty:ident),*>)?, $transaction_trait:ident) => { +macro_rules! ops_trait { + (($transaction_trait:ident $(<$($ty:ident),*>)?) => { $( $variant_snake:ident ($($($arg_name:ident: $arg_type:path),+)?) $(-> $ret_type:path)? );* // Possibly an extra semicolon: $(;)? }) => { + /* paste! { // Enum for all possible operations pub enum $op_enum$(<$($ty),*>)? { @@ -70,6 +74,7 @@ macro_rules! ops_enum { ),* } } + */ // A transaction client /* @@ -123,7 +128,7 @@ mod tests { #[test] fn test_rpc_enums() { - ops_enum!((TcOp1, TcTransaction1) => { + ops_trait!((TcTransaction1) => { func1(hello: Option) -> u32; func2() -> u8; func3(); @@ -131,7 +136,7 @@ mod tests { func5(world: u64); }); - ops_enum!((TcOp2, TcTransaction2) => { + ops_trait!((TcTransaction2) => { func1(hello: String) -> Result; func2(world: String) -> u32 }); diff --git a/components/database/src/interfaces/funder.rs b/components/database/src/interface/funder.rs similarity index 98% rename from components/database/src/interfaces/funder.rs rename to components/database/src/interface/funder.rs index b732b5310..f0a864315 100644 --- a/components/database/src/interfaces/funder.rs +++ b/components/database/src/interface/funder.rs @@ -4,7 +4,7 @@ use proto::app_server::messages::{NamedRelayAddress, RelayAddress}; use proto::crypto::PublicKey; use proto::funder::messages::{Currency, Rate}; -use crate::interfaces::types::{DbOpResult, DbOpSenderResult}; +use crate::interface::types::{DbOpResult, DbOpSenderResult}; use futures::channel::mpsc; diff --git a/components/database/src/interface/mod.rs b/components/database/src/interface/mod.rs new file mode 100644 index 000000000..dd322a6a3 --- /dev/null +++ b/components/database/src/interface/mod.rs @@ -0,0 +1,2 @@ +pub mod funder; +mod types; diff --git a/components/database/src/interfaces/types.rs b/components/database/src/interface/types.rs similarity index 100% rename from components/database/src/interfaces/types.rs rename to components/database/src/interface/types.rs diff --git a/components/database/src/interfaces/mod.rs b/components/database/src/interfaces/mod.rs deleted file mode 100644 index c5bbadd4b..000000000 --- a/components/database/src/interfaces/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod funder; -mod types; diff --git a/components/database/src/lib.rs b/components/database/src/lib.rs index 26d7f5a10..2fc90d7e6 100644 --- a/components/database/src/lib.rs +++ b/components/database/src/lib.rs @@ -17,7 +17,7 @@ mod atomic_db; mod create; mod database; pub mod file_db; -mod interfaces; +pub mod interface; pub use self::atomic_db::AtomicDb; pub use self::database::{database_loop, DatabaseClient, DatabaseClientError, DatabaseRequest}; diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 586817f0c..f9cbafb90 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -28,7 +28,7 @@ mod mutual_credit; // pub mod report; // mod state; // #[allow(unused)] -mod token_channel; +// mod token_channel; // // For testing: diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 740419579..bf4e88474 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -1,18 +1,11 @@ // use common::safe_arithmetic::SafeSignedArithmetic; -// Used for macros: -use paste::paste; - -use common::async_rpc::OpError; -use common::conn::BoxFuture; +use common::async_rpc::AsyncOpResult; use common::ser_utils::ser_string; -use common::{get_out_type, ops_enum}; use proto::crypto::Uid; use proto::funder::messages::PendingTransaction; -use futures::channel::oneshot; - #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct McBalance { /// Amount of credits this side has against the remote side. @@ -39,15 +32,27 @@ impl McBalance { } } -ops_enum!((McOp, McTransaction) => { - get_balance() -> McBalance; - set_balance(balance: i128); - set_local_pending_debt(debt: u128); - set_remote_pending_debt(debt: u128); - get_local_pending_transaction(request_id: Uid) -> Option; - insert_local_pending_transaction(pending_transaction: PendingTransaction); - remove_local_pending_transaction(request_id: Uid); - get_remote_pending_transaction(request_id: Uid) -> Option; - insert_remote_pending_transaction(pending_transaction: PendingTransaction); - remove_remote_pending_transaction(request_id: Uid); -}); +pub trait McTransaction { + fn get_balance(&mut self) -> AsyncOpResult; + fn set_balance(&mut self, new_balance: i128) -> AsyncOpResult<()>; + fn set_local_pending_debt(&mut self, debt: u128) -> AsyncOpResult<()>; + fn set_remote_pending_debt(&mut self, debt: u128) -> AsyncOpResult<()>; + fn get_local_pending_transaction( + &mut self, + request_id: Uid, + ) -> AsyncOpResult>; + fn insert_local_pending_transaction( + &mut self, + pending_transaction: PendingTransaction, + ) -> AsyncOpResult<()>; + fn remove_local_pending_transaction(&mut self, request_id: Uid) -> AsyncOpResult<()>; + fn get_remote_pending_transaction( + &mut self, + request_id: Uid, + ) -> AsyncOpResult>; + fn insert_remote_pending_transaction( + &mut self, + pending_transaction: PendingTransaction, + ) -> AsyncOpResult<()>; + fn remove_remote_pending_transaction(&mut self, request_id: Uid) -> AsyncOpResult<()>; +} diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 8c5fcc8f2..306ceb037 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -10,7 +10,7 @@ use futures::SinkExt; use common::async_rpc::OpError; use common::conn::BoxFuture; -use common::{get_out_type, ops_enum}; +use common::{get_out_type, ops_trait}; use im::hashset::HashSet as ImHashSet; use std::collections::HashMap as ImHashMap; @@ -32,6 +32,8 @@ use proto::funder::messages::{ use signature::signature_buff::hash_token_info; use signature::verify::verify_move_token; +use database::interface::funder::CurrencyConfig; + use crate::mutual_credit::incoming::{ process_operations_list, IncomingMessage, ProcessTransListError, }; @@ -57,13 +59,13 @@ pub enum TcOpError { pub type TcOpResult = Result; pub type TcOpSenderResult = oneshot::Sender>; -pub enum TcStatus { - ConsistentIn, - ConsistentOut, +pub enum TcStatus { + ConsistentIn(MoveTokenHashed), + ConsistentOut(MoveToken, MoveTokenHashed), Inconsistent, } -ops_enum!((TcOp, TcTransaction) => { +ops_trait!((TcMcTransaction) => { mc_get_balance(currency: Currency) -> McBalance; mc_set_balance(currency: Currency, balance: i128); mc_set_local_pending_debt(currency: Currency, debt: u128); @@ -74,30 +76,37 @@ ops_enum!((TcOp, TcTransaction) => { mc_get_remote_pending_transaction(currency: Currency, request_id: Uid) -> Option; mc_insert_remote_pending_transaction(currency: Currency, pending_transaction: PendingTransaction); mc_remove_remote_pending_transaction(currency: Currency, request_id: Uid); +}); + +ops_trait!((TcTransaction) => { + get_tc_status() -> TcStatus; + set_direction_incoming(move_token_hashed: MoveTokenHashed); + set_direction_outgoing(move_token: MoveToken); + + // get_move_token_in() -> Option; + // get_move_token_out() -> Option>; - get_remote_public_key() -> PublicKey; - get_tc_status() -> TcStatus; - get_move_token_in() -> Option; - get_move_token_out() -> Option>; + get_currency_config(currency: Currency) -> CurrencyConfig; - add_local_currency(currency: Currency); + // add_local_currency(currency: Currency); // TODO: Possibly add boolean result here? And to other remove commands? - remove_local_currency(currency: Currency); + // remove_local_currency(currency: Currency); + is_local_currency(currency: Currency) -> bool; + is_remote_currency(currency: Currency) -> bool; add_remote_currency(currency: Currency); remove_remote_currency(currency: Currency); - is_remote_currency(currency: Currency) -> bool; // get_remote_active_currencies() -> - set_remote_active_currencies(currencies: Vec); - is_active_currency(currency: Currency) -> bool; + // set_remote_active_currencies(currencies: Vec); + // is_active_currency(currency: Currency) -> bool; add_mutual_credit(currency: Currency); - set_direction_incoming(move_token_hashed: MoveTokenHashed); - set_direction_outgoing(move_token: MoveToken); }); +impl McTransaction for T where T: TcTransaction {} + /// The currencies set to be active by two sides of the token channel. /// Only currencies that are active on both sides (Intersection) can be used for trading. #[derive(Arbitrary, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] @@ -360,7 +369,6 @@ where // Note that we only verify the signature here, and not at the Incoming part. // This allows the genesis move token to occur smoothly, even though its signature // is not correct. - let remote_public_key = tc_transaction.get_remote_public_key().await?; if !verify_move_token(new_move_token.clone(), &remote_public_key) { return Err(ReceiveMoveTokenError::InvalidSignature); } From 1bc16fa728b03fb2af64a9d60dd22ee719f16420 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 21 Oct 2020 13:24:00 +0300 Subject: [PATCH 114/478] funder: Some work on token_channel. Not compiling yet. --- components/funder/src/lib.rs | 2 +- components/funder/src/token_channel.rs | 146 ++++++++++++------------- 2 files changed, 69 insertions(+), 79 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index f9cbafb90..586817f0c 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -28,7 +28,7 @@ mod mutual_credit; // pub mod report; // mod state; // #[allow(unused)] -// mod token_channel; +mod token_channel; // // For testing: diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 306ceb037..d21c0bf62 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -8,7 +8,7 @@ use paste::paste; use futures::channel::{mpsc, oneshot}; use futures::SinkExt; -use common::async_rpc::OpError; +use common::async_rpc::{AsyncOpResult, OpError}; use common::conn::BoxFuture; use common::{get_out_type, ops_trait}; @@ -65,47 +65,52 @@ pub enum TcStatus { Inconsistent, } -ops_trait!((TcMcTransaction) => { - mc_get_balance(currency: Currency) -> McBalance; - mc_set_balance(currency: Currency, balance: i128); - mc_set_local_pending_debt(currency: Currency, debt: u128); - mc_set_remote_pending_debt(currency: Currency, debt: u128); - mc_get_local_pending_transaction(currency: Currency, request_id: Uid) -> Option; - mc_insert_local_pending_transaction(currency: Currency, pending_transaction: PendingTransaction); - mc_remove_local_pending_transaction(currency: Currency, request_id: Uid); - mc_get_remote_pending_transaction(currency: Currency, request_id: Uid) -> Option; - mc_insert_remote_pending_transaction(currency: Currency, pending_transaction: PendingTransaction); - mc_remove_remote_pending_transaction(currency: Currency, request_id: Uid); -}); - -ops_trait!((TcTransaction) => { - get_tc_status() -> TcStatus; - set_direction_incoming(move_token_hashed: MoveTokenHashed); - set_direction_outgoing(move_token: MoveToken); +pub struct MutualCreditInfo { + pub balance: i128, + pub local_pending_debt: u128, + pub remote_pending_debt: u128, + pub in_fees: u128, + pub out_fees: u128, +} + +pub trait TcTransaction { + type McTransaction: McTransaction; + fn mc_transaction(&mut self, currency: Currency) -> &mut Self::McTransaction; + + fn get_tc_status(&mut self) -> AsyncOpResult>; + fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; + fn set_direction_outgoing(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; // get_move_token_in() -> Option; // get_move_token_out() -> Option>; - get_currency_config(currency: Currency) -> CurrencyConfig; + fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult; + // TODO: Could we somehow return an iterator here? Or maybe a stream? + // How to do this? + /// Sort all active mutual credits, and return a list of mutual credits after a given currency + /// name. If no currency is given, the search will start from the beginning. + fn list_mutual_credits_after( + &mut self, + opt_currency: Option, + max_length: usize, + ) -> AsyncOpResult>; // add_local_currency(currency: Currency); // TODO: Possibly add boolean result here? And to other remove commands? // remove_local_currency(currency: Currency); - is_local_currency(currency: Currency) -> bool; - is_remote_currency(currency: Currency) -> bool; + fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; + fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; - add_remote_currency(currency: Currency); - remove_remote_currency(currency: Currency); + fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; // get_remote_active_currencies() -> // set_remote_active_currencies(currencies: Vec); // is_active_currency(currency: Currency) -> bool; - add_mutual_credit(currency: Currency); -}); - -impl McTransaction for T where T: TcTransaction {} + fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()>; +} /// The currencies set to be active by two sides of the token channel. /// Only currencies that are active on both sides (Intersection) can be used for trading. @@ -300,9 +305,17 @@ where B: CanonicalSerialize + Clone, { match tc_transaction.get_tc_status().await? { - TcStatus::ConsistentIn => handle_in_move_token_dir_in(tc_transaction, new_move_token).await, - TcStatus::ConsistentOut => { - handle_in_move_token_dir_out(tc_transaction, new_move_token, remote_public_key).await + TcStatus::ConsistentIn(move_token_in) => { + handle_in_move_token_dir_in(tc_transaction, move_token_in, new_move_token).await + } + TcStatus::ConsistentOut(move_token_out, _move_token_in) => { + handle_in_move_token_dir_out( + tc_transaction, + move_token_out, + new_move_token, + remote_public_key, + ) + .await } TcStatus::Inconsistent => unreachable!(), } @@ -310,13 +323,12 @@ where async fn handle_in_move_token_dir_in( tc_transaction: &mut impl TcTransaction, + move_token_in: MoveTokenHashed, new_move_token: MoveToken, ) -> Result, ReceiveMoveTokenError> where B: CanonicalSerialize + Clone, { - let move_token_in = tc_transaction.get_move_token_in().await?.unwrap(); - if move_token_in == create_hashed(&new_move_token, &move_token_in.token_info) { // Duplicate Ok(ReceiveMoveTokenOutput::Duplicate) @@ -328,17 +340,22 @@ where async fn handle_in_move_token_dir_out( tc_transaction: &mut impl TcTransaction, + move_token_out: MoveToken, new_move_token: MoveToken, remote_public_key: &PublicKey, ) -> Result, ReceiveMoveTokenError> where B: Clone + CanonicalSerialize, { - let move_token_out = tc_transaction.get_move_token_out().await?.unwrap(); - if new_move_token.old_token == move_token_out.new_token { Ok(ReceiveMoveTokenOutput::Received( - handle_incoming_token_match(tc_transaction, new_move_token, remote_public_key).await?, + handle_incoming_token_match( + tc_transaction, + move_token_out, + new_move_token, + remote_public_key, + ) + .await?, )) // self.outgoing_to_incoming(friend_move_token, new_move_token) } else if move_token_out.old_token == new_move_token.new_token { @@ -353,22 +370,18 @@ where async fn handle_incoming_token_match( tc_transaction: &mut impl TcTransaction, + move_token_out: MoveToken, new_move_token: MoveToken, // remote_max_debts: &ImHashMap, remote_public_key: &PublicKey, ) -> Result, ReceiveMoveTokenError> where B: Clone + CanonicalSerialize, { - // We create a clone `token_channel` on which we are going to apply all the mutations. - // Eventually this cloned TokenChannel is discarded, and we only output the applied mutations. - // let tc_out_borrow = token_channel.get_outgoing().unwrap(); - - let move_token_out = tc_transaction.get_move_token_out().await?.unwrap(); - // Verify signature: // Note that we only verify the signature here, and not at the Incoming part. // This allows the genesis move token to occur smoothly, even though its signature // is not correct. + // TODO: Check if the above statement is still true. if !verify_move_token(new_move_token.clone(), &remote_public_key) { return Err(ReceiveMoveTokenError::InvalidSignature); } @@ -391,7 +404,7 @@ where // - (1) in the xor set. // - (2) in the remote // - (3) (Not in the local set) or (in the local set with balance zero and zero pending debts) - for diff_currency in new_move_token.currencies_diff.as_ref() { + for diff_currency in &new_move_token.currencies_diff { // Check if we need to add currency: if !tc_transaction .is_remote_currency(diff_currency.clone()) @@ -414,7 +427,10 @@ where .is_local_currency(diff_currency.clone()) .await?; if is_local_currency { - let mc_balance = tc_transaction.mc_get_balance(diff_currency.clone()).await?; + let mc_balance = tc_transaction + .mc_transaction(diff_currency.clone()) + .get_balance() + .await?; if mc_balance.balance == 0 && mc_balance.remote_pending_debt == 0 && mc_balance.local_pending_debt == 0 @@ -446,49 +462,23 @@ where // Attempt to apply operations for every currency: for currency_operations in &new_move_token.currencies_operations { - let tc_out_borrow = token_channel.get_outgoing().unwrap(); - let mut mutual_credit = tc_out_borrow - .mutual_credits - .get(¤cy_operations.currency) - .ok_or(ReceiveMoveTokenError::InvalidCurrency)? - .clone(); - - let remote_max_debt = remote_max_debts - .get(¤cy_operations.currency) - .cloned() - .unwrap_or(0); + let remote_max_debt = tc_transaction + .get_currency_config(currency_operations.currency.clone()) + .await? + .remote_max_debt; - let outputs = process_operations_list( - &mut mutual_credit, + let incoming_messages = process_operations_list( + tc_transaction.mc_transaction(currency_operations.currency.clone()), currency_operations.operations.clone(), + ¤cy_operations.currency, + remote_public_key, remote_max_debt, ) + .await .map_err(ReceiveMoveTokenError::InvalidTransaction)?; - let mut incoming_messages = Vec::new(); - // We apply mutations on this token channel, to verify stated balance values // let mut check_mutual_credit = mutual_credit.clone(); - - for output in outputs { - let ProcessOperationOutput { - incoming_message, - mc_mutations, - } = output; - - if let Some(funds) = incoming_message { - incoming_messages.push(funds); - } - for mc_mutation in mc_mutations { - let mutation = TcMutation::McMutation(( - currency_operations.currency.clone(), - mc_mutation.clone(), - )); - token_channel.mutate(&mutation); - move_token_received.mutations.push(mutation); - } - } - let move_token_received_currency = MoveTokenReceivedCurrency { currency: currency_operations.currency.clone(), incoming_messages, From b079cf53e5fdb14c1a3126ff4f778902a2d1c5ad Mon Sep 17 00:00:00 2001 From: real Date: Wed, 21 Oct 2020 13:37:25 +0300 Subject: [PATCH 115/478] funder: token_channel: AsyncOpStream idea --- components/common/src/async_rpc.rs | 3 ++- components/funder/src/token_channel.rs | 14 ++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/components/common/src/async_rpc.rs b/components/common/src/async_rpc.rs index f3e95dc21..87c10478a 100644 --- a/components/common/src/async_rpc.rs +++ b/components/common/src/async_rpc.rs @@ -1,4 +1,4 @@ -use crate::conn::BoxFuture; +use crate::conn::{BoxFuture, BoxStream}; use futures::channel::oneshot; #[derive(Debug)] @@ -8,6 +8,7 @@ pub enum OpError { } pub type AsyncOpResult = BoxFuture<'static, Result>; +pub type AsyncOpStream = BoxStream<'static, Result>; /* macro_rules! ops_enum_func { diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index d21c0bf62..0cb06ac78 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -8,7 +8,7 @@ use paste::paste; use futures::channel::{mpsc, oneshot}; use futures::SinkExt; -use common::async_rpc::{AsyncOpResult, OpError}; +use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; use common::conn::BoxFuture; use common::{get_out_type, ops_trait}; @@ -85,15 +85,9 @@ pub trait TcTransaction { // get_move_token_out() -> Option>; fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult; - // TODO: Could we somehow return an iterator here? Or maybe a stream? - // How to do this? - /// Sort all active mutual credits, and return a list of mutual credits after a given currency - /// name. If no currency is given, the search will start from the beginning. - fn list_mutual_credits_after( - &mut self, - opt_currency: Option, - max_length: usize, - ) -> AsyncOpResult>; + + /// Return a sorted list of all mutual credits + fn list_mutual_credits(&mut self) -> AsyncOpStream; // add_local_currency(currency: Currency); // TODO: Possibly add boolean result here? And to other remove commands? From f00a688fbfac291f316d7b94ba5f2f5eb4e64a14 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 21 Oct 2020 17:29:56 +0300 Subject: [PATCH 116/478] Funder: Middle of some work on token_channel --- components/funder/src/lib.rs | 2 +- components/funder/src/token_channel.rs | 19 ++++++++-- components/funder/src/types.rs | 16 ++++---- components/proto/src/app_server/messages.rs | 18 +++++---- components/proto/src/funder/messages.rs | 38 ++++++------------- components/proto/src/index_client/messages.rs | 9 ++--- components/proto/src/lib.rs | 4 +- components/proto/src/schema/app_server.capnp | 28 +++++++------- components/proto/src/schema/report.capnp | 1 + components/signature/src/canonical.rs | 7 ++-- components/signature/src/signature_buff.rs | 18 ++------- components/signature/src/verify.rs | 15 +------- 12 files changed, 75 insertions(+), 100 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 586817f0c..f9cbafb90 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -28,7 +28,7 @@ mod mutual_credit; // pub mod report; // mod state; // #[allow(unused)] -mod token_channel; +// mod token_channel; // // For testing: diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 0cb06ac78..197ba635a 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -1,19 +1,18 @@ use std::cmp::Ordering; +use std::collections::HashMap as ImHashMap; use std::convert::TryFrom; use derive_more::From; -use paste::paste; - use futures::channel::{mpsc, oneshot}; use futures::SinkExt; +use futures::Stream; use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; use common::conn::BoxFuture; use common::{get_out_type, ops_trait}; use im::hashset::HashSet as ImHashSet; -use std::collections::HashMap as ImHashMap; // use common::ser_utils::ser_map_str_any; @@ -22,7 +21,7 @@ use signature::canonical::CanonicalSerialize; use crypto::hash::sha_512_256; use crypto::identity::compare_public_key; -use proto::crypto::{PublicKey, RandValue, Signature, Uid}; +use proto::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ @@ -84,6 +83,7 @@ pub trait TcTransaction { // get_move_token_in() -> Option; // get_move_token_out() -> Option>; + fn get_move_token_counter(&mut self) -> u128; fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult; /// Return a sorted list of all mutual credits @@ -362,6 +362,14 @@ where } } +async fn hash_token_info( + local_public_key: PublicKey, + remote_public_key: PublicKey, + move_token_counter: u128, + mutual_credit_infos: impl Stream + Unpin, +) -> HashResult { +} + async fn handle_incoming_token_match( tc_transaction: &mut impl TcTransaction, move_token_out: MoveToken, @@ -484,6 +492,9 @@ where } // Create what we expect to be TokenInfo (From the point of view of remote side): + let mutual_credit_infos = tc_transaction.list_mutual_credits(); + while let Some(mutual_credit_info) = mutual_credit_infos.next().await {} + let tc_out_borrow = token_channel.get_outgoing().unwrap(); let mut expected_balances: Vec<_> = tc_out_borrow .mutual_credits diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 6ca350926..997f76035 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -6,15 +6,12 @@ use proto::crypto::{PlainLock, PublicKey, Signature, Uid}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ - CancelSendFundsOp, ChannelerUpdateFriend, Currency, CurrencyOperations, FriendMessage, - FunderIncomingControl, FunderOutgoingControl, MoveToken, PendingTransaction, - RequestSendFundsOp, ResponseSendFundsOp, TokenInfo, UnsignedMoveToken, - UnsignedResponseSendFundsOp, + CancelSendFundsOp, ChannelerUpdateFriend, Currency, FriendMessage, FunderIncomingControl, + FunderOutgoingControl, MoveToken, PendingTransaction, RequestSendFundsOp, ResponseSendFundsOp, + TokenInfo, UnsignedMoveToken, UnsignedResponseSendFundsOp, }; -use signature::signature_buff::{ - create_response_signature_buffer, hash_token_info, move_token_signature_buff, -}; +use signature::signature_buff::{create_response_signature_buffer, move_token_signature_buff}; use identity::IdentityClient; @@ -113,6 +110,8 @@ pub struct MoveTokenHashed { pub new_token: Signature, } +/* +// TODO: Restore: pub fn create_unsigned_move_token( currencies_operations: Vec, relays_diff: Vec>, @@ -128,6 +127,7 @@ pub fn create_unsigned_move_token( info_hash: hash_token_info(token_info), } } +*/ /* pub async fn create_move_token(operations: Vec, @@ -220,7 +220,7 @@ pub enum FunderOutgoing where B: Clone, { - Control(FunderOutgoingControl), + Control(FunderOutgoingControl), Comm(FunderOutgoingComm), } diff --git a/components/proto/src/app_server/messages.rs b/components/proto/src/app_server/messages.rs index fc6a6f5c6..c457aa9e6 100644 --- a/components/proto/src/app_server/messages.rs +++ b/components/proto/src/app_server/messages.rs @@ -2,7 +2,6 @@ use serde::{Deserialize, Serialize}; use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; -use common::mutable_state::MutableState; use common::ser_utils::{ser_b64, ser_string}; use crate::crypto::{InvoiceId, PaymentId, PublicKey, Uid}; @@ -13,12 +12,10 @@ use crate::funder::messages::{ RemoveFriendCurrency, ResetFriendChannel, ResponseClosePayment, SetFriendCurrencyMaxDebt, SetFriendCurrencyRate, SetFriendName, SetFriendRelays, TransactionResult, }; -use crate::index_client::messages::{ - ClientResponseRoutes, IndexClientReport, IndexClientReportMutation, -}; +use crate::index_client::messages::ClientResponseRoutes; use crate::index_server::messages::{NamedIndexServerAddress, RequestRoutes}; use crate::net::messages::NetAddress; -use crate::report::messages::{FunderReport, FunderReportMutation}; +// use crate::report::messages::{FunderReport, FunderReportMutation}; // TODO: Move NamedRelayAddress and RelayAddress to another place in offset-proto? @@ -55,6 +52,7 @@ impl From> for RelayAddress { } */ +/* #[capnp_conv(crate::report_capnp::node_report)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct NodeReport { @@ -68,8 +66,8 @@ pub enum NodeReportMutation { Funder(FunderReportMutation), IndexClient(IndexClientReportMutation), } +*/ -#[capnp_conv(crate::app_server_capnp::report_mutations::opt_app_request_id)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum OptAppRequestId { AppRequestId(Uid), @@ -94,6 +92,7 @@ impl From for Option { } } +/* #[capnp_conv(crate::app_server_capnp::report_mutations)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ReportMutations { @@ -101,17 +100,18 @@ pub struct ReportMutations { pub opt_app_request_id: Option, pub mutations: Vec>, } +*/ #[allow(clippy::large_enum_variant)] #[capnp_conv(crate::app_server_capnp::app_server_to_app)] #[derive(Debug, PartialEq, Eq)] -pub enum AppServerToApp { +pub enum AppServerToApp { /// Funds: TransactionResult(TransactionResult), ResponseClosePayment(ResponseClosePayment), // /// Reports about current state: // Report(NodeReport), - ReportMutations(ReportMutations), + // ReportMutations(ReportMutations), ResponseRoutes(ClientResponseRoutes), } @@ -188,6 +188,7 @@ impl AppToAppServer { // TODO: Move this code to a separate module: +/* #[derive(Debug)] pub struct NodeReportMutateError; @@ -223,6 +224,7 @@ where self.mutate(mutation) } } +*/ #[capnp_conv(crate::app_server_capnp::app_permissions)] #[derive(Arbitrary, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index d806a3d88..3e4b5ee2c 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -22,7 +22,6 @@ use crate::crypto::{ use crate::app_server::messages::{NamedRelayAddress, RelayAddress}; use crate::consts::{MAX_CURRENCY_LEN, MAX_ROUTE_LEN}; use crate::net::messages::NetAddress; -use crate::report::messages::FunderReportMutations; use common::ser_utils::{ser_b64, ser_string, ser_vec_b64}; @@ -180,21 +179,16 @@ impl Into for ResponseSendFundsOp { } /// Balance information for a single currency -#[capnp_conv(crate::report_capnp::balance_info)] #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct BalanceInfo { - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub balance: i128, - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub local_pending_debt: u128, - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub remote_pending_debt: u128, } -#[capnp_conv(crate::report_capnp::currency_balance_info)] #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct CurrencyBalanceInfo { #[serde(with = "ser_string")] @@ -203,7 +197,6 @@ pub struct CurrencyBalanceInfo { } /// Mutual Credit info -#[capnp_conv(crate::report_capnp::mc_info)] #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct McInfo { #[serde(with = "ser_b64")] @@ -215,11 +208,9 @@ pub struct McInfo { /// Token channel counters. /// Both sides agree on these values implicitly. -#[capnp_conv(crate::report_capnp::counters_info)] #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct CountersInfo { pub inconsistency_counter: u64, - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub move_token_counter: u128, } @@ -227,11 +218,13 @@ pub struct CountersInfo { /// Implicit values that both sides agree upon. /// Those values are also signed as part of the prefix hash. /// A hash of this structure is included inside MoveToken. -#[capnp_conv(crate::report_capnp::token_info)] #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct TokenInfo { - pub mc: McInfo, - pub counters: CountersInfo, + pub local_public_key: PublicKey, + pub remote_public_key: PublicKey, + pub balances: Vec, + #[serde(with = "ser_string")] + pub move_token_counter: u128, } #[capnp_conv(crate::funder_capnp::currency_operations)] @@ -830,10 +823,10 @@ pub struct ResponseClosePayment { #[allow(clippy::large_enum_variant)] #[derive(Debug)] -pub enum FunderOutgoingControl { +pub enum FunderOutgoingControl { TransactionResult(TransactionResult), ResponseClosePayment(ResponseClosePayment), - ReportMutations(FunderReportMutations), + // ReportMutations(FunderReportMutations), } impl Currency { @@ -880,8 +873,8 @@ impl BalanceInfo { } } -impl McInfo { - pub fn flip(self) -> McInfo { +impl TokenInfo { + pub fn flip(self) -> TokenInfo { let balances = self .balances .into_iter() @@ -890,20 +883,11 @@ impl McInfo { balance_info: currency_balance_info.balance_info.flip(), }) .collect(); - - McInfo { + TokenInfo { local_public_key: self.remote_public_key, remote_public_key: self.local_public_key, balances, - } - } -} - -impl TokenInfo { - pub fn flip(self) -> TokenInfo { - TokenInfo { - mc: self.mc.flip(), - counters: self.counters, + move_token_counter: self.move_token_counter, } } } diff --git a/components/proto/src/index_client/messages.rs b/components/proto/src/index_client/messages.rs index ca21276cb..027cc6371 100644 --- a/components/proto/src/index_client/messages.rs +++ b/components/proto/src/index_client/messages.rs @@ -27,7 +27,6 @@ pub struct IndexClientState { // IndexClient <--> AppServer communication // --------------------------------------------------- -#[capnp_conv(crate::report_capnp::index_client_report::opt_connected_server)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum OptConnectedServer { PublicKey(PublicKey), @@ -53,7 +52,7 @@ impl From for Option { } } -#[capnp_conv(crate::report_capnp::index_client_report)] +/* #[derive(Debug, Clone, PartialEq, Eq)] /// ISA stands for Index Server Address pub struct IndexClientReport { @@ -63,6 +62,7 @@ pub struct IndexClientReport { #[capnp_conv(with = OptConnectedServer)] pub opt_connected_server: Option, } +*/ #[derive(Debug, Clone, PartialEq, Eq)] pub struct AddIndexServer { @@ -71,7 +71,6 @@ pub struct AddIndexServer { pub name: String, } -#[capnp_conv(crate::report_capnp::index_client_report_mutation::set_connected_server)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum SetConnectedServer { PublicKey(PublicKey), @@ -97,12 +96,10 @@ impl From for Option { } } -#[capnp_conv(crate::report_capnp::index_client_report_mutation)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum IndexClientReportMutation { AddIndexServer(NamedIndexServerAddress), RemoveIndexServer(PublicKey), - #[capnp_conv(with = SetConnectedServer)] SetConnectedServer(Option), } @@ -145,6 +142,7 @@ pub enum AppServerToIndexClient { ApplyMutations(Vec), } +/* // TODO: Move this code somewhere else? impl IndexClientReport where @@ -172,3 +170,4 @@ where } } } +*/ diff --git a/components/proto/src/lib.rs b/components/proto/src/lib.rs index cabaee61c..79035a94a 100644 --- a/components/proto/src/lib.rs +++ b/components/proto/src/lib.rs @@ -26,12 +26,12 @@ pub mod keepalive; pub mod net; pub mod proto_ser; pub mod relay; -pub mod report; +// pub mod report; pub mod secure_channel; pub mod ser_string; pub mod wrapper; -include_schema!(report_capnp, "report_capnp"); +// include_schema!(report_capnp, "report_capnp"); include_schema!(app_server_capnp, "app_server_capnp"); include_schema!(common_capnp, "common_capnp"); include_schema!(dh_capnp, "dh_capnp"); diff --git a/components/proto/src/schema/app_server.capnp b/components/proto/src/schema/app_server.capnp index 59c025b91..3e5ad2fca 100644 --- a/components/proto/src/schema/app_server.capnp +++ b/components/proto/src/schema/app_server.capnp @@ -17,8 +17,8 @@ using import "common.capnp".NetAddress; using import "common.capnp".NamedIndexServerAddress; using import "common.capnp".Currency; -using import "report.capnp".NodeReport; -using import "report.capnp".NodeReportMutation; +# using import "report.capnp".NodeReport; +# using import "report.capnp".NodeReportMutation; using import "index.capnp".RequestRoutes; using import "index.capnp".MultiRoute; @@ -156,16 +156,16 @@ struct AppPermissions { } -struct ReportMutations { - optAppRequestId: union { - appRequestId @0: Uid; - # Mutations were caused by an application request. - empty @1: Void; - # Mutations were caused for some other reason. - } - mutations @2: List(NodeReportMutation); - # A list of mutations -} +# struct ReportMutations { +# optAppRequestId: union { +# appRequestId @0: Uid; +# # Mutations were caused by an application request. +# empty @1: Void; +# # Mutations were caused for some other reason. +# } +# mutations @2: List(NodeReportMutation); +# # A list of mutations +# } struct RequestResult { union { @@ -207,10 +207,10 @@ struct AppServerToApp { # Reports about current state: # report @2: NodeReport; - reportMutations @2: ReportMutations; + # reportMutations @2: ReportMutations; # Routes: - responseRoutes @3: ClientResponseRoutes; + responseRoutes @2: ClientResponseRoutes; } } diff --git a/components/proto/src/schema/report.capnp b/components/proto/src/schema/report.capnp index 5b5973c22..2c3e92638 100644 --- a/components/proto/src/schema/report.capnp +++ b/components/proto/src/schema/report.capnp @@ -39,6 +39,7 @@ struct McInfo { balances @2: List(CurrencyBalanceInfo); } + struct TokenInfo { mc @0: McInfo; counters @1: CountersInfo; diff --git a/components/signature/src/canonical.rs b/components/signature/src/canonical.rs index 4b31bacab..f2eb36f9d 100644 --- a/components/signature/src/canonical.rs +++ b/components/signature/src/canonical.rs @@ -3,9 +3,8 @@ use byteorder::{BigEndian, WriteBytesExt}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ - BalanceInfo, CancelSendFundsOp, CountersInfo, Currency, CurrencyBalanceInfo, - CurrencyOperations, FriendTcOp, FriendsRoute, McInfo, Receipt, RequestSendFundsOp, - ResponseSendFundsOp, TokenInfo, + BalanceInfo, CancelSendFundsOp, Currency, CurrencyBalanceInfo, CurrencyOperations, FriendTcOp, + FriendsRoute, Receipt, RequestSendFundsOp, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -313,6 +312,7 @@ impl CanonicalSerialize for CurrencyBalanceInfo { } } +/* impl CanonicalSerialize for McInfo { fn canonical_serialize(&self) -> Vec { let mut res_bytes = Vec::new(); @@ -340,3 +340,4 @@ impl CanonicalSerialize for TokenInfo { res_bytes } } +*/ diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index 8d59ba637..f21b9a4f5 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -2,16 +2,15 @@ use byteorder::{BigEndian, WriteBytesExt}; use crypto::hash::{self, sha_512_256}; -use proto::crypto::HashResult; +//use proto::crypto::HashResult; use common::int_convert::usize_to_u64; use crate::canonical::CanonicalSerialize; use proto::funder::messages::{ - Currency, PendingTransaction, TokenInfo, UnsignedMoveToken, UnsignedResponseSendFundsOp, + Currency, PendingTransaction, UnsignedMoveToken, UnsignedResponseSendFundsOp, }; use proto::index_server::messages::MutationsUpdate; -use proto::report::messages::MoveTokenHashedReport; pub const FUNDS_RESPONSE_PREFIX: &[u8] = b"FUND_RESPONSE"; pub const FUNDS_CANCEL_PREFIX: &[u8] = b"FUND_CANCEL"; @@ -91,9 +90,11 @@ where } */ +/* pub fn hash_token_info(token_info: &TokenInfo) -> HashResult { sha_512_256(&token_info.canonical_serialize()) } +*/ /* /// Hash operations and local_address: @@ -150,14 +151,3 @@ pub fn create_mutations_update_signature_buff(mutations_update: &MutationsUpdate res_bytes } - -pub fn move_token_hashed_report_signature_buff( - move_token_hashed_report: &MoveTokenHashedReport, -) -> Vec { - let mut sig_buffer = Vec::new(); - sig_buffer.extend_from_slice(&sha_512_256(TOKEN_NEXT)); - sig_buffer.extend_from_slice(&move_token_hashed_report.prefix_hash); - sig_buffer.extend_from_slice(&hash_token_info(&move_token_hashed_report.token_info)); - sig_buffer.extend_from_slice(&move_token_hashed_report.rand_nonce); - sig_buffer -} diff --git a/components/signature/src/verify.rs b/components/signature/src/verify.rs index 1813ecf5a..0460d2602 100644 --- a/components/signature/src/verify.rs +++ b/components/signature/src/verify.rs @@ -8,12 +8,10 @@ use proto::crypto::PublicKey; use proto::funder::messages::{Commit, MoveToken, Receipt}; use proto::index_server::messages::MutationsUpdate; -use proto::report::messages::MoveTokenHashedReport; use crate::canonical::CanonicalSerialize; use crate::signature_buff::{ - create_mutations_update_signature_buff, move_token_hashed_report_signature_buff, - move_token_signature_buff, FUNDS_RESPONSE_PREFIX, + create_mutations_update_signature_buff, move_token_signature_buff, FUNDS_RESPONSE_PREFIX, }; // TODO: Add a local test that makes sure verify_receipt is in sync with verify_commit_signature @@ -83,14 +81,3 @@ pub fn verify_mutations_update(mutations_update: &MutationsUpdate) -> bool { &mutations_update.signature, ) } - -// TODO: Is the public_key argument redundant now? (As it should be exactly the same -// as move_token_hashed_report.local_public_key) -/// Verify that new_token is a valid signature over the rest of the fields. -pub fn verify_move_token_hashed_report( - move_token_hashed_report: &MoveTokenHashedReport, - public_key: &PublicKey, -) -> bool { - let sig_buffer = move_token_hashed_report_signature_buff(move_token_hashed_report); - verify_signature(&sig_buffer, public_key, &move_token_hashed_report.new_token) -} From a57a5f225cc6d28077443124aa5a59d307975fb8 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 21 Oct 2020 17:31:01 +0300 Subject: [PATCH 117/478] funder: Renamed function --- components/funder/src/token_channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 197ba635a..e16364310 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -362,7 +362,7 @@ where } } -async fn hash_token_info( +async fn hash_token_info_stream( local_public_key: PublicKey, remote_public_key: PublicKey, move_token_counter: u128, From 6b890bf8182e6c7ea474b960fd7d4bb342f9230b Mon Sep 17 00:00:00 2001 From: real Date: Wed, 21 Oct 2020 17:32:49 +0300 Subject: [PATCH 118/478] crypto: Renamed function --- components/crypto/src/hash.rs | 4 ++-- components/crypto/src/identity.rs | 4 ++-- components/index_server/src/verifier/hash_clock.rs | 8 ++++---- components/signature/src/signature_buff.rs | 10 +++++----- components/signature/src/verify.rs | 4 ++-- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/components/crypto/src/hash.rs b/components/crypto/src/hash.rs index 19959e7ca..5ca4eb15c 100644 --- a/components/crypto/src/hash.rs +++ b/components/crypto/src/hash.rs @@ -3,7 +3,7 @@ use sha2::{Digest, Sha512Trunc256}; // TODO: Possibly choose a more generic name, to allow changes in the future? /// Calculate SHA512/256 over the given data. -pub fn sha_512_256(data: &[u8]) -> HashResult { +pub fn hash_buffer(data: &[u8]) -> HashResult { let mut hasher = Sha512Trunc256::new(); hasher.update(data); let digest_res = hasher.finalize(); @@ -22,7 +22,7 @@ mod tests { fn hash_basic() { let data = b"This is a test!"; - let hash_res = sha_512_256(&data[..]); + let hash_res = hash_buffer(&data[..]); let expected = [ 0x34, 0x9c, 0x7e, 0xa7, 0x49, 0x8d, 0x04, 0x32, 0xdc, 0xb0, 0x60, 0x4a, 0x9e, 0xd3, diff --git a/components/crypto/src/identity.rs b/components/crypto/src/identity.rs index 9a70e0bc9..8dad8d0d9 100644 --- a/components/crypto/src/identity.rs +++ b/components/crypto/src/identity.rs @@ -3,13 +3,13 @@ use std::cmp::Ordering; use proto::crypto::{PrivateKey, PublicKey, Signature}; use crate::error::CryptoError; -use crate::hash::sha_512_256; +use crate::hash::hash_buffer; use crate::rand::{CryptoRandom, RandGen}; /// Check if one public key is "lower" than another. /// This is used to decide which side begins the token channel. pub fn compare_public_key(pk1: &PublicKey, pk2: &PublicKey) -> Ordering { - sha_512_256(pk1).cmp(&sha_512_256(pk2)) + hash_buffer(pk1).cmp(&hash_buffer(pk2)) } impl RandGen for PrivateKey { diff --git a/components/index_server/src/verifier/hash_clock.rs b/components/index_server/src/verifier/hash_clock.rs index 8eab7da91..3142e13c0 100644 --- a/components/index_server/src/verifier/hash_clock.rs +++ b/components/index_server/src/verifier/hash_clock.rs @@ -1,4 +1,4 @@ -use crypto::hash::sha_512_256; +use crypto::hash::hash_buffer; use proto::crypto::{HashResult, RandValue}; use std::collections::{HashMap, VecDeque}; @@ -20,14 +20,14 @@ fn hash_hashes(hashes: &[HashResult]) -> HashResult { let mut bytes_to_hash = Vec::new(); // Start with a constant prefix: - bytes_to_hash.extend_from_slice(&sha_512_256(HASH_CLOCK_PREFIX)); + bytes_to_hash.extend_from_slice(&hash_buffer(HASH_CLOCK_PREFIX)); // Append prefixes: for hash in hashes { bytes_to_hash.extend_from_slice(hash); } - sha_512_256(&bytes_to_hash) + hash_buffer(&bytes_to_hash) } impl HashClock @@ -74,7 +74,7 @@ where pub fn tick(&mut self, rand_value: RandValue) -> HashResult { let mut expansion = Vec::new(); - let hashed_rand_value = sha_512_256(&rand_value); + let hashed_rand_value = hash_buffer(&rand_value); expansion.push(hashed_rand_value); // Concatenate all hashes, and update hash_info accordingly: diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index f21b9a4f5..f45af4c70 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, WriteBytesExt}; -use crypto::hash::{self, sha_512_256}; +use crypto::hash::{self, hash_buffer}; //use proto::crypto::HashResult; @@ -40,7 +40,7 @@ where let response_send_funds: UnsignedResponseSendFundsOp = response_send_funds.into(); let mut sbuffer = Vec::new(); - sbuffer.extend_from_slice(&hash::sha_512_256(FUNDS_RESPONSE_PREFIX)); + sbuffer.extend_from_slice(&hash::hash_buffer(FUNDS_RESPONSE_PREFIX)); let mut inner_blob = Vec::new(); inner_blob.extend_from_slice(&pending_transaction.request_id); @@ -50,7 +50,7 @@ where .write_u128::(pending_transaction.dest_payment) .unwrap(); - sbuffer.extend_from_slice(&hash::sha_512_256(&inner_blob)); + sbuffer.extend_from_slice(&hash::hash_buffer(&inner_blob)); sbuffer .write_u128::(response_send_funds.serial_num) .unwrap(); @@ -122,7 +122,7 @@ where { let move_token: UnsignedMoveToken = move_token.into(); let mut sig_buffer = Vec::new(); - sig_buffer.extend_from_slice(&sha_512_256(TOKEN_NEXT)); + sig_buffer.extend_from_slice(&hash_buffer(TOKEN_NEXT)); sig_buffer.extend_from_slice(&move_token.old_token); sig_buffer.extend_from_slice(&move_token.info_hash); sig_buffer @@ -132,7 +132,7 @@ pub const MUTATIONS_UPDATE_PREFIX: &[u8] = b"MUTATIONS_UPDATE"; pub fn create_mutations_update_signature_buff(mutations_update: &MutationsUpdate) -> Vec { let mut res_bytes = Vec::new(); - res_bytes.extend_from_slice(&hash::sha_512_256(MUTATIONS_UPDATE_PREFIX)); + res_bytes.extend_from_slice(&hash::hash_buffer(MUTATIONS_UPDATE_PREFIX)); res_bytes.extend_from_slice(&mutations_update.node_public_key); res_bytes diff --git a/components/signature/src/verify.rs b/components/signature/src/verify.rs index 0460d2602..c4e2c1177 100644 --- a/components/signature/src/verify.rs +++ b/components/signature/src/verify.rs @@ -19,7 +19,7 @@ use crate::signature_buff::{ pub fn verify_receipt(receipt: &Receipt, public_key: &PublicKey) -> bool { let mut data = Vec::new(); - data.extend_from_slice(&hash::sha_512_256(FUNDS_RESPONSE_PREFIX)); + data.extend_from_slice(&hash::hash_buffer(FUNDS_RESPONSE_PREFIX)); data.extend(receipt.response_hash.as_ref()); data.extend_from_slice(&receipt.src_plain_lock.hash_lock()); data.extend_from_slice(&receipt.dest_plain_lock.hash_lock()); @@ -36,7 +36,7 @@ pub fn verify_receipt(receipt: &Receipt, public_key: &PublicKey) -> bool { fn verify_commit_signature(commit: &Commit, local_public_key: &PublicKey) -> bool { let mut data = Vec::new(); - data.extend_from_slice(&hash::sha_512_256(FUNDS_RESPONSE_PREFIX)); + data.extend_from_slice(&hash::hash_buffer(FUNDS_RESPONSE_PREFIX)); data.extend(commit.response_hash.as_ref()); data.extend_from_slice(&commit.src_plain_lock.hash_lock()); data.extend_from_slice(&commit.dest_hashed_lock); From 917f5762528eeb4e838b0e9f11258e52773e8e02 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 21 Oct 2020 17:44:03 +0300 Subject: [PATCH 119/478] crypto: Hasher interface --- components/crypto/src/hash.rs | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/components/crypto/src/hash.rs b/components/crypto/src/hash.rs index 5ca4eb15c..10bbf9cf5 100644 --- a/components/crypto/src/hash.rs +++ b/components/crypto/src/hash.rs @@ -1,17 +1,36 @@ use proto::crypto::HashResult; use sha2::{Digest, Sha512Trunc256}; +pub struct Hasher { + inner: Sha512Trunc256, +} + +impl Hasher { + pub fn new() -> Self { + Self { + inner: Sha512Trunc256::new(), + } + } + pub fn update(&mut self, data: &[u8]) -> &mut Self { + self.inner.update(data); + self + } + + pub fn finalize(&self) -> HashResult { + let digest_res = self.inner.clone().finalize(); + + let mut inner = [0x00; HashResult::len()]; + inner.copy_from_slice(digest_res.as_ref()); + + HashResult::from(&inner) + } +} + +// TODO: Possibly remove from interface in the future, use Hasher instead. // TODO: Possibly choose a more generic name, to allow changes in the future? /// Calculate SHA512/256 over the given data. pub fn hash_buffer(data: &[u8]) -> HashResult { - let mut hasher = Sha512Trunc256::new(); - hasher.update(data); - let digest_res = hasher.finalize(); - - let mut inner = [0x00; HashResult::len()]; - inner.copy_from_slice(digest_res.as_ref()); - - HashResult::from(&inner) + Hasher::new().update(data).finalize() } #[cfg(test)] From bc37240fea3ba0ea90dd4aa70be35d6213a4694a Mon Sep 17 00:00:00 2001 From: real Date: Wed, 21 Oct 2020 17:47:26 +0300 Subject: [PATCH 120/478] crypto: hash: Added chain method to Hasher --- components/crypto/src/hash.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/crypto/src/hash.rs b/components/crypto/src/hash.rs index 10bbf9cf5..dd5d96418 100644 --- a/components/crypto/src/hash.rs +++ b/components/crypto/src/hash.rs @@ -11,12 +11,17 @@ impl Hasher { inner: Sha512Trunc256::new(), } } - pub fn update(&mut self, data: &[u8]) -> &mut Self { + + pub fn update(&mut self, data: &[u8]) { + self.inner.update(data); + } + + pub fn chain(mut self, data: &[u8]) -> Self { self.inner.update(data); self } - pub fn finalize(&self) -> HashResult { + pub fn finalize(self) -> HashResult { let digest_res = self.inner.clone().finalize(); let mut inner = [0x00; HashResult::len()]; @@ -30,7 +35,7 @@ impl Hasher { // TODO: Possibly choose a more generic name, to allow changes in the future? /// Calculate SHA512/256 over the given data. pub fn hash_buffer(data: &[u8]) -> HashResult { - Hasher::new().update(data).finalize() + Hasher::new().chain(data).finalize() } #[cfg(test)] From ea051ac614eee2f5f124fd8e7ea30a8aa7e19bde Mon Sep 17 00:00:00 2001 From: real Date: Wed, 21 Oct 2020 19:47:04 +0300 Subject: [PATCH 121/478] funder: Some work on TokenInfo. Not final --- components/funder/src/token_channel.rs | 34 ++++++++++++++--- components/funder/src/types.rs | 2 +- components/proto/src/funder/messages.rs | 49 +++++++++++-------------- components/signature/src/canonical.rs | 6 ++- 4 files changed, 56 insertions(+), 35 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index e16364310..cacd2dee8 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -18,7 +18,7 @@ use im::hashset::HashSet as ImHashSet; use signature::canonical::CanonicalSerialize; -use crypto::hash::sha_512_256; +use crypto::hash::Hasher; use crypto::identity::compare_public_key; use proto::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; @@ -250,7 +250,7 @@ fn token_from_public_key(public_key: &PublicKey) -> Signature { /// Note that the result here is not really a random nonce. This function is used for the first /// deterministic initialization of a token channel. fn rand_nonce_from_public_key(public_key: &PublicKey) -> RandValue { - let public_key_hash = sha_512_256(public_key); + let public_key_hash = Hasher::new().chain(public_key).finalize(); RandValue::try_from(&public_key_hash.as_ref()[..RandValue::len()]).unwrap() } @@ -362,12 +362,28 @@ where } } -async fn hash_token_info_stream( +async fn hash_mutual_credit_infos( + mutual_credit_infos: impl Stream>, +) -> Result { + let hasher = Hasher::new(); + while let Some(mutual_credit_info) = mutual_credit_infos.next().await? { + hasher.update(mutual_credit_info.canonical_serialize()); + } + Ok(hasher.finalize()) +} + +fn hash_token_info_stream( local_public_key: PublicKey, remote_public_key: PublicKey, move_token_counter: u128, - mutual_credit_infos: impl Stream + Unpin, + mutual_credit_infos_hash: HashResult, ) -> HashResult { + Hahser::new() + .chain(local_public_key) + .chain(remote_public_key) + .chain(move_token_counter.canonical_serialize()) + .chain(mutual_credits_infos_hash) + .finalize() } async fn handle_incoming_token_match( @@ -546,7 +562,15 @@ where .flip(); // Verify stated balances: - let info_hash = hash_token_info(&expected_token_info); + let mutual_credit_infos_hash = hash_mutual_credit_infos(mutual_credit_infos).await?; + + let info_hash = hash_token_info_stream( + local_public_key, + remote_public_key, + move_token_counter, + mutual_credit_infos_hash, + ); + if new_move_token.info_hash != info_hash { return Err(ReceiveMoveTokenError::InvalidTokenInfo); } diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 997f76035..066ea9983 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -111,7 +111,7 @@ pub struct MoveTokenHashed { } /* -// TODO: Restore: +// TODO: Restore later: pub fn create_unsigned_move_token( currencies_operations: Vec, relays_diff: Vec>, diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 3e4b5ee2c..5cefb7895 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -5,6 +5,8 @@ use std::fmt; use std::hash::Hash; use std::str::FromStr; +use std::collections::HashMap; + use serde::de::{self, Visitor}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -178,41 +180,18 @@ impl Into for ResponseSendFundsOp { } } -/// Balance information for a single currency #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct BalanceInfo { +pub struct MutualCreditInfo { #[serde(with = "ser_string")] pub balance: i128, #[serde(with = "ser_string")] pub local_pending_debt: u128, #[serde(with = "ser_string")] pub remote_pending_debt: u128, -} - -#[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct CurrencyBalanceInfo { #[serde(with = "ser_string")] - pub currency: Currency, - pub balance_info: BalanceInfo, -} - -/// Mutual Credit info -#[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct McInfo { - #[serde(with = "ser_b64")] - pub local_public_key: PublicKey, - #[serde(with = "ser_b64")] - pub remote_public_key: PublicKey, - pub balances: Vec, -} - -/// Token channel counters. -/// Both sides agree on these values implicitly. -#[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct CountersInfo { - pub inconsistency_counter: u64, + pub in_fees: u128, #[serde(with = "ser_string")] - pub move_token_counter: u128, + pub out_fees: u128, } /// Implicit values that both sides agree upon. @@ -222,7 +201,7 @@ pub struct CountersInfo { pub struct TokenInfo { pub local_public_key: PublicKey, pub remote_public_key: PublicKey, - pub balances: Vec, + pub balances: HashMap, #[serde(with = "ser_string")] pub move_token_counter: u128, } @@ -863,6 +842,7 @@ impl FromStr for Currency { } } +/* impl BalanceInfo { fn flip(self) -> BalanceInfo { BalanceInfo { @@ -872,7 +852,21 @@ impl BalanceInfo { } } } +*/ + +impl MutualCreditInfo { + pub fn flip(self) -> MutualCreditInfo { + Self { + balance: self.balance.checked_neg().unwrap(), + local_pending_debt: self.remote_pending_debt, + remote_pending_debt: self.local_pending_debt, + in_fees: self.out_fees, + out_fees: self.in_fees, + } + } +} +/* impl TokenInfo { pub fn flip(self) -> TokenInfo { let balances = self @@ -891,6 +885,7 @@ impl TokenInfo { } } } +*/ #[cfg(test)] mod tests { diff --git a/components/signature/src/canonical.rs b/components/signature/src/canonical.rs index f2eb36f9d..42411b268 100644 --- a/components/signature/src/canonical.rs +++ b/components/signature/src/canonical.rs @@ -3,8 +3,8 @@ use byteorder::{BigEndian, WriteBytesExt}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ - BalanceInfo, CancelSendFundsOp, Currency, CurrencyBalanceInfo, CurrencyOperations, FriendTcOp, - FriendsRoute, Receipt, RequestSendFundsOp, ResponseSendFundsOp, + CancelSendFundsOp, Currency, CurrencyOperations, FriendTcOp, FriendsRoute, Receipt, + RequestSendFundsOp, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -293,6 +293,7 @@ impl CanonicalSerialize for IndexMutation { } } +/* impl CanonicalSerialize for BalanceInfo { fn canonical_serialize(&self) -> Vec { let mut res_bytes = Vec::new(); @@ -311,6 +312,7 @@ impl CanonicalSerialize for CurrencyBalanceInfo { res_bytes } } +*/ /* impl CanonicalSerialize for McInfo { From ef21ac8b10f14a616e54e2b8ab31a60424a71c0c Mon Sep 17 00:00:00 2001 From: real Date: Wed, 21 Oct 2020 20:02:35 +0300 Subject: [PATCH 122/478] funder: Initial addition of in_fees and out_fees. Currencly u128 --- components/funder/src/mutual_credit/incoming.rs | 10 ++++++++++ components/funder/src/mutual_credit/outgoing.rs | 10 ++++++++++ .../tests/request_cancel_send_funds.rs | 4 ++++ .../tests/request_response_send_funds.rs | 4 ++++ components/funder/src/mutual_credit/tests/utils.rs | 13 +++++++++++-- components/funder/src/mutual_credit/types.rs | 10 ++++++++++ 6 files changed, 49 insertions(+), 2 deletions(-) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 91412f9df..bb3c3468a 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -247,6 +247,16 @@ async fn process_response_send_funds( .set_local_pending_debt(new_local_pending_debt) .await?; + // Update out_fees: + mc_transaction + .set_out_fees( + mc_balance + .out_fees + .checked_add(pending_transaction.left_fees) + .unwrap(), + ) + .await?; + // Decrease balance: let mc_balance = mc_transaction.get_balance().await?; let new_balance = mc_balance diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 9edbecb0f..400869c3c 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -174,6 +174,16 @@ async fn queue_response_send_funds( .set_remote_pending_debt(new_remote_pending_debt) .await?; + // Update in_fees: + mc_transaction + .set_in_fees( + mc_balance + .in_fees + .checked_add(pending_transaction.left_fees) + .unwrap(), + ) + .await?; + // Increase balance: let mc_balance = mc_transaction.get_balance().await?; let new_balance = mc_balance diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index ac37caf33..aac351241 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -70,6 +70,8 @@ async fn task_request_cancel_send_funds() { assert_eq!(mc_balance.balance, 0); assert_eq!(mc_balance.local_pending_debt, 10 + 5); assert_eq!(mc_balance.remote_pending_debt, 0); + assert_eq!(mc_balance.in_fees, 0); + assert_eq!(mc_balance.out_fees, 0); // -----[CancelSendFunds]-------- // ------------------------------ @@ -89,6 +91,8 @@ async fn task_request_cancel_send_funds() { assert_eq!(mc_balance.balance, 0); assert_eq!(mc_balance.local_pending_debt, 0); assert_eq!(mc_balance.remote_pending_debt, 0); + assert_eq!(mc_balance.in_fees, 0); + assert_eq!(mc_balance.out_fees, 0); } #[test] diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index 572c008bf..c39707b69 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -73,6 +73,8 @@ async fn task_request_response_send_funds() { assert_eq!(mc_balance.balance, 0); assert_eq!(mc_balance.local_pending_debt, 10 + 5); assert_eq!(mc_balance.remote_pending_debt, 0); + assert_eq!(mc_balance.in_fees, 0); + assert_eq!(mc_balance.out_fees, 0); // -----[ResponseSendFunds]-------- // -------------------------------- @@ -107,6 +109,8 @@ async fn task_request_response_send_funds() { assert_eq!(mc_balance.balance, -15); assert_eq!(mc_balance.local_pending_debt, 0); assert_eq!(mc_balance.remote_pending_debt, 0); + assert_eq!(mc_balance.in_fees, 0); + assert_eq!(mc_balance.out_fees, 5); } #[test] diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index 98e9d52fc..bb73e4402 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -1,7 +1,6 @@ -use std::collections::HashMap; - use common::async_rpc::OpError; use common::conn::BoxFuture; +use std::collections::HashMap; use proto::crypto::Uid; use proto::funder::messages::{Currency, PendingTransaction}; @@ -70,6 +69,16 @@ impl McTransaction for MutualCredit { Box::pin(async move { Ok(()) }) } + fn set_in_fees(&mut self, in_fees: u128) -> BoxFuture<'static, Result<(), OpError>> { + self.balance.in_fees = in_fees; + Box::pin(async move { Ok(()) }) + } + + fn set_out_fees(&mut self, out_fees: u128) -> BoxFuture<'static, Result<(), OpError>> { + self.balance.out_fees = out_fees; + Box::pin(async move { Ok(()) }) + } + fn get_local_pending_transaction( &mut self, request_id: Uid, diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index bf4e88474..28a4af7ac 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -18,6 +18,12 @@ pub struct McBalance { /// Frozen credits by the remote side #[serde(with = "ser_string")] pub remote_pending_debt: u128, + /// Fees that were received from remote side + #[serde(with = "ser_string")] + pub in_fees: u128, + /// Fees that were given to remote side + #[serde(with = "ser_string")] + pub out_fees: u128, } impl McBalance { @@ -28,6 +34,8 @@ impl McBalance { balance, local_pending_debt: 0, remote_pending_debt: 0, + in_fees: 0, + out_fees: 0, } } } @@ -37,6 +45,8 @@ pub trait McTransaction { fn set_balance(&mut self, new_balance: i128) -> AsyncOpResult<()>; fn set_local_pending_debt(&mut self, debt: u128) -> AsyncOpResult<()>; fn set_remote_pending_debt(&mut self, debt: u128) -> AsyncOpResult<()>; + fn set_in_fees(&mut self, in_fees: u128) -> AsyncOpResult<()>; + fn set_out_fees(&mut self, out_fees: u128) -> AsyncOpResult<()>; fn get_local_pending_transaction( &mut self, request_id: Uid, From 972fab571517fa17df620f4339613cfe36dea124 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 21 Oct 2020 20:06:47 +0300 Subject: [PATCH 123/478] funder: todo comment --- components/funder/src/mutual_credit/types.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 28a4af7ac..7e0b129d1 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -18,6 +18,7 @@ pub struct McBalance { /// Frozen credits by the remote side #[serde(with = "ser_string")] pub remote_pending_debt: u128, + // TODO: in_fees and out_fees should be u256, not u128! /// Fees that were received from remote side #[serde(with = "ser_string")] pub in_fees: u128, From 9ccd5aa826274fcb376156699040aed3e6d52e52 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 23 Oct 2020 13:40:16 +0300 Subject: [PATCH 124/478] common: Added U256 type --- Cargo.lock | 31 +++++++++++++++++++++++++++++++ components/common/Cargo.toml | 1 + components/common/src/lib.rs | 1 + components/common/src/u256.rs | 22 ++++++++++++++++++++++ 4 files changed, 55 insertions(+) create mode 100644 components/common/src/u256.rs diff --git a/Cargo.lock b/Cargo.lock index 2ad01c2a7..f885fad9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -348,6 +348,11 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "crypto-mac" version = "0.8.0" @@ -986,6 +991,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "paste 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", + "uint 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1716,6 +1722,11 @@ name = "rustc-demangle" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc_version" version = "0.2.3" @@ -1869,6 +1880,11 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "stream-cipher" version = "0.4.1" @@ -2029,6 +2045,17 @@ name = "typenum" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "uint" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-segmentation" version = "1.6.0" @@ -2264,6 +2291,7 @@ dependencies = [ "checksum concurrent-queue 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f83c06aff61f2d899eb87c379df3cbf7876f14471dcab474e0b6dc90ab96c080" "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +"checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" "checksum crypto-mac 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" "checksum crypto-mac 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58bcd97a54c7ca5ce2f6eb16f6bede5b0ab5f0055fedc17d2f0b4466e21671ca" "checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" @@ -2367,6 +2395,7 @@ dependencies = [ "checksum rusqlite 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)" = "45d0fd62e1df63d254714e6cb40d0a0e82e7a1623e7a27f679d851af092ae58b" "checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +"checksum rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" "checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" @@ -2385,6 +2414,7 @@ dependencies = [ "checksum smallvec 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f" "checksum smol 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "620cbb3c6e34da57d3a248cda0cd01cd5848164dc062e764e65d06fe3ea7aed5" "checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +"checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" "checksum stream-cipher 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09f8ed9974042b8c3672ff3030a69fcc03b74c47c3d1ecb7755e8a3626011e88" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" @@ -2403,6 +2433,7 @@ dependencies = [ "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" "checksum typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +"checksum uint 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9db035e67dfaf7edd9aebfe8676afcd63eed53c8a4044fed514c8cccf1835177" "checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/components/common/Cargo.toml b/components/common/Cargo.toml index 3e6d2dc26..f42f32803 100644 --- a/components/common/Cargo.toml +++ b/components/common/Cargo.toml @@ -16,6 +16,7 @@ byteorder = "1.1" backtrace = "0.3.14" base64 = "0.10.1" +uint = "0.8.5" [dev-dependencies] diff --git a/components/common/src/lib.rs b/components/common/src/lib.rs index e27693593..cb3b8d8f0 100644 --- a/components/common/src/lib.rs +++ b/components/common/src/lib.rs @@ -18,6 +18,7 @@ pub mod async_rpc; pub mod int_convert; pub mod never; pub mod safe_arithmetic; +pub mod u256; // TODO: Big array might not be needed: #[macro_use] diff --git a/components/common/src/u256.rs b/components/common/src/u256.rs new file mode 100644 index 000000000..e8fb99df2 --- /dev/null +++ b/components/common/src/u256.rs @@ -0,0 +1,22 @@ +use uint::construct_uint; + +construct_uint! { + /// A 256 bit unsigned int + pub struct U256(4); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_u256_basic() { + let mut num = U256::from(1); + for _ in 0..255 { + num <<= 1; + assert!(!num.is_zero()); + } + num <<= 1; + assert!(num.is_zero()); + } +} From 535f0eb7a35b29a04957704c53774203c290cb28 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 23 Oct 2020 13:56:03 +0300 Subject: [PATCH 125/478] Bumped rust version to 1.47.0 stable --- components/app/src/lib.rs | 2 +- components/app_client/src/lib.rs | 2 +- components/app_server/src/lib.rs | 2 +- components/bin/src/bin/stindex.rs | 2 +- components/bin/src/bin/stmgr.rs | 2 +- components/bin/src/bin/stnode.rs | 2 +- components/bin/src/bin/strelay.rs | 2 +- components/bin/src/lib.rs | 2 +- components/capnp_conv/capnp_conv_derive/src/lib.rs | 2 +- components/capnp_conv/src/lib.rs | 2 +- components/channeler/src/lib.rs | 2 +- components/common/src/lib.rs | 2 +- components/connection/src/lib.rs | 2 +- components/crypto/src/lib.rs | 2 +- components/database/src/lib.rs | 2 +- components/funder/src/lib.rs | 2 +- components/identity/src/lib.rs | 2 +- components/index_client/src/lib.rs | 2 +- components/index_server/src/lib.rs | 2 +- components/keepalive/src/lib.rs | 2 +- components/lockfile/src/lib.rs | 2 +- components/mutual_from/src/lib.rs | 2 +- components/net/src/lib.rs | 2 +- components/node/src/lib.rs | 2 +- components/proto/src/lib.rs | 2 +- components/relay/src/lib.rs | 2 +- components/route/src/lib.rs | 2 +- components/secure_channel/src/lib.rs | 2 +- components/signature/src/lib.rs | 2 +- components/stcompact/src/bin/stcompact.rs | 2 +- components/stcompact/src/bin/stcompact_ser_gen.rs | 2 +- components/stcompact/src/lib.rs | 2 +- components/stctrl/src/bin/stctrl.rs | 2 +- components/stctrl/src/bin/stverify.rs | 2 +- components/stctrl/src/lib.rs | 2 +- components/timer/src/lib.rs | 2 +- components/timer/src/timer.rs | 2 +- components/version/src/lib.rs | 2 +- rust-toolchain | 2 +- 39 files changed, 39 insertions(+), 39 deletions(-) diff --git a/components/app/src/lib.rs b/components/app/src/lib.rs index d03f3371e..158c33644 100644 --- a/components/app/src/lib.rs +++ b/components/app/src/lib.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/app_client/src/lib.rs b/components/app_client/src/lib.rs index 0769f92f6..af409f409 100644 --- a/components/app_client/src/lib.rs +++ b/components/app_client/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/app_server/src/lib.rs b/components/app_server/src/lib.rs index 11f757760..4768309a6 100644 --- a/components/app_server/src/lib.rs +++ b/components/app_server/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/bin/src/bin/stindex.rs b/components/bin/src/bin/stindex.rs index 24405a0a0..1346c03d0 100644 --- a/components/bin/src/bin/stindex.rs +++ b/components/bin/src/bin/stindex.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/bin/src/bin/stmgr.rs b/components/bin/src/bin/stmgr.rs index bcf19d3fb..ee5dc70b4 100644 --- a/components/bin/src/bin/stmgr.rs +++ b/components/bin/src/bin/stmgr.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/bin/src/bin/stnode.rs b/components/bin/src/bin/stnode.rs index 50d830444..5ba772e60 100644 --- a/components/bin/src/bin/stnode.rs +++ b/components/bin/src/bin/stnode.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/bin/src/bin/strelay.rs b/components/bin/src/bin/strelay.rs index 2d2e5fd6a..86d63eec1 100644 --- a/components/bin/src/bin/strelay.rs +++ b/components/bin/src/bin/strelay.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/bin/src/lib.rs b/components/bin/src/lib.rs index 3bf207a93..27e9d4b18 100644 --- a/components/bin/src/lib.rs +++ b/components/bin/src/lib.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/capnp_conv/capnp_conv_derive/src/lib.rs b/components/capnp_conv/capnp_conv_derive/src/lib.rs index 713fdfc28..947f1b19c 100644 --- a/components/capnp_conv/capnp_conv_derive/src/lib.rs +++ b/components/capnp_conv/capnp_conv_derive/src/lib.rs @@ -1,7 +1,7 @@ #![crate_type = "lib"] #![recursion_limit = "128"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/capnp_conv/src/lib.rs b/components/capnp_conv/src/lib.rs index 61e8a952e..29097e839 100644 --- a/components/capnp_conv/src/lib.rs +++ b/components/capnp_conv/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/channeler/src/lib.rs b/components/channeler/src/lib.rs index c786b5976..6570fc35a 100644 --- a/components/channeler/src/lib.rs +++ b/components/channeler/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/common/src/lib.rs b/components/common/src/lib.rs index cb3b8d8f0..412ffb5cb 100644 --- a/components/common/src/lib.rs +++ b/components/common/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/connection/src/lib.rs b/components/connection/src/lib.rs index a37dd011a..5c7f8f2cf 100644 --- a/components/connection/src/lib.rs +++ b/components/connection/src/lib.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/crypto/src/lib.rs b/components/crypto/src/lib.rs index 3d2296ccd..900bb8094 100644 --- a/components/crypto/src/lib.rs +++ b/components/crypto/src/lib.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/database/src/lib.rs b/components/database/src/lib.rs index 2fc90d7e6..fcc25a0e2 100644 --- a/components/database/src/lib.rs +++ b/components/database/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index f9cbafb90..bdf1d22b3 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -1,7 +1,7 @@ #![crate_type = "lib"] #![cfg_attr(not(feature = "cargo-clippy"), allow(unknown_lints))] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/identity/src/lib.rs b/components/identity/src/lib.rs index f70d9c48a..2e5babe7d 100644 --- a/components/identity/src/lib.rs +++ b/components/identity/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/index_client/src/lib.rs b/components/index_client/src/lib.rs index 6d76a50f9..432cfcba6 100644 --- a/components/index_client/src/lib.rs +++ b/components/index_client/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/index_server/src/lib.rs b/components/index_server/src/lib.rs index 7647fd9d1..d072faf79 100644 --- a/components/index_server/src/lib.rs +++ b/components/index_server/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/keepalive/src/lib.rs b/components/keepalive/src/lib.rs index bcb6a952b..007d0c990 100644 --- a/components/keepalive/src/lib.rs +++ b/components/keepalive/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/lockfile/src/lib.rs b/components/lockfile/src/lib.rs index 3344df437..02c0aa908 100644 --- a/components/lockfile/src/lib.rs +++ b/components/lockfile/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/mutual_from/src/lib.rs b/components/mutual_from/src/lib.rs index 867334393..897569288 100644 --- a/components/mutual_from/src/lib.rs +++ b/components/mutual_from/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/net/src/lib.rs b/components/net/src/lib.rs index 3a60c07b5..619469ad6 100644 --- a/components/net/src/lib.rs +++ b/components/net/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/node/src/lib.rs b/components/node/src/lib.rs index 3a338c594..839cab6f0 100644 --- a/components/node/src/lib.rs +++ b/components/node/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/proto/src/lib.rs b/components/proto/src/lib.rs index 79035a94a..fa54f7af0 100644 --- a/components/proto/src/lib.rs +++ b/components/proto/src/lib.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/relay/src/lib.rs b/components/relay/src/lib.rs index 8880fb871..9d05a702e 100644 --- a/components/relay/src/lib.rs +++ b/components/relay/src/lib.rs @@ -1,7 +1,7 @@ #![crate_type = "lib"] #![type_length_limit = "291239"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/route/src/lib.rs b/components/route/src/lib.rs index 742bc0dc3..35e7c1529 100644 --- a/components/route/src/lib.rs +++ b/components/route/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/secure_channel/src/lib.rs b/components/secure_channel/src/lib.rs index bc5894cca..c14c82b38 100644 --- a/components/secure_channel/src/lib.rs +++ b/components/secure_channel/src/lib.rs @@ -1,7 +1,7 @@ #![crate_type = "lib"] #![type_length_limit = "2097152"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/signature/src/lib.rs b/components/signature/src/lib.rs index d1e16af75..97febad19 100644 --- a/components/signature/src/lib.rs +++ b/components/signature/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/stcompact/src/bin/stcompact.rs b/components/stcompact/src/bin/stcompact.rs index 08e8ca738..508fa2231 100644 --- a/components/stcompact/src/bin/stcompact.rs +++ b/components/stcompact/src/bin/stcompact.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/stcompact/src/bin/stcompact_ser_gen.rs b/components/stcompact/src/bin/stcompact_ser_gen.rs index edcabd20e..12257a742 100644 --- a/components/stcompact/src/bin/stcompact_ser_gen.rs +++ b/components/stcompact/src/bin/stcompact_ser_gen.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/stcompact/src/lib.rs b/components/stcompact/src/lib.rs index 19ca69ba1..b2d43c15e 100644 --- a/components/stcompact/src/lib.rs +++ b/components/stcompact/src/lib.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/stctrl/src/bin/stctrl.rs b/components/stctrl/src/bin/stctrl.rs index 1938192a3..9bbeddf00 100644 --- a/components/stctrl/src/bin/stctrl.rs +++ b/components/stctrl/src/bin/stctrl.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/stctrl/src/bin/stverify.rs b/components/stctrl/src/bin/stverify.rs index bfb86c858..5c8dea23f 100644 --- a/components/stctrl/src/bin/stverify.rs +++ b/components/stctrl/src/bin/stverify.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/stctrl/src/lib.rs b/components/stctrl/src/lib.rs index c7606b665..01555ea5d 100644 --- a/components/stctrl/src/lib.rs +++ b/components/stctrl/src/lib.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/timer/src/lib.rs b/components/timer/src/lib.rs index a0c84f010..436816bba 100644 --- a/components/timer/src/lib.rs +++ b/components/timer/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/components/timer/src/timer.rs b/components/timer/src/timer.rs index 2f90d4433..83c6a652d 100644 --- a/components/timer/src/timer.rs +++ b/components/timer/src/timer.rs @@ -20,7 +20,7 @@ //! [futures]: https://github.com/alexcrichton/futures //! [futures-timer]: https://github.com/alexcrichton/futures-timer -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow(clippy::implicit_hasher, clippy::module_inception)] use common::conn::BoxStream; diff --git a/components/version/src/lib.rs b/components/version/src/lib.rs index fcc706384..f4dbf8417 100644 --- a/components/version/src/lib.rs +++ b/components/version/src/lib.rs @@ -1,6 +1,6 @@ #![crate_type = "lib"] #![deny(trivial_numeric_casts, warnings)] -#![allow(intra_doc_link_resolution_failure)] +#![allow(broken_intra_doc_links)] #![allow( clippy::too_many_arguments, clippy::implicit_hasher, diff --git a/rust-toolchain b/rust-toolchain index 0a3db35b2..21998d3c2 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.46.0 +1.47.0 From 3afe29691d6e6f66cc7b5c22a5e4546b6415ed9a Mon Sep 17 00:00:00 2001 From: real Date: Fri, 23 Oct 2020 14:03:30 +0300 Subject: [PATCH 126/478] Upgraded quickcheck versions --- Cargo.lock | 1916 ++++++++++++++-------------- components/common/Cargo.toml | 3 + components/crypto/Cargo.toml | 4 +- components/funder/Cargo.toml | 6 +- components/index_client/Cargo.toml | 7 +- components/node/Cargo.toml | 6 +- components/proto/Cargo.toml | 4 +- components/stcompact/Cargo.toml | 6 +- components/stctrl/Cargo.toml | 6 +- 9 files changed, 975 insertions(+), 983 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f885fad9e..0f909a8da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,2459 +4,2447 @@ name = "addr2line" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a49806b9dadc843c61e7c97e72490ad7f7220ae249012fbda9ad0609457c0543" dependencies = [ - "gimli 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gimli", ] [[package]] name = "aead" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672ba0d12aaf256aabcdab516ebed87b5cec4b602316d7a3035fac9b7a9567b" dependencies = [ - "generic-array 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.14.2", ] [[package]] name = "aho-corasick" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" dependencies = [ - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] name = "arrayref" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" [[package]] name = "async-std" version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d68a33ebc8b57800847d00787307f84a562224a14db069b0acefe4c2abbf5d" dependencies = [ - "async-task 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-timer 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kv-log-macro 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project-lite 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smol 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", + "async-task", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-timer", + "kv-log-macro", + "log", + "memchr", + "num_cpus", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "smol", + "wasm-bindgen-futures", ] [[package]] name = "async-task" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17772156ef2829aadc587461c7753af20b7e8db1529bc66855add962a3b35d3" [[package]] name = "atomicwrites" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a2baf2feb820299c53c7ad1cc4f5914a220a1cb76d7ce321d2522a94b54651f" dependencies = [ - "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "nix", + "tempdir", + "winapi", ] [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", + "winapi", ] [[package]] name = "autocfg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "backtrace" version = "0.3.48" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df2f85c8a2abbe3b7d7e748052fdd9b76a0458fdeb16ad4223f5eca78c7c130" dependencies = [ - "addr2line 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "object 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "addr2line", + "cfg-if", + "libc", + "object", + "rustc-demangle", ] [[package]] name = "base64" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "safemem", ] [[package]] name = "base64" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", ] [[package]] name = "base64" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitmaps" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" dependencies = [ - "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum", ] [[package]] name = "blake2b_simd" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" dependencies = [ - "arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref", + "arrayvec", + "constant_time_eq", ] [[package]] name = "block-buffer" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.3", ] [[package]] name = "block-buffer" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbcf92448676f82bb7a334c58bbce8b0d43580fb5362a9d608b18879d12a3d31" dependencies = [ - "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.14.2", ] [[package]] name = "block-padding" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools", ] [[package]] name = "blocking" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d17efb70ce4421e351d61aafd90c16a20fb5bfe339fcdc32a86816280e62ce0" dependencies = [ - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "waker-fn 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel", + "futures-util", + "once_cell", + "parking", + "waker-fn", ] [[package]] name = "bstr" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "memchr", + "regex-automata", + "serde", ] [[package]] name = "bumpalo" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" [[package]] name = "byte-tools" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "bytes" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" [[package]] name = "cache-padded" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24508e28c677875c380c20f4d28124fab6f8ed4ef929a1397d7b1a31e92f1005" [[package]] name = "capnp" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b867c15d8ff93c4d81b69c89280840f877331ef2a1fccbaf947afecc68b51a9e" [[package]] name = "capnpc" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2afedfc194b01c6804ad0a10c7139024b99ee3df6a39bb09bdf759067ababff" dependencies = [ - "capnp 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", + "capnp", ] [[package]] name = "cc" version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chacha20" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "086c0f07ac275808b7bf9a39f2fd013aae1498be83632814c8c4e0bd53f2dc58" dependencies = [ - "stream-cipher 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "stream-cipher", + "zeroize", ] [[package]] name = "chacha20poly1305" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18b0c90556d8e3fec7cf18d84a2f53d27b21288f2fe481b830fadcf809e48205" dependencies = [ - "aead 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chacha20 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "poly1305 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aead", + "chacha20", + "poly1305", + "stream-cipher", + "zeroize", ] [[package]] name = "chrono" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" dependencies = [ - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer", + "num-traits", + "time", ] [[package]] name = "clap" version = "2.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", ] [[package]] name = "clear_on_drop" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" dependencies = [ - "cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", ] [[package]] name = "cluFlock" version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc9a586f6ea37daf0f6154727023de0a52342bb84cf692451f09b2690e1034be" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi", ] [[package]] name = "colored" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "lazy_static", + "winapi", ] [[package]] name = "concurrent-queue" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83c06aff61f2d899eb87c379df3cbf7876f14471dcab474e0b6dc90ab96c080" dependencies = [ - "cache-padded 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cache-padded", ] [[package]] name = "constant_time_eq" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "crossbeam-utils" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "cfg-if", + "lazy_static", ] [[package]] name = "crunchy" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-mac" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.14.2", + "subtle", ] [[package]] name = "crypto-mac" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bcd97a54c7ca5ce2f6eb16f6bede5b0ab5f0055fedc17d2f0b4466e21671ca" dependencies = [ - "generic-array 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.14.2", + "subtle", ] [[package]] name = "csv" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" dependencies = [ - "bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr", + "csv-core", + "itoa", + "ryu", + "serde", ] [[package]] name = "csv-core" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" dependencies = [ - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] name = "curve25519-dalek" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d85653f070353a16313d0046f173f70d1aadd5b42600a14de626f0dfb3473a5" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "digest 0.8.1", + "rand_core 0.5.1", + "subtle", + "zeroize", ] [[package]] name = "derive_more" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d944ac6003ed268757ef1ee686753b57efc5fcf0ebe7b64c9fc81e7e32ff839" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.13", + "rustc_version", + "syn 0.15.44", ] [[package]] name = "derive_more" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "proc-macro2 0.4.30", + "quote 0.6.13", + "regex", + "rustc_version", + "syn 0.15.44", ] [[package]] name = "derive_more" version = "0.99.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2127768764f1556535c01b5326ef94bd60ff08dcfbdc544d53e69ed155610f5d" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18", + "quote 1.0.7", + "syn 1.0.31", ] [[package]] name = "digest" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3", ] [[package]] name = "digest" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.14.2", ] [[package]] name = "dirs" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "redox_users", + "winapi", ] [[package]] name = "ed25519-dalek" version = "1.0.0-pre.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978710b352437433c97b2bff193f2fb1dfd58a093f863dd95e225a19baa599a2" dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clear_on_drop", + "curve25519-dalek", + "rand 0.7.3", + "sha2 0.8.2", ] [[package]] name = "encode_unicode" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "env_logger" version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "humantime", + "log", + "regex", + "termcolor", ] [[package]] name = "env_logger" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "humantime", + "log", + "regex", + "termcolor", ] [[package]] name = "env_logger" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "regex", ] [[package]] name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "fallible-iterator" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fallible-streaming-iterator" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fastrand" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b90eb1dec02087df472ab9f0db65f27edaa654a746830042688bcc2eaf68090f" [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "futures" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" dependencies = [ - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", ] [[package]] name = "futures-channel" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" dependencies = [ - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core", + "futures-sink", ] [[package]] name = "futures-core" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" [[package]] name = "futures-executor" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" dependencies = [ - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core", + "futures-task", + "futures-util", + "num_cpus", ] [[package]] name = "futures-io" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" [[package]] name = "futures-macro" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" dependencies = [ - "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack", + "proc-macro2 1.0.18", + "quote 1.0.7", + "syn 1.0.31", ] [[package]] name = "futures-sink" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" [[package]] name = "futures-task" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" dependencies = [ - "once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell", ] [[package]] name = "futures-timer" version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" dependencies = [ - "gloo-timers 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "send_wrapper 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gloo-timers", + "send_wrapper", ] [[package]] name = "futures-util" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" dependencies = [ - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-nested 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", ] [[package]] name = "futures_codec" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe8859feb7140742ed1a2a85a07941100ad2b5f98a421b353931d718a34144d1" dependencies = [ - "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "memchr", + "pin-project", ] [[package]] name = "generic-array" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" dependencies = [ - "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum", ] [[package]] name = "generic-array" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac746a5f3bbfdadd6106868134545e684693d54d9d44f6e9588a7d54af0bf980" dependencies = [ - "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum", + "version_check", ] [[package]] name = "getrandom" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "wasi", ] [[package]] name = "gimli" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" [[package]] name = "gloo-timers" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" dependencies = [ - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] name = "heck" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" dependencies = [ - "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation", ] [[package]] name = "hermit-abi" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "hkdf" version = "0.9.0-alpha.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e551da9a76291df932270bc2b100d0571588eaa9ef77af7bceee80dba9ace3ad" dependencies = [ - "digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.9.0", + "hmac 0.8.0", ] [[package]] name = "hmac" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b87b580bd66811cc2324a27f3587de707cacf7525b96dca8122f7493e6cce0da" dependencies = [ - "crypto-mac 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-mac 0.8.0", + "digest 0.9.0", ] [[package]] name = "hmac" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deae6d9dbb35ec2c502d62b8f7b1c000a0822c3b0794ba36b3149c0a1c840dff" dependencies = [ - "crypto-mac 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-mac 0.9.1", + "digest 0.9.0", ] [[package]] name = "humantime" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" dependencies = [ - "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error", ] [[package]] name = "im" version = "14.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "696059c87b83c5a258817ecd67c3af915e3ed141891fc35a1e79908801cf0ce7" dependencies = [ - "bitmaps 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xoshiro 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", - "sized-chunks 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitmaps", + "quickcheck", + "rand_core 0.5.1", + "rand_xoshiro", + "serde", + "sized-chunks", + "typenum", + "version_check", ] [[package]] name = "itoa" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" [[package]] name = "js-sys" version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce10c23ad2ea25ceca0093bd3192229da4c5b3c0f2de499c1ecac0d98d452177" dependencies = [ - "wasm-bindgen 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen", ] [[package]] name = "kv-log-macro" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff57d6d215f7ca7eb35a9a64d656ba4d9d2bef114d741dc08048e75e2f5d418" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" [[package]] name = "libsqlite3-sys" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e704a02bcaecd4a08b93a23f6be59d0bd79cd161e0963e9499165a0a35df7bd" dependencies = [ - "cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "pkg-config", + "vcpkg", ] [[package]] name = "linked-hash-map" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" [[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "lru-cache" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" dependencies = [ - "linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map", ] [[package]] name = "memchr" version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "nix" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "cc", + "cfg-if", + "libc", + "void", ] [[package]] name = "num-bigint" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "num-integer", + "num-traits", ] [[package]] name = "num-integer" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "num-traits", ] [[package]] name = "num-traits" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", ] [[package]] name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ - "hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", ] [[package]] name = "object" version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2" [[package]] name = "offset-app" version = "0.1.0" dependencies = [ - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-app-client 0.1.0", - "offset-common 0.1.0", - "offset-connection 0.1.0", - "offset-crypto 0.1.0", - "offset-identity 0.1.0", - "offset-net 0.1.0", - "offset-proto 0.1.0", - "offset-signature 0.1.0", - "offset-timer 0.1.0", - "simple_logger 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "derive_more 0.14.1", + "futures", + "log", + "offset-app-client", + "offset-common", + "offset-connection", + "offset-crypto", + "offset-identity", + "offset-net", + "offset-proto", + "offset-signature", + "offset-timer", + "simple_logger", ] [[package]] name = "offset-app-client" version = "0.1.0" dependencies = [ - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-proto 0.1.0", + "futures", + "offset-common", + "offset-proto", ] [[package]] name = "offset-app-server" version = "0.1.0" dependencies = [ - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "im 14.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-identity 0.1.0", - "offset-proto 0.1.0", - "offset-timer 0.1.0", + "futures", + "im", + "log", + "offset-common", + "offset-crypto", + "offset-identity", + "offset-proto", + "offset-timer", ] [[package]] name = "offset-bin" version = "0.1.0" dependencies = [ - "async-std 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.99.7 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-connection 0.1.0", - "offset-crypto 0.1.0", - "offset-database 0.1.0", - "offset-identity 0.1.0", - "offset-index-server 0.1.0", - "offset-net 0.1.0", - "offset-node 0.1.0", - "offset-proto 0.1.0", - "offset-relay 0.1.0", - "offset-timer 0.1.0", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "async-std", + "base64 0.10.1", + "derive_more 0.99.7", + "env_logger 0.6.2", + "futures", + "log", + "offset-common", + "offset-connection", + "offset-crypto", + "offset-database", + "offset-identity", + "offset-index-server", + "offset-net", + "offset-node", + "offset-proto", + "offset-relay", + "offset-timer", + "serde", + "structopt", + "tempfile", ] [[package]] name = "offset-capnp-conv" version = "0.1.0" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "capnp 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "capnpc 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-capnp-conv-derive 0.1.0", - "pretty_env_logger 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "capnp", + "capnpc", + "derive_more 0.15.0", + "log", + "offset-capnp-conv-derive", + "pretty_env_logger", ] [[package]] name = "offset-capnp-conv-derive" version = "0.1.0" dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "heck", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] name = "offset-channeler" version = "0.1.0" dependencies = [ - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-identity 0.1.0", - "offset-proto 0.1.0", - "offset-relay 0.1.0", - "offset-timer 0.1.0", + "futures", + "log", + "offset-common", + "offset-crypto", + "offset-identity", + "offset-proto", + "offset-relay", + "offset-timer", ] [[package]] name = "offset-common" version = "0.1.0" dependencies = [ - "backtrace 0.3.48 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "paste 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace", + "base64 0.10.1", + "byteorder", + "bytes", + "futures", + "log", + "paste 1.0.1", + "quickcheck", + "quickcheck_derive", + "serde", + "uint", ] [[package]] name = "offset-connection" version = "0.1.0" dependencies = [ - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-identity 0.1.0", - "offset-keepalive 0.1.0", - "offset-net 0.1.0", - "offset-proto 0.1.0", - "offset-secure-channel 0.1.0", - "offset-signature 0.1.0", - "offset-timer 0.1.0", - "offset-version 0.1.0", - "simple_logger 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "derive_more 0.14.1", + "futures", + "log", + "offset-common", + "offset-crypto", + "offset-identity", + "offset-keepalive", + "offset-net", + "offset-proto", + "offset-secure-channel", + "offset-signature", + "offset-timer", + "offset-version", + "simple_logger", ] [[package]] name = "offset-crypto" version = "0.1.0" dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "chacha20poly1305 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.3 (registry+https://github.com/rust-lang/crates.io-index)", - "hkdf 0.9.0-alpha.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-proto 0.1.0", - "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_derive 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x25519-dalek 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.3", + "byteorder", + "bytes", + "chacha20poly1305", + "derive_more 0.14.1", + "ed25519-dalek", + "hkdf", + "hmac 0.9.0", + "offset-common", + "offset-proto", + "quickcheck", + "quickcheck_derive", + "rand 0.7.3", + "rand_core 0.5.1", + "serde", + "sha2 0.9.0", + "x25519-dalek", ] [[package]] name = "offset-database" version = "0.1.0" dependencies = [ - "atomicwrites 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "im 14.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-proto 0.1.0", - "rusqlite 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atomicwrites", + "base64 0.9.3", + "futures", + "im", + "log", + "offset-common", + "offset-proto", + "rusqlite", + "serde", + "serde_json", + "tempfile", ] [[package]] name = "offset-funder" version = "0.1.0" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "im 14.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-database 0.1.0", - "offset-identity 0.1.0", - "offset-proto 0.1.0", - "offset-signature 0.1.0", - "paste 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pretty_env_logger 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_derive 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "bytes", + "derive_more 0.15.0", + "futures", + "im", + "log", + "offset-common", + "offset-crypto", + "offset-database", + "offset-identity", + "offset-proto", + "offset-signature", + "paste 1.0.1", + "pretty_env_logger", + "quickcheck", + "quickcheck_derive", + "quickcheck_macros 0.9.1", + "rand 0.7.3", + "serde", ] [[package]] name = "offset-identity" version = "0.1.0" dependencies = [ - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-proto 0.1.0", + "futures", + "offset-common", + "offset-crypto", + "offset-proto", ] [[package]] name = "offset-index-client" version = "0.1.0" dependencies = [ - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-database 0.1.0", - "offset-identity 0.1.0", - "offset-proto 0.1.0", - "offset-signature 0.1.0", - "offset-timer 0.1.0", - "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_derive 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2", + "futures", + "log", + "offset-common", + "offset-crypto", + "offset-database", + "offset-identity", + "offset-proto", + "offset-signature", + "offset-timer", + "quickcheck", + "quickcheck_derive", + "quickcheck_macros 0.9.1", + "rand 0.7.3", + "serde", ] [[package]] name = "offset-index-server" version = "0.1.0" dependencies = [ - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-identity 0.1.0", - "offset-proto 0.1.0", - "offset-signature 0.1.0", - "offset-timer 0.1.0", + "env_logger 0.6.2", + "futures", + "log", + "offset-common", + "offset-crypto", + "offset-identity", + "offset-proto", + "offset-signature", + "offset-timer", ] [[package]] name = "offset-keepalive" version = "0.1.0" dependencies = [ - "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-proto 0.1.0", - "offset-timer 0.1.0", + "derive_more 0.15.0", + "futures", + "log", + "offset-common", + "offset-crypto", + "offset-proto", + "offset-timer", ] [[package]] name = "offset-lockfile" version = "0.1.0" dependencies = [ - "cluFlock 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cluFlock", + "tempfile", ] [[package]] name = "offset-mutual-from" version = "0.1.0" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] name = "offset-net" version = "0.1.0" dependencies = [ - "async-std 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures_codec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-proto 0.1.0", + "async-std", + "bytes", + "env_logger 0.6.2", + "futures", + "futures_codec", + "log", + "offset-common", + "offset-proto", ] [[package]] name = "offset-node" version = "0.1.0" dependencies = [ - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-app-server 0.1.0", - "offset-channeler 0.1.0", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-database 0.1.0", - "offset-funder 0.1.0", - "offset-identity 0.1.0", - "offset-index-client 0.1.0", - "offset-net 0.1.0", - "offset-proto 0.1.0", - "offset-relay 0.1.0", - "offset-signature 0.1.0", - "offset-timer 0.1.0", - "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_derive 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", + "derive_more 0.14.1", + "futures", + "log", + "offset-app-server", + "offset-channeler", + "offset-common", + "offset-crypto", + "offset-database", + "offset-funder", + "offset-identity", + "offset-index-client", + "offset-net", + "offset-proto", + "offset-relay", + "offset-signature", + "offset-timer", + "quickcheck", + "quickcheck_derive", + "quickcheck_macros 0.9.1", + "rand 0.7.3", + "serde", ] [[package]] name = "offset-proto" version = "0.1.0" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "capnp 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "capnpc 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "im 14.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-capnp-conv 0.1.0", - "offset-common 0.1.0", - "offset-mutual-from 0.1.0", - "paste 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_derive 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1", + "byteorder", + "bytes", + "capnp", + "capnpc", + "derive_more 0.14.1", + "im", + "num-bigint", + "num-traits", + "offset-capnp-conv", + "offset-common", + "offset-mutual-from", + "paste 0.1.16", + "quickcheck", + "quickcheck_derive", + "rand 0.7.3", + "serde", + "serde_json", + "tempfile", ] [[package]] name = "offset-relay" version = "0.1.0" dependencies = [ - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-identity 0.1.0", - "offset-proto 0.1.0", - "offset-timer 0.1.0", + "derive_more 0.14.1", + "futures", + "log", + "offset-common", + "offset-crypto", + "offset-identity", + "offset-proto", + "offset-timer", ] [[package]] name = "offset-route" version = "0.1.0" dependencies = [ - "num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-proto 0.1.0", + "num-bigint", + "num-traits", + "offset-common", + "offset-crypto", + "offset-proto", ] [[package]] name = "offset-secure-channel" version = "0.1.0" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-identity 0.1.0", - "offset-proto 0.1.0", - "offset-timer 0.1.0", - "pretty_env_logger 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "derive_more 0.15.0", + "futures", + "log", + "offset-common", + "offset-crypto", + "offset-identity", + "offset-proto", + "offset-timer", + "pretty_env_logger", ] [[package]] name = "offset-signature" version = "0.1.0" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", - "offset-crypto 0.1.0", - "offset-proto 0.1.0", + "byteorder", + "offset-common", + "offset-crypto", + "offset-proto", ] [[package]] name = "offset-stcompact" version = "0.1.0" dependencies = [ - "async-std 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.99.7 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-app 0.1.0", - "offset-app-client 0.1.0", - "offset-common 0.1.0", - "offset-connection 0.1.0", - "offset-crypto 0.1.0", - "offset-database 0.1.0", - "offset-identity 0.1.0", - "offset-lockfile 0.1.0", - "offset-net 0.1.0", - "offset-node 0.1.0", - "offset-proto 0.1.0", - "offset-route 0.1.0", - "offset-timer 0.1.0", - "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_derive 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "async-std", + "base64 0.10.1", + "derive_more 0.99.7", + "env_logger 0.6.2", + "futures", + "log", + "offset-app", + "offset-app-client", + "offset-common", + "offset-connection", + "offset-crypto", + "offset-database", + "offset-identity", + "offset-lockfile", + "offset-net", + "offset-node", + "offset-proto", + "offset-route", + "offset-timer", + "quickcheck", + "quickcheck_derive", + "quickcheck_macros 0.9.1", + "rand 0.7.3", + "serde", + "serde_json", + "structopt", + "tempfile", ] [[package]] name = "offset-stctrl" version = "0.1.0" dependencies = [ - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-app 0.1.0", - "offset-mutual-from 0.1.0", - "offset-route 0.1.0", - "prettytable-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_derive 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "derive_more 0.14.1", + "env_logger 0.6.2", + "futures", + "log", + "offset-app", + "offset-mutual-from", + "offset-route", + "prettytable-rs", + "quickcheck", + "quickcheck_derive", + "quickcheck_macros 0.9.1", + "rand 0.7.3", + "serde", + "structopt", + "tempfile", ] [[package]] name = "offset-test" version = "0.1.0" dependencies = [ - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-app 0.1.0", - "offset-app-client 0.1.0", - "offset-bin 0.1.0", - "offset-common 0.1.0", - "offset-connection 0.1.0", - "offset-crypto 0.1.0", - "offset-database 0.1.0", - "offset-funder 0.1.0", - "offset-identity 0.1.0", - "offset-index-server 0.1.0", - "offset-net 0.1.0", - "offset-node 0.1.0", - "offset-proto 0.1.0", - "offset-relay 0.1.0", - "offset-stcompact 0.1.0", - "offset-stctrl 0.1.0", - "offset-timer 0.1.0", - "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2", + "futures", + "log", + "offset-app", + "offset-app-client", + "offset-bin", + "offset-common", + "offset-connection", + "offset-crypto", + "offset-database", + "offset-funder", + "offset-identity", + "offset-index-server", + "offset-net", + "offset-node", + "offset-proto", + "offset-relay", + "offset-stcompact", + "offset-stctrl", + "offset-timer", + "quickcheck", + "quickcheck_macros 0.8.0", + "rand 0.7.3", + "serde_json", + "tempfile", ] [[package]] name = "offset-timer" version = "0.1.0" dependencies = [ - "async-std 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", + "async-std", + "bytes", + "futures", + "log", + "offset-common", ] [[package]] name = "offset-version" version = "0.1.0" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "offset-common 0.1.0", + "byteorder", + "futures", + "log", + "offset-common", ] [[package]] name = "once_cell" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" [[package]] name = "opaque-debug" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "parking" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4029bc3504a62d92e42f30b9095fdef73b8a0b2a06aa41ce2935143b05a1a06" [[package]] name = "paste" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d508492eeb1e5c38ee696371bf7b9fc33c83d46a7d451606b96458fbbbdc2dec" dependencies = [ - "paste-impl 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", + "paste-impl", + "proc-macro-hack", ] [[package]] name = "paste" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0520af26d4cf99643dbbe093a61507922b57232d9978d8491fdc8f7b44573c8c" [[package]] name = "paste-impl" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f328a6a63192b333fce5fbb4be79db6758a4d518dfac6d54412f1492f72d32" dependencies = [ - "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack", + "proc-macro2 1.0.18", + "quote 1.0.7", + "syn 1.0.31", ] [[package]] name = "pin-project" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e75373ff9037d112bb19bc61333a06a159eaeb217660dcfbea7d88e1db823919" dependencies = [ - "pin-project-internal 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project-internal", ] [[package]] name = "pin-project-internal" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10b4b44893d3c370407a1d6a5cfde7c41ae0478e31c516c85f67eb3adc51be6d" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18", + "quote 1.0.7", + "syn 1.0.31", ] [[package]] name = "pin-project-lite" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" [[package]] name = "poly1305" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b42192ab143ed7619bf888a7f9c6733a9a2153b218e2cd557cfdb52fbf9bb1" dependencies = [ - "universal-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "universal-hash", ] [[package]] name = "ppv-lite86" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" [[package]] name = "pretty_env_logger" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed8d1e63042e889b85228620629b51c011d380eed2c7e0015f8a644def280c28" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term", + "chrono", + "env_logger 0.5.13", + "log", ] [[package]] name = "prettytable-rs" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fd04b170004fa2daccf418a7f8253aaf033c27760b5f225889024cf66d7ac2e" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "csv", + "encode_unicode", + "lazy_static", + "term", + "unicode-width", ] [[package]] name = "proc-macro-hack" version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" [[package]] name = "proc-macro-nested" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0afe1bd463b9e9ed51d0e0f0b50b6b146aec855c56fd182bb242388710a9b6de" [[package]] name = "proc-macro2" version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0", ] [[package]] name = "proc-macro2" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quickcheck" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44883e74aa97ad63db83c4bf8ca490f02b2fc02f92575e720c8551e843c945f" dependencies = [ - "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.1", + "log", + "rand 0.7.3", + "rand_core 0.5.1", ] [[package]] name = "quickcheck_derive" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "695566b1208e5a3e5a613d3326fcdb78203e1493c81514bfb4f4460ce0694deb" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18", + "syn 1.0.31", + "synstructure", ] [[package]] name = "quickcheck_macros" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7dfc1c4a1e048f5cc7d36a4c4118dfcf31d217c79f4b9a61bad65d68185752c" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "quickcheck_macros" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608c156fd8e97febc07dc9c2e2c80bf74cfc6ef26893eae3daf8bc2bc94a4b7f" +dependencies = [ + "proc-macro2 1.0.18", + "quote 1.0.7", + "syn 1.0.31", ] [[package]] name = "quote" version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", ] [[package]] name = "quote" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18", ] [[package]] name = "rand" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", ] [[package]] name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "libc", + "rand_chacha", + "rand_core 0.5.1", + "rand_hc", ] [[package]] name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ - "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core 0.5.1", ] [[package]] name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2", ] [[package]] name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1", ] [[package]] name = "rand_xoshiro" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1", ] [[package]] name = "rdrand" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" [[package]] name = "redox_users" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "redox_syscall", + "rust-argon2", ] [[package]] name = "regex" version = "1.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" dependencies = [ - "aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", ] [[package]] name = "regex-automata" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", ] [[package]] name = "regex-syntax" version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" [[package]] name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] name = "rusqlite" version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45d0fd62e1df63d254714e6cb40d0a0e82e7a1623e7a27f679d851af092ae58b" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libsqlite3-sys 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "libsqlite3-sys", + "lru-cache", + "memchr", + "smallvec", + "time", ] [[package]] name = "rust-argon2" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" dependencies = [ - "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.11.0", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", ] [[package]] name = "rustc-demangle" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" [[package]] name = "rustc-hex" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver", ] [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "safemem" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" [[package]] name = "scoped-tls" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver-parser", ] [[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "send_wrapper" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" [[package]] name = "serde" version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d" dependencies = [ - "serde_derive 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18", + "quote 1.0.7", + "syn 1.0.31", ] [[package]] name = "serde_json" version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226" dependencies = [ - "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", ] [[package]] name = "sha2" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug", ] [[package]] name = "sha2" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72377440080fd008550fe9b441e854e43318db116f90181eef92e9ae9aedab48" dependencies = [ - "block-buffer 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer 0.8.0", + "digest 0.9.0", + "fake-simd", + "opaque-debug", ] [[package]] name = "simple_logger" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0c4611f32f4c2bac73754f22dca1f57e6c1945e0590dae4e5f2a077b92367" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "chrono", + "colored", + "log", + "winapi", ] [[package]] name = "sized-chunks" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59044ea371ad781ff976f7b06480b9f0180e834eda94114f2afb4afc12b7718" dependencies = [ - "bitmaps 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitmaps", + "typenum", ] [[package]] name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "smallvec" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f" [[package]] name = "smol" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "620cbb3c6e34da57d3a248cda0cd01cd5848164dc062e764e65d06fe3ea7aed5" dependencies = [ - "async-task 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blocking 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "concurrent-queue 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fastrand 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wepoll-sys-stjepang 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "async-task", + "blocking", + "concurrent-queue", + "fastrand", + "futures-io", + "futures-util", + "libc", + "once_cell", + "scoped-tls", + "slab", + "socket2", + "wepoll-sys-stjepang", + "winapi", ] [[package]] name = "socket2" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "redox_syscall", + "winapi", ] [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stream-cipher" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f8ed9974042b8c3672ff3030a69fcc03b74c47c3d1ecb7755e8a3626011e88" dependencies = [ - "generic-array 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.14.2", ] [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" dependencies = [ - "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "clap", + "structopt-derive", ] [[package]] name = "structopt-derive" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "heck", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] name = "subtle" version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "syn" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "502d53007c02d7605a05df1c1a73ee436952781653da5d0bf57ad608f66932c1" [[package]] name = "syn" version = "0.15.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", ] [[package]] name = "syn" version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synstructure" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18", + "quote 1.0.7", + "unicode-xid 0.2.0", ] [[package]] name = "synstructure" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18", + "quote 1.0.7", + "syn 1.0.31", + "unicode-xid 0.2.0", ] [[package]] name = "tempdir" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" dependencies = [ - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6", + "remove_dir_all", ] [[package]] name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "rand 0.7.3", + "redox_syscall", + "remove_dir_all", + "winapi", ] [[package]] name = "term" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "dirs", + "winapi", ] [[package]] name = "termcolor" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" dependencies = [ - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width", ] [[package]] name = "thread_local" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", ] [[package]] name = "time" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi", ] [[package]] name = "typenum" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" [[package]] name = "uint" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9db035e67dfaf7edd9aebfe8676afcd63eed53c8a4044fed514c8cccf1835177" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "crunchy", + "rustc-hex", + "static_assertions", ] [[package]] name = "unicode-segmentation" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" [[package]] name = "unicode-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" [[package]] name = "universal-hash" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" dependencies = [ - "generic-array 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.14.2", + "subtle", ] [[package]] name = "vcpkg" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" [[package]] name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" [[package]] name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "waker-fn" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9571542c2ce85ce642e6b58b3364da2fb53526360dfb7c211add4f5c23105ff7" [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasm-bindgen" version = "0.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2dc4aa152834bc334f506c1a06b866416a8b6697d5c9f75b9a689c8486def0" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded84f06e0ed21499f6184df0e0cb3494727b0c5da89534e0fcc55c51d812101" dependencies = [ - "bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)", + "bumpalo", + "lazy_static", + "log", + "proc-macro2 1.0.18", + "quote 1.0.7", + "syn 1.0.31", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64487204d863f109eb77e8462189d111f27cb5712cc9fdb3461297a76963a2f6" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "838e423688dac18d73e31edce74ddfac468e37b1506ad163ffaf0a46f703ffe3" dependencies = [ - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7", + "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3156052d8ec77142051a533cdd686cba889537b213f948cd1d20869926e68e92" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18", + "quote 1.0.7", + "syn 1.0.31", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9ba19973a58daf4db6f352eda73dc0e289493cd29fb2632eb172085b6521acd" [[package]] name = "web-sys" version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b72fe77fd39e4bd3eaa4412fd299a0be6b3dfe9d2597e2f1c20beb968f41d17" dependencies = [ - "js-sys 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys", + "wasm-bindgen", ] [[package]] name = "wepoll-sys-stjepang" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd319e971980166b53e17b1026812ad66c6b54063be879eb182342b55284694" dependencies = [ - "cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", ] [[package]] name = "winapi" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "x25519-dalek" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637ff90c9540fa3073bb577e65033069e4bae7c79d49d74aa3ffdf5342a53217" dependencies = [ - "curve25519-dalek 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek", + "rand_core 0.5.1", + "zeroize", ] [[package]] name = "zeroize" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" dependencies = [ - "zeroize_derive 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize_derive", ] [[package]] name = "zeroize_derive" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum addr2line 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a49806b9dadc843c61e7c97e72490ad7f7220ae249012fbda9ad0609457c0543" -"checksum aead 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3672ba0d12aaf256aabcdab516ebed87b5cec4b602316d7a3035fac9b7a9567b" -"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" -"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" -"checksum async-std 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00d68a33ebc8b57800847d00787307f84a562224a14db069b0acefe4c2abbf5d" -"checksum async-task 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c17772156ef2829aadc587461c7753af20b7e8db1529bc66855add962a3b35d3" -"checksum atomicwrites 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6a2baf2feb820299c53c7ad1cc4f5914a220a1cb76d7ce321d2522a94b54651f" -"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum backtrace 0.3.48 (registry+https://github.com/rust-lang/crates.io-index)" = "0df2f85c8a2abbe3b7d7e748052fdd9b76a0458fdeb16ad4223f5eca78c7c130" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" -"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum bitmaps 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" -"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" -"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -"checksum block-buffer 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dbcf92448676f82bb7a334c58bbce8b0d43580fb5362a9d608b18879d12a3d31" -"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -"checksum blocking 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9d17efb70ce4421e351d61aafd90c16a20fb5bfe339fcdc32a86816280e62ce0" -"checksum bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931" -"checksum bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" -"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" -"checksum cache-padded 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24508e28c677875c380c20f4d28124fab6f8ed4ef929a1397d7b1a31e92f1005" -"checksum capnp 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b867c15d8ff93c4d81b69c89280840f877331ef2a1fccbaf947afecc68b51a9e" -"checksum capnpc 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d2afedfc194b01c6804ad0a10c7139024b99ee3df6a39bb09bdf759067ababff" -"checksum cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)" = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chacha20 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "086c0f07ac275808b7bf9a39f2fd013aae1498be83632814c8c4e0bd53f2dc58" -"checksum chacha20poly1305 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "18b0c90556d8e3fec7cf18d84a2f53d27b21288f2fe481b830fadcf809e48205" -"checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" -"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" -"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" -"checksum cluFlock 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dc9a586f6ea37daf0f6154727023de0a52342bb84cf692451f09b2690e1034be" -"checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" -"checksum concurrent-queue 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f83c06aff61f2d899eb87c379df3cbf7876f14471dcab474e0b6dc90ab96c080" -"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" -"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -"checksum crypto-mac 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -"checksum crypto-mac 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58bcd97a54c7ca5ce2f6eb16f6bede5b0ab5f0055fedc17d2f0b4466e21671ca" -"checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" -"checksum csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -"checksum curve25519-dalek 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d85653f070353a16313d0046f173f70d1aadd5b42600a14de626f0dfb3473a5" -"checksum derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d944ac6003ed268757ef1ee686753b57efc5fcf0ebe7b64c9fc81e7e32ff839" -"checksum derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe" -"checksum derive_more 0.99.7 (registry+https://github.com/rust-lang/crates.io-index)" = "2127768764f1556535c01b5326ef94bd60ff08dcfbdc544d53e69ed155610f5d" -"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -"checksum digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -"checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" -"checksum ed25519-dalek 1.0.0-pre.3 (registry+https://github.com/rust-lang/crates.io-index)" = "978710b352437433c97b2bff193f2fb1dfd58a093f863dd95e225a19baa599a2" -"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" -"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" -"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" -"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" -"checksum fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" -"checksum fastrand 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b90eb1dec02087df472ab9f0db65f27edaa654a746830042688bcc2eaf68090f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" -"checksum futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" -"checksum futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" -"checksum futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" -"checksum futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" -"checksum futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" -"checksum futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" -"checksum futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" -"checksum futures-timer 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" -"checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" -"checksum futures_codec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8859feb7140742ed1a2a85a07941100ad2b5f98a421b353931d718a34144d1" -"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum generic-array 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ac746a5f3bbfdadd6106868134545e684693d54d9d44f6e9588a7d54af0bf980" -"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum gimli 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" -"checksum gloo-timers 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" -"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" -"checksum hkdf 0.9.0-alpha.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e551da9a76291df932270bc2b100d0571588eaa9ef77af7bceee80dba9ace3ad" -"checksum hmac 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b87b580bd66811cc2324a27f3587de707cacf7525b96dca8122f7493e6cce0da" -"checksum hmac 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "deae6d9dbb35ec2c502d62b8f7b1c000a0822c3b0794ba36b3149c0a1c840dff" -"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -"checksum im 14.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "696059c87b83c5a258817ecd67c3af915e3ed141891fc35a1e79908801cf0ce7" -"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" -"checksum js-sys 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "ce10c23ad2ea25ceca0093bd3192229da4c5b3c0f2de499c1ecac0d98d452177" -"checksum kv-log-macro 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4ff57d6d215f7ca7eb35a9a64d656ba4d9d2bef114d741dc08048e75e2f5d418" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" -"checksum libsqlite3-sys 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e704a02bcaecd4a08b93a23f6be59d0bd79cd161e0963e9499165a0a35df7bd" -"checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" -"checksum num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -"checksum num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" -"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" -"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -"checksum object 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2" -"checksum once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" -"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" -"checksum parking 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c4029bc3504a62d92e42f30b9095fdef73b8a0b2a06aa41ce2935143b05a1a06" -"checksum paste 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "d508492eeb1e5c38ee696371bf7b9fc33c83d46a7d451606b96458fbbbdc2dec" -"checksum paste 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0520af26d4cf99643dbbe093a61507922b57232d9978d8491fdc8f7b44573c8c" -"checksum paste-impl 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "84f328a6a63192b333fce5fbb4be79db6758a4d518dfac6d54412f1492f72d32" -"checksum pin-project 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e75373ff9037d112bb19bc61333a06a159eaeb217660dcfbea7d88e1db823919" -"checksum pin-project-internal 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "10b4b44893d3c370407a1d6a5cfde7c41ae0478e31c516c85f67eb3adc51be6d" -"checksum pin-project-lite 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715" -"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -"checksum pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" -"checksum poly1305 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b42192ab143ed7619bf888a7f9c6733a9a2153b218e2cd557cfdb52fbf9bb1" -"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" -"checksum pretty_env_logger 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8d1e63042e889b85228620629b51c011d380eed2c7e0015f8a644def280c28" -"checksum prettytable-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0fd04b170004fa2daccf418a7f8253aaf033c27760b5f225889024cf66d7ac2e" -"checksum proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" -"checksum proc-macro-nested 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0afe1bd463b9e9ed51d0e0f0b50b6b146aec855c56fd182bb242388710a9b6de" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" -"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -"checksum quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a44883e74aa97ad63db83c4bf8ca490f02b2fc02f92575e720c8551e843c945f" -"checksum quickcheck_derive 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c21ac135ba4077d64a7f461ef1a131fa02a546ed85870053b70f739d254dd1e8" -"checksum quickcheck_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7dfc1c4a1e048f5cc7d36a4c4118dfcf31d217c79f4b9a61bad65d68185752c" -"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_xoshiro 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" -"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" -"checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" -"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" -"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rusqlite 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)" = "45d0fd62e1df63d254714e6cb40d0a0e82e7a1623e7a27f679d851af092ae58b" -"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" -"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" -"checksum rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" -"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" -"checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum send_wrapper 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" -"checksum serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)" = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d" -"checksum serde_derive 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250" -"checksum serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226" -"checksum sha2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -"checksum sha2 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "72377440080fd008550fe9b441e854e43318db116f90181eef92e9ae9aedab48" -"checksum simple_logger 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fea0c4611f32f4c2bac73754f22dca1f57e6c1945e0590dae4e5f2a077b92367" -"checksum sized-chunks 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d59044ea371ad781ff976f7b06480b9f0180e834eda94114f2afb4afc12b7718" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f" -"checksum smol 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "620cbb3c6e34da57d3a248cda0cd01cd5848164dc062e764e65d06fe3ea7aed5" -"checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" -"checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -"checksum stream-cipher 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09f8ed9974042b8c3672ff3030a69fcc03b74c47c3d1ecb7755e8a3626011e88" -"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" -"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" -"checksum subtle 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "502d53007c02d7605a05df1c1a73ee436952781653da5d0bf57ad608f66932c1" -"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" -"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -"checksum syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" -"checksum synstructure 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" -"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7" -"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" -"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" -"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -"checksum typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" -"checksum uint 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9db035e67dfaf7edd9aebfe8676afcd63eed53c8a4044fed514c8cccf1835177" -"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" -"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum universal-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" -"checksum vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" -"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" -"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum waker-fn 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9571542c2ce85ce642e6b58b3364da2fb53526360dfb7c211add4f5c23105ff7" -"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum wasm-bindgen 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)" = "4c2dc4aa152834bc334f506c1a06b866416a8b6697d5c9f75b9a689c8486def0" -"checksum wasm-bindgen-backend 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)" = "ded84f06e0ed21499f6184df0e0cb3494727b0c5da89534e0fcc55c51d812101" -"checksum wasm-bindgen-futures 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "64487204d863f109eb77e8462189d111f27cb5712cc9fdb3461297a76963a2f6" -"checksum wasm-bindgen-macro 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)" = "838e423688dac18d73e31edce74ddfac468e37b1506ad163ffaf0a46f703ffe3" -"checksum wasm-bindgen-macro-support 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)" = "3156052d8ec77142051a533cdd686cba889537b213f948cd1d20869926e68e92" -"checksum wasm-bindgen-shared 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ba19973a58daf4db6f352eda73dc0e289493cd29fb2632eb172085b6521acd" -"checksum web-sys 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "7b72fe77fd39e4bd3eaa4412fd299a0be6b3dfe9d2597e2f1c20beb968f41d17" -"checksum wepoll-sys-stjepang 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd319e971980166b53e17b1026812ad66c6b54063be879eb182342b55284694" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum x25519-dalek 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "637ff90c9540fa3073bb577e65033069e4bae7c79d49d74aa3ffdf5342a53217" -"checksum zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" -"checksum zeroize_derive 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" + "proc-macro2 1.0.18", + "quote 1.0.7", + "syn 1.0.31", + "synstructure", +] diff --git a/components/common/Cargo.toml b/components/common/Cargo.toml index f42f32803..edb87eb58 100644 --- a/components/common/Cargo.toml +++ b/components/common/Cargo.toml @@ -18,6 +18,9 @@ backtrace = "0.3.14" base64 = "0.10.1" uint = "0.8.5" +quickcheck = "0.9.2" +quickcheck_derive = "0.3.0" + [dev-dependencies] serde = {version = "1.0.104", features = ["derive"]} diff --git a/components/crypto/Cargo.toml b/components/crypto/Cargo.toml index d14f6fd19..d2a68b5d4 100644 --- a/components/crypto/Cargo.toml +++ b/components/crypto/Cargo.toml @@ -26,8 +26,8 @@ base64 = "0.9" derive_more = "0.14.0" # Quickcheck: -quickcheck = {version = "0.9"} -quickcheck_derive = {version = "0.2.1"} +quickcheck = "0.9.2" +quickcheck_derive = "0.3" rand = "0.7.3" rand_core = "0.5.1" diff --git a/components/funder/Cargo.toml b/components/funder/Cargo.toml index 96bec8b7b..80a56f155 100644 --- a/components/funder/Cargo.toml +++ b/components/funder/Cargo.toml @@ -29,9 +29,9 @@ im = {version = "14.1.0", features = ["serde", "quickcheck"]} byteorder = {version = "1.1", features = ["i128"]} # Quickcheck: -quickcheck = {version = "0.9"} -quickcheck_macros = {version = "0.8"} -quickcheck_derive = {version = "0.2.1"} +quickcheck = "0.9.2" +quickcheck_derive = "0.3" +quickcheck_macros = "0.9.1" rand = {version = "0.7.2"} paste = "1.0.1" diff --git a/components/index_client/Cargo.toml b/components/index_client/Cargo.toml index 1f5381d4c..f6cdb72e0 100644 --- a/components/index_client/Cargo.toml +++ b/components/index_client/Cargo.toml @@ -23,9 +23,10 @@ futures = "0.3.1" serde = {version = "1.0.104", features = ["derive"]} # Quickcheck: -quickcheck = {version = "0.9"} -quickcheck_macros = {version = "0.8"} -quickcheck_derive = {version = "0.2.1"} +quickcheck_macros = "0.9.1" +quickcheck = "0.9.2" +quickcheck_derive = "0.3" + rand = {version = "0.7.2"} [dev-dependencies] diff --git a/components/node/Cargo.toml b/components/node/Cargo.toml index 66816a973..c72a52856 100644 --- a/components/node/Cargo.toml +++ b/components/node/Cargo.toml @@ -29,7 +29,7 @@ serde = {version = "1.0.104", features = ["derive"]} derive_more = "0.14.0" # Quickcheck: -quickcheck = {version = "0.9"} -quickcheck_macros = {version = "0.8"} -quickcheck_derive = {version = "0.2.1"} +quickcheck = "0.9.2" +quickcheck_derive = "0.3" +quickcheck_macros = "0.9.1" rand = {version = "0.7.2"} diff --git a/components/proto/Cargo.toml b/components/proto/Cargo.toml index 0b4484406..7bb482c06 100644 --- a/components/proto/Cargo.toml +++ b/components/proto/Cargo.toml @@ -33,8 +33,8 @@ num-traits = "0.2.6" paste = "0.1.5" # Quickcheck: -quickcheck = {version = "0.9"} -quickcheck_derive = {version = "0.2.1"} +quickcheck = "0.9.2" +quickcheck_derive = "0.3" rand = {version = "0.7.2"} [dev-dependencies] diff --git a/components/stcompact/Cargo.toml b/components/stcompact/Cargo.toml index b70c242e6..f11b6efe9 100644 --- a/components/stcompact/Cargo.toml +++ b/components/stcompact/Cargo.toml @@ -48,9 +48,9 @@ derive_more = "0.99.2" serde_json = "1.0.44" # Quickcheck: -quickcheck = {version = "0.9"} -quickcheck_macros = {version = "0.8"} -quickcheck_derive = {version = "0.2.1"} +quickcheck = "0.9.2" +quickcheck_derive = "0.3" +quickcheck_macros = "0.9.1" rand = {version = "0.7.2"} [dev-dependencies] diff --git a/components/stctrl/Cargo.toml b/components/stctrl/Cargo.toml index 65d9491b7..1a53c9dce 100644 --- a/components/stctrl/Cargo.toml +++ b/components/stctrl/Cargo.toml @@ -37,9 +37,9 @@ structopt = "0.2.15" derive_more = "0.14.0" # Quickcheck: -quickcheck = {version = "0.9"} -quickcheck_macros = {version = "0.8"} -quickcheck_derive = {version = "0.2.1"} +quickcheck = "0.9.2" +quickcheck_derive = "0.3" +quickcheck_macros = "0.9.1" rand = {version = "0.7.2"} [dev_dependencies] From 557fffffbf0aa4dd7ccc94bb2faf012625cd1816 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 23 Oct 2020 14:16:42 +0300 Subject: [PATCH 127/478] funder: mutual_credit: Using U256 instead of u128 for fees accounting --- Cargo.lock | 1 - components/common/Cargo.toml | 1 - components/common/src/u256.rs | 12 ++++++++++++ components/funder/src/mutual_credit/incoming.rs | 2 +- components/funder/src/mutual_credit/outgoing.rs | 2 +- .../tests/request_cancel_send_funds.rs | 8 ++++---- .../tests/request_response_send_funds.rs | 8 ++++---- components/funder/src/mutual_credit/tests/utils.rs | 8 +++++--- components/funder/src/mutual_credit/types.rs | 13 +++++++------ 9 files changed, 34 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f909a8da..559c024bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1094,7 +1094,6 @@ dependencies = [ "log", "paste 1.0.1", "quickcheck", - "quickcheck_derive", "serde", "uint", ] diff --git a/components/common/Cargo.toml b/components/common/Cargo.toml index edb87eb58..38d3c7392 100644 --- a/components/common/Cargo.toml +++ b/components/common/Cargo.toml @@ -19,7 +19,6 @@ base64 = "0.10.1" uint = "0.8.5" quickcheck = "0.9.2" -quickcheck_derive = "0.3.0" [dev-dependencies] diff --git a/components/common/src/u256.rs b/components/common/src/u256.rs index e8fb99df2..3a154787f 100644 --- a/components/common/src/u256.rs +++ b/components/common/src/u256.rs @@ -1,3 +1,4 @@ +use quickcheck::{Arbitrary, Gen}; use uint::construct_uint; construct_uint! { @@ -5,6 +6,17 @@ construct_uint! { pub struct U256(4); } +impl Arbitrary for U256 { + fn arbitrary(g: &mut G) -> Self { + U256([ + u64::arbitrary(g), + u64::arbitrary(g), + u64::arbitrary(g), + u64::arbitrary(g), + ]) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index bb3c3468a..5af3f6dc5 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -252,7 +252,7 @@ async fn process_response_send_funds( .set_out_fees( mc_balance .out_fees - .checked_add(pending_transaction.left_fees) + .checked_add(pending_transaction.left_fees.into()) .unwrap(), ) .await?; diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 400869c3c..c5560e457 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -179,7 +179,7 @@ async fn queue_response_send_funds( .set_in_fees( mc_balance .in_fees - .checked_add(pending_transaction.left_fees) + .checked_add(pending_transaction.left_fees.into()) .unwrap(), ) .await?; diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index aac351241..cc43aa2a1 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -70,8 +70,8 @@ async fn task_request_cancel_send_funds() { assert_eq!(mc_balance.balance, 0); assert_eq!(mc_balance.local_pending_debt, 10 + 5); assert_eq!(mc_balance.remote_pending_debt, 0); - assert_eq!(mc_balance.in_fees, 0); - assert_eq!(mc_balance.out_fees, 0); + assert_eq!(mc_balance.in_fees, 0.into()); + assert_eq!(mc_balance.out_fees, 0.into()); // -----[CancelSendFunds]-------- // ------------------------------ @@ -91,8 +91,8 @@ async fn task_request_cancel_send_funds() { assert_eq!(mc_balance.balance, 0); assert_eq!(mc_balance.local_pending_debt, 0); assert_eq!(mc_balance.remote_pending_debt, 0); - assert_eq!(mc_balance.in_fees, 0); - assert_eq!(mc_balance.out_fees, 0); + assert_eq!(mc_balance.in_fees, 0.into()); + assert_eq!(mc_balance.out_fees, 0.into()); } #[test] diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index c39707b69..9004902d3 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -73,8 +73,8 @@ async fn task_request_response_send_funds() { assert_eq!(mc_balance.balance, 0); assert_eq!(mc_balance.local_pending_debt, 10 + 5); assert_eq!(mc_balance.remote_pending_debt, 0); - assert_eq!(mc_balance.in_fees, 0); - assert_eq!(mc_balance.out_fees, 0); + assert_eq!(mc_balance.in_fees, 0.into()); + assert_eq!(mc_balance.out_fees, 0.into()); // -----[ResponseSendFunds]-------- // -------------------------------- @@ -109,8 +109,8 @@ async fn task_request_response_send_funds() { assert_eq!(mc_balance.balance, -15); assert_eq!(mc_balance.local_pending_debt, 0); assert_eq!(mc_balance.remote_pending_debt, 0); - assert_eq!(mc_balance.in_fees, 0); - assert_eq!(mc_balance.out_fees, 5); + assert_eq!(mc_balance.in_fees, 0.into()); + assert_eq!(mc_balance.out_fees, 5.into()); } #[test] diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index bb73e4402..d4d9f324d 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -1,6 +1,8 @@ +use std::collections::HashMap; + use common::async_rpc::OpError; use common::conn::BoxFuture; -use std::collections::HashMap; +use common::u256::U256; use proto::crypto::Uid; use proto::funder::messages::{Currency, PendingTransaction}; @@ -69,12 +71,12 @@ impl McTransaction for MutualCredit { Box::pin(async move { Ok(()) }) } - fn set_in_fees(&mut self, in_fees: u128) -> BoxFuture<'static, Result<(), OpError>> { + fn set_in_fees(&mut self, in_fees: U256) -> BoxFuture<'static, Result<(), OpError>> { self.balance.in_fees = in_fees; Box::pin(async move { Ok(()) }) } - fn set_out_fees(&mut self, out_fees: u128) -> BoxFuture<'static, Result<(), OpError>> { + fn set_out_fees(&mut self, out_fees: U256) -> BoxFuture<'static, Result<(), OpError>> { self.balance.out_fees = out_fees; Box::pin(async move { Ok(()) }) } diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 7e0b129d1..5e71c7def 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -2,6 +2,7 @@ use common::async_rpc::AsyncOpResult; use common::ser_utils::ser_string; +use common::u256::U256; use proto::crypto::Uid; use proto::funder::messages::PendingTransaction; @@ -21,10 +22,10 @@ pub struct McBalance { // TODO: in_fees and out_fees should be u256, not u128! /// Fees that were received from remote side #[serde(with = "ser_string")] - pub in_fees: u128, + pub in_fees: U256, /// Fees that were given to remote side #[serde(with = "ser_string")] - pub out_fees: u128, + pub out_fees: U256, } impl McBalance { @@ -35,8 +36,8 @@ impl McBalance { balance, local_pending_debt: 0, remote_pending_debt: 0, - in_fees: 0, - out_fees: 0, + in_fees: 0.into(), + out_fees: 0.into(), } } } @@ -46,8 +47,8 @@ pub trait McTransaction { fn set_balance(&mut self, new_balance: i128) -> AsyncOpResult<()>; fn set_local_pending_debt(&mut self, debt: u128) -> AsyncOpResult<()>; fn set_remote_pending_debt(&mut self, debt: u128) -> AsyncOpResult<()>; - fn set_in_fees(&mut self, in_fees: u128) -> AsyncOpResult<()>; - fn set_out_fees(&mut self, out_fees: u128) -> AsyncOpResult<()>; + fn set_in_fees(&mut self, in_fees: U256) -> AsyncOpResult<()>; + fn set_out_fees(&mut self, out_fees: U256) -> AsyncOpResult<()>; fn get_local_pending_transaction( &mut self, request_id: Uid, From 612a9e6b61ca1bc24c80e9f2b906bebd43ac0611 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 24 Oct 2020 10:49:16 +0300 Subject: [PATCH 128/478] funder: Some work on TokenInfo canonicalization --- .../funder/src/mutual_credit/tests/utils.rs | 4 +- components/funder/src/mutual_credit/types.rs | 41 +-------------- components/funder/src/token_channel.rs | 18 +++---- components/proto/src/funder/messages.rs | 51 +++++++++++++++---- components/signature/src/canonical.rs | 12 +++-- components/signature/src/signature_buff.rs | 12 ++--- 6 files changed, 65 insertions(+), 73 deletions(-) diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index d4d9f324d..e5da27aab 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -5,9 +5,9 @@ use common::conn::BoxFuture; use common::u256::U256; use proto::crypto::Uid; -use proto::funder::messages::{Currency, PendingTransaction}; +use proto::funder::messages::{Currency, McBalance, PendingTransaction}; -use crate::mutual_credit::types::{McBalance, McTransaction}; +use crate::mutual_credit::types::McTransaction; #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct McPendingTransactions { diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 5e71c7def..18e05ecd7 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -1,46 +1,9 @@ -// use common::safe_arithmetic::SafeSignedArithmetic; - use common::async_rpc::AsyncOpResult; -use common::ser_utils::ser_string; +// use common::ser_utils::ser_string; use common::u256::U256; use proto::crypto::Uid; -use proto::funder::messages::PendingTransaction; - -#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] -pub struct McBalance { - /// Amount of credits this side has against the remote side. - /// The other side keeps the negation of this value. - #[serde(with = "ser_string")] - pub balance: i128, - /// Frozen credits by our side - #[serde(with = "ser_string")] - pub local_pending_debt: u128, - /// Frozen credits by the remote side - #[serde(with = "ser_string")] - pub remote_pending_debt: u128, - // TODO: in_fees and out_fees should be u256, not u128! - /// Fees that were received from remote side - #[serde(with = "ser_string")] - pub in_fees: U256, - /// Fees that were given to remote side - #[serde(with = "ser_string")] - pub out_fees: U256, -} - -impl McBalance { - // TODO: Remove unused hint - #[allow(unused)] - pub fn new(balance: i128) -> McBalance { - McBalance { - balance, - local_pending_debt: 0, - remote_pending_debt: 0, - in_fees: 0.into(), - out_fees: 0.into(), - } - } -} +use proto::funder::messages::{McBalance, PendingTransaction}; pub trait McTransaction { fn get_balance(&mut self) -> AsyncOpResult; diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index cacd2dee8..51250e244 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -64,14 +64,6 @@ pub enum TcStatus { Inconsistent, } -pub struct MutualCreditInfo { - pub balance: i128, - pub local_pending_debt: u128, - pub remote_pending_debt: u128, - pub in_fees: u128, - pub out_fees: u128, -} - pub trait TcTransaction { type McTransaction: McTransaction; fn mc_transaction(&mut self, currency: Currency) -> &mut Self::McTransaction; @@ -362,8 +354,8 @@ where } } -async fn hash_mutual_credit_infos( - mutual_credit_infos: impl Stream>, +async fn hash_mc_infos( + mc_infos: impl Stream>, ) -> Result { let hasher = Hasher::new(); while let Some(mutual_credit_info) = mutual_credit_infos.next().await? { @@ -508,8 +500,10 @@ where } // Create what we expect to be TokenInfo (From the point of view of remote side): - let mutual_credit_infos = tc_transaction.list_mutual_credits(); - while let Some(mutual_credit_info) = mutual_credit_infos.next().await {} + let mc_infos = tc_transaction.list_mutual_credits(); + while let Some(mc_info) = mc_infos.next().await { + mutual_cred + } let tc_out_borrow = token_channel.get_outgoing().unwrap(); let mut expected_balances: Vec<_> = tc_out_borrow diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 5cefb7895..f35817b11 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -5,8 +5,6 @@ use std::fmt; use std::hash::Hash; use std::str::FromStr; -use std::collections::HashMap; - use serde::de::{self, Visitor}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -26,6 +24,7 @@ use crate::consts::{MAX_CURRENCY_LEN, MAX_ROUTE_LEN}; use crate::net::messages::NetAddress; use common::ser_utils::{ser_b64, ser_string, ser_vec_b64}; +use common::u256::U256; use crate::wrapper::Wrapper; @@ -180,18 +179,47 @@ impl Into for ResponseSendFundsOp { } } -#[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct MutualCreditInfo { +#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] +pub struct McBalance { + /// Amount of credits this side has against the remote side. + /// The other side keeps the negation of this value. #[serde(with = "ser_string")] pub balance: i128, + /// Frozen credits by our side #[serde(with = "ser_string")] pub local_pending_debt: u128, + /// Frozen credits by the remote side #[serde(with = "ser_string")] pub remote_pending_debt: u128, + // TODO: in_fees and out_fees should be u256, not u128! + /// Fees that were received from remote side #[serde(with = "ser_string")] - pub in_fees: u128, + pub in_fees: U256, + /// Fees that were given to remote side #[serde(with = "ser_string")] - pub out_fees: u128, + pub out_fees: U256, +} + +impl McBalance { + pub fn new(balance: i128) -> McBalance { + McBalance { + balance, + local_pending_debt: 0, + remote_pending_debt: 0, + in_fees: 0.into(), + out_fees: 0.into(), + } + } + + pub fn flip(self) -> Self { + Self { + balance: self.balance.checked_neg().unwrap(), + local_pending_debt: self.remote_pending_debt, + remote_pending_debt: self.local_pending_debt, + in_fees: self.out_fees, + out_fees: self.in_fees, + } + } } /// Implicit values that both sides agree upon. @@ -201,7 +229,10 @@ pub struct MutualCreditInfo { pub struct TokenInfo { pub local_public_key: PublicKey, pub remote_public_key: PublicKey, - pub balances: HashMap, + /// Hash of a sorted list of all the balances + pub balances_hash: HashResult, + // pub balances: HashMap, + /// Current token counter. Used as an alternative form of monotone time #[serde(with = "ser_string")] pub move_token_counter: u128, } @@ -854,8 +885,9 @@ impl BalanceInfo { } */ -impl MutualCreditInfo { - pub fn flip(self) -> MutualCreditInfo { +/* +impl McBalance { + pub fn flip(self) -> McInfo { Self { balance: self.balance.checked_neg().unwrap(), local_pending_debt: self.remote_pending_debt, @@ -865,6 +897,7 @@ impl MutualCreditInfo { } } } +*/ /* impl TokenInfo { diff --git a/components/signature/src/canonical.rs b/components/signature/src/canonical.rs index 42411b268..f7e46d7b1 100644 --- a/components/signature/src/canonical.rs +++ b/components/signature/src/canonical.rs @@ -4,7 +4,7 @@ use byteorder::{BigEndian, WriteBytesExt}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ CancelSendFundsOp, Currency, CurrencyOperations, FriendTcOp, FriendsRoute, Receipt, - RequestSendFundsOp, ResponseSendFundsOp, + RequestSendFundsOp, ResponseSendFundsOp, TokenInfo, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -334,12 +334,16 @@ impl CanonicalSerialize for CountersInfo { } } +*/ impl CanonicalSerialize for TokenInfo { fn canonical_serialize(&self) -> Vec { let mut res_bytes = Vec::new(); - res_bytes.extend_from_slice(&self.mc.canonical_serialize()); - res_bytes.extend_from_slice(&self.counters.canonical_serialize()); + res_bytes.extend_from_slice(&self.local_public_key); + res_bytes.extend_from_slice(&self.remote_public_key); + res_bytes.extend_from_slice(&self.balances_hash); + res_bytes + .write_u128::(self.move_token_counter) + .unwrap(); res_bytes } } -*/ diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index f45af4c70..df9c0fc7f 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -2,16 +2,16 @@ use byteorder::{BigEndian, WriteBytesExt}; use crypto::hash::{self, hash_buffer}; -//use proto::crypto::HashResult; - use common::int_convert::usize_to_u64; -use crate::canonical::CanonicalSerialize; +use proto::crypto::HashResult; use proto::funder::messages::{ - Currency, PendingTransaction, UnsignedMoveToken, UnsignedResponseSendFundsOp, + Currency, PendingTransaction, TokenInfo, UnsignedMoveToken, UnsignedResponseSendFundsOp, }; use proto::index_server::messages::MutationsUpdate; +use crate::canonical::CanonicalSerialize; + pub const FUNDS_RESPONSE_PREFIX: &[u8] = b"FUND_RESPONSE"; pub const FUNDS_CANCEL_PREFIX: &[u8] = b"FUND_CANCEL"; @@ -90,11 +90,9 @@ where } */ -/* pub fn hash_token_info(token_info: &TokenInfo) -> HashResult { - sha_512_256(&token_info.canonical_serialize()) + hash_buffer(&token_info.canonical_serialize()) } -*/ /* /// Hash operations and local_address: From bf20d6db5712199cfc34bc17627c69dbdc57477d Mon Sep 17 00:00:00 2001 From: real Date: Sat, 24 Oct 2020 11:52:54 +0300 Subject: [PATCH 129/478] signature: Added canonicalization code for McBalance --- components/signature/src/canonical.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/components/signature/src/canonical.rs b/components/signature/src/canonical.rs index f7e46d7b1..617ac041b 100644 --- a/components/signature/src/canonical.rs +++ b/components/signature/src/canonical.rs @@ -3,7 +3,7 @@ use byteorder::{BigEndian, WriteBytesExt}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ - CancelSendFundsOp, Currency, CurrencyOperations, FriendTcOp, FriendsRoute, Receipt, + CancelSendFundsOp, Currency, CurrencyOperations, FriendTcOp, FriendsRoute, McBalance, Receipt, RequestSendFundsOp, ResponseSendFundsOp, TokenInfo, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; @@ -335,6 +335,28 @@ impl CanonicalSerialize for CountersInfo { } */ + +impl CanonicalSerialize for McBalance { + fn canonical_serialize(&self) -> Vec { + let mut res_bytes = Vec::new(); + res_bytes.write_i128::(self.balance).unwrap(); + res_bytes + .write_u128::(self.local_pending_debt) + .unwrap(); + res_bytes + .write_u128::(self.remote_pending_debt) + .unwrap(); + + // Write in/out fees as big endian: + let mut temp_array = [0u8; 16]; + self.in_fees.to_big_endian(&mut temp_array); + res_bytes.extend_from_slice(&temp_array); + self.out_fees.to_big_endian(&mut temp_array); + res_bytes.extend_from_slice(&temp_array); + + res_bytes + } +} impl CanonicalSerialize for TokenInfo { fn canonical_serialize(&self) -> Vec { let mut res_bytes = Vec::new(); From 203dba955fab9c6f12a951b7e4c2cf441d75af45 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 24 Oct 2020 11:53:51 +0300 Subject: [PATCH 130/478] funder: token_channel: Work on handle_incoming_token_match(). Not done yet --- components/funder/src/token_channel.rs | 154 ++++++++++--------------- 1 file changed, 58 insertions(+), 96 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 51250e244..85bba5bd8 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -6,7 +6,7 @@ use derive_more::From; use futures::channel::{mpsc, oneshot}; use futures::SinkExt; -use futures::Stream; +use futures::{Stream, StreamExt, TryStreamExt}; use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; use common::conn::BoxFuture; @@ -18,14 +18,14 @@ use im::hashset::HashSet as ImHashSet; use signature::canonical::CanonicalSerialize; -use crypto::hash::Hasher; +use crypto::hash::{hash_buffer, Hasher}; use crypto::identity::compare_public_key; use proto::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ - BalanceInfo, CountersInfo, Currency, CurrencyBalanceInfo, CurrencyOperations, McInfo, + BalanceInfo, CountersInfo, Currency, CurrencyBalanceInfo, CurrencyOperations, McBalance, MoveToken, PendingTransaction, TokenInfo, UnsignedMoveToken, }; use signature::signature_buff::hash_token_info; @@ -37,7 +37,7 @@ use crate::mutual_credit::incoming::{ process_operations_list, IncomingMessage, ProcessTransListError, }; use crate::mutual_credit::outgoing::queue_operation; -use crate::mutual_credit::types::{McBalance, McOp, McTransaction}; +use crate::mutual_credit::types::{McOp, McTransaction}; use crate::types::{create_hashed, create_unsigned_move_token, MoveTokenHashed}; @@ -75,11 +75,13 @@ pub trait TcTransaction { // get_move_token_in() -> Option; // get_move_token_out() -> Option>; - fn get_move_token_counter(&mut self) -> u128; + fn get_move_token_counter(&mut self) -> AsyncOpResult; + fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; + fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult; /// Return a sorted list of all mutual credits - fn list_mutual_credits(&mut self) -> AsyncOpStream; + fn list_mutual_credits(&mut self) -> AsyncOpStream<(Currency, McBalance)>; // add_local_currency(currency: Currency); // TODO: Possibly add boolean result here? And to other remove commands? @@ -285,6 +287,7 @@ fn initial_move_token( async fn handle_in_move_token( tc_transaction: &mut impl TcTransaction, new_move_token: MoveToken, + local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result, ReceiveMoveTokenError> where @@ -299,6 +302,7 @@ where tc_transaction, move_token_out, new_move_token, + local_public_key, remote_public_key, ) .await @@ -328,6 +332,7 @@ async fn handle_in_move_token_dir_out( tc_transaction: &mut impl TcTransaction, move_token_out: MoveToken, new_move_token: MoveToken, + local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result, ReceiveMoveTokenError> where @@ -339,6 +344,7 @@ where tc_transaction, move_token_out, new_move_token, + local_public_key, remote_public_key, ) .await?, @@ -354,34 +360,33 @@ where } } +// TODO: Should we move this function to offset-signature crate? async fn hash_mc_infos( - mc_infos: impl Stream>, -) -> Result { - let hasher = Hasher::new(); - while let Some(mutual_credit_info) = mutual_credit_infos.next().await? { - hasher.update(mutual_credit_info.canonical_serialize()); + mut mc_infos: impl Stream> + Unpin, +) -> Result { + let mut hasher = Hasher::new(); + // Last seen currency, used to verify sorted order: + let mut opt_last_currency: Option = None; + + while let Some(item) = mc_infos.next().await { + let (currency, mc_balance) = item?; + // Ensure that the list is sorted: + if let Some(last_currency) = opt_last_currency { + assert!(last_currency <= currency); + } + // Update the last currency: + opt_last_currency = Some(currency.clone()); + hasher.update(&hash_buffer(¤cy.canonical_serialize())); + hasher.update(&mc_balance.canonical_serialize()); } Ok(hasher.finalize()) } -fn hash_token_info_stream( - local_public_key: PublicKey, - remote_public_key: PublicKey, - move_token_counter: u128, - mutual_credit_infos_hash: HashResult, -) -> HashResult { - Hahser::new() - .chain(local_public_key) - .chain(remote_public_key) - .chain(move_token_counter.canonical_serialize()) - .chain(mutual_credits_infos_hash) - .finalize() -} - async fn handle_incoming_token_match( tc_transaction: &mut impl TcTransaction, move_token_out: MoveToken, new_move_token: MoveToken, // remote_max_debts: &ImHashMap, + local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result, ReceiveMoveTokenError> where @@ -450,9 +455,8 @@ where tc_transaction .remove_remote_currency(diff_currency.clone()) .await?; - // TODO: We need to report outside that we removed this currency somehow. - // TODO: Somehow unite all code for removing remote currencies. - todo!(); + // TODO: Do We need to report outside that we removed this currency somehow? + // TODO: Somehow unite all code for removing remote currencies. } else { // We are not allowed to remove this currency! return Err(ReceiveMoveTokenError::CanNotRemoveCurrencyInUse); @@ -461,8 +465,7 @@ where tc_transaction .remove_remote_currency(diff_currency.clone()) .await?; - // TODO: We need to report outside that we removed this currency somehow. - todo!(); + // TODO: Do We need to report outside that we removed this currency somehow? } } } @@ -499,81 +502,40 @@ where .push(move_token_received_currency); } + let move_token_counter = tc_transaction.get_move_token_counter().await?; + let new_move_token_counter = move_token_counter + .checked_add(1) + .ok_or(ReceiveMoveTokenError::MoveTokenCounterOverflow)?; + + // Calculate `info_hash` as seen by the remote side. // Create what we expect to be TokenInfo (From the point of view of remote side): let mc_infos = tc_transaction.list_mutual_credits(); - while let Some(mc_info) = mc_infos.next().await { - mutual_cred - } - - let tc_out_borrow = token_channel.get_outgoing().unwrap(); - let mut expected_balances: Vec<_> = tc_out_borrow - .mutual_credits - .iter() - .map(|(currency, mc)| CurrencyBalanceInfo { - currency: currency.clone(), - balance_info: BalanceInfo { - balance: mc.state().balance.balance, - local_pending_debt: mc.state().balance.local_pending_debt, - remote_pending_debt: mc.state().balance.remote_pending_debt, - }, - }) - .collect(); - - // Canonicalize: - expected_balances.sort_by(|cbi1, cbi2| cbi1.currency.cmp(&cbi2.currency)); - let expected_token_info = TokenInfo { - mc: McInfo { - local_public_key: tc_out_borrow - .tc_outgoing - .token_info - .mc - .local_public_key - .clone(), - remote_public_key: tc_out_borrow - .tc_outgoing - .token_info - .mc - .remote_public_key - .clone(), - balances: expected_balances, - }, - counters: CountersInfo { - inconsistency_counter: tc_out_borrow - .tc_outgoing - .token_info - .counters - .inconsistency_counter, - move_token_counter: tc_out_borrow - .tc_outgoing - .token_info - .counters - .move_token_counter - .checked_add(1) - .ok_or(ReceiveMoveTokenError::MoveTokenCounterOverflow)?, - }, - } - .flip(); - - // Verify stated balances: - let mutual_credit_infos_hash = hash_mutual_credit_infos(mutual_credit_infos).await?; + let token_info = TokenInfo { + local_public_key: remote_public_key.clone(), + remote_public_key: local_public_key.clone(), + balances_hash: hash_mc_infos( + mc_infos.map_ok(|(currency, mc_balance)| (currency, mc_balance.flip())), + ) + .await?, + move_token_counter: new_move_token_counter, + }; - let info_hash = hash_token_info_stream( - local_public_key, - remote_public_key, - move_token_counter, - mutual_credit_infos_hash, - ); + let info_hash = hash_token_info(&token_info); if new_move_token.info_hash != info_hash { return Err(ReceiveMoveTokenError::InvalidTokenInfo); } - move_token_received - .mutations - .push(TcMutation::SetDirection(SetDirection::Incoming( - create_hashed(&new_move_token, &expected_token_info), - ))); + // Update move_token_counter: + tc_transaction + .set_move_token_counter(new_move_token_counter) + .await?; + + // Set direction to outgoing, with the newly received move token: + tc_transaction + .set_direction_outgoing(new_move_token) + .await?; Ok(move_token_received) } From b1255d0dcd8c55647a0b17ce4df691976c8c2990 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 24 Oct 2020 12:58:11 +0300 Subject: [PATCH 131/478] funder: token_channel: work on handle_out_move_token(). Not compiling yet --- components/funder/src/lib.rs | 2 +- components/funder/src/token_channel.rs | 204 ++++++++++++++++++--- components/funder/src/types.rs | 27 +-- components/proto/src/funder/messages.rs | 4 + components/signature/src/signature_buff.rs | 6 +- components/signature/src/verify.rs | 4 +- 6 files changed, 194 insertions(+), 53 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index bdf1d22b3..d0e92ebea 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -28,7 +28,7 @@ mod mutual_credit; // pub mod report; // mod state; // #[allow(unused)] -// mod token_channel; +mod token_channel; // // For testing: diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 85bba5bd8..6679d3a4c 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -1,18 +1,14 @@ -use std::cmp::Ordering; -use std::collections::HashMap as ImHashMap; +// use std::cmp::Ordering; use std::convert::TryFrom; use derive_more::From; -use futures::channel::{mpsc, oneshot}; -use futures::SinkExt; +use futures::channel::oneshot; +// use futures::SinkExt; use futures::{Stream, StreamExt, TryStreamExt}; use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; -use common::conn::BoxFuture; -use common::{get_out_type, ops_trait}; - -use im::hashset::HashSet as ImHashSet; +// use common::conn::BoxFuture; // use common::ser_utils::ser_map_str_any; @@ -21,12 +17,14 @@ use signature::canonical::CanonicalSerialize; use crypto::hash::{hash_buffer, Hasher}; use crypto::identity::compare_public_key; +use identity::IdentityClient; + use proto::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ BalanceInfo, CountersInfo, Currency, CurrencyBalanceInfo, CurrencyOperations, McBalance, - MoveToken, PendingTransaction, TokenInfo, UnsignedMoveToken, + MoveToken, PendingTransaction, TokenInfo, }; use signature::signature_buff::hash_token_info; use signature::verify::verify_move_token; @@ -36,10 +34,10 @@ use database::interface::funder::CurrencyConfig; use crate::mutual_credit::incoming::{ process_operations_list, IncomingMessage, ProcessTransListError, }; -use crate::mutual_credit::outgoing::queue_operation; +use crate::mutual_credit::outgoing::{queue_operation, QueueOperationError}; use crate::mutual_credit::types::{McOp, McTransaction}; -use crate::types::{create_hashed, create_unsigned_move_token, MoveTokenHashed}; +use crate::types::{create_hashed, MoveTokenHashed}; /* #[derive(Arbitrary, Debug, Clone, Serialize, Deserialize)] @@ -90,6 +88,9 @@ pub trait TcTransaction { fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; + fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; @@ -100,6 +101,7 @@ pub trait TcTransaction { fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()>; } +/* /// The currencies set to be active by two sides of the token channel. /// Only currencies that are active on both sides (Intersection) can be used for trading. #[derive(Arbitrary, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] @@ -122,6 +124,7 @@ impl ActiveCurrencies { self.local.clone().intersection(self.remote.clone()) } } +*/ #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct TcOutgoing { @@ -215,15 +218,15 @@ pub enum ReceiveMoveTokenOutput { #[derive(Debug)] pub struct SendMoveTokenOutput { - pub unsigned_move_token: UnsignedMoveToken, - // pub mutations: Vec>, - pub token_info: TokenInfo, + pub move_token: MoveToken, } -#[derive(Debug)] +#[derive(Debug, From)] pub enum SendMoveTokenError { - LocalCurrencyAlreadyExists, + InvalidTokenChannelStatus, CanNotRemoveCurrencyInUse, + QueueOperationError(QueueOperationError), + OpError(OpError), } /// Create a token from a public key @@ -397,7 +400,7 @@ where // This allows the genesis move token to occur smoothly, even though its signature // is not correct. // TODO: Check if the above statement is still true. - if !verify_move_token(new_move_token.clone(), &remote_public_key) { + if !verify_move_token(&new_move_token, &remote_public_key) { return Err(ReceiveMoveTokenError::InvalidSignature); } @@ -416,9 +419,9 @@ where // - Add to remote currencies every currency that is in the xor set, but not in the current // set. // - Remove from remote currencies currencies that satisfy the following requirements: - // - (1) in the xor set. - // - (2) in the remote - // - (3) (Not in the local set) or (in the local set with balance zero and zero pending debts) + // - (1) in the xor set. + // - (2) in the remote set + // - (3) (Not in the local set) or (in the local set with balance zero and zero pending debts) for diff_currency in &new_move_token.currencies_diff { // Check if we need to add currency: if !tc_transaction @@ -540,8 +543,167 @@ where Ok(move_token_received) } -fn handle_out_move_token(tc_transaction: &mut impl TcTransaction) { +/* +pub async fn sign_move_token<'a, B>( + unsigned_move_token: UnsignedMoveToken, + identity_client: &'a mut IdentityClient, +) -> MoveToken +where + B: CanonicalSerialize + Clone + 'a, +{ + let signature_buff = move_token_signature_buff(unsigned_move_token.clone()); + let new_token = identity_client + .request_signature(signature_buff) + .await + .unwrap(); + + MoveToken { + old_token: unsigned_move_token.old_token, + currencies_operations: unsigned_move_token.currencies_operations, + relays_diff: unsigned_move_token.relays_diff, + currencies_diff: unsigned_move_token.currencies_diff, + info_hash: unsigned_move_token.info_hash, + new_token, + } +} +*/ + +async fn handle_out_move_token( + tc_transaction: &mut impl TcTransaction, + identity_client: &mut IdentityClient, + currencies_operations: Vec, + relays_diff: Vec>, + currencies_diff: Vec, +) -> Result, SendMoveTokenError> { + // We expect that our current state is incoming: + let move_token_in = match tc_transaction.get_tc_status().await? { + TcStatus::ConsistentIn(move_token_in) => move_token_in, + TcStatus::ConsistentOut(_move_token_out, _move_token_in) => { + return Err(SendMoveTokenError::InvalidTokenChannelStatus) + } + }; + + // Handle currencies_diff: + for diff_currency in ¤cies_diff { + // Check if we need to add currency: + if !tc_transaction + .is_local_currency(diff_currency.clone()) + .await? + { + // Add a new local currency. + tc_transaction + .add_local_currency(diff_currency.clone()) + .await?; + + // If we also have this currency as a remote currency, add a new mutual credit: + if tc_transaction + .is_remote_currency(diff_currency.clone()) + .await? + { + tc_transaction.add_mutual_credit(diff_currency.clone()); + } + } else { + let is_remote_currency = tc_transaction + .is_remote_currency(diff_currency.clone()) + .await?; + if is_remote_currency { + let mc_balance = tc_transaction + .mc_transaction(diff_currency.clone()) + .get_balance() + .await?; + if mc_balance.balance == 0 + && mc_balance.remote_pending_debt == 0 + && mc_balance.local_pending_debt == 0 + { + // We may remove the currency if the balance and pending debts are exactly + // zero: + tc_transaction + .remove_local_currency(diff_currency.clone()) + .await?; + // TODO: Do We need to report outside that we removed this currency somehow? + // TODO: Somehow unite all code for removing local currencies. + } else { + // We are not allowed to remove this currency! + // TODO: Should be an error instead? + return Err(SendMoveTokenError::CanNotRemoveCurrencyInUse); + } + } else { + tc_transaction + .remove_remote_currency(diff_currency.clone()) + .await?; + // TODO: Do We need to report outside that we removed this currency somehow? + } + } + } + + // TODO: Continue here: todo!(); + + // Update mutual credits: + for currency_operations in ¤cies_operations { + for operation in currency_operations.operations { + let currency = currency_operations.currency.clone(); + queue_operation( + tc_transaction.mc_transaction(currency.clone()), + operation, + ¤cy, + &local_public_key, + ) + .await?; + } + } + + let tc_in_borrow = token_channel.get_incoming().unwrap(); + + let mut balances: Vec<_> = tc_in_borrow + .mutual_credits + .iter() + .map(|(currency, mutual_credit)| CurrencyBalanceInfo { + currency: currency.clone(), + balance_info: BalanceInfo { + balance: mutual_credit.state().balance.balance, + local_pending_debt: mutual_credit.state().balance.local_pending_debt, + remote_pending_debt: mutual_credit.state().balance.remote_pending_debt, + }, + }) + .collect(); + + // Canonicalize balances: + balances.sort_by(|cbi1, cbi2| cbi1.currency.cmp(&cbi2.currency)); + + let tc_in_borrow = token_channel.get_incoming().unwrap(); + let cur_token_info = &tc_in_borrow.tc_incoming.move_token_in.token_info; + + let token_info = TokenInfo { + mc: McInfo { + local_public_key: cur_token_info.mc.remote_public_key.clone(), + remote_public_key: cur_token_info.mc.local_public_key.clone(), + balances, + }, + counters: CountersInfo { + move_token_counter: cur_token_info.counters.move_token_counter.wrapping_add(1), + inconsistency_counter: cur_token_info.counters.inconsistency_counter, + }, + }; + + let mut move_token = MoveToken { + old_token: move_token_in.new_token, + currencies_operations, + relays_diff, + currencies_diff, + info_hash, + // Still not known: + new_token: Signature::from(&[0; Signature::len()]), + }; + + // Fill in signature: + let signature_buff = move_token_signature_buff(move_token.clone()); + move_token.new_token = identity_client + .request_signature(signature_buff) + .await + .unwrap(); + + Ok(move_token) } /* diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 066ea9983..2a14ad0e4 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -8,36 +8,13 @@ use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ CancelSendFundsOp, ChannelerUpdateFriend, Currency, FriendMessage, FunderIncomingControl, FunderOutgoingControl, MoveToken, PendingTransaction, RequestSendFundsOp, ResponseSendFundsOp, - TokenInfo, UnsignedMoveToken, UnsignedResponseSendFundsOp, + TokenInfo, UnsignedResponseSendFundsOp, }; -use signature::signature_buff::{create_response_signature_buffer, move_token_signature_buff}; +use signature::signature_buff::create_response_signature_buffer; use identity::IdentityClient; -pub async fn sign_move_token<'a, B>( - unsigned_move_token: UnsignedMoveToken, - identity_client: &'a mut IdentityClient, -) -> MoveToken -where - B: CanonicalSerialize + Clone + 'a, -{ - let signature_buff = move_token_signature_buff(unsigned_move_token.clone()); - let new_token = identity_client - .request_signature(signature_buff) - .await - .unwrap(); - - MoveToken { - old_token: unsigned_move_token.old_token, - currencies_operations: unsigned_move_token.currencies_operations, - relays_diff: unsigned_move_token.relays_diff, - currencies_diff: unsigned_move_token.currencies_diff, - info_hash: unsigned_move_token.info_hash, - new_token, - } -} - pub async fn create_response_send_funds<'a>( currency: &Currency, pending_transaction: &'a PendingTransaction, diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index f35817b11..f673f9b26 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -259,6 +259,7 @@ pub struct MoveToken { pub new_token: Signature, } +/* #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct UnsignedMoveToken { #[serde(with = "ser_b64")] @@ -269,7 +270,9 @@ pub struct UnsignedMoveToken { #[serde(with = "ser_b64")] pub info_hash: HashResult, } +*/ +/* impl Into> for MoveToken { fn into(self) -> UnsignedMoveToken { UnsignedMoveToken { @@ -281,6 +284,7 @@ impl Into> for MoveToken { } } } +*/ #[capnp_conv(crate::common_capnp::currency)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index df9c0fc7f..bab7f263f 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -6,7 +6,7 @@ use common::int_convert::usize_to_u64; use proto::crypto::HashResult; use proto::funder::messages::{ - Currency, PendingTransaction, TokenInfo, UnsignedMoveToken, UnsignedResponseSendFundsOp, + Currency, MoveToken, PendingTransaction, TokenInfo, UnsignedResponseSendFundsOp, }; use proto::index_server::messages::MutationsUpdate; @@ -113,12 +113,10 @@ where } */ -pub fn move_token_signature_buff(move_token: MT) -> Vec +pub fn move_token_signature_buff(move_token: &MoveToken) -> Vec where B: CanonicalSerialize + Clone, - MT: Into>, { - let move_token: UnsignedMoveToken = move_token.into(); let mut sig_buffer = Vec::new(); sig_buffer.extend_from_slice(&hash_buffer(TOKEN_NEXT)); sig_buffer.extend_from_slice(&move_token.old_token); diff --git a/components/signature/src/verify.rs b/components/signature/src/verify.rs index c4e2c1177..547f63fd9 100644 --- a/components/signature/src/verify.rs +++ b/components/signature/src/verify.rs @@ -62,11 +62,11 @@ pub fn verify_commit(commit: &Commit, local_public_key: &PublicKey) -> bool { } /// Verify that new_token is a valid signature over the rest of the fields. -pub fn verify_move_token(move_token: MoveToken, public_key: &PublicKey) -> bool +pub fn verify_move_token(move_token: &MoveToken, public_key: &PublicKey) -> bool where B: CanonicalSerialize + Clone, { - let sig_buffer = move_token_signature_buff(move_token.clone()); + let sig_buffer = move_token_signature_buff(move_token); verify_signature(&sig_buffer, public_key, &move_token.new_token) } From e0415817f760bf223179e3a8a2e93bb894d53a11 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 24 Oct 2020 16:58:21 +0300 Subject: [PATCH 132/478] funder: Initial impl for handle_out_move_token(). Not done yet --- components/funder/src/token_channel.rs | 75 ++++++++++++-------------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 6679d3a4c..c3887bb48 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -26,7 +26,7 @@ use proto::funder::messages::{ BalanceInfo, CountersInfo, Currency, CurrencyBalanceInfo, CurrencyOperations, McBalance, MoveToken, PendingTransaction, TokenInfo, }; -use signature::signature_buff::hash_token_info; +use signature::signature_buff::{hash_token_info, move_token_signature_buff}; use signature::verify::verify_move_token; use database::interface::funder::CurrencyConfig; @@ -225,6 +225,7 @@ pub struct SendMoveTokenOutput { pub enum SendMoveTokenError { InvalidTokenChannelStatus, CanNotRemoveCurrencyInUse, + MoveTokenCounterOverflow, QueueOperationError(QueueOperationError), OpError(OpError), } @@ -366,7 +367,7 @@ where // TODO: Should we move this function to offset-signature crate? async fn hash_mc_infos( mut mc_infos: impl Stream> + Unpin, -) -> Result { +) -> Result { let mut hasher = Hasher::new(); // Last seen currency, used to verify sorted order: let mut opt_last_currency: Option = None; @@ -574,7 +575,12 @@ async fn handle_out_move_token( currencies_operations: Vec, relays_diff: Vec>, currencies_diff: Vec, -) -> Result, SendMoveTokenError> { + local_public_key: &PublicKey, + remote_public_key: &PublicKey, +) -> Result, SendMoveTokenError> +where + B: CanonicalSerialize + Clone, +{ // We expect that our current state is incoming: let move_token_in = match tc_transaction.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => move_token_in, @@ -636,54 +642,31 @@ async fn handle_out_move_token( } } - // TODO: Continue here: - todo!(); - // Update mutual credits: for currency_operations in ¤cies_operations { - for operation in currency_operations.operations { - let currency = currency_operations.currency.clone(); + for operation in currency_operations.operations.iter().cloned() { queue_operation( - tc_transaction.mc_transaction(currency.clone()), + tc_transaction.mc_transaction(currency_operations.currency.clone()), operation, - ¤cy, - &local_public_key, + ¤cy_operations.currency, + local_public_key, ) .await?; } } - let tc_in_borrow = token_channel.get_incoming().unwrap(); - - let mut balances: Vec<_> = tc_in_borrow - .mutual_credits - .iter() - .map(|(currency, mutual_credit)| CurrencyBalanceInfo { - currency: currency.clone(), - balance_info: BalanceInfo { - balance: mutual_credit.state().balance.balance, - local_pending_debt: mutual_credit.state().balance.local_pending_debt, - remote_pending_debt: mutual_credit.state().balance.remote_pending_debt, - }, - }) - .collect(); - - // Canonicalize balances: - balances.sort_by(|cbi1, cbi2| cbi1.currency.cmp(&cbi2.currency)); - - let tc_in_borrow = token_channel.get_incoming().unwrap(); - let cur_token_info = &tc_in_borrow.tc_incoming.move_token_in.token_info; + let new_move_token_counter = tc_transaction + .get_move_token_counter() + .await? + .checked_add(1) + .ok_or(SendMoveTokenError::MoveTokenCounterOverflow)?; + let mc_infos = tc_transaction.list_mutual_credits(); let token_info = TokenInfo { - mc: McInfo { - local_public_key: cur_token_info.mc.remote_public_key.clone(), - remote_public_key: cur_token_info.mc.local_public_key.clone(), - balances, - }, - counters: CountersInfo { - move_token_counter: cur_token_info.counters.move_token_counter.wrapping_add(1), - inconsistency_counter: cur_token_info.counters.inconsistency_counter, - }, + local_public_key: local_public_key.clone(), + remote_public_key: remote_public_key.clone(), + balances_hash: hash_mc_infos(mc_infos).await?, + move_token_counter: new_move_token_counter, }; let mut move_token = MoveToken { @@ -691,18 +674,26 @@ async fn handle_out_move_token( currencies_operations, relays_diff, currencies_diff, - info_hash, + info_hash: hash_token_info(&token_info), // Still not known: new_token: Signature::from(&[0; Signature::len()]), }; // Fill in signature: - let signature_buff = move_token_signature_buff(move_token.clone()); + let signature_buff = move_token_signature_buff(&move_token); move_token.new_token = identity_client .request_signature(signature_buff) .await .unwrap(); + // TODO: We need to be able to remember the last incoming move token. + // How to store this data inside the database? How to save it here? + + // Set the direction to be outgoing: + tc_transaction + .set_direction_outgoing(move_token.clone()) + .await?; + Ok(move_token) } From 629f0bd16d8153efdafb5f0d72cf47f4e86de2a5 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 24 Oct 2020 19:34:11 +0300 Subject: [PATCH 133/478] database: Saving last incoming move token for in outgoing state. --- components/database/src/create.rs | 103 +++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 8 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 1dc9c6a1f..b732a4029 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -98,14 +98,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { CHECK (is_consistent = true) DEFAULT true, move_token_counter BLOB NOT NULL, - opt_move_token_out BLOB, - opt_move_token_in BLOB, - -- Two options: - -- 1. Incoming mode: No outgoing token, there is incoming token. - -- 2. Outgoing mode: We keep the last incoming token if exists, - -- and there is a pending outgoing token. - CHECK ((opt_move_token_out IS NULL AND opt_move_token_in IS NOT NULL) - OR (opt_move_token_out IS NOT NULL)), + is_incoming BOOL NOT NULL, + FOREIGN KEY(friend_public_key, is_consistent) REFERENCES friends(friend_public_key, is_consistent) ON DELETE CASCADE @@ -118,6 +112,99 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE TABLE consistent_channels_incoming( + friend_public_key BLOB NOT NULL PRIMARY KEY, + is_incoming BOOL NOT NULL + CHECK (is_incoming = true) + DEFAULT true, + old_token BLOB NOT NULL, + new_token BLOB NOT NULL, + + FOREIGN KEY(friend_public_key, is_incoming) + REFERENCES consistent_channels(friend_public_key, is_incoming) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_consistent_channels_incoming ON consistent_channels_incoming(friend_public_key);", + params![], + )?; + + tx.execute( + "CREATE TABLE consistent_channels_outgoing( + friend_public_key BLOB NOT NULL PRIMARY KEY, + is_incoming BOOL NOT NULL + CHECK (is_incoming = false) + DEFAULT false, + move_token_out BLOB NOT NULL, + + -- Do we save a previously received hashed incoming move token? + is_with_incoming BOOL NOT NULL, + + FOREIGN KEY(friend_public_key, is_incoming) + REFERENCES consistent_channels(friend_public_key, is_incoming) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_consistent_channels_outgoing ON consistent_channels_outgoing(friend_public_key);", + params![], + )?; + + tx.execute( + "CREATE TABLE consistent_channels_outgoing_with_incoming( + friend_public_key BLOB NOT NULL PRIMARY KEY, + is_with_incoming BOOL NOT NULL + CHECK (is_with_incoming = true) + DEFAULT true, + + -- Data saved for last incoming move token. + -- The list of balances for the last incoming move token is saved in a separate table. + old_token BLOB NOT NULL, + move_token_counter BLOB NOT NULL, + new_token BLOB NOT NULL, + + FOREIGN KEY(friend_public_key, is_with_incoming) + REFERENCES consistent_channels_outgoing(friend_public_key, is_with_incoming) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_consistent_channels_outgoing_with_incoming ON consistent_channels_outgoing_with_incoming(friend_public_key);", + params![], + )?; + + tx.execute( + "CREATE TABLE last_incoming_balances( + friend_public_key BLOB NOT NULL, + currency TEXT NOT NULL, + + balance BLOB NOT NULL, + local_pending_debt BLOB NOT NULL, + remote_pending_debt BLOB NOT NULL, + in_fees BLOB NOT NULL, + out_fees BLOB NOT NULL, + + PRIMARY KEY(friend_public_key, currency), + FOREIGN KEY(friend_public_key) + REFERENCES consistent_channels_outgoing_with_incoming(friend_public_key) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_last_incoming_balances ON last_incoming_balances(friend_public_key, currency);", + params![], + )?; + tx.execute( "CREATE TABLE inconsistent_channels( friend_public_key BLOB NOT NULL PRIMARY KEY, From 3dfdfa18b649d80dd45a9993dd59e164e05e01d3 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 24 Oct 2020 19:44:20 +0300 Subject: [PATCH 134/478] funder: todo comment --- components/funder/src/token_channel.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index c3887bb48..b34693498 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -56,6 +56,8 @@ pub enum TcOpError { pub type TcOpResult = Result; pub type TcOpSenderResult = oneshot::Sender>; +// TODO: MoveTokenHashed contains too much information. +// We may remove some of the information, for example: local and remote public keys. pub enum TcStatus { ConsistentIn(MoveTokenHashed), ConsistentOut(MoveToken, MoveTokenHashed), From 8aeb3a26f19d8c72702ab54df0b4d228ba301458 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 29 Oct 2020 13:26:56 +0200 Subject: [PATCH 135/478] funder: Removed redundant information from TokenInfo --- components/funder/src/lib.rs | 2 +- components/funder/src/token_channel.rs | 18 +++++++--------- components/proto/src/funder/messages.rs | 2 -- components/signature/src/canonical.rs | 4 +++- components/signature/src/signature_buff.rs | 24 +++++++++++++++++----- 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index d0e92ebea..293488f9b 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -27,7 +27,7 @@ extern crate quickcheck_derive; mod mutual_credit; // pub mod report; // mod state; -// #[allow(unused)] +#[allow(unused)] mod token_channel; // // For testing: diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index b34693498..7bdfabefd 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -23,8 +23,7 @@ use proto::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ - BalanceInfo, CountersInfo, Currency, CurrencyBalanceInfo, CurrencyOperations, McBalance, - MoveToken, PendingTransaction, TokenInfo, + Currency, CurrencyOperations, McBalance, MoveToken, PendingTransaction, TokenInfo, }; use signature::signature_buff::{hash_token_info, move_token_signature_buff}; use signature::verify::verify_move_token; @@ -35,7 +34,7 @@ use crate::mutual_credit::incoming::{ process_operations_list, IncomingMessage, ProcessTransListError, }; use crate::mutual_credit::outgoing::{queue_operation, QueueOperationError}; -use crate::mutual_credit::types::{McOp, McTransaction}; +use crate::mutual_credit::types::McTransaction; use crate::types::{create_hashed, MoveTokenHashed}; @@ -254,6 +253,7 @@ fn rand_nonce_from_public_key(public_key: &PublicKey) -> RandValue { RandValue::try_from(&public_key_hash.as_ref()[..RandValue::len()]).unwrap() } +/* /// Create an initial move token in the relationship between two public keys. /// To canonicalize the initial move token (Having an equal move token for both sides), we sort the /// two public keys in some way. @@ -263,8 +263,6 @@ fn initial_move_token( ) -> (MoveToken, TokenInfo) { let token_info = TokenInfo { mc: McInfo { - local_public_key: low_public_key.clone(), - remote_public_key: high_public_key.clone(), balances: Vec::new(), }, counters: CountersInfo { @@ -289,6 +287,7 @@ fn initial_move_token( (move_token, token_info) } +*/ async fn handle_in_move_token( tc_transaction: &mut impl TcTransaction, @@ -518,8 +517,6 @@ where let mc_infos = tc_transaction.list_mutual_credits(); let token_info = TokenInfo { - local_public_key: remote_public_key.clone(), - remote_public_key: local_public_key.clone(), balances_hash: hash_mc_infos( mc_infos.map_ok(|(currency, mc_balance)| (currency, mc_balance.flip())), ) @@ -527,7 +524,7 @@ where move_token_counter: new_move_token_counter, }; - let info_hash = hash_token_info(&token_info); + let info_hash = hash_token_info(remote_public_key, local_public_key, &token_info); if new_move_token.info_hash != info_hash { return Err(ReceiveMoveTokenError::InvalidTokenInfo); @@ -589,6 +586,7 @@ where TcStatus::ConsistentOut(_move_token_out, _move_token_in) => { return Err(SendMoveTokenError::InvalidTokenChannelStatus) } + TcStatus::Inconsistent => return Err(SendMoveTokenError::InvalidTokenChannelStatus), }; // Handle currencies_diff: @@ -665,8 +663,6 @@ where let mc_infos = tc_transaction.list_mutual_credits(); let token_info = TokenInfo { - local_public_key: local_public_key.clone(), - remote_public_key: remote_public_key.clone(), balances_hash: hash_mc_infos(mc_infos).await?, move_token_counter: new_move_token_counter, }; @@ -676,7 +672,7 @@ where currencies_operations, relays_diff, currencies_diff, - info_hash: hash_token_info(&token_info), + info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), // Still not known: new_token: Signature::from(&[0; Signature::len()]), }; diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index f673f9b26..ba873937b 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -227,8 +227,6 @@ impl McBalance { /// A hash of this structure is included inside MoveToken. #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct TokenInfo { - pub local_public_key: PublicKey, - pub remote_public_key: PublicKey, /// Hash of a sorted list of all the balances pub balances_hash: HashResult, // pub balances: HashMap, diff --git a/components/signature/src/canonical.rs b/components/signature/src/canonical.rs index 617ac041b..371d8124e 100644 --- a/components/signature/src/canonical.rs +++ b/components/signature/src/canonical.rs @@ -4,7 +4,7 @@ use byteorder::{BigEndian, WriteBytesExt}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ CancelSendFundsOp, Currency, CurrencyOperations, FriendTcOp, FriendsRoute, McBalance, Receipt, - RequestSendFundsOp, ResponseSendFundsOp, TokenInfo, + RequestSendFundsOp, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -357,6 +357,7 @@ impl CanonicalSerialize for McBalance { res_bytes } } +/* impl CanonicalSerialize for TokenInfo { fn canonical_serialize(&self) -> Vec { let mut res_bytes = Vec::new(); @@ -369,3 +370,4 @@ impl CanonicalSerialize for TokenInfo { res_bytes } } +*/ diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index bab7f263f..e9e76896f 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -1,10 +1,10 @@ use byteorder::{BigEndian, WriteBytesExt}; -use crypto::hash::{self, hash_buffer}; +use crypto::hash; use common::int_convert::usize_to_u64; -use proto::crypto::HashResult; +use proto::crypto::{HashResult, PublicKey}; use proto::funder::messages::{ Currency, MoveToken, PendingTransaction, TokenInfo, UnsignedResponseSendFundsOp, }; @@ -90,8 +90,22 @@ where } */ -pub fn hash_token_info(token_info: &TokenInfo) -> HashResult { - hash_buffer(&token_info.canonical_serialize()) +pub fn hash_token_info( + local_public_key: &PublicKey, + remote_public_key: &PublicKey, + token_info: &TokenInfo, +) -> HashResult { + let mut move_token_counter_buff = Vec::new(); + move_token_counter_buff + .write_u128::(token_info.move_token_counter) + .unwrap(); + + hash::Hasher::new() + .chain(&local_public_key) + .chain(&remote_public_key) + .chain(&token_info.balances_hash) + .chain(&move_token_counter_buff) + .finalize() } /* @@ -118,7 +132,7 @@ where B: CanonicalSerialize + Clone, { let mut sig_buffer = Vec::new(); - sig_buffer.extend_from_slice(&hash_buffer(TOKEN_NEXT)); + sig_buffer.extend_from_slice(&hash::hash_buffer(TOKEN_NEXT)); sig_buffer.extend_from_slice(&move_token.old_token); sig_buffer.extend_from_slice(&move_token.info_hash); sig_buffer From 06bd0b14d99469baf5f655473c483a4764603ee6 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 29 Oct 2020 13:58:34 +0200 Subject: [PATCH 136/478] funder: token_channel: Thoughts on handle_out_move_token(). Not done yet. Work in progress, doesn't compile --- components/funder/src/token_channel.rs | 41 ++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 7bdfabefd..3952edcc7 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -71,8 +71,21 @@ pub trait TcTransaction { fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; fn set_direction_outgoing(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; - // get_move_token_in() -> Option; - // get_move_token_out() -> Option>; + /// Set last incoming move token (Only relevant when the current state is outgoing) + fn set_last_incoming( + &mut self, + old_token: Signature, + move_token_counter: u128, + new_token: Signature, + ) -> AsyncOpResult<()>; + + /// Set last known balance during an incoming move token (Only relevant when the current state + /// is outgoing) + fn set_last_incoming_balance( + &mut self, + currency: Currency, + mc_balance: McBalance, + ) -> AsyncOpResult<()>; fn get_move_token_counter(&mut self) -> AsyncOpResult; fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; @@ -687,6 +700,30 @@ where // TODO: We need to be able to remember the last incoming move token. // How to store this data inside the database? How to save it here? + tc_transaction + .set_last_incoming( + move_token_in.old_token, + move_token_in.token_info.move_token_counter, + move_token_in.new_token, + ) + .await?; + + // Remember the balances for the last incoming move token: + let mutual_credits_list = tc_transaction.list_mutual_credits(); + for elem in mutual_credits_list.next().await { + let (currency, mc_balance) = elem?; + todo!(); + } + todo!(); + + // TODO: Issue to think about: How to make sure we can store the last incoming balances without + // loading all of them into memory? Do we need to make a modification to how the db works, + // perhaps? + + tc_transaction + .set_last_incoming_balance(currency, mc_balance) + .await?; + // Set the direction to be outgoing: tc_transaction .set_direction_outgoing(move_token.clone()) From 5c023a2aff463e5a42e99b684b12e7176c10cb0a Mon Sep 17 00:00:00 2001 From: real Date: Thu, 29 Oct 2020 17:51:12 +0200 Subject: [PATCH 137/478] funder: Some work on handle_out_move_token() --- components/funder/src/token_channel.rs | 45 ++------------------------ 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 3952edcc7..92aef9ce0 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -71,22 +71,6 @@ pub trait TcTransaction { fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; fn set_direction_outgoing(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; - /// Set last incoming move token (Only relevant when the current state is outgoing) - fn set_last_incoming( - &mut self, - old_token: Signature, - move_token_counter: u128, - new_token: Signature, - ) -> AsyncOpResult<()>; - - /// Set last known balance during an incoming move token (Only relevant when the current state - /// is outgoing) - fn set_last_incoming_balance( - &mut self, - currency: Currency, - mc_balance: McBalance, - ) -> AsyncOpResult<()>; - fn get_move_token_counter(&mut self) -> AsyncOpResult; fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; @@ -697,34 +681,9 @@ where .await .unwrap(); - // TODO: We need to be able to remember the last incoming move token. - // How to store this data inside the database? How to save it here? - - tc_transaction - .set_last_incoming( - move_token_in.old_token, - move_token_in.token_info.move_token_counter, - move_token_in.new_token, - ) - .await?; - - // Remember the balances for the last incoming move token: - let mutual_credits_list = tc_transaction.list_mutual_credits(); - for elem in mutual_credits_list.next().await { - let (currency, mc_balance) = elem?; - todo!(); - } - todo!(); - - // TODO: Issue to think about: How to make sure we can store the last incoming balances without - // loading all of them into memory? Do we need to make a modification to how the db works, - // perhaps? - - tc_transaction - .set_last_incoming_balance(currency, mc_balance) - .await?; - // Set the direction to be outgoing: + // TODO: This should also save the last incoming move token, in an atomic way. + // Should probably be implemented inside the database code. tc_transaction .set_direction_outgoing(move_token.clone()) .await?; From 954a5c0d4b0fae946570aa38c50d2dc5cc4247e1 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 30 Oct 2020 13:24:16 +0200 Subject: [PATCH 138/478] funder: token_channel: impl create_token_channel() --- components/funder/src/token_channel.rs | 471 +++---------------------- 1 file changed, 47 insertions(+), 424 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 92aef9ce0..0d8db2957 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -1,16 +1,12 @@ -// use std::cmp::Ordering; +use std::cmp::Ordering; use std::convert::TryFrom; use derive_more::From; use futures::channel::oneshot; -// use futures::SinkExt; use futures::{Stream, StreamExt, TryStreamExt}; use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; -// use common::conn::BoxFuture; - -// use common::ser_utils::ser_map_str_any; use signature::canonical::CanonicalSerialize; @@ -19,12 +15,12 @@ use crypto::identity::compare_public_key; use identity::IdentityClient; -use proto::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; - use proto::app_server::messages::RelayAddress; +use proto::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; use proto::funder::messages::{ Currency, CurrencyOperations, McBalance, MoveToken, PendingTransaction, TokenInfo, }; + use signature::signature_buff::{hash_token_info, move_token_signature_buff}; use signature::verify::verify_move_token; @@ -38,14 +34,6 @@ use crate::mutual_credit::types::McTransaction; use crate::types::{create_hashed, MoveTokenHashed}; -/* -#[derive(Arbitrary, Debug, Clone, Serialize, Deserialize)] -pub enum SetDirection { - Incoming(MoveTokenHashed), - Outgoing((MoveToken, TokenInfo)), -} -*/ - #[derive(Debug)] pub enum TcOpError { SendOpFailed, @@ -76,13 +64,9 @@ pub trait TcTransaction { fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult; - /// Return a sorted list of all mutual credits + /// Return a sorted async iterator of all mutual credits fn list_mutual_credits(&mut self) -> AsyncOpStream<(Currency, McBalance)>; - // add_local_currency(currency: Currency); - // TODO: Possibly add boolean result here? And to other remove commands? - // remove_local_currency(currency: Currency); - fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; @@ -92,38 +76,9 @@ pub trait TcTransaction { fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; - // get_remote_active_currencies() -> - // set_remote_active_currencies(currencies: Vec); - // is_active_currency(currency: Currency) -> bool; - fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()>; } -/* -/// The currencies set to be active by two sides of the token channel. -/// Only currencies that are active on both sides (Intersection) can be used for trading. -#[derive(Arbitrary, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct ActiveCurrencies { - /// Currencies set to be active by local side - pub local: ImHashSet, - /// Currencies set to be active by remote side - pub remote: ImHashSet, -} - -impl ActiveCurrencies { - fn new() -> Self { - Self { - local: ImHashSet::new(), - remote: ImHashSet::new(), - } - } - - pub fn calc_active(&self) -> ImHashSet { - self.local.clone().intersection(self.remote.clone()) - } -} -*/ - #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct TcOutgoing { pub move_token_out: MoveToken, @@ -143,38 +98,6 @@ pub enum TcDirection { Outgoing(TcOutgoing), } -/* -#[derive(Clone, Debug)] -pub struct TcInBorrow<'a> { - pub tc_incoming: &'a TcIncoming, - mutual_credits: &'a ImHashMap, - active_currencies: &'a ActiveCurrencies, -} - -#[derive(Clone, Debug)] -pub struct TcOutBorrow<'a, B> { - pub tc_outgoing: &'a TcOutgoing, - mutual_credits: &'a ImHashMap, - active_currencies: &'a ActiveCurrencies, -} - -#[derive(Clone, Debug)] -pub enum TcDirectionBorrow<'a, B> { - In(TcInBorrow<'a>), - Out(TcOutBorrow<'a, B>), -} -*/ - -/* -#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] -pub struct TokenChannel { - // direction: TcDirection, - tc_transaction: TcTransaction, - // mutual_credits: ImHashMap, - // active_currencies: ActiveCurrencies, -} -*/ - #[derive(Debug, From)] pub enum ReceiveMoveTokenError { ChainInconsistency, @@ -250,41 +173,66 @@ fn rand_nonce_from_public_key(public_key: &PublicKey) -> RandValue { RandValue::try_from(&public_key_hash.as_ref()[..RandValue::len()]).unwrap() } -/* /// Create an initial move token in the relationship between two public keys. /// To canonicalize the initial move token (Having an equal move token for both sides), we sort the /// two public keys in some way. -fn initial_move_token( - low_public_key: &PublicKey, - high_public_key: &PublicKey, -) -> (MoveToken, TokenInfo) { +fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKey) -> MoveToken { let token_info = TokenInfo { - mc: McInfo { - balances: Vec::new(), - }, - counters: CountersInfo { - inconsistency_counter: 0, - move_token_counter: 0, - }, + // No balances yet: + balances_hash: hash_buffer(&[]), + move_token_counter: 0, }; + // let info_hash = hash_token_info(remote_public_key, local_public_key, &token_info); + // This is a special initialization case. // Note that this is the only case where new_token is not a valid signature. // We do this because we want to have synchronization between the two sides of the token // channel, however, the remote side has no means of generating the signature (Because he // doesn't have the private key). Therefore we use a dummy new_token instead. - let move_token = MoveToken { + let move_token_out = MoveToken { old_token: token_from_public_key(&low_public_key), currencies_operations: Vec::new(), relays_diff: Vec::new(), currencies_diff: Vec::new(), - info_hash: hash_token_info(&token_info), + info_hash: hash_token_info(&low_public_key, &high_public_key, &token_info), new_token: token_from_public_key(&high_public_key), }; - (move_token, token_info) + move_token_out +} + +/// A new token channel status, as seen by the local side +pub enum NewTokenChannel { + Incoming(MoveTokenHashed), + Outgoing(MoveToken), +} + +/// Create a new token channel, and determines the initial state for the local side. +/// The initial state is determined according to the order between the two provided public keys. +/// Note that this function does not affect the database, it only returns a new state for the token +/// channel. +pub async fn create_token_channel( + local_public_key: &PublicKey, + remote_public_key: &PublicKey, +) -> NewTokenChannel +where + B: CanonicalSerialize + Clone, +{ + if compare_public_key(&local_public_key, &remote_public_key) == Ordering::Less { + // We are the first sender + NewTokenChannel::Outgoing(initial_move_token(local_public_key, remote_public_key)) + } else { + // We are the second sender + let move_token_in = initial_move_token(remote_public_key, local_public_key); + let token_info = TokenInfo { + // No balances yet: + balances_hash: hash_buffer(&[]), + move_token_counter: 0, + }; + NewTokenChannel::Incoming(create_hashed::(&move_token_in, &token_info)) + } } -*/ async fn handle_in_move_token( tc_transaction: &mut impl TcTransaction, @@ -540,31 +488,6 @@ where Ok(move_token_received) } -/* -pub async fn sign_move_token<'a, B>( - unsigned_move_token: UnsignedMoveToken, - identity_client: &'a mut IdentityClient, -) -> MoveToken -where - B: CanonicalSerialize + Clone + 'a, -{ - let signature_buff = move_token_signature_buff(unsigned_move_token.clone()); - let new_token = identity_client - .request_signature(signature_buff) - .await - .unwrap(); - - MoveToken { - old_token: unsigned_move_token.old_token, - currencies_operations: unsigned_move_token.currencies_operations, - relays_diff: unsigned_move_token.relays_diff, - currencies_diff: unsigned_move_token.currencies_diff, - info_hash: unsigned_move_token.info_hash, - new_token, - } -} -*/ - async fn handle_out_move_token( tc_transaction: &mut impl TcTransaction, identity_client: &mut IdentityClient, @@ -691,6 +614,8 @@ where Ok(move_token) } +// TODO: Implement: new_from_local_reset, new_from_remote_reset. + /* impl TokenChannel where @@ -842,308 +767,6 @@ where } } - pub fn mutate(&mut self, d_mutation: &TcMutation) { - match d_mutation { - TcMutation::McMutation((currency, mc_mutation)) => { - let mutual_credit = self.mutual_credits.get_mut(currency).unwrap(); - mutual_credit.mutate(mc_mutation); - } - TcMutation::SetDirection(ref set_direction) => { - self.direction = match set_direction { - SetDirection::Incoming(friend_move_token_hashed) => { - let tc_incoming = TcIncoming { - move_token_in: friend_move_token_hashed.clone(), - }; - TcDirection::Incoming(tc_incoming) - } - SetDirection::Outgoing((friend_move_token, token_info)) => { - let tc_outgoing = TcOutgoing { - move_token_out: friend_move_token.clone(), - token_info: token_info.clone(), - opt_prev_move_token_in: self - .get_last_incoming_move_token_hashed() - .cloned(), - }; - TcDirection::Outgoing(tc_outgoing) - } - }; - } - TcMutation::SetLocalActiveCurrencies(ref currencies) => { - self.active_currencies.local = currencies.iter().cloned().collect(); - } - TcMutation::SetRemoteActiveCurrencies(ref currencies) => { - self.active_currencies.remote = currencies.iter().cloned().collect(); - } - TcMutation::AddMutualCredit(ref currency) => { - assert!(self.active_currencies.local.contains(currency)); - assert!(self.active_currencies.remote.contains(currency)); - - let token_info = match &self.direction { - TcDirection::Incoming(tc_incoming) => { - tc_incoming.move_token_in.token_info.clone().flip() - } - TcDirection::Outgoing(tc_outgoing) => tc_outgoing.token_info.clone(), - }; - - let balance = 0; - let new_mutual_credit = MutualCredit::new( - &token_info.mc.local_public_key, - &token_info.mc.remote_public_key, - currency, - balance, - ); - let res = self - .mutual_credits - .insert(currency.clone(), new_mutual_credit); - // Make sure that this currency was not already present: - assert!(res.is_none()); - } - } - } - - pub fn get_inconsistency_counter(&self) -> u64 { - match &self.direction { - TcDirection::Incoming(tc_incoming) => { - tc_incoming - .move_token_in - .token_info - .counters - .inconsistency_counter - } - TcDirection::Outgoing(tc_outgoing) => { - tc_outgoing.token_info.counters.inconsistency_counter - } - } - } - - pub fn get_outgoing(&self) -> Option> { - match self.get_direction() { - TcDirectionBorrow::In(_) => None, - TcDirectionBorrow::Out(tc_out_borrow) => Some(tc_out_borrow), - } - } - - pub fn get_incoming(&self) -> Option> { - match self.get_direction() { - TcDirectionBorrow::In(tc_in_borrow) => Some(tc_in_borrow), - TcDirectionBorrow::Out(_) => None, - } - } - - pub fn simulate_receive_move_token( - &self, - new_move_token: MoveToken, - remote_max_debts: &ImHashMap, - ) -> Result, ReceiveMoveTokenError> { - match &self.get_direction() { - TcDirectionBorrow::In(tc_in_borrow) => tc_in_borrow.handle_incoming(new_move_token), - TcDirectionBorrow::Out(tc_out_borrow) => { - tc_out_borrow.handle_incoming(new_move_token, remote_max_debts) - } - } - } -} -*/ - -/* -// TODO: Reimplement later -impl<'a> TcInBorrow<'a> { - /// Create a full TokenChannel (Incoming direction) - fn create_token_channel(&self) -> TokenChannel { - TokenChannel { - direction: TcDirection::Incoming(self.tc_incoming.clone()), - mutual_credits: self.mutual_credits.clone(), - active_currencies: self.active_currencies.clone(), - } - } - - /// Handle an incoming move token during Incoming direction: - fn handle_incoming( - &self, - new_move_token: MoveToken, - ) -> Result, ReceiveMoveTokenError> - where - B: CanonicalSerialize + Clone, - { - // We compare the whole move token message and not just the signature (new_token) - // because we don't check the signature in this flow. - if self.tc_incoming.move_token_in - == create_hashed(&new_move_token, &self.tc_incoming.move_token_in.token_info) - { - // Duplicate - Ok(ReceiveMoveTokenOutput::Duplicate) - } else { - // Inconsistency - Err(ReceiveMoveTokenError::ChainInconsistency) - } - } - - pub fn simulate_send_move_token( - &self, - currencies_operations: Vec, - opt_local_relays: Option>>, - opt_active_currencies: Option>, - rand_nonce: RandValue, - ) -> Result, SendMoveTokenError> - where - B: CanonicalSerialize + Clone, - { - // We create a clone `token_channel` on which we are going to apply all the mutations. - // Eventually this cloned TokenChannel is discarded, and we only output the applied mutations. - let mut token_channel = self.create_token_channel(); - let tc_in_borrow = token_channel.get_incoming().unwrap(); - - let mut tc_mutations = Vec::new(); - - if let Some(active_currencies) = opt_active_currencies.as_ref() { - for mutual_credit_currency in tc_in_borrow.mutual_credits.keys() { - if !active_currencies.contains(&mutual_credit_currency) { - return Err(SendMoveTokenError::CanNotRemoveCurrencyInUse); - } - } - - let mutation = TcMutation::SetLocalActiveCurrencies(active_currencies.clone()); - token_channel.mutate(&mutation); - tc_mutations.push(mutation); - - let tc_in_borrow = token_channel.get_incoming().unwrap(); - let active_currencies = &tc_in_borrow.active_currencies; - - // Find the new currencies we need to initialize. - // Calculate: - // (local ^ remote) \ mutual_credit_currencies: - let intersection = active_currencies - .remote - .clone() - .intersection(active_currencies.local.clone()); - - let mutual_credit_currencies: ImHashSet<_> = - tc_in_borrow.mutual_credits.keys().cloned().collect(); - - let new_currencies = intersection.relative_complement(mutual_credit_currencies); - - for new_currency in new_currencies { - let mutation = TcMutation::AddMutualCredit(new_currency.clone()); - token_channel.mutate(&mutation); - tc_mutations.push(mutation); - } - } - - // Update mutual credits: - for currency_operations in ¤cies_operations { - let tc_in_borrow = token_channel.get_incoming().unwrap(); - let mutual_credit = tc_in_borrow - .mutual_credits - .get(¤cy_operations.currency) - .unwrap() - .clone(); - - let mut outgoing_mc = OutgoingMc::new(&mutual_credit); - for op in ¤cy_operations.operations { - let mc_mutations = outgoing_mc.queue_operation(op).unwrap(); - for mc_mutation in mc_mutations { - let mutation = TcMutation::McMutation(( - currency_operations.currency.clone(), - mc_mutation.clone(), - )); - token_channel.mutate(&mutation); - tc_mutations.push(mutation); - } - } - } - - let tc_in_borrow = token_channel.get_incoming().unwrap(); - - let mut balances: Vec<_> = tc_in_borrow - .mutual_credits - .iter() - .map(|(currency, mutual_credit)| CurrencyBalanceInfo { - currency: currency.clone(), - balance_info: BalanceInfo { - balance: mutual_credit.state().balance.balance, - local_pending_debt: mutual_credit.state().balance.local_pending_debt, - remote_pending_debt: mutual_credit.state().balance.remote_pending_debt, - }, - }) - .collect(); - - // Canonicalize balances: - balances.sort_by(|cbi1, cbi2| cbi1.currency.cmp(&cbi2.currency)); - - let tc_in_borrow = token_channel.get_incoming().unwrap(); - let cur_token_info = &tc_in_borrow.tc_incoming.move_token_in.token_info; - - let token_info = TokenInfo { - mc: McInfo { - local_public_key: cur_token_info.mc.remote_public_key.clone(), - remote_public_key: cur_token_info.mc.local_public_key.clone(), - balances, - }, - counters: CountersInfo { - move_token_counter: cur_token_info.counters.move_token_counter.wrapping_add(1), - inconsistency_counter: cur_token_info.counters.inconsistency_counter, - }, - }; - - let unsigned_move_token = create_unsigned_move_token( - currencies_operations, - opt_local_relays, - opt_active_currencies, - &token_info, - tc_in_borrow.tc_incoming.move_token_in.new_token.clone(), - rand_nonce, - ); - - Ok(SendMoveTokenOutput { - unsigned_move_token, - mutations: tc_mutations, - token_info, - }) - } - - pub fn create_outgoing_mc(&self, currency: &Currency) -> Option { - Some(OutgoingMc::new(self.mutual_credits.get(currency)?)) - } -} - -impl<'a, B> TcOutBorrow<'a, B> -where - B: Clone + CanonicalSerialize, -{ - /// Handle an incoming move token during Outgoing direction: - fn handle_incoming( - &self, - new_move_token: MoveToken, - remote_max_debts: &ImHashMap, - ) -> Result, ReceiveMoveTokenError> { - if new_move_token.old_token == self.tc_outgoing.move_token_out.new_token { - Ok(ReceiveMoveTokenOutput::Received( - self.handle_incoming_token_match(new_move_token, remote_max_debts)?, - )) - // self.outgoing_to_incoming(friend_move_token, new_move_token) - } else if self.tc_outgoing.move_token_out.old_token == new_move_token.new_token { - // We should retransmit our move token message to the remote side. - Ok(ReceiveMoveTokenOutput::RetransmitOutgoing( - self.tc_outgoing.move_token_out.clone(), - )) - } else { - Err(ReceiveMoveTokenError::ChainInconsistency) - } - } - - /// Create a full TokenChannel (Outgoing direction) - fn create_token_channel(&self) -> TokenChannel { - TokenChannel { - direction: TcDirection::Outgoing(self.tc_outgoing.clone()), - mutual_credits: self.mutual_credits.clone(), - active_currencies: self.active_currencies.clone(), - } - } - - /// Get the current outgoing move token - pub fn create_outgoing_move_token(&self) -> MoveToken { - self.tc_outgoing.move_token_out.clone() - } } */ From 20719352643061add474ea4d54a7489a5895491d Mon Sep 17 00:00:00 2001 From: real Date: Fri, 30 Oct 2020 19:28:35 +0200 Subject: [PATCH 139/478] funder: Work on init_token_channel_from_remote_reset() --- components/funder/src/token_channel.rs | 153 ++++++++++++++++++----- components/proto/src/funder/messages.rs | 3 +- components/proto/src/schema/funder.capnp | 4 +- 3 files changed, 130 insertions(+), 30 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 0d8db2957..59ecbe0f7 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -1,5 +1,6 @@ use std::cmp::Ordering; use std::convert::TryFrom; +use std::iter::IntoIterator; use derive_more::From; @@ -48,7 +49,7 @@ pub type TcOpSenderResult = oneshot::Sender>; pub enum TcStatus { ConsistentIn(MoveTokenHashed), ConsistentOut(MoveToken, MoveTokenHashed), - Inconsistent, + Inconsistent(Signature, u128), // (local_reset_token, local_reset_move_token_counter) } pub trait TcTransaction { @@ -58,14 +59,22 @@ pub trait TcTransaction { fn get_tc_status(&mut self) -> AsyncOpResult>; fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; fn set_direction_outgoing(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; + fn set_direction_outgoing_empty_incoming( + &mut self, + move_token: MoveToken, + ) -> AsyncOpResult<()>; fn get_move_token_counter(&mut self) -> AsyncOpResult; fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult; - /// Return a sorted async iterator of all mutual credits - fn list_mutual_credits(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + /// Return a sorted async iterator of all balances + fn list_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + + /// Return a sorted async iterator of all local reset proposal balances + /// Only relevant for inconsistent channels + fn list_local_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; @@ -202,36 +211,119 @@ fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKey move_token_out } -/// A new token channel status, as seen by the local side -pub enum NewTokenChannel { - Incoming(MoveTokenHashed), - Outgoing(MoveToken), +#[derive(Debug, From)] +pub enum InitTokenChannelError { + InvalidTokenChannelStatus, + InvalidResetMoveToken, + InvalidTokenInfo, + InvalidSignature, + OpError(OpError), } /// Create a new token channel, and determines the initial state for the local side. /// The initial state is determined according to the order between the two provided public keys. /// Note that this function does not affect the database, it only returns a new state for the token /// channel. -pub async fn create_token_channel( +pub async fn init_token_channel( + tc_transaction: &mut impl TcTransaction, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> NewTokenChannel +) -> Result<(), InitTokenChannelError> where B: CanonicalSerialize + Clone, { - if compare_public_key(&local_public_key, &remote_public_key) == Ordering::Less { - // We are the first sender - NewTokenChannel::Outgoing(initial_move_token(local_public_key, remote_public_key)) - } else { - // We are the second sender - let move_token_in = initial_move_token(remote_public_key, local_public_key); - let token_info = TokenInfo { - // No balances yet: - balances_hash: hash_buffer(&[]), - move_token_counter: 0, - }; - NewTokenChannel::Incoming(create_hashed::(&move_token_in, &token_info)) + Ok( + if compare_public_key(&local_public_key, &remote_public_key) == Ordering::Less { + // We are the first sender + tc_transaction + .set_direction_outgoing_empty_incoming(initial_move_token( + local_public_key, + remote_public_key, + )) + .await? + } else { + // We are the second sender + let move_token_in = initial_move_token(remote_public_key, local_public_key); + let token_info = TokenInfo { + // No balances yet: + balances_hash: hash_buffer(&[]), + move_token_counter: 0, + }; + tc_transaction + .set_direction_incoming(create_hashed::(&move_token_in, &token_info)) + .await? + }, + ) +} + +/// Remote side has accepted our reset proposal +/// Adjust token channel accordingly. +pub async fn init_token_channel_from_remote_reset( + tc_transaction: &mut impl TcTransaction, + reset_move_token: &MoveToken, + local_public_key: &PublicKey, + remote_public_key: &PublicKey, +) -> Result<(), InitTokenChannelError> +where + B: Clone + CanonicalSerialize, +{ + // TODO: Should we verify the signature here? + // Verify signature: + if !verify_move_token(&reset_move_token, &remote_public_key) { + return Err(InitTokenChannelError::InvalidSignature); } + + // Make sure that the MoveToken message is empty: + if !reset_move_token.relays_diff.is_empty() + || !reset_move_token.currencies_diff.is_empty() + || !reset_move_token.currencies_operations.is_empty() + { + return Err(InitTokenChannelError::InvalidResetMoveToken); + } + + let (local_reset_token, local_reset_move_token_counter) = match tc_transaction + .get_tc_status() + .await? + { + TcStatus::ConsistentIn(_) => return Err(InitTokenChannelError::InvalidTokenChannelStatus), + + TcStatus::ConsistentOut(_, _) => { + return Err(InitTokenChannelError::InvalidTokenChannelStatus) + } + TcStatus::Inconsistent(local_reset_token, local_reset_move_token_counter) => { + (local_reset_token, local_reset_move_token_counter) + } + }; + + // Calculate `info_hash` as seen by the remote side. + // Create what we expect to be TokenInfo (From the point of view of remote side): + let mc_balances = tc_transaction.list_local_reset_balances(); + + let token_info = TokenInfo { + balances_hash: hash_mc_infos( + mc_balances.map_ok(|(currency, mc_balance)| (currency, mc_balance.flip())), + ) + .await?, + move_token_counter: local_reset_move_token_counter, + }; + + let info_hash = hash_token_info(remote_public_key, local_public_key, &token_info); + if reset_move_token.info_hash != info_hash { + return Err(InitTokenChannelError::InvalidTokenInfo); + } + + // Update move_token_counter: + tc_transaction + .set_move_token_counter(local_reset_move_token_counter) + .await?; + + // Set direction to outgoing, with the newly received move token: + let new_move_token_hashed = create_hashed(&reset_move_token, &token_info); + tc_transaction + .set_direction_incoming(new_move_token_hashed) + .await?; + + Ok(()) } async fn handle_in_move_token( @@ -257,7 +349,9 @@ where ) .await } - TcStatus::Inconsistent => unreachable!(), + TcStatus::Inconsistent(_local_reset_token, _local_reset_move_token_counter) => { + unreachable!() + } } } @@ -459,11 +553,11 @@ where // Calculate `info_hash` as seen by the remote side. // Create what we expect to be TokenInfo (From the point of view of remote side): - let mc_infos = tc_transaction.list_mutual_credits(); + let mc_balances = tc_transaction.list_balances(); let token_info = TokenInfo { balances_hash: hash_mc_infos( - mc_infos.map_ok(|(currency, mc_balance)| (currency, mc_balance.flip())), + mc_balances.map_ok(|(currency, mc_balance)| (currency, mc_balance.flip())), ) .await?, move_token_counter: new_move_token_counter, @@ -481,8 +575,9 @@ where .await?; // Set direction to outgoing, with the newly received move token: + let new_move_token_hashed = create_hashed(&new_move_token, &token_info); tc_transaction - .set_direction_outgoing(new_move_token) + .set_direction_incoming(new_move_token_hashed) .await?; Ok(move_token_received) @@ -506,7 +601,9 @@ where TcStatus::ConsistentOut(_move_token_out, _move_token_in) => { return Err(SendMoveTokenError::InvalidTokenChannelStatus) } - TcStatus::Inconsistent => return Err(SendMoveTokenError::InvalidTokenChannelStatus), + TcStatus::Inconsistent(_local_reset_token, _local_reset_move_token_counter) => { + return Err(SendMoveTokenError::InvalidTokenChannelStatus) + } }; // Handle currencies_diff: @@ -580,10 +677,10 @@ where .await? .checked_add(1) .ok_or(SendMoveTokenError::MoveTokenCounterOverflow)?; - let mc_infos = tc_transaction.list_mutual_credits(); + let mc_balances = tc_transaction.list_balances(); let token_info = TokenInfo { - balances_hash: hash_mc_infos(mc_infos).await?, + balances_hash: hash_mc_infos(mc_balances).await?, move_token_counter: new_move_token_counter, }; diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index ba873937b..776a72df5 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -364,7 +364,8 @@ pub struct CurrencyBalance { pub struct ResetTerms { #[serde(with = "ser_b64")] pub reset_token: Signature, - pub inconsistency_counter: u64, + #[capnp_conv(with = Wrapper)] + pub move_token_counter: u128, pub balance_for_reset: Vec, } diff --git a/components/proto/src/schema/funder.capnp b/components/proto/src/schema/funder.capnp index e03a965a9..65782f926 100644 --- a/components/proto/src/schema/funder.capnp +++ b/components/proto/src/schema/funder.capnp @@ -61,7 +61,9 @@ struct CurrencyBalance { struct ResetTerms { resetToken @0: Signature; - inconsistencyCounter @1: UInt64; + moveTokenCounter @1: CustomUInt128; + # Newly proposed moveTokenCounter. Must be larger than both side's + # previous moveTokenCounter. balanceForReset @2: List(CurrencyBalance); # List of expected balance for each currency } From bfa0a4490019dc68b2ad8596f6b78d0b373f2f7a Mon Sep 17 00:00:00 2001 From: real Date: Fri, 30 Oct 2020 19:33:26 +0200 Subject: [PATCH 140/478] funder: replaced assertion with error return value --- components/funder/src/token_channel.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 59ecbe0f7..f40a89301 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -120,7 +120,7 @@ pub enum ReceiveMoveTokenError { InvalidCurrency, InvalidAddActiveCurrencies, CanNotRemoveCurrencyInUse, - InvalidState, + InvalidTokenChannelStatus, OpError(OpError), } @@ -350,7 +350,7 @@ where .await } TcStatus::Inconsistent(_local_reset_token, _local_reset_move_token_counter) => { - unreachable!() + return Err(ReceiveMoveTokenError::InvalidTokenChannelStatus); } } } From ec84e1c1418bfc1e53e8530eeedff64dfb9763ee Mon Sep 17 00:00:00 2001 From: real Date: Fri, 30 Oct 2020 20:32:09 +0200 Subject: [PATCH 141/478] funder: Extra check for init_token_channel_from_remote_reset() --- components/funder/src/token_channel.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index f40a89301..6e8fc3243 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -217,9 +217,12 @@ pub enum InitTokenChannelError { InvalidResetMoveToken, InvalidTokenInfo, InvalidSignature, + InvalidResetToken, OpError(OpError), } +// TODO: How to handle errors here? +// Some errors might not be recoverable /// Create a new token channel, and determines the initial state for the local side. /// The initial state is determined according to the order between the two provided public keys. /// Note that this function does not affect the database, it only returns a new state for the token @@ -256,6 +259,9 @@ where ) } +// TODO: How to handle errors here? +// Some errors might not be recoverable +// TODO: Should we check the signature ourselves, or the user of this function should? /// Remote side has accepted our reset proposal /// Adjust token channel accordingly. pub async fn init_token_channel_from_remote_reset( @@ -267,12 +273,12 @@ pub async fn init_token_channel_from_remote_reset( where B: Clone + CanonicalSerialize, { - // TODO: Should we verify the signature here? // Verify signature: if !verify_move_token(&reset_move_token, &remote_public_key) { return Err(InitTokenChannelError::InvalidSignature); } + // TODO: Maybe we can allow reset token messages that are not empty? // Make sure that the MoveToken message is empty: if !reset_move_token.relays_diff.is_empty() || !reset_move_token.currencies_diff.is_empty() @@ -295,6 +301,10 @@ where } }; + if local_reset_token != reset_move_token.old_token { + return Err(InitTokenChannelError::InvalidResetToken); + } + // Calculate `info_hash` as seen by the remote side. // Create what we expect to be TokenInfo (From the point of view of remote side): let mc_balances = tc_transaction.list_local_reset_balances(); From f193cd7e0b7815c92be80e928d8fb3089c53a998 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 31 Oct 2020 19:43:50 +0200 Subject: [PATCH 142/478] funder: token_channel: Some work on error handling --- components/funder/src/token_channel.rs | 264 ++++++++++++++++--------- 1 file changed, 169 insertions(+), 95 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 6e8fc3243..a51db3318 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -44,11 +44,10 @@ pub enum TcOpError { pub type TcOpResult = Result; pub type TcOpSenderResult = oneshot::Sender>; -// TODO: MoveTokenHashed contains too much information. -// We may remove some of the information, for example: local and remote public keys. +/// Status of a TokenChannel. Could be either outgoing, incoming or inconsistent. pub enum TcStatus { - ConsistentIn(MoveTokenHashed), - ConsistentOut(MoveToken, MoveTokenHashed), + ConsistentIn(MoveTokenHashed), // (move_token_in) + ConsistentOut(MoveToken, MoveTokenHashed), // (move_token_out, last_move_token_in) Inconsistent(Signature, u128), // (local_reset_token, local_reset_move_token_counter) } @@ -63,6 +62,11 @@ pub trait TcTransaction { &mut self, move_token: MoveToken, ) -> AsyncOpResult<()>; + fn set_inconsistent( + &mut self, + local_reset_token: Signature, + local_reset_move_token_counter: u128, + ) -> AsyncOpResult<()>; fn get_move_token_counter(&mut self) -> AsyncOpResult; fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; @@ -88,40 +92,16 @@ pub trait TcTransaction { fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()>; } -#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] -pub struct TcOutgoing { - pub move_token_out: MoveToken, - pub token_info: TokenInfo, - pub opt_prev_move_token_in: Option, -} - -#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] -pub struct TcIncoming { - pub move_token_in: MoveTokenHashed, -} - -#[allow(clippy::large_enum_variant)] -#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] -pub enum TcDirection { - Incoming(TcIncoming), - Outgoing(TcOutgoing), -} - +/// Unrecoverable TokenChannel error #[derive(Debug, From)] -pub enum ReceiveMoveTokenError { - ChainInconsistency, +pub enum TokenChannelError { InvalidTransaction(ProcessTransListError), - InvalidSignature, - InvalidTokenInfo, - InvalidInconsistencyCounter, MoveTokenCounterOverflow, - InvalidMoveTokenCounter, - TooManyOperations, - InvalidCurrency, - InvalidAddActiveCurrencies, CanNotRemoveCurrencyInUse, InvalidTokenChannelStatus, + RequestSignatureError, OpError(OpError), + QueueOperationError(QueueOperationError), } #[derive(Debug)] @@ -143,21 +123,7 @@ pub enum ReceiveMoveTokenOutput { Duplicate, RetransmitOutgoing(MoveToken), Received(MoveTokenReceived), - // In case of a reset, all the local pending requests will be canceled. -} - -#[derive(Debug)] -pub struct SendMoveTokenOutput { - pub move_token: MoveToken, -} - -#[derive(Debug, From)] -pub enum SendMoveTokenError { - InvalidTokenChannelStatus, - CanNotRemoveCurrencyInUse, - MoveTokenCounterOverflow, - QueueOperationError(QueueOperationError), - OpError(OpError), + ChainInconsistent(Signature, u128), // (local_reset_token, local_reset_move_token_counter) } /// Create a token from a public key @@ -211,18 +177,6 @@ fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKey move_token_out } -#[derive(Debug, From)] -pub enum InitTokenChannelError { - InvalidTokenChannelStatus, - InvalidResetMoveToken, - InvalidTokenInfo, - InvalidSignature, - InvalidResetToken, - OpError(OpError), -} - -// TODO: How to handle errors here? -// Some errors might not be recoverable /// Create a new token channel, and determines the initial state for the local side. /// The initial state is determined according to the order between the two provided public keys. /// Note that this function does not affect the database, it only returns a new state for the token @@ -231,7 +185,7 @@ pub async fn init_token_channel( tc_transaction: &mut impl TcTransaction, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> Result<(), InitTokenChannelError> +) -> Result<(), TokenChannelError> where B: CanonicalSerialize + Clone, { @@ -259,6 +213,7 @@ where ) } +/* // TODO: How to handle errors here? // Some errors might not be recoverable // TODO: Should we check the signature ourselves, or the user of this function should? @@ -335,23 +290,32 @@ where Ok(()) } +*/ -async fn handle_in_move_token( +pub async fn handle_in_move_token( tc_transaction: &mut impl TcTransaction, + identity_client: &mut IdentityClient, new_move_token: MoveToken, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> Result, ReceiveMoveTokenError> +) -> Result, TokenChannelError> where B: CanonicalSerialize + Clone, { match tc_transaction.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => { - handle_in_move_token_dir_in(tc_transaction, move_token_in, new_move_token).await + handle_in_move_token_dir_in( + tc_transaction, + identity_client, + move_token_in, + new_move_token, + ) + .await } TcStatus::ConsistentOut(move_token_out, _move_token_in) => { handle_in_move_token_dir_out( tc_transaction, + identity_client, move_token_out, new_move_token, local_public_key, @@ -359,17 +323,75 @@ where ) .await } - TcStatus::Inconsistent(_local_reset_token, _local_reset_move_token_counter) => { - return Err(ReceiveMoveTokenError::InvalidTokenChannelStatus); + TcStatus::Inconsistent(local_reset_token, local_reset_move_token_counter) => { + // Might be a reset move token + if new_move_token.old_token == local_reset_token { + // This is a reset move token! + // TODO: Implement handler for reset token here: + todo!(); + } else { + Ok(ReceiveMoveTokenOutput::ChainInconsistent( + local_reset_token, + local_reset_move_token_counter, + )) + } } } } +/// Generate a reset token, to be used by remote side if he wants to accept the reset terms. +async fn create_reset_token( + identity_client: &mut IdentityClient, +) -> Result { + // TODO: + // Some ideas: + // - Use a random generator to randomly generate an identity client. + // - Sign over a blob that contains: + // - hash(prefix ("INCONSISTENT_TOKEN")) + // - Both public keys. + // - Current counter + 1 + /* + let signature_buff = + let local_reset_token = identity_client + .request_signature(signature_buff) + .await + .map_err(|_| TokenChannelError::RequestSignatureError)?; + */ + todo!() +} + +async fn set_inconsistent( + tc_transaction: &mut impl TcTransaction, + identity_client: &mut IdentityClient, +) -> Result<(Signature, u128), TokenChannelError> { + let local_reset_token = create_reset_token(identity_client).await?; + + // We increase by 2, because the other side might have already signed a move token that equals + // to our move token plus 1, so he might not be willing to sign another move token with the + // same `move_token_counter`. There could be a gap of size `1` as a result, but we don't care + // about it, as long as the `move_token_counter` values are monotonic. + let local_reset_move_token_counter = tc_transaction + .get_move_token_counter() + .await? + .checked_add(2) + .ok_or(TokenChannelError::MoveTokenCounterOverflow)?; + + tc_transaction + .set_inconsistent( + local_reset_token.clone(), + local_reset_move_token_counter.clone(), + ) + .await?; + + Ok((local_reset_token, local_reset_move_token_counter)) +} + async fn handle_in_move_token_dir_in( tc_transaction: &mut impl TcTransaction, + identity_client: &mut IdentityClient, move_token_in: MoveTokenHashed, new_move_token: MoveToken, -) -> Result, ReceiveMoveTokenError> +) -> Result, TokenChannelError> where B: CanonicalSerialize + Clone, { @@ -378,31 +400,49 @@ where Ok(ReceiveMoveTokenOutput::Duplicate) } else { // Inconsistency - Err(ReceiveMoveTokenError::ChainInconsistency) + let (local_reset_token, local_reset_move_token_counter) = + set_inconsistent(tc_transaction, identity_client).await?; + Ok(ReceiveMoveTokenOutput::ChainInconsistent( + local_reset_token, + local_reset_move_token_counter, + )) } } async fn handle_in_move_token_dir_out( tc_transaction: &mut impl TcTransaction, + identity_client: &mut IdentityClient, move_token_out: MoveToken, new_move_token: MoveToken, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> Result, ReceiveMoveTokenError> +) -> Result, TokenChannelError> where B: Clone + CanonicalSerialize, { if new_move_token.old_token == move_token_out.new_token { - Ok(ReceiveMoveTokenOutput::Received( - handle_incoming_token_match( - tc_transaction, - move_token_out, - new_move_token, - local_public_key, - remote_public_key, - ) - .await?, - )) + let output = handle_incoming_token_match( + tc_transaction, + move_token_out, + new_move_token, + local_public_key, + remote_public_key, + ) + .await?; + match output { + IncomingTokenMatchOutput::MoveTokenReceived(move_token_received) => { + return Ok(ReceiveMoveTokenOutput::Received(move_token_received)) + } + IncomingTokenMatchOutput::InvalidIncoming(_) => { + // Inconsistency + let (local_reset_token, local_reset_move_token_counter) = + set_inconsistent(tc_transaction, identity_client).await?; + Ok(ReceiveMoveTokenOutput::ChainInconsistent( + local_reset_token, + local_reset_move_token_counter, + )) + } + } // self.outgoing_to_incoming(friend_move_token, new_move_token) } else if move_token_out.old_token == new_move_token.new_token { // We should retransmit our move token message to the remote side. @@ -410,7 +450,13 @@ where move_token_out.clone(), )) } else { - Err(ReceiveMoveTokenError::ChainInconsistency) + // Inconsistency + let (local_reset_token, local_reset_move_token_counter) = + set_inconsistent(tc_transaction, identity_client).await?; + Ok(ReceiveMoveTokenOutput::ChainInconsistent( + local_reset_token, + local_reset_move_token_counter, + )) } } @@ -436,13 +482,25 @@ async fn hash_mc_infos( Ok(hasher.finalize()) } +enum InvalidIncoming { + InvalidSignature, + InvalidOperation, + InvalidTokenInfo, + CanNotRemoveCurrencyInUse, +} + +enum IncomingTokenMatchOutput { + MoveTokenReceived(MoveTokenReceived), + InvalidIncoming(InvalidIncoming), +} + async fn handle_incoming_token_match( tc_transaction: &mut impl TcTransaction, move_token_out: MoveToken, new_move_token: MoveToken, // remote_max_debts: &ImHashMap, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> Result, ReceiveMoveTokenError> +) -> Result, TokenChannelError> where B: Clone + CanonicalSerialize, { @@ -452,7 +510,9 @@ where // is not correct. // TODO: Check if the above statement is still true. if !verify_move_token(&new_move_token, &remote_public_key) { - return Err(ReceiveMoveTokenError::InvalidSignature); + return Ok(IncomingTokenMatchOutput::InvalidIncoming( + InvalidIncoming::InvalidSignature, + )); } // Aggregate results for every currency: @@ -513,7 +573,9 @@ where // TODO: Somehow unite all code for removing remote currencies. } else { // We are not allowed to remove this currency! - return Err(ReceiveMoveTokenError::CanNotRemoveCurrencyInUse); + return Ok(IncomingTokenMatchOutput::InvalidIncoming( + InvalidIncoming::CanNotRemoveCurrencyInUse, + )); } } else { tc_transaction @@ -534,15 +596,23 @@ where .await? .remote_max_debt; - let incoming_messages = process_operations_list( + let res = process_operations_list( tc_transaction.mc_transaction(currency_operations.currency.clone()), currency_operations.operations.clone(), ¤cy_operations.currency, remote_public_key, remote_max_debt, ) - .await - .map_err(ReceiveMoveTokenError::InvalidTransaction)?; + .await; + + let incoming_messages = match res { + Ok(incoming_messages) => incoming_messages, + Err(_) => { + return Ok(IncomingTokenMatchOutput::InvalidIncoming( + InvalidIncoming::InvalidOperation, + )) + } + }; // We apply mutations on this token channel, to verify stated balance values // let mut check_mutual_credit = mutual_credit.clone(); @@ -559,7 +629,7 @@ where let move_token_counter = tc_transaction.get_move_token_counter().await?; let new_move_token_counter = move_token_counter .checked_add(1) - .ok_or(ReceiveMoveTokenError::MoveTokenCounterOverflow)?; + .ok_or(TokenChannelError::MoveTokenCounterOverflow)?; // Calculate `info_hash` as seen by the remote side. // Create what we expect to be TokenInfo (From the point of view of remote side): @@ -576,7 +646,9 @@ where let info_hash = hash_token_info(remote_public_key, local_public_key, &token_info); if new_move_token.info_hash != info_hash { - return Err(ReceiveMoveTokenError::InvalidTokenInfo); + return Ok(IncomingTokenMatchOutput::InvalidIncoming( + InvalidIncoming::InvalidTokenInfo, + )); } // Update move_token_counter: @@ -590,10 +662,12 @@ where .set_direction_incoming(new_move_token_hashed) .await?; - Ok(move_token_received) + Ok(IncomingTokenMatchOutput::MoveTokenReceived( + move_token_received, + )) } -async fn handle_out_move_token( +pub async fn handle_out_move_token( tc_transaction: &mut impl TcTransaction, identity_client: &mut IdentityClient, currencies_operations: Vec, @@ -601,7 +675,7 @@ async fn handle_out_move_token( currencies_diff: Vec, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> Result, SendMoveTokenError> +) -> Result, TokenChannelError> where B: CanonicalSerialize + Clone, { @@ -609,10 +683,10 @@ where let move_token_in = match tc_transaction.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => move_token_in, TcStatus::ConsistentOut(_move_token_out, _move_token_in) => { - return Err(SendMoveTokenError::InvalidTokenChannelStatus) + return Err(TokenChannelError::InvalidTokenChannelStatus) } TcStatus::Inconsistent(_local_reset_token, _local_reset_move_token_counter) => { - return Err(SendMoveTokenError::InvalidTokenChannelStatus) + return Err(TokenChannelError::InvalidTokenChannelStatus) } }; @@ -658,7 +732,7 @@ where } else { // We are not allowed to remove this currency! // TODO: Should be an error instead? - return Err(SendMoveTokenError::CanNotRemoveCurrencyInUse); + return Err(TokenChannelError::CanNotRemoveCurrencyInUse); } } else { tc_transaction @@ -686,7 +760,7 @@ where .get_move_token_counter() .await? .checked_add(1) - .ok_or(SendMoveTokenError::MoveTokenCounterOverflow)?; + .ok_or(TokenChannelError::MoveTokenCounterOverflow)?; let mc_balances = tc_transaction.list_balances(); let token_info = TokenInfo { @@ -709,7 +783,7 @@ where move_token.new_token = identity_client .request_signature(signature_buff) .await - .unwrap(); + .map_err(|_| TokenChannelError::RequestSignatureError)?; // Set the direction to be outgoing: // TODO: This should also save the last incoming move token, in an atomic way. From 10a1f0864c1e4680d985ab002c503031dbb0b03e Mon Sep 17 00:00:00 2001 From: real Date: Sat, 31 Oct 2020 20:32:06 +0200 Subject: [PATCH 143/478] funder: Derived Debug for two structs --- components/funder/src/token_channel.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index a51db3318..6c7089e9d 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -482,6 +482,7 @@ async fn hash_mc_infos( Ok(hasher.finalize()) } +#[derive(Debug)] enum InvalidIncoming { InvalidSignature, InvalidOperation, @@ -489,6 +490,7 @@ enum InvalidIncoming { CanNotRemoveCurrencyInUse, } +#[derive(Debug)] enum IncomingTokenMatchOutput { MoveTokenReceived(MoveTokenReceived), InvalidIncoming(InvalidIncoming), From 1bb7d87632d736721ddaf5c338c34c932f9445b5 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 31 Oct 2020 21:47:16 +0200 Subject: [PATCH 144/478] funder: token_channel: Realized db transactions mistake. Wrote TODO comments --- components/funder/src/token_channel.rs | 61 +++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 6c7089e9d..ed1b7f9d1 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -68,6 +68,12 @@ pub trait TcTransaction { local_reset_move_token_counter: u128, ) -> AsyncOpResult<()>; + /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) + fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; + + /// Simulate incoming token, to be used before an outgoing reset move token (a local reset) + fn set_incoming_from_inconsistent(&mut self) -> AsyncOpResult<()>; + fn get_move_token_counter(&mut self) -> AsyncOpResult; fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; @@ -327,8 +333,56 @@ where // Might be a reset move token if new_move_token.old_token == local_reset_token { // This is a reset move token! - // TODO: Implement handler for reset token here: - todo!(); + let token_info = TokenInfo { + balances_hash: hash_mc_infos(tc_transaction.list_local_reset_balances()) + .await?, + move_token_counter: local_reset_move_token_counter + .checked_sub(1) + .ok_or(TokenChannelError::MoveTokenCounterOverflow)?, + }; + + let move_token_out = MoveToken { + old_token: Signature::from(&[0; Signature::len()]), + currencies_operations: Vec::new(), + relays_diff: Vec::new(), + currencies_diff: Vec::new(), + info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), + new_token: local_reset_token.clone(), + }; + + tc_transaction + .set_outgoing_from_inconsistent(move_token_out.clone()) + .await?; + + let output = handle_incoming_token_match( + tc_transaction, + move_token_out, + new_move_token, + local_public_key, + remote_public_key, + ) + .await?; + + match output { + IncomingTokenMatchOutput::MoveTokenReceived(move_token_received) => { + Ok(ReceiveMoveTokenOutput::Received(move_token_received)) + } + IncomingTokenMatchOutput::InvalidIncoming(_) => { + // TODO: This is wrong, because the balances might have already been + // modified. How to make the previous changes atomic/revertible? + todo!(); + tc_transaction + .set_inconsistent( + local_reset_token.clone(), + local_reset_move_token_counter, + ) + .await?; + Ok(ReceiveMoveTokenOutput::ChainInconsistent( + local_reset_token, + local_reset_move_token_counter, + )) + } + } } else { Ok(ReceiveMoveTokenOutput::ChainInconsistent( local_reset_token, @@ -434,6 +488,9 @@ where return Ok(ReceiveMoveTokenOutput::Received(move_token_received)) } IncomingTokenMatchOutput::InvalidIncoming(_) => { + // TODO: This is probably wrong, because we might have already changed some + // balances. + todo!(); // Inconsistency let (local_reset_token, local_reset_move_token_counter) = set_inconsistent(tc_transaction, identity_client).await?; From 3e59bd21ae6067278642cb443e14bd50b26c5adf Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 10:43:06 +0200 Subject: [PATCH 145/478] database: Added Transaction trait --- components/database/src/lib.rs | 1 + components/database/src/transaction.rs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 components/database/src/transaction.rs diff --git a/components/database/src/lib.rs b/components/database/src/lib.rs index fcc25a0e2..26abd9e0d 100644 --- a/components/database/src/lib.rs +++ b/components/database/src/lib.rs @@ -18,6 +18,7 @@ mod create; mod database; pub mod file_db; pub mod interface; +pub mod transaction; pub use self::atomic_db::AtomicDb; pub use self::database::{database_loop, DatabaseClient, DatabaseClientError, DatabaseRequest}; diff --git a/components/database/src/transaction.rs b/components/database/src/transaction.rs new file mode 100644 index 000000000..c9ba57871 --- /dev/null +++ b/components/database/src/transaction.rs @@ -0,0 +1,17 @@ +use std::fmt::Debug; + +use futures::future::BoxFuture; +use futures::Future; + +/// A database transaction. Enforced using closure syntax. +/// Supports nested transactions. +trait Transaction { + /// Begin a new transaction. + /// Transaction ends at the end of the closure scope. + fn transaction<'a, F, FR, T, E>(&'a mut self, f: F) -> BoxFuture<'a, Result> + where + F: (FnOnce(&'a mut Self) -> FR) + Send + 'a, + FR: Future> + Send + 'a, + T: Send + 'a, + E: Debug + Send + 'a; +} From 06b3f9dbda2b7d239d19f6261a2698338b951b61 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 10:43:50 +0200 Subject: [PATCH 146/478] funder: Removed unused hint --- components/funder/src/mutual_credit/incoming.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 5af3f6dc5..4cd31fc90 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -57,8 +57,6 @@ pub struct ProcessTransListError { process_trans_error: ProcessOperationError, } -// TODO: Remove later: -#[allow(unused)] pub async fn process_operations_list( mc_transaction: &mut impl McTransaction, operations: Vec, From 6156b1b4a81c48c4243aa552732926794c68eaf8 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 11:45:15 +0200 Subject: [PATCH 147/478] funder: Some work on token_channel atomicity and transactions --- components/database/src/transaction.rs | 20 +- .../funder/src/mutual_credit/incoming.rs | 57 ++-- .../funder/src/mutual_credit/outgoing.rs | 53 ++- .../tests/request_cancel_send_funds.rs | 2 +- .../tests/request_response_send_funds.rs | 2 +- .../funder/src/mutual_credit/tests/utils.rs | 4 +- components/funder/src/mutual_credit/types.rs | 2 +- components/funder/src/token_channel.rs | 317 +++++++++++------- 8 files changed, 270 insertions(+), 187 deletions(-) diff --git a/components/database/src/transaction.rs b/components/database/src/transaction.rs index c9ba57871..c4f18c5e1 100644 --- a/components/database/src/transaction.rs +++ b/components/database/src/transaction.rs @@ -1,11 +1,10 @@ -use std::fmt::Debug; - use futures::future::BoxFuture; use futures::Future; +/* /// A database transaction. Enforced using closure syntax. /// Supports nested transactions. -trait Transaction { +pub trait TransactionLegacy { /// Begin a new transaction. /// Transaction ends at the end of the closure scope. fn transaction<'a, F, FR, T, E>(&'a mut self, f: F) -> BoxFuture<'a, Result> @@ -15,3 +14,18 @@ trait Transaction { T: Send + 'a, E: Debug + Send + 'a; } +*/ + +/// A database transaction. Enforced using closure syntax. +/// Supports nested transactions. +pub trait Transaction { + /// Begin a new transaction. + /// Transaction ends at the end of the closure scope. + /// If the returned boolean is true, the transaction was successful. Otherwise, the transaction + /// was canceled. + fn transaction<'a, F, FR, T>(&'a mut self, f: F) -> BoxFuture<'a, (T, bool)> + where + F: (FnOnce(&'a mut Self) -> FR) + Send + 'a, + FR: Future + Send + 'a, + T: Send + 'a; +} diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 4cd31fc90..5a7170f56 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -16,7 +16,7 @@ use signature::signature_buff::create_response_signature_buffer; use crate::types::create_pending_transaction; -use super::types::McTransaction; +use super::types::McClient; #[derive(Debug)] pub struct IncomingResponseSendFundsOp { @@ -58,7 +58,7 @@ pub struct ProcessTransListError { } pub async fn process_operations_list( - mc_transaction: &mut impl McTransaction, + mc_client: &mut impl McClient, operations: Vec, currency: &Currency, remote_public_key: &PublicKey, @@ -68,7 +68,7 @@ pub async fn process_operations_list( for (index, friend_tc_op) in operations.into_iter().enumerate() { match process_operation( - mc_transaction, + mc_client, friend_tc_op, currency, remote_public_key, @@ -89,7 +89,7 @@ pub async fn process_operations_list( } pub async fn process_operation( - mc_transaction: &mut impl McTransaction, + mc_client: &mut impl McClient, friend_tc_op: FriendTcOp, currency: &Currency, remote_public_key: &PublicKey, @@ -97,26 +97,21 @@ pub async fn process_operation( ) -> Result { match friend_tc_op { FriendTcOp::RequestSendFunds(request_send_funds) => { - process_request_send_funds(mc_transaction, request_send_funds, remote_max_debt).await + process_request_send_funds(mc_client, request_send_funds, remote_max_debt).await } FriendTcOp::ResponseSendFunds(response_send_funds) => { - process_response_send_funds( - mc_transaction, - response_send_funds, - currency, - remote_public_key, - ) - .await + process_response_send_funds(mc_client, response_send_funds, currency, remote_public_key) + .await } FriendTcOp::CancelSendFunds(cancel_send_funds) => { - process_cancel_send_funds(mc_transaction, cancel_send_funds).await + process_cancel_send_funds(mc_client, cancel_send_funds).await } } } /// Process an incoming RequestSendFundsOp async fn process_request_send_funds( - mc_transaction: &mut impl McTransaction, + mc_client: &mut impl McClient, request_send_funds: RequestSendFundsOp, remote_max_debt: u128, ) -> Result { @@ -129,7 +124,7 @@ async fn process_request_send_funds( } // Make sure that we don't have this request as a pending request already: - let opt_remote_pending_transaction = mc_transaction + let opt_remote_pending_transaction = mc_client .get_remote_pending_transaction(request_send_funds.request_id.clone()) .await?; if opt_remote_pending_transaction.is_some() { @@ -143,7 +138,7 @@ async fn process_request_send_funds( .ok_or(ProcessOperationError::CreditsCalcOverflow)?; // Make sure we can freeze the credits - let mc_balance = mc_transaction.get_balance().await?; + let mc_balance = mc_client.get_balance().await?; let new_remote_pending_debt = mc_balance .remote_pending_debt @@ -170,11 +165,11 @@ async fn process_request_send_funds( // Add pending transaction: let pending_transaction = create_pending_transaction(&request_send_funds); - mc_transaction + mc_client .insert_remote_pending_transaction(pending_transaction) .await?; // If we are here, we can freeze the credits: - mc_transaction + mc_client .set_remote_pending_debt(new_remote_pending_debt) .await?; @@ -182,7 +177,7 @@ async fn process_request_send_funds( } async fn process_response_send_funds( - mc_transaction: &mut impl McTransaction, + mc_client: &mut impl McClient, response_send_funds: ResponseSendFundsOp, currency: &Currency, remote_public_key: &PublicKey, @@ -191,7 +186,7 @@ async fn process_response_send_funds( // and access saved request details. // Obtain pending request: - let pending_transaction = mc_transaction + let pending_transaction = mc_client .get_local_pending_transaction(response_send_funds.request_id.clone()) .await? .ok_or(ProcessOperationError::RequestDoesNotExist)?; @@ -231,22 +226,22 @@ async fn process_response_send_funds( // request message processing. // Remove entry from local_pending hashmap: - mc_transaction + mc_client .remove_local_pending_transaction(response_send_funds.request_id.clone()) .await?; // Decrease frozen credits: - let mc_balance = mc_transaction.get_balance().await?; + let mc_balance = mc_client.get_balance().await?; let new_local_pending_debt = mc_balance .local_pending_debt .checked_sub(freeze_credits) .unwrap(); - mc_transaction + mc_client .set_local_pending_debt(new_local_pending_debt) .await?; // Update out_fees: - mc_transaction + mc_client .set_out_fees( mc_balance .out_fees @@ -256,12 +251,12 @@ async fn process_response_send_funds( .await?; // Decrease balance: - let mc_balance = mc_transaction.get_balance().await?; + let mc_balance = mc_client.get_balance().await?; let new_balance = mc_balance .balance .checked_sub_unsigned(freeze_credits) .unwrap(); - mc_transaction.set_balance(new_balance).await?; + mc_client.set_balance(new_balance).await?; Ok(IncomingMessage::Response(IncomingResponseSendFundsOp { pending_transaction, @@ -270,19 +265,19 @@ async fn process_response_send_funds( } async fn process_cancel_send_funds( - mc_transaction: &mut impl McTransaction, + mc_client: &mut impl McClient, cancel_send_funds: CancelSendFundsOp, ) -> Result { // Make sure that id exists in local_pending hashmap, // and access saved request details. // Obtain pending request: - let pending_transaction = mc_transaction + let pending_transaction = mc_client .get_local_pending_transaction(cancel_send_funds.request_id.clone()) .await? .ok_or(ProcessOperationError::RequestDoesNotExist)?; - mc_transaction + mc_client .remove_local_pending_transaction(cancel_send_funds.request_id.clone()) .await?; @@ -291,14 +286,14 @@ async fn process_cancel_send_funds( .checked_add(pending_transaction.left_fees) .unwrap(); - let mc_balance = mc_transaction.get_balance().await?; + let mc_balance = mc_client.get_balance().await?; // Decrease frozen credits: let new_local_pending_debt = mc_balance .local_pending_debt .checked_sub(freeze_credits) .unwrap(); - mc_transaction + mc_client .set_local_pending_debt(new_local_pending_debt) .await?; diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index c5560e457..5bd8dca8b 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -12,7 +12,7 @@ use proto::funder::messages::{ }; use signature::signature_buff::create_response_signature_buffer; -use crate::mutual_credit::types::McTransaction; +use crate::mutual_credit::types::McClient; use crate::types::create_pending_transaction; #[derive(Debug, From)] @@ -33,7 +33,7 @@ pub enum QueueOperationError { // TODO: Remove later: #[allow(unused)] pub async fn queue_operation( - mc_transaction: &mut impl McTransaction, + mc_client: &mut impl McClient, operation: FriendTcOp, currency: &Currency, local_public_key: &PublicKey, @@ -41,25 +41,20 @@ pub async fn queue_operation( // TODO: Maybe remove clone from here later: match operation { FriendTcOp::RequestSendFunds(request_send_funds) => { - queue_request_send_funds(mc_transaction, request_send_funds).await + queue_request_send_funds(mc_client, request_send_funds).await } FriendTcOp::ResponseSendFunds(response_send_funds) => { - queue_response_send_funds( - mc_transaction, - response_send_funds, - currency, - local_public_key, - ) - .await + queue_response_send_funds(mc_client, response_send_funds, currency, local_public_key) + .await } FriendTcOp::CancelSendFunds(cancel_send_funds) => { - queue_cancel_send_funds(mc_transaction, cancel_send_funds).await + queue_cancel_send_funds(mc_client, cancel_send_funds).await } } } async fn queue_request_send_funds( - mc_transaction: &mut impl McTransaction, + mc_client: &mut impl McClient, request_send_funds: RequestSendFundsOp, ) -> Result<(), QueueOperationError> { if !request_send_funds.route.is_part_valid() { @@ -76,7 +71,7 @@ async fn queue_request_send_funds( .checked_add(request_send_funds.left_fees) .ok_or(QueueOperationError::CreditsCalcOverflow)?; - let mc_balance = mc_transaction.get_balance().await?; + let mc_balance = mc_client.get_balance().await?; // Make sure we can freeze the credits let new_local_pending_debt = mc_balance @@ -85,7 +80,7 @@ async fn queue_request_send_funds( .ok_or(QueueOperationError::CreditsCalcOverflow)?; // Make sure that we don't have this request as a pending request already: - if mc_transaction + if mc_client .get_local_pending_transaction(request_send_funds.request_id.clone()) .await? .is_some() @@ -95,12 +90,12 @@ async fn queue_request_send_funds( // Add pending transaction: let pending_transaction = create_pending_transaction(&request_send_funds); - mc_transaction + mc_client .insert_local_pending_transaction(pending_transaction) .await?; // If we are here, we can freeze the credits: - mc_transaction + mc_client .set_local_pending_debt(new_local_pending_debt) .await?; @@ -108,7 +103,7 @@ async fn queue_request_send_funds( } async fn queue_response_send_funds( - mc_transaction: &mut impl McTransaction, + mc_client: &mut impl McClient, response_send_funds: ResponseSendFundsOp, currency: &Currency, local_public_key: &PublicKey, @@ -117,7 +112,7 @@ async fn queue_response_send_funds( // and access saved request details. // Obtain pending request: - let pending_transaction = mc_transaction + let pending_transaction = mc_client .get_remote_pending_transaction(response_send_funds.request_id.clone()) .await? .ok_or(QueueOperationError::RequestDoesNotExist)?; @@ -157,12 +152,12 @@ async fn queue_response_send_funds( .unwrap(); // Remove entry from remote_pending hashmap: - mc_transaction + mc_client .remove_remote_pending_transaction(response_send_funds.request_id) .await?; // Decrease frozen credits - let mc_balance = mc_transaction.get_balance().await?; + let mc_balance = mc_client.get_balance().await?; let new_remote_pending_debt = mc_balance .remote_pending_debt .checked_sub(freeze_credits) @@ -170,12 +165,12 @@ async fn queue_response_send_funds( // Above unwrap() should never fail. This was already checked when a request message was // received. - mc_transaction + mc_client .set_remote_pending_debt(new_remote_pending_debt) .await?; // Update in_fees: - mc_transaction + mc_client .set_in_fees( mc_balance .in_fees @@ -185,7 +180,7 @@ async fn queue_response_send_funds( .await?; // Increase balance: - let mc_balance = mc_transaction.get_balance().await?; + let mc_balance = mc_client.get_balance().await?; let new_balance = mc_balance .balance .checked_add_unsigned(freeze_credits) @@ -193,20 +188,20 @@ async fn queue_response_send_funds( // Above unwrap() should never fail. This was already checked when a request message was // received. - mc_transaction.set_balance(new_balance).await?; + mc_client.set_balance(new_balance).await?; Ok(()) } async fn queue_cancel_send_funds( - mc_transaction: &mut impl McTransaction, + mc_client: &mut impl McClient, cancel_send_funds: CancelSendFundsOp, ) -> Result<(), QueueOperationError> { // Make sure that id exists in remote_pending hashmap, // and access saved request details. // Obtain pending request: - let pending_transaction = mc_transaction + let pending_transaction = mc_client .get_remote_pending_transaction(cancel_send_funds.request_id.clone()) .await? .ok_or(QueueOperationError::RequestDoesNotExist)?; @@ -217,18 +212,18 @@ async fn queue_cancel_send_funds( .unwrap(); // Remove entry from remote hashmap: - mc_transaction + mc_client .remove_remote_pending_transaction(cancel_send_funds.request_id.clone()) .await?; // Decrease frozen credits: - let mc_balance = mc_transaction.get_balance().await?; + let mc_balance = mc_client.get_balance().await?; let new_remote_pending_debt = mc_balance .remote_pending_debt .checked_sub(freeze_credits) .unwrap(); - mc_transaction + mc_client .set_remote_pending_debt(new_remote_pending_debt) .await?; diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index cc43aa2a1..fa3ca88d5 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -13,7 +13,7 @@ use proto::funder::messages::{ }; use crate::mutual_credit::tests::utils::MutualCredit; -use crate::mutual_credit::types::McTransaction; +use crate::mutual_credit::types::McClient; use crate::mutual_credit::incoming::process_operations_list; use crate::mutual_credit::outgoing::queue_operation; diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index 9004902d3..8cacd4d4b 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -14,7 +14,7 @@ use proto::funder::messages::{ use signature::signature_buff::create_response_signature_buffer; use crate::mutual_credit::tests::utils::MutualCredit; -use crate::mutual_credit::types::McTransaction; +use crate::mutual_credit::types::McClient; use crate::types::create_pending_transaction; use crate::mutual_credit::incoming::process_operations_list; diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index e5da27aab..e99e024c5 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -7,7 +7,7 @@ use common::u256::U256; use proto::crypto::Uid; use proto::funder::messages::{Currency, McBalance, PendingTransaction}; -use crate::mutual_credit::types::McTransaction; +use crate::mutual_credit::types::McClient; #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct McPendingTransactions { @@ -50,7 +50,7 @@ impl MutualCredit { } } -impl McTransaction for MutualCredit { +impl McClient for MutualCredit { fn get_balance(&mut self) -> BoxFuture<'static, Result> { let mc_balance = self.balance.clone(); Box::pin(async move { Ok(mc_balance) }) diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 18e05ecd7..4ddcfcfb0 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -5,7 +5,7 @@ use common::u256::U256; use proto::crypto::Uid; use proto::funder::messages::{McBalance, PendingTransaction}; -pub trait McTransaction { +pub trait McClient { fn get_balance(&mut self) -> AsyncOpResult; fn set_balance(&mut self, new_balance: i128) -> AsyncOpResult<()>; fn set_local_pending_debt(&mut self, debt: u128) -> AsyncOpResult<()>; diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index ed1b7f9d1..66279716e 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -26,12 +26,13 @@ use signature::signature_buff::{hash_token_info, move_token_signature_buff}; use signature::verify::verify_move_token; use database::interface::funder::CurrencyConfig; +use database::transaction::Transaction; use crate::mutual_credit::incoming::{ process_operations_list, IncomingMessage, ProcessTransListError, }; use crate::mutual_credit::outgoing::{queue_operation, QueueOperationError}; -use crate::mutual_credit::types::McTransaction; +use crate::mutual_credit::types::McClient; use crate::types::{create_hashed, MoveTokenHashed}; @@ -51,9 +52,9 @@ pub enum TcStatus { Inconsistent(Signature, u128), // (local_reset_token, local_reset_move_token_counter) } -pub trait TcTransaction { - type McTransaction: McTransaction; - fn mc_transaction(&mut self, currency: Currency) -> &mut Self::McTransaction; +pub trait TcClient { + type McClient: McClient; + fn mc_client(&mut self, currency: Currency) -> &mut Self::McClient; fn get_tc_status(&mut self) -> AsyncOpResult>; fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; @@ -188,7 +189,7 @@ fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKey /// Note that this function does not affect the database, it only returns a new state for the token /// channel. pub async fn init_token_channel( - tc_transaction: &mut impl TcTransaction, + tc_client: &mut impl TcClient, local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result<(), TokenChannelError> @@ -198,7 +199,7 @@ where Ok( if compare_public_key(&local_public_key, &remote_public_key) == Ordering::Less { // We are the first sender - tc_transaction + tc_client .set_direction_outgoing_empty_incoming(initial_move_token( local_public_key, remote_public_key, @@ -212,7 +213,7 @@ where balances_hash: hash_buffer(&[]), move_token_counter: 0, }; - tc_transaction + tc_client .set_direction_incoming(create_hashed::(&move_token_in, &token_info)) .await? }, @@ -226,7 +227,7 @@ where /// Remote side has accepted our reset proposal /// Adjust token channel accordingly. pub async fn init_token_channel_from_remote_reset( - tc_transaction: &mut impl TcTransaction, + tc_client: &mut impl TcTransaction, reset_move_token: &MoveToken, local_public_key: &PublicKey, remote_public_key: &PublicKey, @@ -248,7 +249,7 @@ where return Err(InitTokenChannelError::InvalidResetMoveToken); } - let (local_reset_token, local_reset_move_token_counter) = match tc_transaction + let (local_reset_token, local_reset_move_token_counter) = match tc_client .get_tc_status() .await? { @@ -268,7 +269,7 @@ where // Calculate `info_hash` as seen by the remote side. // Create what we expect to be TokenInfo (From the point of view of remote side): - let mc_balances = tc_transaction.list_local_reset_balances(); + let mc_balances = tc_client.list_local_reset_balances(); let token_info = TokenInfo { balances_hash: hash_mc_infos( @@ -284,13 +285,13 @@ where } // Update move_token_counter: - tc_transaction + tc_client .set_move_token_counter(local_reset_move_token_counter) .await?; // Set direction to outgoing, with the newly received move token: let new_move_token_hashed = create_hashed(&reset_move_token, &token_info); - tc_transaction + tc_client .set_direction_incoming(new_move_token_hashed) .await?; @@ -298,29 +299,27 @@ where } */ -pub async fn handle_in_move_token( - tc_transaction: &mut impl TcTransaction, +pub async fn handle_in_move_token( + tc_client: &mut C, identity_client: &mut IdentityClient, new_move_token: MoveToken, local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result, TokenChannelError> where - B: CanonicalSerialize + Clone, + // TODO: Can we somehow get rid of the Sync requirement for `B`? + B: CanonicalSerialize + Clone + Send + Sync, + C: TcClient + Transaction + Send, + C::McClient: Send, { - match tc_transaction.get_tc_status().await? { + match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => { - handle_in_move_token_dir_in( - tc_transaction, - identity_client, - move_token_in, - new_move_token, - ) - .await + handle_in_move_token_dir_in(tc_client, identity_client, move_token_in, new_move_token) + .await } TcStatus::ConsistentOut(move_token_out, _move_token_in) => { handle_in_move_token_dir_out( - tc_transaction, + tc_client, identity_client, move_token_out, new_move_token, @@ -334,8 +333,7 @@ where if new_move_token.old_token == local_reset_token { // This is a reset move token! let token_info = TokenInfo { - balances_hash: hash_mc_infos(tc_transaction.list_local_reset_balances()) - .await?, + balances_hash: hash_mc_infos(tc_client.list_local_reset_balances()).await?, move_token_counter: local_reset_move_token_counter .checked_sub(1) .ok_or(TokenChannelError::MoveTokenCounterOverflow)?, @@ -350,28 +348,46 @@ where new_token: local_reset_token.clone(), }; - tc_transaction - .set_outgoing_from_inconsistent(move_token_out.clone()) - .await?; - - let output = handle_incoming_token_match( - tc_transaction, - move_token_out, - new_move_token, - local_public_key, - remote_public_key, - ) - .await?; - - match output { + // Atomically attempt to handle a reset move token: + let (output, _was_committed) = tc_client + .transaction(|tc_client| { + Box::pin(async move { + let output = async move { + // Simulate an outgoing move token with the correct `old_token`: + tc_client + .set_outgoing_from_inconsistent(move_token_out.clone()) + .await?; + + // Attempt to receive an incoming token: + handle_incoming_token_match( + tc_client, + move_token_out, + new_move_token, + local_public_key, + remote_public_key, + ) + .await + } + .await; + + // Decide whether we should commit the transaction + let should_commit = match &output { + Ok(IncomingTokenMatchOutput::MoveTokenReceived(_)) => true, + Ok(IncomingTokenMatchOutput::InvalidIncoming(_)) => false, + Err(_) => false, + }; + (output, should_commit) + }) + }) + .await; + + match output? { IncomingTokenMatchOutput::MoveTokenReceived(move_token_received) => { Ok(ReceiveMoveTokenOutput::Received(move_token_received)) } IncomingTokenMatchOutput::InvalidIncoming(_) => { - // TODO: This is wrong, because the balances might have already been - // modified. How to make the previous changes atomic/revertible? - todo!(); - tc_transaction + // In this case the transaction was not committed: + tc_client .set_inconsistent( local_reset_token.clone(), local_reset_move_token_counter, @@ -415,7 +431,7 @@ async fn create_reset_token( } async fn set_inconsistent( - tc_transaction: &mut impl TcTransaction, + tc_client: &mut impl TcClient, identity_client: &mut IdentityClient, ) -> Result<(Signature, u128), TokenChannelError> { let local_reset_token = create_reset_token(identity_client).await?; @@ -424,13 +440,13 @@ async fn set_inconsistent( // to our move token plus 1, so he might not be willing to sign another move token with the // same `move_token_counter`. There could be a gap of size `1` as a result, but we don't care // about it, as long as the `move_token_counter` values are monotonic. - let local_reset_move_token_counter = tc_transaction + let local_reset_move_token_counter = tc_client .get_move_token_counter() .await? .checked_add(2) .ok_or(TokenChannelError::MoveTokenCounterOverflow)?; - tc_transaction + tc_client .set_inconsistent( local_reset_token.clone(), local_reset_move_token_counter.clone(), @@ -441,7 +457,7 @@ async fn set_inconsistent( } async fn handle_in_move_token_dir_in( - tc_transaction: &mut impl TcTransaction, + tc_client: &mut impl TcClient, identity_client: &mut IdentityClient, move_token_in: MoveTokenHashed, new_move_token: MoveToken, @@ -455,7 +471,7 @@ where } else { // Inconsistency let (local_reset_token, local_reset_move_token_counter) = - set_inconsistent(tc_transaction, identity_client).await?; + set_inconsistent(tc_client, identity_client).await?; Ok(ReceiveMoveTokenOutput::ChainInconsistent( local_reset_token, local_reset_move_token_counter, @@ -463,8 +479,8 @@ where } } -async fn handle_in_move_token_dir_out( - tc_transaction: &mut impl TcTransaction, +async fn handle_in_move_token_dir_out( + tc_client: &mut C, identity_client: &mut IdentityClient, move_token_out: MoveToken, new_move_token: MoveToken, @@ -472,28 +488,48 @@ async fn handle_in_move_token_dir_out( remote_public_key: &PublicKey, ) -> Result, TokenChannelError> where - B: Clone + CanonicalSerialize, + B: Clone + CanonicalSerialize + Send + Sync, + C: TcClient + Transaction + Send, + C::McClient: Send, { if new_move_token.old_token == move_token_out.new_token { - let output = handle_incoming_token_match( - tc_transaction, - move_token_out, - new_move_token, - local_public_key, - remote_public_key, - ) - .await?; - match output { + // Atomically attempt to handle an incoming move token: + let (output, _was_committed) = tc_client + .transaction(|tc_client| { + Box::pin(async move { + let output = async move { + // Attempt to receive an incoming token: + handle_incoming_token_match( + tc_client, + move_token_out, + new_move_token, + local_public_key, + remote_public_key, + ) + .await + } + .await; + + // Decide whether we should commit the transaction + let should_commit = match &output { + Ok(IncomingTokenMatchOutput::MoveTokenReceived(_)) => true, + Ok(IncomingTokenMatchOutput::InvalidIncoming(_)) => false, + Err(_) => false, + }; + (output, should_commit) + }) + }) + .await; + + match output? { IncomingTokenMatchOutput::MoveTokenReceived(move_token_received) => { return Ok(ReceiveMoveTokenOutput::Received(move_token_received)) } IncomingTokenMatchOutput::InvalidIncoming(_) => { - // TODO: This is probably wrong, because we might have already changed some - // balances. - todo!(); // Inconsistency + // In this case the transaction was not committed: let (local_reset_token, local_reset_move_token_counter) = - set_inconsistent(tc_transaction, identity_client).await?; + set_inconsistent(tc_client, identity_client).await?; Ok(ReceiveMoveTokenOutput::ChainInconsistent( local_reset_token, local_reset_move_token_counter, @@ -509,7 +545,7 @@ where } else { // Inconsistency let (local_reset_token, local_reset_move_token_counter) = - set_inconsistent(tc_transaction, identity_client).await?; + set_inconsistent(tc_client, identity_client).await?; Ok(ReceiveMoveTokenOutput::ChainInconsistent( local_reset_token, local_reset_move_token_counter, @@ -553,8 +589,73 @@ enum IncomingTokenMatchOutput { InvalidIncoming(InvalidIncoming), } +/* +#[derive(Debug, From)] +enum IncomingTransactionError { + InvalidIncoming(InvalidIncoming), + TokenChannelError(TokenChannelError), +} + +/// A transactional function. No changes occur if a failure happens. +async fn handle_incoming_token_match_transact( + tc_client: &mut C, + move_token_out: MoveToken, + new_move_token: MoveToken, // remote_max_debts: &ImHashMap, + local_public_key: &PublicKey, + remote_public_key: &PublicKey, +) -> Result, TokenChannelError> +where + B: Clone + CanonicalSerialize + Send, + C: TcClient + Transaction + Send, + C::McClient: Send, +{ + let incoming_output = tc_client + .transaction(move |tc_client| { + Box::pin(async move { + let output = handle_incoming_token_match( + tc_client, + move_token_out, + new_move_token, + local_public_key, + remote_public_key, + ) + .await?; + + // We map "Transaction failure" to Err(...), and "Transaction success" into Ok(...) + match output { + IncomingTokenMatchOutput::InvalidIncoming(invalid_incoming) => { + // Transaction failed + Err(IncomingTransactionError::InvalidIncoming(invalid_incoming)) + } + IncomingTokenMatchOutput::MoveTokenReceived(move_token_received) => { + // Transaction succeeded + Ok(move_token_received) + } + } + }) + }) + .await; + + // We map back into recoverable and unrecoverable errors: + match incoming_output { + Ok(move_token_received) => Ok(IncomingTokenMatchOutput::MoveTokenReceived( + // Transaction succeeded + move_token_received, + )), + Err(IncomingTransactionError::InvalidIncoming(invalid_incoming)) => { + // Transaction failed, recoverable error + Ok(IncomingTokenMatchOutput::InvalidIncoming(invalid_incoming)) + } + Err(IncomingTransactionError::TokenChannelError(token_channel_error)) => { + // Unrecoverable error + Err(token_channel_error) + } + } +} +*/ + async fn handle_incoming_token_match( - tc_transaction: &mut impl TcTransaction, + tc_client: &mut impl TcClient, move_token_out: MoveToken, new_move_token: MoveToken, // remote_max_debts: &ImHashMap, local_public_key: &PublicKey, @@ -594,29 +695,19 @@ where // - (3) (Not in the local set) or (in the local set with balance zero and zero pending debts) for diff_currency in &new_move_token.currencies_diff { // Check if we need to add currency: - if !tc_transaction - .is_remote_currency(diff_currency.clone()) - .await? - { + if !tc_client.is_remote_currency(diff_currency.clone()).await? { // Add a new remote currency. - tc_transaction - .add_remote_currency(diff_currency.clone()) - .await?; + tc_client.add_remote_currency(diff_currency.clone()).await?; // If we also have this currency as a local currency, add a new mutual credit: - if tc_transaction - .is_local_currency(diff_currency.clone()) - .await? - { - tc_transaction.add_mutual_credit(diff_currency.clone()); + if tc_client.is_local_currency(diff_currency.clone()).await? { + tc_client.add_mutual_credit(diff_currency.clone()); } } else { - let is_local_currency = tc_transaction - .is_local_currency(diff_currency.clone()) - .await?; + let is_local_currency = tc_client.is_local_currency(diff_currency.clone()).await?; if is_local_currency { - let mc_balance = tc_transaction - .mc_transaction(diff_currency.clone()) + let mc_balance = tc_client + .mc_client(diff_currency.clone()) .get_balance() .await?; if mc_balance.balance == 0 @@ -625,7 +716,7 @@ where { // We may remove the currency if the balance and pending debts are exactly // zero: - tc_transaction + tc_client .remove_remote_currency(diff_currency.clone()) .await?; // TODO: Do We need to report outside that we removed this currency somehow? @@ -637,7 +728,7 @@ where )); } } else { - tc_transaction + tc_client .remove_remote_currency(diff_currency.clone()) .await?; // TODO: Do We need to report outside that we removed this currency somehow? @@ -650,13 +741,13 @@ where // Attempt to apply operations for every currency: for currency_operations in &new_move_token.currencies_operations { - let remote_max_debt = tc_transaction + let remote_max_debt = tc_client .get_currency_config(currency_operations.currency.clone()) .await? .remote_max_debt; let res = process_operations_list( - tc_transaction.mc_transaction(currency_operations.currency.clone()), + tc_client.mc_client(currency_operations.currency.clone()), currency_operations.operations.clone(), ¤cy_operations.currency, remote_public_key, @@ -685,14 +776,14 @@ where .push(move_token_received_currency); } - let move_token_counter = tc_transaction.get_move_token_counter().await?; + let move_token_counter = tc_client.get_move_token_counter().await?; let new_move_token_counter = move_token_counter .checked_add(1) .ok_or(TokenChannelError::MoveTokenCounterOverflow)?; // Calculate `info_hash` as seen by the remote side. // Create what we expect to be TokenInfo (From the point of view of remote side): - let mc_balances = tc_transaction.list_balances(); + let mc_balances = tc_client.list_balances(); let token_info = TokenInfo { balances_hash: hash_mc_infos( @@ -711,13 +802,13 @@ where } // Update move_token_counter: - tc_transaction + tc_client .set_move_token_counter(new_move_token_counter) .await?; // Set direction to outgoing, with the newly received move token: let new_move_token_hashed = create_hashed(&new_move_token, &token_info); - tc_transaction + tc_client .set_direction_incoming(new_move_token_hashed) .await?; @@ -727,7 +818,7 @@ where } pub async fn handle_out_move_token( - tc_transaction: &mut impl TcTransaction, + tc_client: &mut impl TcClient, identity_client: &mut IdentityClient, currencies_operations: Vec, relays_diff: Vec>, @@ -739,7 +830,7 @@ where B: CanonicalSerialize + Clone, { // We expect that our current state is incoming: - let move_token_in = match tc_transaction.get_tc_status().await? { + let move_token_in = match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => move_token_in, TcStatus::ConsistentOut(_move_token_out, _move_token_in) => { return Err(TokenChannelError::InvalidTokenChannelStatus) @@ -752,29 +843,19 @@ where // Handle currencies_diff: for diff_currency in ¤cies_diff { // Check if we need to add currency: - if !tc_transaction - .is_local_currency(diff_currency.clone()) - .await? - { + if !tc_client.is_local_currency(diff_currency.clone()).await? { // Add a new local currency. - tc_transaction - .add_local_currency(diff_currency.clone()) - .await?; + tc_client.add_local_currency(diff_currency.clone()).await?; // If we also have this currency as a remote currency, add a new mutual credit: - if tc_transaction - .is_remote_currency(diff_currency.clone()) - .await? - { - tc_transaction.add_mutual_credit(diff_currency.clone()); + if tc_client.is_remote_currency(diff_currency.clone()).await? { + tc_client.add_mutual_credit(diff_currency.clone()); } } else { - let is_remote_currency = tc_transaction - .is_remote_currency(diff_currency.clone()) - .await?; + let is_remote_currency = tc_client.is_remote_currency(diff_currency.clone()).await?; if is_remote_currency { - let mc_balance = tc_transaction - .mc_transaction(diff_currency.clone()) + let mc_balance = tc_client + .mc_client(diff_currency.clone()) .get_balance() .await?; if mc_balance.balance == 0 @@ -783,7 +864,7 @@ where { // We may remove the currency if the balance and pending debts are exactly // zero: - tc_transaction + tc_client .remove_local_currency(diff_currency.clone()) .await?; // TODO: Do We need to report outside that we removed this currency somehow? @@ -794,7 +875,7 @@ where return Err(TokenChannelError::CanNotRemoveCurrencyInUse); } } else { - tc_transaction + tc_client .remove_remote_currency(diff_currency.clone()) .await?; // TODO: Do We need to report outside that we removed this currency somehow? @@ -806,7 +887,7 @@ where for currency_operations in ¤cies_operations { for operation in currency_operations.operations.iter().cloned() { queue_operation( - tc_transaction.mc_transaction(currency_operations.currency.clone()), + tc_client.mc_client(currency_operations.currency.clone()), operation, ¤cy_operations.currency, local_public_key, @@ -815,12 +896,12 @@ where } } - let new_move_token_counter = tc_transaction + let new_move_token_counter = tc_client .get_move_token_counter() .await? .checked_add(1) .ok_or(TokenChannelError::MoveTokenCounterOverflow)?; - let mc_balances = tc_transaction.list_balances(); + let mc_balances = tc_client.list_balances(); let token_info = TokenInfo { balances_hash: hash_mc_infos(mc_balances).await?, @@ -847,9 +928,7 @@ where // Set the direction to be outgoing: // TODO: This should also save the last incoming move token, in an atomic way. // Should probably be implemented inside the database code. - tc_transaction - .set_direction_outgoing(move_token.clone()) - .await?; + tc_client.set_direction_outgoing(move_token.clone()).await?; Ok(move_token) } From ed9ca1c3a8572191f683a708f5b5faa6fb802006 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 11:48:33 +0200 Subject: [PATCH 148/478] funder: Added TODO comment --- components/funder/src/token_channel.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 66279716e..9d1079b59 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -836,7 +836,9 @@ where return Err(TokenChannelError::InvalidTokenChannelStatus) } TcStatus::Inconsistent(_local_reset_token, _local_reset_move_token_counter) => { - return Err(TokenChannelError::InvalidTokenChannelStatus) + // TODO: Possibly add here some code for outgoing move token handling + todo!(); + return Err(TokenChannelError::InvalidTokenChannelStatus); } }; From 1e3b334368177c91e6f049efd545023d74fc27ff Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 12:19:23 +0200 Subject: [PATCH 149/478] funder: Removed redundant call --- components/funder/src/token_channel.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 9d1079b59..4cf3bfecf 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -387,12 +387,6 @@ where } IncomingTokenMatchOutput::InvalidIncoming(_) => { // In this case the transaction was not committed: - tc_client - .set_inconsistent( - local_reset_token.clone(), - local_reset_move_token_counter, - ) - .await?; Ok(ReceiveMoveTokenOutput::ChainInconsistent( local_reset_token, local_reset_move_token_counter, From e64074af47e21eb897980e64307b0266e4a6cc41 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 12:19:35 +0200 Subject: [PATCH 150/478] funder: Removed old comments --- components/funder/src/token_channel.rs | 144 ------------------------- 1 file changed, 144 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 4cf3bfecf..9256b5ce8 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -220,85 +220,6 @@ where ) } -/* -// TODO: How to handle errors here? -// Some errors might not be recoverable -// TODO: Should we check the signature ourselves, or the user of this function should? -/// Remote side has accepted our reset proposal -/// Adjust token channel accordingly. -pub async fn init_token_channel_from_remote_reset( - tc_client: &mut impl TcTransaction, - reset_move_token: &MoveToken, - local_public_key: &PublicKey, - remote_public_key: &PublicKey, -) -> Result<(), InitTokenChannelError> -where - B: Clone + CanonicalSerialize, -{ - // Verify signature: - if !verify_move_token(&reset_move_token, &remote_public_key) { - return Err(InitTokenChannelError::InvalidSignature); - } - - // TODO: Maybe we can allow reset token messages that are not empty? - // Make sure that the MoveToken message is empty: - if !reset_move_token.relays_diff.is_empty() - || !reset_move_token.currencies_diff.is_empty() - || !reset_move_token.currencies_operations.is_empty() - { - return Err(InitTokenChannelError::InvalidResetMoveToken); - } - - let (local_reset_token, local_reset_move_token_counter) = match tc_client - .get_tc_status() - .await? - { - TcStatus::ConsistentIn(_) => return Err(InitTokenChannelError::InvalidTokenChannelStatus), - - TcStatus::ConsistentOut(_, _) => { - return Err(InitTokenChannelError::InvalidTokenChannelStatus) - } - TcStatus::Inconsistent(local_reset_token, local_reset_move_token_counter) => { - (local_reset_token, local_reset_move_token_counter) - } - }; - - if local_reset_token != reset_move_token.old_token { - return Err(InitTokenChannelError::InvalidResetToken); - } - - // Calculate `info_hash` as seen by the remote side. - // Create what we expect to be TokenInfo (From the point of view of remote side): - let mc_balances = tc_client.list_local_reset_balances(); - - let token_info = TokenInfo { - balances_hash: hash_mc_infos( - mc_balances.map_ok(|(currency, mc_balance)| (currency, mc_balance.flip())), - ) - .await?, - move_token_counter: local_reset_move_token_counter, - }; - - let info_hash = hash_token_info(remote_public_key, local_public_key, &token_info); - if reset_move_token.info_hash != info_hash { - return Err(InitTokenChannelError::InvalidTokenInfo); - } - - // Update move_token_counter: - tc_client - .set_move_token_counter(local_reset_move_token_counter) - .await?; - - // Set direction to outgoing, with the newly received move token: - let new_move_token_hashed = create_hashed(&reset_move_token, &token_info); - tc_client - .set_direction_incoming(new_move_token_hashed) - .await?; - - Ok(()) -} -*/ - pub async fn handle_in_move_token( tc_client: &mut C, identity_client: &mut IdentityClient, @@ -583,71 +504,6 @@ enum IncomingTokenMatchOutput { InvalidIncoming(InvalidIncoming), } -/* -#[derive(Debug, From)] -enum IncomingTransactionError { - InvalidIncoming(InvalidIncoming), - TokenChannelError(TokenChannelError), -} - -/// A transactional function. No changes occur if a failure happens. -async fn handle_incoming_token_match_transact( - tc_client: &mut C, - move_token_out: MoveToken, - new_move_token: MoveToken, // remote_max_debts: &ImHashMap, - local_public_key: &PublicKey, - remote_public_key: &PublicKey, -) -> Result, TokenChannelError> -where - B: Clone + CanonicalSerialize + Send, - C: TcClient + Transaction + Send, - C::McClient: Send, -{ - let incoming_output = tc_client - .transaction(move |tc_client| { - Box::pin(async move { - let output = handle_incoming_token_match( - tc_client, - move_token_out, - new_move_token, - local_public_key, - remote_public_key, - ) - .await?; - - // We map "Transaction failure" to Err(...), and "Transaction success" into Ok(...) - match output { - IncomingTokenMatchOutput::InvalidIncoming(invalid_incoming) => { - // Transaction failed - Err(IncomingTransactionError::InvalidIncoming(invalid_incoming)) - } - IncomingTokenMatchOutput::MoveTokenReceived(move_token_received) => { - // Transaction succeeded - Ok(move_token_received) - } - } - }) - }) - .await; - - // We map back into recoverable and unrecoverable errors: - match incoming_output { - Ok(move_token_received) => Ok(IncomingTokenMatchOutput::MoveTokenReceived( - // Transaction succeeded - move_token_received, - )), - Err(IncomingTransactionError::InvalidIncoming(invalid_incoming)) => { - // Transaction failed, recoverable error - Ok(IncomingTokenMatchOutput::InvalidIncoming(invalid_incoming)) - } - Err(IncomingTransactionError::TokenChannelError(token_channel_error)) => { - // Unrecoverable error - Err(token_channel_error) - } - } -} -*/ - async fn handle_incoming_token_match( tc_client: &mut impl TcClient, move_token_out: MoveToken, From 0f740e253800979a52a3b8df4247f89d784c2007 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 12:43:03 +0200 Subject: [PATCH 151/478] funder: impl create_reset_token() --- components/funder/src/token_channel.rs | 83 +++++++++++++++------- components/signature/src/signature_buff.rs | 18 +++++ 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 9256b5ce8..6a9f2bdad 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -9,8 +9,6 @@ use futures::{Stream, StreamExt, TryStreamExt}; use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; -use signature::canonical::CanonicalSerialize; - use crypto::hash::{hash_buffer, Hasher}; use crypto::identity::compare_public_key; @@ -22,7 +20,10 @@ use proto::funder::messages::{ Currency, CurrencyOperations, McBalance, MoveToken, PendingTransaction, TokenInfo, }; -use signature::signature_buff::{hash_token_info, move_token_signature_buff}; +use signature::canonical::CanonicalSerialize; +use signature::signature_buff::{ + hash_token_info, move_token_signature_buff, reset_token_signature_buff, +}; use signature::verify::verify_move_token; use database::interface::funder::CurrencyConfig; @@ -165,8 +166,6 @@ fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKey move_token_counter: 0, }; - // let info_hash = hash_token_info(remote_public_key, local_public_key, &token_info); - // This is a special initialization case. // Note that this is the only case where new_token is not a valid signature. // We do this because we want to have synchronization between the two sides of the token @@ -235,8 +234,15 @@ where { match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => { - handle_in_move_token_dir_in(tc_client, identity_client, move_token_in, new_move_token) - .await + handle_in_move_token_dir_in( + tc_client, + identity_client, + local_public_key, + remote_public_key, + move_token_in, + new_move_token, + ) + .await } TcStatus::ConsistentOut(move_token_out, _move_token_in) => { handle_in_move_token_dir_out( @@ -327,30 +333,30 @@ where /// Generate a reset token, to be used by remote side if he wants to accept the reset terms. async fn create_reset_token( identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + remote_public_key: &PublicKey, + move_token_counter: u128, ) -> Result { - // TODO: // Some ideas: // - Use a random generator to randomly generate an identity client. // - Sign over a blob that contains: - // - hash(prefix ("INCONSISTENT_TOKEN")) + // - hash(prefix ("SOME_STRING")) // - Both public keys. - // - Current counter + 1 - /* - let signature_buff = - let local_reset_token = identity_client - .request_signature(signature_buff) + // - local_reset_move_token_counter + let sign_buffer = + reset_token_signature_buff(local_public_key, remote_public_key, move_token_counter); + Ok(identity_client + .request_signature(sign_buffer) .await - .map_err(|_| TokenChannelError::RequestSignatureError)?; - */ - todo!() + .map_err(|_| TokenChannelError::RequestSignatureError)?) } async fn set_inconsistent( tc_client: &mut impl TcClient, identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + remote_public_key: &PublicKey, ) -> Result<(Signature, u128), TokenChannelError> { - let local_reset_token = create_reset_token(identity_client).await?; - // We increase by 2, because the other side might have already signed a move token that equals // to our move token plus 1, so he might not be willing to sign another move token with the // same `move_token_counter`. There could be a gap of size `1` as a result, but we don't care @@ -361,6 +367,15 @@ async fn set_inconsistent( .checked_add(2) .ok_or(TokenChannelError::MoveTokenCounterOverflow)?; + // Create a local reset token, to be used by the remote side to accept our terms: + let local_reset_token = create_reset_token( + identity_client, + local_public_key, + remote_public_key, + local_reset_move_token_counter, + ) + .await?; + tc_client .set_inconsistent( local_reset_token.clone(), @@ -374,6 +389,8 @@ async fn set_inconsistent( async fn handle_in_move_token_dir_in( tc_client: &mut impl TcClient, identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + remote_public_key: &PublicKey, move_token_in: MoveTokenHashed, new_move_token: MoveToken, ) -> Result, TokenChannelError> @@ -385,8 +402,13 @@ where Ok(ReceiveMoveTokenOutput::Duplicate) } else { // Inconsistency - let (local_reset_token, local_reset_move_token_counter) = - set_inconsistent(tc_client, identity_client).await?; + let (local_reset_token, local_reset_move_token_counter) = set_inconsistent( + tc_client, + identity_client, + local_public_key, + remote_public_key, + ) + .await?; Ok(ReceiveMoveTokenOutput::ChainInconsistent( local_reset_token, local_reset_move_token_counter, @@ -443,8 +465,13 @@ where IncomingTokenMatchOutput::InvalidIncoming(_) => { // Inconsistency // In this case the transaction was not committed: - let (local_reset_token, local_reset_move_token_counter) = - set_inconsistent(tc_client, identity_client).await?; + let (local_reset_token, local_reset_move_token_counter) = set_inconsistent( + tc_client, + identity_client, + local_public_key, + remote_public_key, + ) + .await?; Ok(ReceiveMoveTokenOutput::ChainInconsistent( local_reset_token, local_reset_move_token_counter, @@ -459,8 +486,13 @@ where )) } else { // Inconsistency - let (local_reset_token, local_reset_move_token_counter) = - set_inconsistent(tc_client, identity_client).await?; + let (local_reset_token, local_reset_move_token_counter) = set_inconsistent( + tc_client, + identity_client, + local_public_key, + remote_public_key, + ) + .await?; Ok(ReceiveMoveTokenOutput::ChainInconsistent( local_reset_token, local_reset_move_token_counter, @@ -536,7 +568,6 @@ where // currencies_diff represents a "xor" between the previous set of currencies and the new set of // currencies. // - // TODO: // - Add to remote currencies every currency that is in the xor set, but not in the current // set. // - Remove from remote currencies currencies that satisfy the following requirements: diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index e9e76896f..40cb3fd20 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -138,6 +138,24 @@ where sig_buffer } +// TODO: Rethink string in this prefix: +pub const RESET_TOKEN_PREFIX: &[u8] = b"RESET_TOKEN"; + +pub fn reset_token_signature_buff( + local_public_key: &PublicKey, + remote_public_key: &PublicKey, + move_token_counter: u128, +) -> Vec { + let mut sig_buffer = Vec::new(); + sig_buffer.extend_from_slice(&hash::hash_buffer(RESET_TOKEN_PREFIX)); + sig_buffer.extend_from_slice(&local_public_key); + sig_buffer.extend_from_slice(&remote_public_key); + sig_buffer + .write_u128::(move_token_counter) + .unwrap(); + sig_buffer +} + pub const MUTATIONS_UPDATE_PREFIX: &[u8] = b"MUTATIONS_UPDATE"; pub fn create_mutations_update_signature_buff(mutations_update: &MutationsUpdate) -> Vec { From be9b6d5225349206047e7cde6b1788647b0b3d85 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 12:52:58 +0200 Subject: [PATCH 152/478] funder: Added entries to TcStatus::Inconsistent() --- components/funder/src/token_channel.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 6a9f2bdad..897e8b48e 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -50,7 +50,8 @@ pub type TcOpSenderResult = oneshot::Sender>; pub enum TcStatus { ConsistentIn(MoveTokenHashed), // (move_token_in) ConsistentOut(MoveToken, MoveTokenHashed), // (move_token_out, last_move_token_in) - Inconsistent(Signature, u128), // (local_reset_token, local_reset_move_token_counter) + Inconsistent(Signature, u128, Option<(Signature, u128)>), + // (local_reset_token, local_reset_move_token_counter, Option<(remote_reset_token, remote_reset_move_token_counter)>) } pub trait TcClient { @@ -255,7 +256,7 @@ where ) .await } - TcStatus::Inconsistent(local_reset_token, local_reset_move_token_counter) => { + TcStatus::Inconsistent(local_reset_token, local_reset_move_token_counter, _opt_remote) => { // Might be a reset move token if new_move_token.old_token == local_reset_token { // This is a reset move token! @@ -716,7 +717,11 @@ where TcStatus::ConsistentOut(_move_token_out, _move_token_in) => { return Err(TokenChannelError::InvalidTokenChannelStatus) } - TcStatus::Inconsistent(_local_reset_token, _local_reset_move_token_counter) => { + TcStatus::Inconsistent( + _local_reset_token, + _local_reset_move_token_counter, + _opt_remote, + ) => { // TODO: Possibly add here some code for outgoing move token handling todo!(); return Err(TokenChannelError::InvalidTokenChannelStatus); From e839e385a0e56610097de33645a4f5205aefe75e Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 13:28:11 +0200 Subject: [PATCH 153/478] funder: token_channel: impl accept_remote_reset() --- components/funder/src/token_channel.rs | 83 ++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 6 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index 897e8b48e..d78ed8b04 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -75,7 +75,10 @@ pub trait TcClient { fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; /// Simulate incoming token, to be used before an outgoing reset move token (a local reset) - fn set_incoming_from_inconsistent(&mut self) -> AsyncOpResult<()>; + fn set_incoming_from_inconsistent( + &mut self, + move_token_hashed: MoveTokenHashed, + ) -> AsyncOpResult<()>; fn get_move_token_counter(&mut self) -> AsyncOpResult; fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; @@ -89,6 +92,10 @@ pub trait TcClient { /// Only relevant for inconsistent channels fn list_local_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + /// Return a sorted async iterator of all remote reset proposal balances + /// Only relevant for inconsistent channels + fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; @@ -172,7 +179,7 @@ fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKey // We do this because we want to have synchronization between the two sides of the token // channel, however, the remote side has no means of generating the signature (Because he // doesn't have the private key). Therefore we use a dummy new_token instead. - let move_token_out = MoveToken { + let move_token_out = MoveToken:: { old_token: token_from_public_key(&low_public_key), currencies_operations: Vec::new(), relays_diff: Vec::new(), @@ -260,6 +267,8 @@ where // Might be a reset move token if new_move_token.old_token == local_reset_token { // This is a reset move token! + + // Simulate an outgoing move token with the correct `new_token`: let token_info = TokenInfo { balances_hash: hash_mc_infos(tc_client.list_local_reset_balances()).await?, move_token_counter: local_reset_move_token_counter @@ -281,7 +290,6 @@ where .transaction(|tc_client| { Box::pin(async move { let output = async move { - // Simulate an outgoing move token with the correct `old_token`: tc_client .set_outgoing_from_inconsistent(move_token_out.clone()) .await?; @@ -722,8 +730,6 @@ where _local_reset_move_token_counter, _opt_remote, ) => { - // TODO: Possibly add here some code for outgoing move token handling - todo!(); return Err(TokenChannelError::InvalidTokenChannelStatus); } }; @@ -821,7 +827,72 @@ where Ok(move_token) } -// TODO: Implement: new_from_local_reset, new_from_remote_reset. +/// Apply a token channel reset, accepting remote side's +/// reset terms. +pub async fn accept_remote_reset( + tc_client: &mut impl TcClient, + identity_client: &mut IdentityClient, + currencies_operations: Vec, + relays_diff: Vec>, + currencies_diff: Vec, + local_public_key: &PublicKey, + remote_public_key: &PublicKey, +) -> Result, TokenChannelError> +where + B: CanonicalSerialize + Clone, +{ + // Make sure that we are in inconsistent state, + // and that the remote side has already sent his reset terms: + let (remote_reset_token, remote_reset_move_token_counter) = match tc_client + .get_tc_status() + .await? + { + TcStatus::ConsistentIn(_) => return Err(TokenChannelError::InvalidTokenChannelStatus), + TcStatus::ConsistentOut(_, _) => return Err(TokenChannelError::InvalidTokenChannelStatus), + TcStatus::Inconsistent(_, _, None) => { + // We don't have the remote side's reset terms yet: + return Err(TokenChannelError::InvalidTokenChannelStatus); + } + TcStatus::Inconsistent( + _local_reset_token, + _local_reset_move_token_counter, + Some((remote_reset_token, remote_reset_move_token_counter)), + ) => (remote_reset_token, remote_reset_move_token_counter), + }; + + // Simulate an incoming move token with the correct `new_token`: + let token_info = TokenInfo { + balances_hash: hash_mc_infos(tc_client.list_remote_reset_balances()).await?, + move_token_counter: remote_reset_move_token_counter + .checked_sub(1) + .ok_or(TokenChannelError::MoveTokenCounterOverflow)?, + }; + + let move_token_in = MoveToken:: { + old_token: Signature::from(&[0; Signature::len()]), + currencies_operations: Vec::new(), + relays_diff: Vec::new(), + currencies_diff: Vec::new(), + info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), + new_token: remote_reset_token.clone(), + }; + + tc_client + .set_incoming_from_inconsistent(create_hashed(&move_token_in, &token_info)) + .await?; + + // Create an outgoing move token, to be sent to the remote side: + handle_out_move_token( + tc_client, + identity_client, + currencies_operations, + relays_diff, + currencies_diff, + local_public_key, + remote_public_key, + ) + .await +} /* impl TokenChannel From 4189f99d4b18e5866d641ab6a0c87fb080f7e4c8 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 18:37:12 +0200 Subject: [PATCH 154/478] funder: Simplified match clause syntax --- components/funder/src/token_channel.rs | 30 ++++++++++++-------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index d78ed8b04..c0f9b9d9b 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -843,22 +843,20 @@ where { // Make sure that we are in inconsistent state, // and that the remote side has already sent his reset terms: - let (remote_reset_token, remote_reset_move_token_counter) = match tc_client - .get_tc_status() - .await? - { - TcStatus::ConsistentIn(_) => return Err(TokenChannelError::InvalidTokenChannelStatus), - TcStatus::ConsistentOut(_, _) => return Err(TokenChannelError::InvalidTokenChannelStatus), - TcStatus::Inconsistent(_, _, None) => { - // We don't have the remote side's reset terms yet: - return Err(TokenChannelError::InvalidTokenChannelStatus); - } - TcStatus::Inconsistent( - _local_reset_token, - _local_reset_move_token_counter, - Some((remote_reset_token, remote_reset_move_token_counter)), - ) => (remote_reset_token, remote_reset_move_token_counter), - }; + let (remote_reset_token, remote_reset_move_token_counter) = + match tc_client.get_tc_status().await? { + TcStatus::ConsistentIn(_) + | TcStatus::ConsistentOut(_, _) + | TcStatus::Inconsistent(_, _, None) => { + // We don't have the remote side's reset terms yet: + return Err(TokenChannelError::InvalidTokenChannelStatus); + } + TcStatus::Inconsistent( + _local_reset_token, + _local_reset_move_token_counter, + Some((remote_reset_token, remote_reset_move_token_counter)), + ) => (remote_reset_token, remote_reset_move_token_counter), + }; // Simulate an incoming move token with the correct `new_token`: let token_info = TokenInfo { From 6ca7f09a62b1ff6fd84ca3afd290c8806ab85cd3 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 18:38:03 +0200 Subject: [PATCH 155/478] funder: Removed old comment --- components/funder/src/token_channel.rs | 154 ------------------------- 1 file changed, 154 deletions(-) diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel.rs index c0f9b9d9b..37b0a1130 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel.rs @@ -892,160 +892,6 @@ where .await } -/* -impl TokenChannel -where - B: Clone + CanonicalSerialize, -{ - pub fn new(local_public_key: &PublicKey, remote_public_key: &PublicKey) -> Self { - if compare_public_key(&local_public_key, &remote_public_key) == Ordering::Less { - // We are the first sender - let (move_token_out, token_info) = - initial_move_token(local_public_key, remote_public_key); - let tc_outgoing = TcOutgoing { - move_token_out, - token_info, - opt_prev_move_token_in: None, - }; - TokenChannel { - direction: TcDirection::Outgoing(tc_outgoing), - mutual_credits: ImHashMap::new(), - active_currencies: ActiveCurrencies::new(), - } - } else { - // We are the second sender - let (move_token_in_full, token_info) = - initial_move_token(remote_public_key, local_public_key); - let move_token_in = create_hashed::(&move_token_in_full, &token_info); - - let tc_incoming = TcIncoming { move_token_in }; - TokenChannel { - direction: TcDirection::Incoming(tc_incoming), - mutual_credits: ImHashMap::new(), - active_currencies: ActiveCurrencies::new(), - } - } - } - - pub fn get_mutual_credits(&self) -> &ImHashMap { - &self.mutual_credits - } - - pub fn get_active_currencies(&self) -> &ActiveCurrencies { - &self.active_currencies - } - - pub fn new_from_remote_reset( - reset_move_token: &MoveToken, - remote_token_info: &TokenInfo, - ) -> TokenChannel { - let mutual_credits: ImHashMap = remote_token_info - .mc - .balances - .iter() - .map(|currency_balance_info| { - ( - currency_balance_info.currency.clone(), - MutualCredit::new( - &remote_token_info.mc.remote_public_key, - &remote_token_info.mc.local_public_key, - ¤cy_balance_info.currency, - currency_balance_info - .balance_info - .balance - .checked_neg() - .unwrap(), - ), - ) - }) - .collect(); - - let active_currencies: ImHashSet<_> = mutual_credits.keys().cloned().collect(); - - let tc_incoming = TcIncoming { - move_token_in: create_hashed(&reset_move_token, remote_token_info), - }; - - TokenChannel { - direction: TcDirection::Incoming(tc_incoming), - mutual_credits, - active_currencies: ActiveCurrencies { - local: active_currencies.clone(), - remote: active_currencies, - }, - } - } - - pub fn new_from_local_reset( - reset_move_token: &MoveToken, - token_info: &TokenInfo, - opt_last_incoming_move_token: Option, - ) -> TokenChannel { - let mutual_credits: ImHashMap = token_info - .mc - .balances - .iter() - .map(|currency_balance_info| { - ( - currency_balance_info.currency.clone(), - MutualCredit::new( - &token_info.mc.local_public_key, - &token_info.mc.remote_public_key, - ¤cy_balance_info.currency, - currency_balance_info.balance_info.balance, - ), - ) - }) - .collect(); - - let active_currencies: ImHashSet<_> = mutual_credits.keys().cloned().collect(); - let tc_outgoing = TcOutgoing { - move_token_out: reset_move_token.clone(), - token_info: token_info.clone(), - opt_prev_move_token_in: opt_last_incoming_move_token, - }; - - TokenChannel { - direction: TcDirection::Outgoing(tc_outgoing), - mutual_credits, - active_currencies: ActiveCurrencies { - local: active_currencies.clone(), - remote: active_currencies, - }, - } - } - - pub fn get_direction(&self) -> TcDirectionBorrow<'_, B> { - match &self.direction { - TcDirection::Incoming(tc_incoming) => TcDirectionBorrow::In(TcInBorrow { - tc_incoming: &tc_incoming, - mutual_credits: &self.mutual_credits, - active_currencies: &self.active_currencies, - }), - TcDirection::Outgoing(tc_outgoing) => TcDirectionBorrow::Out(TcOutBorrow { - tc_outgoing: &tc_outgoing, - mutual_credits: &self.mutual_credits, - active_currencies: &self.active_currencies, - }), - } - } - - /// Get the last incoming move token - /// If no such incoming move token exists (Maybe this is the beginning of the relationship), - /// returns None. - pub fn get_last_incoming_move_token_hashed(&self) -> Option<&MoveTokenHashed> { - match &self.direction { - TcDirection::Incoming(tc_incoming) => Some(&tc_incoming.move_token_in), - TcDirection::Outgoing(tc_outgoing) => match &tc_outgoing.opt_prev_move_token_in { - None => None, - Some(prev_move_token_in) => Some(prev_move_token_in), - }, - } - } - -} -*/ - // TODO: Restore tests /* From acacf7eb24f6b91f957307fecd9ef818643193c3 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 18:46:29 +0200 Subject: [PATCH 156/478] funder: Refactored token_channel into a separate directory. --- components/funder/src/token_channel/mod.rs | 9 ++ .../src/{ => token_channel}/token_channel.rs | 72 +----------- components/funder/src/token_channel/types.rs | 109 ++++++++++++++++++ 3 files changed, 119 insertions(+), 71 deletions(-) create mode 100644 components/funder/src/token_channel/mod.rs rename components/funder/src/{ => token_channel}/token_channel.rs (93%) create mode 100644 components/funder/src/token_channel/types.rs diff --git a/components/funder/src/token_channel/mod.rs b/components/funder/src/token_channel/mod.rs new file mode 100644 index 000000000..a7d6ff522 --- /dev/null +++ b/components/funder/src/token_channel/mod.rs @@ -0,0 +1,9 @@ +mod token_channel; +mod types; + +pub use self::token_channel::{ + accept_remote_reset, handle_in_move_token, handle_out_move_token, init_token_channel, + TokenChannelError, +}; + +pub use types::TcClient; diff --git a/components/funder/src/token_channel.rs b/components/funder/src/token_channel/token_channel.rs similarity index 93% rename from components/funder/src/token_channel.rs rename to components/funder/src/token_channel/token_channel.rs index 37b0a1130..9887d99cd 100644 --- a/components/funder/src/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -35,79 +35,9 @@ use crate::mutual_credit::incoming::{ use crate::mutual_credit::outgoing::{queue_operation, QueueOperationError}; use crate::mutual_credit::types::McClient; +use crate::token_channel::types::{TcClient, TcStatus}; use crate::types::{create_hashed, MoveTokenHashed}; -#[derive(Debug)] -pub enum TcOpError { - SendOpFailed, - ResponseOpFailed(oneshot::Canceled), -} - -pub type TcOpResult = Result; -pub type TcOpSenderResult = oneshot::Sender>; - -/// Status of a TokenChannel. Could be either outgoing, incoming or inconsistent. -pub enum TcStatus { - ConsistentIn(MoveTokenHashed), // (move_token_in) - ConsistentOut(MoveToken, MoveTokenHashed), // (move_token_out, last_move_token_in) - Inconsistent(Signature, u128, Option<(Signature, u128)>), - // (local_reset_token, local_reset_move_token_counter, Option<(remote_reset_token, remote_reset_move_token_counter)>) -} - -pub trait TcClient { - type McClient: McClient; - fn mc_client(&mut self, currency: Currency) -> &mut Self::McClient; - - fn get_tc_status(&mut self) -> AsyncOpResult>; - fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; - fn set_direction_outgoing(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; - fn set_direction_outgoing_empty_incoming( - &mut self, - move_token: MoveToken, - ) -> AsyncOpResult<()>; - fn set_inconsistent( - &mut self, - local_reset_token: Signature, - local_reset_move_token_counter: u128, - ) -> AsyncOpResult<()>; - - /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) - fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; - - /// Simulate incoming token, to be used before an outgoing reset move token (a local reset) - fn set_incoming_from_inconsistent( - &mut self, - move_token_hashed: MoveTokenHashed, - ) -> AsyncOpResult<()>; - - fn get_move_token_counter(&mut self) -> AsyncOpResult; - fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; - - fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult; - - /// Return a sorted async iterator of all balances - fn list_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; - - /// Return a sorted async iterator of all local reset proposal balances - /// Only relevant for inconsistent channels - fn list_local_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; - - /// Return a sorted async iterator of all remote reset proposal balances - /// Only relevant for inconsistent channels - fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; - - fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; - fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; - - fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; - fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; - - fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; - fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; - - fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()>; -} - /// Unrecoverable TokenChannel error #[derive(Debug, From)] pub enum TokenChannelError { diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs new file mode 100644 index 000000000..3154dc9da --- /dev/null +++ b/components/funder/src/token_channel/types.rs @@ -0,0 +1,109 @@ +use std::cmp::Ordering; +use std::convert::TryFrom; +use std::iter::IntoIterator; + +use derive_more::From; + +use futures::channel::oneshot; +use futures::{Stream, StreamExt, TryStreamExt}; + +use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; + +use crypto::hash::{hash_buffer, Hasher}; +use crypto::identity::compare_public_key; + +use identity::IdentityClient; + +use proto::app_server::messages::RelayAddress; +use proto::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; +use proto::funder::messages::{ + Currency, CurrencyOperations, McBalance, MoveToken, PendingTransaction, TokenInfo, +}; + +use signature::canonical::CanonicalSerialize; +use signature::signature_buff::{ + hash_token_info, move_token_signature_buff, reset_token_signature_buff, +}; +use signature::verify::verify_move_token; + +use database::interface::funder::CurrencyConfig; +use database::transaction::Transaction; + +use crate::mutual_credit::incoming::{ + process_operations_list, IncomingMessage, ProcessTransListError, +}; +use crate::mutual_credit::outgoing::{queue_operation, QueueOperationError}; +use crate::mutual_credit::types::McClient; + +use crate::types::{create_hashed, MoveTokenHashed}; + +#[derive(Debug)] +pub enum TcOpError { + SendOpFailed, + ResponseOpFailed(oneshot::Canceled), +} + +pub type TcOpResult = Result; +pub type TcOpSenderResult = oneshot::Sender>; + +/// Status of a TokenChannel. Could be either outgoing, incoming or inconsistent. +pub enum TcStatus { + ConsistentIn(MoveTokenHashed), // (move_token_in) + ConsistentOut(MoveToken, MoveTokenHashed), // (move_token_out, last_move_token_in) + Inconsistent(Signature, u128, Option<(Signature, u128)>), + // (local_reset_token, local_reset_move_token_counter, Option<(remote_reset_token, remote_reset_move_token_counter)>) +} + +pub trait TcClient { + type McClient: McClient; + fn mc_client(&mut self, currency: Currency) -> &mut Self::McClient; + + fn get_tc_status(&mut self) -> AsyncOpResult>; + fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; + fn set_direction_outgoing(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; + fn set_direction_outgoing_empty_incoming( + &mut self, + move_token: MoveToken, + ) -> AsyncOpResult<()>; + fn set_inconsistent( + &mut self, + local_reset_token: Signature, + local_reset_move_token_counter: u128, + ) -> AsyncOpResult<()>; + + /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) + fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; + + /// Simulate incoming token, to be used before an outgoing reset move token (a local reset) + fn set_incoming_from_inconsistent( + &mut self, + move_token_hashed: MoveTokenHashed, + ) -> AsyncOpResult<()>; + + fn get_move_token_counter(&mut self) -> AsyncOpResult; + fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; + + fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult; + + /// Return a sorted async iterator of all balances + fn list_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + + /// Return a sorted async iterator of all local reset proposal balances + /// Only relevant for inconsistent channels + fn list_local_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + + /// Return a sorted async iterator of all remote reset proposal balances + /// Only relevant for inconsistent channels + fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + + fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; + fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; + + fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + + fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + + fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()>; +} From 68a1a4da139336b3fc89bf4407ffee1e4d455a8f Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 18:53:37 +0200 Subject: [PATCH 157/478] funder: Removed unused imports --- .../funder/src/token_channel/token_channel.rs | 14 ++------ components/funder/src/token_channel/types.rs | 35 +++---------------- 2 files changed, 7 insertions(+), 42 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 9887d99cd..7f325ac78 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -1,13 +1,11 @@ use std::cmp::Ordering; use std::convert::TryFrom; -use std::iter::IntoIterator; use derive_more::From; -use futures::channel::oneshot; use futures::{Stream, StreamExt, TryStreamExt}; -use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; +use common::async_rpc::OpError; use crypto::hash::{hash_buffer, Hasher}; use crypto::identity::compare_public_key; @@ -15,10 +13,8 @@ use crypto::identity::compare_public_key; use identity::IdentityClient; use proto::app_server::messages::RelayAddress; -use proto::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; -use proto::funder::messages::{ - Currency, CurrencyOperations, McBalance, MoveToken, PendingTransaction, TokenInfo, -}; +use proto::crypto::{HashResult, PublicKey, RandValue, Signature}; +use proto::funder::messages::{Currency, CurrencyOperations, McBalance, MoveToken, TokenInfo}; use signature::canonical::CanonicalSerialize; use signature::signature_buff::{ @@ -26,7 +22,6 @@ use signature::signature_buff::{ }; use signature::verify::verify_move_token; -use database::interface::funder::CurrencyConfig; use database::transaction::Transaction; use crate::mutual_credit::incoming::{ @@ -227,7 +222,6 @@ where // Attempt to receive an incoming token: handle_incoming_token_match( tc_client, - move_token_out, new_move_token, local_public_key, remote_public_key, @@ -377,7 +371,6 @@ where // Attempt to receive an incoming token: handle_incoming_token_match( tc_client, - move_token_out, new_move_token, local_public_key, remote_public_key, @@ -477,7 +470,6 @@ enum IncomingTokenMatchOutput { async fn handle_incoming_token_match( tc_client: &mut impl TcClient, - move_token_out: MoveToken, new_move_token: MoveToken, // remote_max_debts: &ImHashMap, local_public_key: &PublicKey, remote_public_key: &PublicKey, diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 3154dc9da..361dbcf32 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -1,41 +1,14 @@ -use std::cmp::Ordering; -use std::convert::TryFrom; -use std::iter::IntoIterator; - -use derive_more::From; - use futures::channel::oneshot; -use futures::{Stream, StreamExt, TryStreamExt}; - -use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; -use crypto::hash::{hash_buffer, Hasher}; -use crypto::identity::compare_public_key; +use common::async_rpc::{AsyncOpResult, AsyncOpStream}; -use identity::IdentityClient; - -use proto::app_server::messages::RelayAddress; -use proto::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; -use proto::funder::messages::{ - Currency, CurrencyOperations, McBalance, MoveToken, PendingTransaction, TokenInfo, -}; - -use signature::canonical::CanonicalSerialize; -use signature::signature_buff::{ - hash_token_info, move_token_signature_buff, reset_token_signature_buff, -}; -use signature::verify::verify_move_token; +use proto::crypto::Signature; +use proto::funder::messages::{Currency, McBalance, MoveToken}; use database::interface::funder::CurrencyConfig; -use database::transaction::Transaction; -use crate::mutual_credit::incoming::{ - process_operations_list, IncomingMessage, ProcessTransListError, -}; -use crate::mutual_credit::outgoing::{queue_operation, QueueOperationError}; use crate::mutual_credit::types::McClient; - -use crate::types::{create_hashed, MoveTokenHashed}; +use crate::types::MoveTokenHashed; #[derive(Debug)] pub enum TcOpError { From b0d14c0cc4385ff0f6202c3abcf8f25e5e8c59ef Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 18:55:10 +0200 Subject: [PATCH 158/478] funder: token_channel: Created tests submodule --- components/funder/src/token_channel/mod.rs | 3 + components/funder/src/token_channel/tests.rs | 364 +++++++++++++++++++ 2 files changed, 367 insertions(+) create mode 100644 components/funder/src/token_channel/tests.rs diff --git a/components/funder/src/token_channel/mod.rs b/components/funder/src/token_channel/mod.rs index a7d6ff522..39a34044a 100644 --- a/components/funder/src/token_channel/mod.rs +++ b/components/funder/src/token_channel/mod.rs @@ -1,6 +1,9 @@ mod token_channel; mod types; +#[cfg(test)] +mod tests; + pub use self::token_channel::{ accept_remote_reset, handle_in_move_token, handle_out_move_token, init_token_channel, TokenChannelError, diff --git a/components/funder/src/token_channel/tests.rs b/components/funder/src/token_channel/tests.rs new file mode 100644 index 000000000..f6561950e --- /dev/null +++ b/components/funder/src/token_channel/tests.rs @@ -0,0 +1,364 @@ +// TODO: Restore tests +/* + +#[cfg(test)] +mod tests { + use super::*; + + use proto::crypto::PrivateKey; + // use proto::funder::messages::FriendTcOp; + + use crypto::identity::Identity; + use crypto::identity::SoftwareEd25519Identity; + use crypto::rand::RandGen; + use crypto::test_utils::DummyRandom; + + use signature::signature_buff::move_token_signature_buff; + + /// A helper function to sign an UnsignedMoveToken using an identity: + fn dummy_sign_move_token( + unsigned_move_token: UnsignedMoveToken, + identity: &I, + ) -> MoveToken + where + B: CanonicalSerialize + Clone, + I: Identity, + { + let signature_buff = move_token_signature_buff(unsigned_move_token.clone()); + + MoveToken { + old_token: unsigned_move_token.old_token, + currencies_operations: unsigned_move_token.currencies_operations, + opt_local_relays: unsigned_move_token.opt_local_relays, + opt_active_currencies: unsigned_move_token.opt_active_currencies, + info_hash: unsigned_move_token.info_hash, + rand_nonce: unsigned_move_token.rand_nonce, + new_token: identity.sign(&signature_buff), + } + } + + #[test] + fn test_initial_direction() { + let pk_a = PublicKey::from(&[0xaa; PublicKey::len()]); + let pk_b = PublicKey::from(&[0xbb; PublicKey::len()]); + let token_channel_a_b = TokenChannel::::new(&pk_a, &pk_b); + let token_channel_b_a = TokenChannel::::new(&pk_b, &pk_a); + + // Only one of those token channels is outgoing: + let is_a_b_outgoing = token_channel_a_b.get_outgoing().is_some(); + let is_b_a_outgoing = token_channel_b_a.get_outgoing().is_some(); + assert!(is_a_b_outgoing ^ is_b_a_outgoing); + + let (out_tc, in_tc) = if is_a_b_outgoing { + (token_channel_a_b, token_channel_b_a) + } else { + (token_channel_b_a, token_channel_a_b) + }; + + let out_hashed = match &out_tc.direction { + TcDirection::Incoming(_) => unreachable!(), + TcDirection::Outgoing(outgoing) => { + create_hashed(&outgoing.move_token_out, &outgoing.token_info) + } + }; + + let in_hashed = match &in_tc.direction { + TcDirection::Outgoing(_) => unreachable!(), + TcDirection::Incoming(incoming) => &incoming.move_token_in, + }; + + assert_eq!(&out_hashed, in_hashed); + + // assert_eq!(create_hashed(&out_tc.move_token_out), in_tc.move_token_in); + // assert_eq!(out_tc.get_cur_move_token_hashed(), in_tc.get_cur_move_token_hashed()); + let tc_outgoing = match out_tc.get_direction() { + TcDirectionBorrow::Out(tc_out_borrow) => tc_out_borrow.tc_outgoing, + TcDirectionBorrow::In(_) => unreachable!(), + }; + assert!(tc_outgoing.opt_prev_move_token_in.is_none()); + } + + /// Sort the two identity client. + /// The result will be a pair where the first is initially configured to have outgoing message, + /// and the second is initially configured to have incoming message. + fn sort_sides(identity1: I, identity2: I) -> (I, I) + where + I: Identity, + { + let pk1 = identity1.get_public_key(); + let pk2 = identity2.get_public_key(); + let token_channel12 = TokenChannel::::new(&pk1, &pk2); // (local, remote) + if token_channel12.get_outgoing().is_some() { + (identity1, identity2) + } else { + (identity2, identity1) + } + } + /// Before: tc1: outgoing, tc2: incoming + /// Send AddCurrency: tc2 -> tc1 + /// After: tc1: incoming, tc2: outgoing + fn add_currencies( + _identity1: &I, + identity2: &I, + tc1: &mut TokenChannel, + tc2: &mut TokenChannel, + currencies: &[Currency], + ) where + I: Identity, + { + assert!(tc1.get_outgoing().is_some()); + assert!(!tc2.get_outgoing().is_some()); + + let tc2_in_borrow = tc2.get_incoming().unwrap(); + let currencies_operations = vec![]; + + let rand_nonce = RandValue::from(&[7; RandValue::len()]); + let opt_local_relays = None; + let opt_active_currencies = Some(currencies.to_vec()); + + let SendMoveTokenOutput { + unsigned_move_token, + mutations, + token_info, + } = tc2_in_borrow + .simulate_send_move_token( + currencies_operations, + opt_local_relays, + opt_active_currencies, + rand_nonce, + ) + .unwrap(); + + for tc_mutation in mutations { + tc2.mutate(&tc_mutation); + } + + // This is the only mutation we can not produce from inside TokenChannel, because it + // requires a signature: + let friend_move_token = dummy_sign_move_token(unsigned_move_token, identity2); + let tc_mutation = TcMutation::SetDirection(SetDirection::Outgoing(( + friend_move_token.clone(), + token_info.clone(), + ))); + tc2.mutate(&tc_mutation); + + assert!(tc2.get_outgoing().is_some()); + + let receive_move_token_output = tc1 + .simulate_receive_move_token(friend_move_token.clone(), &ImHashMap::new()) + .unwrap(); + + let move_token_received = match receive_move_token_output { + ReceiveMoveTokenOutput::Received(move_token_received) => move_token_received, + _ => unreachable!(), + }; + + assert!(move_token_received.currencies.is_empty()); + + // let mut seen_mc_mutation = false; + // let mut seen_set_direction = false; + + for tc_mutation in &move_token_received.mutations { + tc1.mutate(tc_mutation); + } + + assert!(!tc1.get_outgoing().is_some()); + match &tc1.direction { + TcDirection::Outgoing(_) => unreachable!(), + TcDirection::Incoming(tc_incoming) => { + assert_eq!( + tc_incoming.move_token_in, + create_hashed(&friend_move_token, &token_info) + ); + } + }; + + for currency in currencies { + assert!(tc2.active_currencies.local.contains(currency)); + assert!(tc1.active_currencies.remote.contains(currency)); + } + } + + /* + /// Before: tc1: outgoing, tc2: incoming + /// Send SetRemoteMaxDebt: tc2 -> tc1 + /// After: tc1: incoming, tc2: outgoing + fn set_remote_max_debt21( + _identity1: &I, + identity2: &I, + tc1: &mut TokenChannel, + tc2: &mut TokenChannel, + currency: &Currency, + ) where + I: Identity, + { + assert!(tc1.get_outgoing().is_some()); + assert!(tc2.get_incoming().is_some()); + + let tc2_in_borrow = tc2.get_incoming().unwrap(); + // let mut outgoing_mc = tc2_in_borrow.create_outgoing_mc(¤cy).unwrap(); + // + // let friend_tc_op = FriendTcOp::SetRemoteMaxDebt(100); + // + // let mc_mutations = outgoing_mc.queue_operation(&friend_tc_op).unwrap(); + let currency_operations = CurrencyOperations { + currency: currency.clone(), + operations: vec![friend_tc_op], + }; + let currencies_operations = vec![currency_operations]; + + let rand_nonce = RandValue::from(&[5; RandValue::len()]); + let opt_local_relays = None; + let opt_active_currencies = None; + + let SendMoveTokenOutput { + unsigned_move_token, + mutations, + token_info, + } = tc2_in_borrow + .simulate_send_move_token( + currencies_operations, + opt_local_relays, + opt_active_currencies, + rand_nonce, + ) + .unwrap(); + + for tc_mutation in mutations { + tc2.mutate(&tc_mutation); + } + + let friend_move_token = dummy_sign_move_token(unsigned_move_token, identity2); + let tc_mutation = TcMutation::SetDirection(SetDirection::Outgoing(( + friend_move_token.clone(), + token_info.clone(), + ))); + tc2.mutate(&tc_mutation); + + assert!(tc2.get_outgoing().is_some()); + + let receive_move_token_output = tc1 + .simulate_receive_move_token(friend_move_token.clone()) + .unwrap(); + + let move_token_received = match receive_move_token_output { + ReceiveMoveTokenOutput::Received(move_token_received) => move_token_received, + _ => unreachable!(), + }; + + assert!(move_token_received.currencies[0] + .incoming_messages + .is_empty()); + assert_eq!(move_token_received.mutations.len(), 2); + + let mut seen_mc_mutation = false; + let mut seen_set_direction = false; + + for i in 0..2 { + match &move_token_received.mutations[i] { + TcMutation::McMutation(mc_mutation) => { + seen_mc_mutation = true; + assert_eq!( + mc_mutation, + &(currency.clone(), McMutation::SetLocalMaxDebt(100)) + ); + } + TcMutation::SetDirection(set_direction) => { + seen_set_direction = true; + match set_direction { + SetDirection::Incoming(incoming_friend_move_token) => assert_eq!( + &create_hashed(&friend_move_token, &token_info), + incoming_friend_move_token + ), + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } + assert!(seen_mc_mutation && seen_set_direction); + + for tc_mutation in &move_token_received.mutations { + tc1.mutate(tc_mutation); + } + + assert!(!tc1.get_outgoing().is_some()); + match &tc1.direction { + TcDirection::Outgoing(_) => unreachable!(), + TcDirection::Incoming(tc_incoming) => { + assert_eq!( + tc_incoming.move_token_in, + create_hashed(&friend_move_token, &token_info) + ); + } + }; + + assert_eq!( + tc1.mutual_credits + .get(¤cy) + .unwrap() + .state() + .balance + .local_max_debt, + 100 + ); + } + */ + + /// This tests sends a SetRemoteMaxDebt(100) in both ways. + #[test] + fn test_simulate_receive_move_token_basic() { + let currency = Currency::try_from("FST".to_owned()).unwrap(); + + let mut rng1 = DummyRandom::new(&[1u8]); + let pkcs8 = PrivateKey::rand_gen(&mut rng1); + let identity1 = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); + + let mut rng2 = DummyRandom::new(&[2u8]); + let pkcs8 = PrivateKey::rand_gen(&mut rng2); + let identity2 = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); + + let (identity1, identity2) = sort_sides(identity1, identity2); + + let pk1 = identity1.get_public_key(); + let pk2 = identity2.get_public_key(); + let mut tc1 = TokenChannel::::new(&pk1, &pk2); // (local, remote) + let mut tc2 = TokenChannel::::new(&pk2, &pk1); // (local, remote) + + // Current state: tc1 --> tc2 + // tc1: outgoing + // tc2: incoming + add_currencies( + &identity1, + &identity2, + &mut tc1, + &mut tc2, + &[currency.clone()], + ); + + // Current state: tc2 --> tc1 + // tc1: incoming + // tc2: outgoing + add_currencies( + &identity2, + &identity1, + &mut tc2, + &mut tc1, + &[currency.clone()], + ); + + // Current state: tc1 --> tc2 + // tc1: outgoing + // tc2: incoming + // set_remote_max_debt21(&identity1, &identity2, &mut tc1, &mut tc2, ¤cy); + + // Current state: tc2 --> tc1 + // tc1: incoming + // tc2: outgoing + // set_remote_max_debt21(&identity2, &identity1, &mut tc2, &mut tc1, ¤cy); + } + + // TODO: Add more tests. + // - Test behaviour of Duplicate, ChainInconsistency +} +*/ From 32eee3fa4008e90bdd3199ec8767843b13e6ff44 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 19:14:43 +0200 Subject: [PATCH 159/478] funder: Removed unused function --- components/funder/src/token_channel/token_channel.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 7f325ac78..add084428 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -81,14 +81,6 @@ fn token_from_public_key(public_key: &PublicKey) -> Signature { Signature::from(&buff) } -/// Generate a random nonce from public key. -/// Note that the result here is not really a random nonce. This function is used for the first -/// deterministic initialization of a token channel. -fn rand_nonce_from_public_key(public_key: &PublicKey) -> RandValue { - let public_key_hash = Hasher::new().chain(public_key).finalize(); - RandValue::try_from(&public_key_hash.as_ref()[..RandValue::len()]).unwrap() -} - /// Create an initial move token in the relationship between two public keys. /// To canonicalize the initial move token (Having an equal move token for both sides), we sort the /// two public keys in some way. From 0e9a0e9da125a16a02b5348435a8758c067bec28 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 20:53:18 +0200 Subject: [PATCH 160/478] funder: Some work towards token_channel tests --- components/funder/src/mutual_credit/mod.rs | 6 +- .../funder/src/mutual_credit/tests/mod.rs | 2 + .../tests/request_cancel_send_funds.rs | 4 +- .../tests/request_response_send_funds.rs | 4 +- .../funder/src/mutual_credit/tests/utils.rs | 10 +- components/funder/src/token_channel/tests.rs | 364 ----------------- .../funder/src/token_channel/tests/mod.rs | 1 + .../funder/src/token_channel/tests/tests.rs | 354 +++++++++++++++++ .../funder/src/token_channel/tests/utils.rs | 140 +++++++ .../funder/src/token_channel/token_channel.rs | 369 +----------------- components/funder/src/token_channel/types.rs | 4 +- 11 files changed, 515 insertions(+), 743 deletions(-) delete mode 100644 components/funder/src/token_channel/tests.rs create mode 100644 components/funder/src/token_channel/tests/mod.rs create mode 100644 components/funder/src/token_channel/tests/tests.rs create mode 100644 components/funder/src/token_channel/tests/utils.rs diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index a3521f69d..fa3389384 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -1,5 +1,9 @@ pub mod incoming; pub mod outgoing; #[cfg(test)] -mod tests; +pub mod tests; + pub mod types; + +#[cfg(test)] +pub use tests::MockMutualCredit; diff --git a/components/funder/src/mutual_credit/tests/mod.rs b/components/funder/src/mutual_credit/tests/mod.rs index 0a9c0128f..35d5b9423 100644 --- a/components/funder/src/mutual_credit/tests/mod.rs +++ b/components/funder/src/mutual_credit/tests/mod.rs @@ -1,3 +1,5 @@ mod request_cancel_send_funds; mod request_response_send_funds; mod utils; + +pub use utils::MockMutualCredit; diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index fa3ca88d5..a480799f7 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -12,7 +12,7 @@ use proto::funder::messages::{ CancelSendFundsOp, Currency, FriendTcOp, FriendsRoute, RequestSendFundsOp, }; -use crate::mutual_credit::tests::utils::MutualCredit; +use crate::mutual_credit::tests::utils::MockMutualCredit; use crate::mutual_credit::types::McClient; use crate::mutual_credit::incoming::process_operations_list; @@ -30,7 +30,7 @@ async fn task_request_cancel_send_funds() { let remote_public_key = public_key_b.clone(); let balance = 0; - let mut mc_transaction = MutualCredit::new(¤cy, balance); + let mut mc_transaction = MockMutualCredit::new(¤cy, balance); // -----[RequestSendFunds]-------- // ----------------------------- diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index 8cacd4d4b..9f8f6da68 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -13,7 +13,7 @@ use proto::funder::messages::{ }; use signature::signature_buff::create_response_signature_buffer; -use crate::mutual_credit::tests::utils::MutualCredit; +use crate::mutual_credit::tests::utils::MockMutualCredit; use crate::mutual_credit::types::McClient; use crate::types::create_pending_transaction; @@ -27,7 +27,7 @@ async fn task_request_response_send_funds() { let remote_public_key = PublicKey::from(&[0xbb; PublicKey::len()]); let balance = 0; - let mut mc_transaction = MutualCredit::new(¤cy, balance); + let mut mc_transaction = MockMutualCredit::new(¤cy, balance); // -----[RequestSendFunds]-------- // ----------------------------- diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index e99e024c5..096c4e2a1 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -27,7 +27,7 @@ impl McPendingTransactions { } #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] -pub struct MutualCredit { +pub struct MockMutualCredit { /// Currency in use (How much is one credit worth?) pub currency: Currency, /// Current credit balance with respect to remote side @@ -36,13 +36,13 @@ pub struct MutualCredit { pub pending_transactions: McPendingTransactions, } -impl MutualCredit { +impl MockMutualCredit { pub fn new( // TODO: Should we move instead of take a reference here? currency: &Currency, balance: i128, - ) -> MutualCredit { - MutualCredit { + ) -> MockMutualCredit { + MockMutualCredit { currency: currency.clone(), balance: McBalance::new(balance), pending_transactions: McPendingTransactions::new(), @@ -50,7 +50,7 @@ impl MutualCredit { } } -impl McClient for MutualCredit { +impl McClient for MockMutualCredit { fn get_balance(&mut self) -> BoxFuture<'static, Result> { let mc_balance = self.balance.clone(); Box::pin(async move { Ok(mc_balance) }) diff --git a/components/funder/src/token_channel/tests.rs b/components/funder/src/token_channel/tests.rs deleted file mode 100644 index f6561950e..000000000 --- a/components/funder/src/token_channel/tests.rs +++ /dev/null @@ -1,364 +0,0 @@ -// TODO: Restore tests -/* - -#[cfg(test)] -mod tests { - use super::*; - - use proto::crypto::PrivateKey; - // use proto::funder::messages::FriendTcOp; - - use crypto::identity::Identity; - use crypto::identity::SoftwareEd25519Identity; - use crypto::rand::RandGen; - use crypto::test_utils::DummyRandom; - - use signature::signature_buff::move_token_signature_buff; - - /// A helper function to sign an UnsignedMoveToken using an identity: - fn dummy_sign_move_token( - unsigned_move_token: UnsignedMoveToken, - identity: &I, - ) -> MoveToken - where - B: CanonicalSerialize + Clone, - I: Identity, - { - let signature_buff = move_token_signature_buff(unsigned_move_token.clone()); - - MoveToken { - old_token: unsigned_move_token.old_token, - currencies_operations: unsigned_move_token.currencies_operations, - opt_local_relays: unsigned_move_token.opt_local_relays, - opt_active_currencies: unsigned_move_token.opt_active_currencies, - info_hash: unsigned_move_token.info_hash, - rand_nonce: unsigned_move_token.rand_nonce, - new_token: identity.sign(&signature_buff), - } - } - - #[test] - fn test_initial_direction() { - let pk_a = PublicKey::from(&[0xaa; PublicKey::len()]); - let pk_b = PublicKey::from(&[0xbb; PublicKey::len()]); - let token_channel_a_b = TokenChannel::::new(&pk_a, &pk_b); - let token_channel_b_a = TokenChannel::::new(&pk_b, &pk_a); - - // Only one of those token channels is outgoing: - let is_a_b_outgoing = token_channel_a_b.get_outgoing().is_some(); - let is_b_a_outgoing = token_channel_b_a.get_outgoing().is_some(); - assert!(is_a_b_outgoing ^ is_b_a_outgoing); - - let (out_tc, in_tc) = if is_a_b_outgoing { - (token_channel_a_b, token_channel_b_a) - } else { - (token_channel_b_a, token_channel_a_b) - }; - - let out_hashed = match &out_tc.direction { - TcDirection::Incoming(_) => unreachable!(), - TcDirection::Outgoing(outgoing) => { - create_hashed(&outgoing.move_token_out, &outgoing.token_info) - } - }; - - let in_hashed = match &in_tc.direction { - TcDirection::Outgoing(_) => unreachable!(), - TcDirection::Incoming(incoming) => &incoming.move_token_in, - }; - - assert_eq!(&out_hashed, in_hashed); - - // assert_eq!(create_hashed(&out_tc.move_token_out), in_tc.move_token_in); - // assert_eq!(out_tc.get_cur_move_token_hashed(), in_tc.get_cur_move_token_hashed()); - let tc_outgoing = match out_tc.get_direction() { - TcDirectionBorrow::Out(tc_out_borrow) => tc_out_borrow.tc_outgoing, - TcDirectionBorrow::In(_) => unreachable!(), - }; - assert!(tc_outgoing.opt_prev_move_token_in.is_none()); - } - - /// Sort the two identity client. - /// The result will be a pair where the first is initially configured to have outgoing message, - /// and the second is initially configured to have incoming message. - fn sort_sides(identity1: I, identity2: I) -> (I, I) - where - I: Identity, - { - let pk1 = identity1.get_public_key(); - let pk2 = identity2.get_public_key(); - let token_channel12 = TokenChannel::::new(&pk1, &pk2); // (local, remote) - if token_channel12.get_outgoing().is_some() { - (identity1, identity2) - } else { - (identity2, identity1) - } - } - /// Before: tc1: outgoing, tc2: incoming - /// Send AddCurrency: tc2 -> tc1 - /// After: tc1: incoming, tc2: outgoing - fn add_currencies( - _identity1: &I, - identity2: &I, - tc1: &mut TokenChannel, - tc2: &mut TokenChannel, - currencies: &[Currency], - ) where - I: Identity, - { - assert!(tc1.get_outgoing().is_some()); - assert!(!tc2.get_outgoing().is_some()); - - let tc2_in_borrow = tc2.get_incoming().unwrap(); - let currencies_operations = vec![]; - - let rand_nonce = RandValue::from(&[7; RandValue::len()]); - let opt_local_relays = None; - let opt_active_currencies = Some(currencies.to_vec()); - - let SendMoveTokenOutput { - unsigned_move_token, - mutations, - token_info, - } = tc2_in_borrow - .simulate_send_move_token( - currencies_operations, - opt_local_relays, - opt_active_currencies, - rand_nonce, - ) - .unwrap(); - - for tc_mutation in mutations { - tc2.mutate(&tc_mutation); - } - - // This is the only mutation we can not produce from inside TokenChannel, because it - // requires a signature: - let friend_move_token = dummy_sign_move_token(unsigned_move_token, identity2); - let tc_mutation = TcMutation::SetDirection(SetDirection::Outgoing(( - friend_move_token.clone(), - token_info.clone(), - ))); - tc2.mutate(&tc_mutation); - - assert!(tc2.get_outgoing().is_some()); - - let receive_move_token_output = tc1 - .simulate_receive_move_token(friend_move_token.clone(), &ImHashMap::new()) - .unwrap(); - - let move_token_received = match receive_move_token_output { - ReceiveMoveTokenOutput::Received(move_token_received) => move_token_received, - _ => unreachable!(), - }; - - assert!(move_token_received.currencies.is_empty()); - - // let mut seen_mc_mutation = false; - // let mut seen_set_direction = false; - - for tc_mutation in &move_token_received.mutations { - tc1.mutate(tc_mutation); - } - - assert!(!tc1.get_outgoing().is_some()); - match &tc1.direction { - TcDirection::Outgoing(_) => unreachable!(), - TcDirection::Incoming(tc_incoming) => { - assert_eq!( - tc_incoming.move_token_in, - create_hashed(&friend_move_token, &token_info) - ); - } - }; - - for currency in currencies { - assert!(tc2.active_currencies.local.contains(currency)); - assert!(tc1.active_currencies.remote.contains(currency)); - } - } - - /* - /// Before: tc1: outgoing, tc2: incoming - /// Send SetRemoteMaxDebt: tc2 -> tc1 - /// After: tc1: incoming, tc2: outgoing - fn set_remote_max_debt21( - _identity1: &I, - identity2: &I, - tc1: &mut TokenChannel, - tc2: &mut TokenChannel, - currency: &Currency, - ) where - I: Identity, - { - assert!(tc1.get_outgoing().is_some()); - assert!(tc2.get_incoming().is_some()); - - let tc2_in_borrow = tc2.get_incoming().unwrap(); - // let mut outgoing_mc = tc2_in_borrow.create_outgoing_mc(¤cy).unwrap(); - // - // let friend_tc_op = FriendTcOp::SetRemoteMaxDebt(100); - // - // let mc_mutations = outgoing_mc.queue_operation(&friend_tc_op).unwrap(); - let currency_operations = CurrencyOperations { - currency: currency.clone(), - operations: vec![friend_tc_op], - }; - let currencies_operations = vec![currency_operations]; - - let rand_nonce = RandValue::from(&[5; RandValue::len()]); - let opt_local_relays = None; - let opt_active_currencies = None; - - let SendMoveTokenOutput { - unsigned_move_token, - mutations, - token_info, - } = tc2_in_borrow - .simulate_send_move_token( - currencies_operations, - opt_local_relays, - opt_active_currencies, - rand_nonce, - ) - .unwrap(); - - for tc_mutation in mutations { - tc2.mutate(&tc_mutation); - } - - let friend_move_token = dummy_sign_move_token(unsigned_move_token, identity2); - let tc_mutation = TcMutation::SetDirection(SetDirection::Outgoing(( - friend_move_token.clone(), - token_info.clone(), - ))); - tc2.mutate(&tc_mutation); - - assert!(tc2.get_outgoing().is_some()); - - let receive_move_token_output = tc1 - .simulate_receive_move_token(friend_move_token.clone()) - .unwrap(); - - let move_token_received = match receive_move_token_output { - ReceiveMoveTokenOutput::Received(move_token_received) => move_token_received, - _ => unreachable!(), - }; - - assert!(move_token_received.currencies[0] - .incoming_messages - .is_empty()); - assert_eq!(move_token_received.mutations.len(), 2); - - let mut seen_mc_mutation = false; - let mut seen_set_direction = false; - - for i in 0..2 { - match &move_token_received.mutations[i] { - TcMutation::McMutation(mc_mutation) => { - seen_mc_mutation = true; - assert_eq!( - mc_mutation, - &(currency.clone(), McMutation::SetLocalMaxDebt(100)) - ); - } - TcMutation::SetDirection(set_direction) => { - seen_set_direction = true; - match set_direction { - SetDirection::Incoming(incoming_friend_move_token) => assert_eq!( - &create_hashed(&friend_move_token, &token_info), - incoming_friend_move_token - ), - _ => unreachable!(), - } - } - _ => unreachable!(), - } - } - assert!(seen_mc_mutation && seen_set_direction); - - for tc_mutation in &move_token_received.mutations { - tc1.mutate(tc_mutation); - } - - assert!(!tc1.get_outgoing().is_some()); - match &tc1.direction { - TcDirection::Outgoing(_) => unreachable!(), - TcDirection::Incoming(tc_incoming) => { - assert_eq!( - tc_incoming.move_token_in, - create_hashed(&friend_move_token, &token_info) - ); - } - }; - - assert_eq!( - tc1.mutual_credits - .get(¤cy) - .unwrap() - .state() - .balance - .local_max_debt, - 100 - ); - } - */ - - /// This tests sends a SetRemoteMaxDebt(100) in both ways. - #[test] - fn test_simulate_receive_move_token_basic() { - let currency = Currency::try_from("FST".to_owned()).unwrap(); - - let mut rng1 = DummyRandom::new(&[1u8]); - let pkcs8 = PrivateKey::rand_gen(&mut rng1); - let identity1 = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); - - let mut rng2 = DummyRandom::new(&[2u8]); - let pkcs8 = PrivateKey::rand_gen(&mut rng2); - let identity2 = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); - - let (identity1, identity2) = sort_sides(identity1, identity2); - - let pk1 = identity1.get_public_key(); - let pk2 = identity2.get_public_key(); - let mut tc1 = TokenChannel::::new(&pk1, &pk2); // (local, remote) - let mut tc2 = TokenChannel::::new(&pk2, &pk1); // (local, remote) - - // Current state: tc1 --> tc2 - // tc1: outgoing - // tc2: incoming - add_currencies( - &identity1, - &identity2, - &mut tc1, - &mut tc2, - &[currency.clone()], - ); - - // Current state: tc2 --> tc1 - // tc1: incoming - // tc2: outgoing - add_currencies( - &identity2, - &identity1, - &mut tc2, - &mut tc1, - &[currency.clone()], - ); - - // Current state: tc1 --> tc2 - // tc1: outgoing - // tc2: incoming - // set_remote_max_debt21(&identity1, &identity2, &mut tc1, &mut tc2, ¤cy); - - // Current state: tc2 --> tc1 - // tc1: incoming - // tc2: outgoing - // set_remote_max_debt21(&identity2, &identity1, &mut tc2, &mut tc1, ¤cy); - } - - // TODO: Add more tests. - // - Test behaviour of Duplicate, ChainInconsistency -} -*/ diff --git a/components/funder/src/token_channel/tests/mod.rs b/components/funder/src/token_channel/tests/mod.rs new file mode 100644 index 000000000..d50801f20 --- /dev/null +++ b/components/funder/src/token_channel/tests/mod.rs @@ -0,0 +1 @@ +// mod utils; diff --git a/components/funder/src/token_channel/tests/tests.rs b/components/funder/src/token_channel/tests/tests.rs new file mode 100644 index 000000000..50d1a06aa --- /dev/null +++ b/components/funder/src/token_channel/tests/tests.rs @@ -0,0 +1,354 @@ +use common::test_executor::TestExecutor; + +use proto::crypto::PrivateKey; +use proto::funder::messages::MoveToken; +// use proto::funder::messages::FriendTcOp; + +use crypto::identity::{Identity, SoftwareEd25519Identity}; +use crypto::rand::RandGen; +use crypto::test_utils::DummyRandom; + +use signature::signature_buff::move_token_signature_buff; + +/* +async fn task_initial_direction(executor: TestExecutor) { + init_move_token + + init_token_channel( + tc_client: tc_client, + local_public_key, + remote_public_key).await; + +} +*/ + +#[test] +fn test_initial_direction() { + let test_executor = TestExecutor::new(); + let res = test_executor.run(task_initial_direction(test_executor)); + assert!(res.is_output()); +} + +#[test] +fn test_initial_direction() { + let pk_a = PublicKey::from(&[0xaa; PublicKey::len()]); + let pk_b = PublicKey::from(&[0xbb; PublicKey::len()]); + let token_channel_a_b = TokenChannel::::new(&pk_a, &pk_b); + let token_channel_b_a = TokenChannel::::new(&pk_b, &pk_a); + + // Only one of those token channels is outgoing: + let is_a_b_outgoing = token_channel_a_b.get_outgoing().is_some(); + let is_b_a_outgoing = token_channel_b_a.get_outgoing().is_some(); + assert!(is_a_b_outgoing ^ is_b_a_outgoing); + + let (out_tc, in_tc) = if is_a_b_outgoing { + (token_channel_a_b, token_channel_b_a) + } else { + (token_channel_b_a, token_channel_a_b) + }; + + let out_hashed = match &out_tc.direction { + TcDirection::Incoming(_) => unreachable!(), + TcDirection::Outgoing(outgoing) => { + create_hashed(&outgoing.move_token_out, &outgoing.token_info) + } + }; + + let in_hashed = match &in_tc.direction { + TcDirection::Outgoing(_) => unreachable!(), + TcDirection::Incoming(incoming) => &incoming.move_token_in, + }; + + assert_eq!(&out_hashed, in_hashed); + + // assert_eq!(create_hashed(&out_tc.move_token_out), in_tc.move_token_in); + // assert_eq!(out_tc.get_cur_move_token_hashed(), in_tc.get_cur_move_token_hashed()); + let tc_outgoing = match out_tc.get_direction() { + TcDirectionBorrow::Out(tc_out_borrow) => tc_out_borrow.tc_outgoing, + TcDirectionBorrow::In(_) => unreachable!(), + }; + assert!(tc_outgoing.opt_prev_move_token_in.is_none()); +} + +/// Sort the two identity client. +/// The result will be a pair where the first is initially configured to have outgoing message, +/// and the second is initially configured to have incoming message. +fn sort_sides(identity1: I, identity2: I) -> (I, I) +where + I: Identity, +{ + let pk1 = identity1.get_public_key(); + let pk2 = identity2.get_public_key(); + let token_channel12 = TokenChannel::::new(&pk1, &pk2); // (local, remote) + if token_channel12.get_outgoing().is_some() { + (identity1, identity2) + } else { + (identity2, identity1) + } +} +/// Before: tc1: outgoing, tc2: incoming +/// Send AddCurrency: tc2 -> tc1 +/// After: tc1: incoming, tc2: outgoing +fn add_currencies( + _identity1: &I, + identity2: &I, + tc1: &mut TokenChannel, + tc2: &mut TokenChannel, + currencies: &[Currency], +) where + I: Identity, +{ + assert!(tc1.get_outgoing().is_some()); + assert!(!tc2.get_outgoing().is_some()); + + let tc2_in_borrow = tc2.get_incoming().unwrap(); + let currencies_operations = vec![]; + + let rand_nonce = RandValue::from(&[7; RandValue::len()]); + let opt_local_relays = None; + let opt_active_currencies = Some(currencies.to_vec()); + + let SendMoveTokenOutput { + unsigned_move_token, + mutations, + token_info, + } = tc2_in_borrow + .simulate_send_move_token( + currencies_operations, + opt_local_relays, + opt_active_currencies, + rand_nonce, + ) + .unwrap(); + + for tc_mutation in mutations { + tc2.mutate(&tc_mutation); + } + + // This is the only mutation we can not produce from inside TokenChannel, because it + // requires a signature: + let friend_move_token = dummy_sign_move_token(unsigned_move_token, identity2); + let tc_mutation = TcMutation::SetDirection(SetDirection::Outgoing(( + friend_move_token.clone(), + token_info.clone(), + ))); + tc2.mutate(&tc_mutation); + + assert!(tc2.get_outgoing().is_some()); + + let receive_move_token_output = tc1 + .simulate_receive_move_token(friend_move_token.clone(), &ImHashMap::new()) + .unwrap(); + + let move_token_received = match receive_move_token_output { + ReceiveMoveTokenOutput::Received(move_token_received) => move_token_received, + _ => unreachable!(), + }; + + assert!(move_token_received.currencies.is_empty()); + + // let mut seen_mc_mutation = false; + // let mut seen_set_direction = false; + + for tc_mutation in &move_token_received.mutations { + tc1.mutate(tc_mutation); + } + + assert!(!tc1.get_outgoing().is_some()); + match &tc1.direction { + TcDirection::Outgoing(_) => unreachable!(), + TcDirection::Incoming(tc_incoming) => { + assert_eq!( + tc_incoming.move_token_in, + create_hashed(&friend_move_token, &token_info) + ); + } + }; + + for currency in currencies { + assert!(tc2.active_currencies.local.contains(currency)); + assert!(tc1.active_currencies.remote.contains(currency)); + } +} + +/* +/// Before: tc1: outgoing, tc2: incoming +/// Send SetRemoteMaxDebt: tc2 -> tc1 +/// After: tc1: incoming, tc2: outgoing +fn set_remote_max_debt21( + _identity1: &I, + identity2: &I, + tc1: &mut TokenChannel, + tc2: &mut TokenChannel, + currency: &Currency, +) where + I: Identity, +{ + assert!(tc1.get_outgoing().is_some()); + assert!(tc2.get_incoming().is_some()); + + let tc2_in_borrow = tc2.get_incoming().unwrap(); + // let mut outgoing_mc = tc2_in_borrow.create_outgoing_mc(¤cy).unwrap(); + // + // let friend_tc_op = FriendTcOp::SetRemoteMaxDebt(100); + // + // let mc_mutations = outgoing_mc.queue_operation(&friend_tc_op).unwrap(); + let currency_operations = CurrencyOperations { + currency: currency.clone(), + operations: vec![friend_tc_op], + }; + let currencies_operations = vec![currency_operations]; + + let rand_nonce = RandValue::from(&[5; RandValue::len()]); + let opt_local_relays = None; + let opt_active_currencies = None; + + let SendMoveTokenOutput { + unsigned_move_token, + mutations, + token_info, + } = tc2_in_borrow + .simulate_send_move_token( + currencies_operations, + opt_local_relays, + opt_active_currencies, + rand_nonce, + ) + .unwrap(); + + for tc_mutation in mutations { + tc2.mutate(&tc_mutation); + } + + let friend_move_token = dummy_sign_move_token(unsigned_move_token, identity2); + let tc_mutation = TcMutation::SetDirection(SetDirection::Outgoing(( + friend_move_token.clone(), + token_info.clone(), + ))); + tc2.mutate(&tc_mutation); + + assert!(tc2.get_outgoing().is_some()); + + let receive_move_token_output = tc1 + .simulate_receive_move_token(friend_move_token.clone()) + .unwrap(); + + let move_token_received = match receive_move_token_output { + ReceiveMoveTokenOutput::Received(move_token_received) => move_token_received, + _ => unreachable!(), + }; + + assert!(move_token_received.currencies[0] + .incoming_messages + .is_empty()); + assert_eq!(move_token_received.mutations.len(), 2); + + let mut seen_mc_mutation = false; + let mut seen_set_direction = false; + + for i in 0..2 { + match &move_token_received.mutations[i] { + TcMutation::McMutation(mc_mutation) => { + seen_mc_mutation = true; + assert_eq!( + mc_mutation, + &(currency.clone(), McMutation::SetLocalMaxDebt(100)) + ); + } + TcMutation::SetDirection(set_direction) => { + seen_set_direction = true; + match set_direction { + SetDirection::Incoming(incoming_friend_move_token) => assert_eq!( + &create_hashed(&friend_move_token, &token_info), + incoming_friend_move_token + ), + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } + assert!(seen_mc_mutation && seen_set_direction); + + for tc_mutation in &move_token_received.mutations { + tc1.mutate(tc_mutation); + } + + assert!(!tc1.get_outgoing().is_some()); + match &tc1.direction { + TcDirection::Outgoing(_) => unreachable!(), + TcDirection::Incoming(tc_incoming) => { + assert_eq!( + tc_incoming.move_token_in, + create_hashed(&friend_move_token, &token_info) + ); + } + }; + + assert_eq!( + tc1.mutual_credits + .get(¤cy) + .unwrap() + .state() + .balance + .local_max_debt, + 100 + ); +} +*/ + +/// This tests sends a SetRemoteMaxDebt(100) in both ways. +#[test] +fn test_simulate_receive_move_token_basic() { + let currency = Currency::try_from("FST".to_owned()).unwrap(); + + let mut rng1 = DummyRandom::new(&[1u8]); + let pkcs8 = PrivateKey::rand_gen(&mut rng1); + let identity1 = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); + + let mut rng2 = DummyRandom::new(&[2u8]); + let pkcs8 = PrivateKey::rand_gen(&mut rng2); + let identity2 = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); + + let (identity1, identity2) = sort_sides(identity1, identity2); + + let pk1 = identity1.get_public_key(); + let pk2 = identity2.get_public_key(); + let mut tc1 = TokenChannel::::new(&pk1, &pk2); // (local, remote) + let mut tc2 = TokenChannel::::new(&pk2, &pk1); // (local, remote) + + // Current state: tc1 --> tc2 + // tc1: outgoing + // tc2: incoming + add_currencies( + &identity1, + &identity2, + &mut tc1, + &mut tc2, + &[currency.clone()], + ); + + // Current state: tc2 --> tc1 + // tc1: incoming + // tc2: outgoing + add_currencies( + &identity2, + &identity1, + &mut tc2, + &mut tc1, + &[currency.clone()], + ); + + // Current state: tc1 --> tc2 + // tc1: outgoing + // tc2: incoming + // set_remote_max_debt21(&identity1, &identity2, &mut tc1, &mut tc2, ¤cy); + + // Current state: tc2 --> tc1 + // tc1: incoming + // tc2: outgoing + // set_remote_max_debt21(&identity2, &identity1, &mut tc2, &mut tc1, ¤cy); +} + +// TODO: Add more tests. +// - Test behaviour of Duplicate, ChainInconsistency diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs new file mode 100644 index 000000000..622d9ec57 --- /dev/null +++ b/components/funder/src/token_channel/tests/utils.rs @@ -0,0 +1,140 @@ +use std::collections::HashMap; + +use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; + +use proto::crypto::Signature; +use proto::funder::messages::{Currency, McBalance, MoveToken}; + +use crate::mutual_credit::tests::MockMutualCredit; + +use crate::token_channel::types::TcStatus; +use crate::token_channel::TcClient; +use crate::types::MoveTokenHashed; + +#[derive(Debug)] +pub struct MockLocalResetTerms { + reset_token: Signature, + reset_move_token_counter: u128, + reset_balances: Vec<(Currency, McBalance)>, +} + +#[derive(Debug)] +pub struct MockRemoteResetTerms { + reset_token: Signature, + reset_move_token_counter: u128, + reset_balances: Vec<(Currency, McBalance)>, +} + +#[derive(Debug)] +pub enum MockTcDirection { + In(MoveTokenHashed), + Out(MoveToken, Option), +} + +#[derive(Debug)] +pub struct TcConsistent { + mutual_credits: HashMap, + direction: MockTcDirection, +} + +#[derive(Debug)] +pub enum MockTcStatus { + Consistent(TcConsistent), + Inconsistent(MockLocalResetTerms, Option), +} + +#[derive(Debug)] +pub struct MockTokenChannel { + status: MockTcStatus, +} + +impl TcClient for MockTokenChannel +where + B: Send, +{ + type McClient = MockMutualCredit; + + fn mc_client(&mut self, currency: Currency) -> &mut Self::McClient { + match self.status { + MockTcStatus::Consistent(tc_consistent) => { + tc_consistent.mutual_credits.get_mut(¤cy).unwrap() + } + _ => unreachable!(), + } + } + + fn get_tc_status(&mut self) -> AsyncOpResult> { + Box::pin(async move { + match self.status { + MockTcStatus::Consistent(tc_consistent) => match tc_consistent.direction { + MockTcDirection::In(move_token_in) => TcStatus::ConsistentIn(move_token_in), + MockTcDirection::Out(move_token_out, opt_move_token_in) => { + TcStatus::ConsistentOut(move_token_out, opt_move_token_out) + } + }, + MockTcStatus::Inconsistent(local_reset_terms, opt_remote_reset_terms) => { + TcStatus::Inconsistent( + local_reset_terms.reset_token, + local_reset_terms.reset_move_token_counter, + opt_remote_reset_terms.map(|remote_reset_terms| { + ( + remote_reset_terms.reset_token, + remote_reset_terms.reset_move_token_counter, + ) + }), + ) + } + } + }) + } + + /* + fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; + fn set_direction_outgoing(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; + fn set_direction_outgoing_empty_incoming( + &mut self, + move_token: MoveToken, + ) -> AsyncOpResult<()>; + fn set_inconsistent( + &mut self, + local_reset_token: Signature, + local_reset_move_token_counter: u128, + ) -> AsyncOpResult<()>; + + /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) + fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; + + /// Simulate incoming token, to be used before an outgoing reset move token (a local reset) + fn set_incoming_from_inconsistent( + &mut self, + move_token_hashed: MoveTokenHashed, + ) -> AsyncOpResult<()>; + + fn get_move_token_counter(&mut self) -> AsyncOpResult; + fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; + + fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult; + + /// Return a sorted async iterator of all balances + fn list_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + + /// Return a sorted async iterator of all local reset proposal balances + /// Only relevant for inconsistent channels + fn list_local_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + + /// Return a sorted async iterator of all remote reset proposal balances + /// Only relevant for inconsistent channels + fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + + fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; + fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; + + fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + + fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + + fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()>; + */ +} diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index add084428..ebfe39277 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -169,7 +169,7 @@ where ) .await } - TcStatus::ConsistentOut(move_token_out, _move_token_in) => { + TcStatus::ConsistentOut(move_token_out, _opt_move_token_in) => { handle_in_move_token_dir_out( tc_client, identity_client, @@ -636,7 +636,7 @@ where // We expect that our current state is incoming: let move_token_in = match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => move_token_in, - TcStatus::ConsistentOut(_move_token_out, _move_token_in) => { + TcStatus::ConsistentOut(_move_token_out, _opt_move_token_in) => { return Err(TokenChannelError::InvalidTokenChannelStatus) } TcStatus::Inconsistent( @@ -805,368 +805,3 @@ where ) .await } - -// TODO: Restore tests -/* - -#[cfg(test)] -mod tests { - use super::*; - - use proto::crypto::PrivateKey; - // use proto::funder::messages::FriendTcOp; - - use crypto::identity::Identity; - use crypto::identity::SoftwareEd25519Identity; - use crypto::rand::RandGen; - use crypto::test_utils::DummyRandom; - - use signature::signature_buff::move_token_signature_buff; - - /// A helper function to sign an UnsignedMoveToken using an identity: - fn dummy_sign_move_token( - unsigned_move_token: UnsignedMoveToken, - identity: &I, - ) -> MoveToken - where - B: CanonicalSerialize + Clone, - I: Identity, - { - let signature_buff = move_token_signature_buff(unsigned_move_token.clone()); - - MoveToken { - old_token: unsigned_move_token.old_token, - currencies_operations: unsigned_move_token.currencies_operations, - opt_local_relays: unsigned_move_token.opt_local_relays, - opt_active_currencies: unsigned_move_token.opt_active_currencies, - info_hash: unsigned_move_token.info_hash, - rand_nonce: unsigned_move_token.rand_nonce, - new_token: identity.sign(&signature_buff), - } - } - - #[test] - fn test_initial_direction() { - let pk_a = PublicKey::from(&[0xaa; PublicKey::len()]); - let pk_b = PublicKey::from(&[0xbb; PublicKey::len()]); - let token_channel_a_b = TokenChannel::::new(&pk_a, &pk_b); - let token_channel_b_a = TokenChannel::::new(&pk_b, &pk_a); - - // Only one of those token channels is outgoing: - let is_a_b_outgoing = token_channel_a_b.get_outgoing().is_some(); - let is_b_a_outgoing = token_channel_b_a.get_outgoing().is_some(); - assert!(is_a_b_outgoing ^ is_b_a_outgoing); - - let (out_tc, in_tc) = if is_a_b_outgoing { - (token_channel_a_b, token_channel_b_a) - } else { - (token_channel_b_a, token_channel_a_b) - }; - - let out_hashed = match &out_tc.direction { - TcDirection::Incoming(_) => unreachable!(), - TcDirection::Outgoing(outgoing) => { - create_hashed(&outgoing.move_token_out, &outgoing.token_info) - } - }; - - let in_hashed = match &in_tc.direction { - TcDirection::Outgoing(_) => unreachable!(), - TcDirection::Incoming(incoming) => &incoming.move_token_in, - }; - - assert_eq!(&out_hashed, in_hashed); - - // assert_eq!(create_hashed(&out_tc.move_token_out), in_tc.move_token_in); - // assert_eq!(out_tc.get_cur_move_token_hashed(), in_tc.get_cur_move_token_hashed()); - let tc_outgoing = match out_tc.get_direction() { - TcDirectionBorrow::Out(tc_out_borrow) => tc_out_borrow.tc_outgoing, - TcDirectionBorrow::In(_) => unreachable!(), - }; - assert!(tc_outgoing.opt_prev_move_token_in.is_none()); - } - - /// Sort the two identity client. - /// The result will be a pair where the first is initially configured to have outgoing message, - /// and the second is initially configured to have incoming message. - fn sort_sides(identity1: I, identity2: I) -> (I, I) - where - I: Identity, - { - let pk1 = identity1.get_public_key(); - let pk2 = identity2.get_public_key(); - let token_channel12 = TokenChannel::::new(&pk1, &pk2); // (local, remote) - if token_channel12.get_outgoing().is_some() { - (identity1, identity2) - } else { - (identity2, identity1) - } - } - /// Before: tc1: outgoing, tc2: incoming - /// Send AddCurrency: tc2 -> tc1 - /// After: tc1: incoming, tc2: outgoing - fn add_currencies( - _identity1: &I, - identity2: &I, - tc1: &mut TokenChannel, - tc2: &mut TokenChannel, - currencies: &[Currency], - ) where - I: Identity, - { - assert!(tc1.get_outgoing().is_some()); - assert!(!tc2.get_outgoing().is_some()); - - let tc2_in_borrow = tc2.get_incoming().unwrap(); - let currencies_operations = vec![]; - - let rand_nonce = RandValue::from(&[7; RandValue::len()]); - let opt_local_relays = None; - let opt_active_currencies = Some(currencies.to_vec()); - - let SendMoveTokenOutput { - unsigned_move_token, - mutations, - token_info, - } = tc2_in_borrow - .simulate_send_move_token( - currencies_operations, - opt_local_relays, - opt_active_currencies, - rand_nonce, - ) - .unwrap(); - - for tc_mutation in mutations { - tc2.mutate(&tc_mutation); - } - - // This is the only mutation we can not produce from inside TokenChannel, because it - // requires a signature: - let friend_move_token = dummy_sign_move_token(unsigned_move_token, identity2); - let tc_mutation = TcMutation::SetDirection(SetDirection::Outgoing(( - friend_move_token.clone(), - token_info.clone(), - ))); - tc2.mutate(&tc_mutation); - - assert!(tc2.get_outgoing().is_some()); - - let receive_move_token_output = tc1 - .simulate_receive_move_token(friend_move_token.clone(), &ImHashMap::new()) - .unwrap(); - - let move_token_received = match receive_move_token_output { - ReceiveMoveTokenOutput::Received(move_token_received) => move_token_received, - _ => unreachable!(), - }; - - assert!(move_token_received.currencies.is_empty()); - - // let mut seen_mc_mutation = false; - // let mut seen_set_direction = false; - - for tc_mutation in &move_token_received.mutations { - tc1.mutate(tc_mutation); - } - - assert!(!tc1.get_outgoing().is_some()); - match &tc1.direction { - TcDirection::Outgoing(_) => unreachable!(), - TcDirection::Incoming(tc_incoming) => { - assert_eq!( - tc_incoming.move_token_in, - create_hashed(&friend_move_token, &token_info) - ); - } - }; - - for currency in currencies { - assert!(tc2.active_currencies.local.contains(currency)); - assert!(tc1.active_currencies.remote.contains(currency)); - } - } - - /* - /// Before: tc1: outgoing, tc2: incoming - /// Send SetRemoteMaxDebt: tc2 -> tc1 - /// After: tc1: incoming, tc2: outgoing - fn set_remote_max_debt21( - _identity1: &I, - identity2: &I, - tc1: &mut TokenChannel, - tc2: &mut TokenChannel, - currency: &Currency, - ) where - I: Identity, - { - assert!(tc1.get_outgoing().is_some()); - assert!(tc2.get_incoming().is_some()); - - let tc2_in_borrow = tc2.get_incoming().unwrap(); - // let mut outgoing_mc = tc2_in_borrow.create_outgoing_mc(¤cy).unwrap(); - // - // let friend_tc_op = FriendTcOp::SetRemoteMaxDebt(100); - // - // let mc_mutations = outgoing_mc.queue_operation(&friend_tc_op).unwrap(); - let currency_operations = CurrencyOperations { - currency: currency.clone(), - operations: vec![friend_tc_op], - }; - let currencies_operations = vec![currency_operations]; - - let rand_nonce = RandValue::from(&[5; RandValue::len()]); - let opt_local_relays = None; - let opt_active_currencies = None; - - let SendMoveTokenOutput { - unsigned_move_token, - mutations, - token_info, - } = tc2_in_borrow - .simulate_send_move_token( - currencies_operations, - opt_local_relays, - opt_active_currencies, - rand_nonce, - ) - .unwrap(); - - for tc_mutation in mutations { - tc2.mutate(&tc_mutation); - } - - let friend_move_token = dummy_sign_move_token(unsigned_move_token, identity2); - let tc_mutation = TcMutation::SetDirection(SetDirection::Outgoing(( - friend_move_token.clone(), - token_info.clone(), - ))); - tc2.mutate(&tc_mutation); - - assert!(tc2.get_outgoing().is_some()); - - let receive_move_token_output = tc1 - .simulate_receive_move_token(friend_move_token.clone()) - .unwrap(); - - let move_token_received = match receive_move_token_output { - ReceiveMoveTokenOutput::Received(move_token_received) => move_token_received, - _ => unreachable!(), - }; - - assert!(move_token_received.currencies[0] - .incoming_messages - .is_empty()); - assert_eq!(move_token_received.mutations.len(), 2); - - let mut seen_mc_mutation = false; - let mut seen_set_direction = false; - - for i in 0..2 { - match &move_token_received.mutations[i] { - TcMutation::McMutation(mc_mutation) => { - seen_mc_mutation = true; - assert_eq!( - mc_mutation, - &(currency.clone(), McMutation::SetLocalMaxDebt(100)) - ); - } - TcMutation::SetDirection(set_direction) => { - seen_set_direction = true; - match set_direction { - SetDirection::Incoming(incoming_friend_move_token) => assert_eq!( - &create_hashed(&friend_move_token, &token_info), - incoming_friend_move_token - ), - _ => unreachable!(), - } - } - _ => unreachable!(), - } - } - assert!(seen_mc_mutation && seen_set_direction); - - for tc_mutation in &move_token_received.mutations { - tc1.mutate(tc_mutation); - } - - assert!(!tc1.get_outgoing().is_some()); - match &tc1.direction { - TcDirection::Outgoing(_) => unreachable!(), - TcDirection::Incoming(tc_incoming) => { - assert_eq!( - tc_incoming.move_token_in, - create_hashed(&friend_move_token, &token_info) - ); - } - }; - - assert_eq!( - tc1.mutual_credits - .get(¤cy) - .unwrap() - .state() - .balance - .local_max_debt, - 100 - ); - } - */ - - /// This tests sends a SetRemoteMaxDebt(100) in both ways. - #[test] - fn test_simulate_receive_move_token_basic() { - let currency = Currency::try_from("FST".to_owned()).unwrap(); - - let mut rng1 = DummyRandom::new(&[1u8]); - let pkcs8 = PrivateKey::rand_gen(&mut rng1); - let identity1 = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); - - let mut rng2 = DummyRandom::new(&[2u8]); - let pkcs8 = PrivateKey::rand_gen(&mut rng2); - let identity2 = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); - - let (identity1, identity2) = sort_sides(identity1, identity2); - - let pk1 = identity1.get_public_key(); - let pk2 = identity2.get_public_key(); - let mut tc1 = TokenChannel::::new(&pk1, &pk2); // (local, remote) - let mut tc2 = TokenChannel::::new(&pk2, &pk1); // (local, remote) - - // Current state: tc1 --> tc2 - // tc1: outgoing - // tc2: incoming - add_currencies( - &identity1, - &identity2, - &mut tc1, - &mut tc2, - &[currency.clone()], - ); - - // Current state: tc2 --> tc1 - // tc1: incoming - // tc2: outgoing - add_currencies( - &identity2, - &identity1, - &mut tc2, - &mut tc1, - &[currency.clone()], - ); - - // Current state: tc1 --> tc2 - // tc1: outgoing - // tc2: incoming - // set_remote_max_debt21(&identity1, &identity2, &mut tc1, &mut tc2, ¤cy); - - // Current state: tc2 --> tc1 - // tc1: incoming - // tc2: outgoing - // set_remote_max_debt21(&identity2, &identity1, &mut tc2, &mut tc1, ¤cy); - } - - // TODO: Add more tests. - // - Test behaviour of Duplicate, ChainInconsistency -} -*/ diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 361dbcf32..7a543bf8c 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -21,8 +21,8 @@ pub type TcOpSenderResult = oneshot::Sender>; /// Status of a TokenChannel. Could be either outgoing, incoming or inconsistent. pub enum TcStatus { - ConsistentIn(MoveTokenHashed), // (move_token_in) - ConsistentOut(MoveToken, MoveTokenHashed), // (move_token_out, last_move_token_in) + ConsistentIn(MoveTokenHashed), // (move_token_in) + ConsistentOut(MoveToken, Option), // (move_token_out, last_move_token_in) Inconsistent(Signature, u128, Option<(Signature, u128)>), // (local_reset_token, local_reset_move_token_counter, Option<(remote_reset_token, remote_reset_move_token_counter)>) } From cb81626cbab485e7373c2087d27d163f588c9b95 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 21:08:01 +0200 Subject: [PATCH 161/478] funder: Work on mocking token_channel for tests --- components/common/src/async_rpc.rs | 4 +- .../funder/src/token_channel/tests/mod.rs | 2 +- .../funder/src/token_channel/tests/utils.rs | 112 ++++++++++++------ 3 files changed, 82 insertions(+), 36 deletions(-) diff --git a/components/common/src/async_rpc.rs b/components/common/src/async_rpc.rs index 87c10478a..73fa0ea8d 100644 --- a/components/common/src/async_rpc.rs +++ b/components/common/src/async_rpc.rs @@ -7,8 +7,8 @@ pub enum OpError { ResponseOpFailed(oneshot::Canceled), } -pub type AsyncOpResult = BoxFuture<'static, Result>; -pub type AsyncOpStream = BoxStream<'static, Result>; +pub type AsyncOpResult<'a, T> = BoxFuture<'a, Result>; +pub type AsyncOpStream<'a, T> = BoxStream<'a, Result>; /* macro_rules! ops_enum_func { diff --git a/components/funder/src/token_channel/tests/mod.rs b/components/funder/src/token_channel/tests/mod.rs index d50801f20..95adf51c8 100644 --- a/components/funder/src/token_channel/tests/mod.rs +++ b/components/funder/src/token_channel/tests/mod.rs @@ -1 +1 @@ -// mod utils; +mod utils; diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 622d9ec57..faa5d6068 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -5,8 +5,9 @@ use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; use proto::crypto::Signature; use proto::funder::messages::{Currency, McBalance, MoveToken}; -use crate::mutual_credit::tests::MockMutualCredit; +use database::interface::funder::CurrencyConfig; +use crate::mutual_credit::tests::MockMutualCredit; use crate::token_channel::types::TcStatus; use crate::token_channel::TcClient; use crate::types::MoveTokenHashed; @@ -50,12 +51,12 @@ pub struct MockTokenChannel { impl TcClient for MockTokenChannel where - B: Send, + B: Clone + Send, { type McClient = MockMutualCredit; fn mc_client(&mut self, currency: Currency) -> &mut Self::McClient { - match self.status { + match &mut self.status { MockTcStatus::Consistent(tc_consistent) => { tc_consistent.mutual_credits.get_mut(¤cy).unwrap() } @@ -65,76 +66,121 @@ where fn get_tc_status(&mut self) -> AsyncOpResult> { Box::pin(async move { - match self.status { - MockTcStatus::Consistent(tc_consistent) => match tc_consistent.direction { - MockTcDirection::In(move_token_in) => TcStatus::ConsistentIn(move_token_in), + Ok(match &self.status { + MockTcStatus::Consistent(tc_consistent) => match &tc_consistent.direction { + MockTcDirection::In(move_token_in) => { + TcStatus::ConsistentIn(move_token_in.clone()) + } MockTcDirection::Out(move_token_out, opt_move_token_in) => { - TcStatus::ConsistentOut(move_token_out, opt_move_token_out) + TcStatus::ConsistentOut(move_token_out.clone(), opt_move_token_in.clone()) } }, MockTcStatus::Inconsistent(local_reset_terms, opt_remote_reset_terms) => { TcStatus::Inconsistent( - local_reset_terms.reset_token, + local_reset_terms.reset_token.clone(), local_reset_terms.reset_move_token_counter, - opt_remote_reset_terms.map(|remote_reset_terms| { + opt_remote_reset_terms.as_ref().map(|remote_reset_terms| { ( - remote_reset_terms.reset_token, - remote_reset_terms.reset_move_token_counter, + remote_reset_terms.reset_token.clone(), + remote_reset_terms.reset_move_token_counter.clone(), ) }), ) } - } + }) }) } - /* - fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; - fn set_direction_outgoing(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; + fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()> { + todo!(); + } + + fn set_direction_outgoing(&mut self, move_token: MoveToken) -> AsyncOpResult<()> { + todo!(); + } + fn set_direction_outgoing_empty_incoming( &mut self, move_token: MoveToken, - ) -> AsyncOpResult<()>; + ) -> AsyncOpResult<()> { + todo!(); + } + fn set_inconsistent( &mut self, local_reset_token: Signature, local_reset_move_token_counter: u128, - ) -> AsyncOpResult<()>; + ) -> AsyncOpResult<()> { + todo!(); + } /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) - fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; + fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()> { + todo!(); + } /// Simulate incoming token, to be used before an outgoing reset move token (a local reset) fn set_incoming_from_inconsistent( &mut self, move_token_hashed: MoveTokenHashed, - ) -> AsyncOpResult<()>; + ) -> AsyncOpResult<()> { + todo!(); + } + + fn get_move_token_counter(&mut self) -> AsyncOpResult { + todo!(); + } - fn get_move_token_counter(&mut self) -> AsyncOpResult; - fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; + fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()> { + todo!(); + } - fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult; + fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult { + todo!(); + } /// Return a sorted async iterator of all balances - fn list_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + fn list_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)> { + todo!(); + } /// Return a sorted async iterator of all local reset proposal balances /// Only relevant for inconsistent channels - fn list_local_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + fn list_local_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)> { + todo!(); + } /// Return a sorted async iterator of all remote reset proposal balances /// Only relevant for inconsistent channels - fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)> { + todo!(); + } - fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; - fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; + fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult { + todo!(); + } - fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; - fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult { + todo!(); + } - fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; - fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()> { + todo!(); + } - fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()>; - */ + fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()> { + todo!(); + } + + fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()> { + todo!(); + } + + fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()> { + todo!(); + } + + fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()> { + todo!(); + } } From 14ccb7dc29751170d021823f39cfd00fae215b96 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 21:35:19 +0200 Subject: [PATCH 162/478] funder: token_channel: impl Draft for load_remote_reset_terms() --- .../funder/src/token_channel/token_channel.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index ebfe39277..73ae94b50 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -805,3 +805,20 @@ where ) .await } + +/// Load the remote reset terms information from a remote side's inconsistency message +pub async fn load_remote_reset_terms( + tc_client: &mut impl TcClient, + remote_reset_token: Signature, + remote_reset_move_token_counter: u128, + // TODO: Should `remote_reset_balances` be a Vec or a HashMap? + remote_reset_balances: Vec<(Currency, McBalance)>, +) { + // TODO: + // - Change our state to inconsistent, if required. + // - Update remote_reset_{token, move_token_counter}. + // - Insert all `remote_reset_balance-s`, possibly one by one? + // + // Think about the interface with the database. + todo!(); +} From 817c4fad8d6add4138c8bef1fc546b095fa09546 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 4 Nov 2020 21:35:49 +0200 Subject: [PATCH 163/478] funder: Work on token_channel mocking for tests. Not done yet --- .../funder/src/token_channel/tests/utils.rs | 79 ++++++++++++------- 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index faa5d6068..2c2251b34 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -1,4 +1,6 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; + +use futures::future; use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; @@ -36,6 +38,8 @@ pub enum MockTcDirection { pub struct TcConsistent { mutual_credits: HashMap, direction: MockTcDirection, + local_currencies: HashSet, + remote_currencies: HashSet, } #[derive(Debug)] @@ -65,47 +69,68 @@ where } fn get_tc_status(&mut self) -> AsyncOpResult> { - Box::pin(async move { - Ok(match &self.status { - MockTcStatus::Consistent(tc_consistent) => match &tc_consistent.direction { - MockTcDirection::In(move_token_in) => { - TcStatus::ConsistentIn(move_token_in.clone()) - } - MockTcDirection::Out(move_token_out, opt_move_token_in) => { - TcStatus::ConsistentOut(move_token_out.clone(), opt_move_token_in.clone()) - } - }, - MockTcStatus::Inconsistent(local_reset_terms, opt_remote_reset_terms) => { - TcStatus::Inconsistent( - local_reset_terms.reset_token.clone(), - local_reset_terms.reset_move_token_counter, - opt_remote_reset_terms.as_ref().map(|remote_reset_terms| { - ( - remote_reset_terms.reset_token.clone(), - remote_reset_terms.reset_move_token_counter.clone(), - ) - }), - ) + let res = Ok(match &self.status { + MockTcStatus::Consistent(tc_consistent) => match &tc_consistent.direction { + MockTcDirection::In(move_token_in) => TcStatus::ConsistentIn(move_token_in.clone()), + MockTcDirection::Out(move_token_out, opt_move_token_in) => { + TcStatus::ConsistentOut(move_token_out.clone(), opt_move_token_in.clone()) } - }) - }) + }, + MockTcStatus::Inconsistent(local_reset_terms, opt_remote_reset_terms) => { + TcStatus::Inconsistent( + local_reset_terms.reset_token.clone(), + local_reset_terms.reset_move_token_counter, + opt_remote_reset_terms.as_ref().map(|remote_reset_terms| { + ( + remote_reset_terms.reset_token.clone(), + remote_reset_terms.reset_move_token_counter.clone(), + ) + }), + ) + } + }); + Box::pin(future::ready(res)) } fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()> { - todo!(); + let tc_consistent = match &mut self.status { + MockTcStatus::Consistent(tc_consistent) => tc_consistent, + _ => unreachable!(), + }; + + tc_consistent.direction = MockTcDirection::In(move_token_hashed); + Box::pin(future::ready(Ok(()))) } fn set_direction_outgoing(&mut self, move_token: MoveToken) -> AsyncOpResult<()> { - todo!(); + let tc_consistent = match &mut self.status { + MockTcStatus::Consistent(tc_consistent) => tc_consistent, + _ => unreachable!(), + }; + + let last_move_token_in = match &tc_consistent.direction { + MockTcDirection::In(move_token_in) => move_token_in.clone(), + _ => unreachable!(), + }; + + tc_consistent.direction = MockTcDirection::Out(move_token, Some(last_move_token_in)); + Box::pin(future::ready(Ok(()))) } fn set_direction_outgoing_empty_incoming( &mut self, move_token: MoveToken, ) -> AsyncOpResult<()> { - todo!(); + let tc_consistent = match &mut self.status { + MockTcStatus::Consistent(tc_consistent) => tc_consistent, + _ => unreachable!(), + }; + + tc_consistent.direction = MockTcDirection::Out(move_token, None); + Box::pin(future::ready(Ok(()))) } + // TODO: How do remote side sets reset terms? fn set_inconsistent( &mut self, local_reset_token: Signature, From 7b8b67776bd9539328fb7e958a6d9b71ef306b0c Mon Sep 17 00:00:00 2001 From: real Date: Mon, 9 Nov 2020 14:03:05 +0200 Subject: [PATCH 164/478] funder: Added load_remote_reset_terms() implementation --- .../funder/src/token_channel/tests/utils.rs | 17 +++++++ .../funder/src/token_channel/token_channel.rs | 47 +++++++++++++++---- components/funder/src/token_channel/types.rs | 15 ++++++ 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 2c2251b34..a80cc8ddf 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -139,6 +139,23 @@ where todo!(); } + /// Set remote terms for reset. Can only be called if we are in inconsistent state. + fn set_inconsistent_remote_terms( + &mut self, + remote_reset_token: Signature, + remote_reset_move_token_counter: u128, + ) -> AsyncOpResult<()> { + todo!(); + } + + fn add_remote_reset_balance( + &mut self, + currency: Currency, + reset_balance: McBalance, + ) -> AsyncOpResult<()> { + todo!(); + } + /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()> { todo!(); diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 73ae94b50..b84e77125 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -276,6 +276,8 @@ async fn create_reset_token( .map_err(|_| TokenChannelError::RequestSignatureError)?) } +/// Set token channel to be inconsistent +/// Local reset terms are automatically calculated async fn set_inconsistent( tc_client: &mut impl TcClient, identity_client: &mut IdentityClient, @@ -807,18 +809,43 @@ where } /// Load the remote reset terms information from a remote side's inconsistency message +/// Optionally returns local reset terms (If not already inconsistent) pub async fn load_remote_reset_terms( tc_client: &mut impl TcClient, + identity_client: &mut IdentityClient, remote_reset_token: Signature, remote_reset_move_token_counter: u128, - // TODO: Should `remote_reset_balances` be a Vec or a HashMap? - remote_reset_balances: Vec<(Currency, McBalance)>, -) { - // TODO: - // - Change our state to inconsistent, if required. - // - Update remote_reset_{token, move_token_counter}. - // - Insert all `remote_reset_balance-s`, possibly one by one? - // - // Think about the interface with the database. - todo!(); + remote_reset_balances: impl IntoIterator, + local_public_key: &PublicKey, + remote_public_key: &PublicKey, +) -> Result, TokenChannelError> { + // Check our current state: + let ret_val = match tc_client.get_tc_status().await? { + TcStatus::ConsistentIn(_) | TcStatus::ConsistentOut(_, _) => { + // Change our token channel status to inconsistent: + Some( + set_inconsistent( + tc_client, + identity_client, + local_public_key, + remote_public_key, + ) + .await?, + ) + } + TcStatus::Inconsistent(_, _, _) => None, + }; + + // Set remote reset terms: + tc_client + .set_inconsistent_remote_terms(remote_reset_token, remote_reset_move_token_counter) + .await?; + + for (currency, mc_balance) in remote_reset_balances.into_iter() { + tc_client + .add_remote_reset_balance(currency, mc_balance) + .await?; + } + + Ok(ret_val) } diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 7a543bf8c..a7947bf0d 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -44,6 +44,21 @@ pub trait TcClient { local_reset_move_token_counter: u128, ) -> AsyncOpResult<()>; + /// Set remote terms for reset. Can only be called if we are in inconsistent state. + fn set_inconsistent_remote_terms( + &mut self, + remote_reset_token: Signature, + remote_reset_move_token_counter: u128, + ) -> AsyncOpResult<()>; + + /// Add a new remote reset balance to the remote reset terms list + /// Can only be called if we already called `set_inconsistent_remote_terms()`. + fn add_remote_reset_balance( + &mut self, + currency: Currency, + reset_balance: McBalance, + ) -> AsyncOpResult<()>; + /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; From 982198627864f6acc2aa0130ce529e061306dd13 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 9 Nov 2020 14:32:07 +0200 Subject: [PATCH 165/478] funder: Use ResetBalance instead of McBalance --- .../funder/src/token_channel/tests/utils.rs | 8 +++--- .../funder/src/token_channel/token_channel.rs | 28 ++++++++++++++++--- components/funder/src/token_channel/types.rs | 25 +++++++++++++++-- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index a80cc8ddf..28246b996 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -10,7 +10,7 @@ use proto::funder::messages::{Currency, McBalance, MoveToken}; use database::interface::funder::CurrencyConfig; use crate::mutual_credit::tests::MockMutualCredit; -use crate::token_channel::types::TcStatus; +use crate::token_channel::types::{ResetBalance, TcStatus}; use crate::token_channel::TcClient; use crate::types::MoveTokenHashed; @@ -151,7 +151,7 @@ where fn add_remote_reset_balance( &mut self, currency: Currency, - reset_balance: McBalance, + reset_balance: ResetBalance, ) -> AsyncOpResult<()> { todo!(); } @@ -188,13 +188,13 @@ where /// Return a sorted async iterator of all local reset proposal balances /// Only relevant for inconsistent channels - fn list_local_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)> { + fn list_local_reset_balances(&mut self) -> AsyncOpStream<(Currency, ResetBalance)> { todo!(); } /// Return a sorted async iterator of all remote reset proposal balances /// Only relevant for inconsistent channels - fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)> { + fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, ResetBalance)> { todo!(); } diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index b84e77125..3e07d9b34 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -1,4 +1,5 @@ use std::cmp::Ordering; +use std::collections::HashMap; use std::convert::TryFrom; use derive_more::From; @@ -30,7 +31,7 @@ use crate::mutual_credit::incoming::{ use crate::mutual_credit::outgoing::{queue_operation, QueueOperationError}; use crate::mutual_credit::types::McClient; -use crate::token_channel::types::{TcClient, TcStatus}; +use crate::token_channel::types::{ResetBalance, ResetTerms, TcClient, TcStatus}; use crate::types::{create_hashed, MoveTokenHashed}; /// Unrecoverable TokenChannel error @@ -144,6 +145,17 @@ where ) } +/// Create a new McBalance (with zero pending fees) based on a given ResetBalance +fn reset_balance_to_mc_balance(reset_balance: ResetBalance) -> McBalance { + McBalance { + balance: reset_balance.balance, + local_pending_debt: 0, + remote_pending_debt: 0, + in_fees: reset_balance.in_fees, + out_fees: reset_balance.out_fees, + } +} + pub async fn handle_in_move_token( tc_client: &mut C, identity_client: &mut IdentityClient, @@ -187,7 +199,12 @@ where // Simulate an outgoing move token with the correct `new_token`: let token_info = TokenInfo { - balances_hash: hash_mc_infos(tc_client.list_local_reset_balances()).await?, + balances_hash: hash_mc_infos(tc_client.list_local_reset_balances().map_ok( + |(currency, mc_balance)| { + (currency, reset_balance_to_mc_balance(mc_balance)) + }, + )) + .await?, move_token_counter: local_reset_move_token_counter .checked_sub(1) .ok_or(TokenChannelError::MoveTokenCounterOverflow)?, @@ -776,7 +793,10 @@ where // Simulate an incoming move token with the correct `new_token`: let token_info = TokenInfo { - balances_hash: hash_mc_infos(tc_client.list_remote_reset_balances()).await?, + balances_hash: hash_mc_infos(tc_client.list_remote_reset_balances().map_ok( + |(currency, reset_balance)| (currency, reset_balance_to_mc_balance(reset_balance)), + )) + .await?, move_token_counter: remote_reset_move_token_counter .checked_sub(1) .ok_or(TokenChannelError::MoveTokenCounterOverflow)?, @@ -815,7 +835,7 @@ pub async fn load_remote_reset_terms( identity_client: &mut IdentityClient, remote_reset_token: Signature, remote_reset_move_token_counter: u128, - remote_reset_balances: impl IntoIterator, + remote_reset_balances: impl IntoIterator, local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result, TokenChannelError> { diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index a7947bf0d..332e55d1c 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -1,6 +1,9 @@ +use std::collections::HashMap; + use futures::channel::oneshot; use common::async_rpc::{AsyncOpResult, AsyncOpStream}; +use common::u256::U256; use proto::crypto::Signature; use proto::funder::messages::{Currency, McBalance, MoveToken}; @@ -19,6 +22,22 @@ pub enum TcOpError { pub type TcOpResult = Result; pub type TcOpSenderResult = oneshot::Sender>; +// TODO: Might move to proto in the future: +/// Balances for resetting a currency +pub struct ResetBalance { + pub balance: i128, + pub in_fees: U256, + pub out_fees: U256, +} + +// TODO: Might move to proto in the future: +/// Reset terms for a token channel +pub struct ResetTerms { + pub reset_token: Signature, + pub move_token_counter: u128, + pub balances_for_reset: HashMap, +} + /// Status of a TokenChannel. Could be either outgoing, incoming or inconsistent. pub enum TcStatus { ConsistentIn(MoveTokenHashed), // (move_token_in) @@ -56,7 +75,7 @@ pub trait TcClient { fn add_remote_reset_balance( &mut self, currency: Currency, - reset_balance: McBalance, + reset_balance: ResetBalance, ) -> AsyncOpResult<()>; /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) @@ -78,11 +97,11 @@ pub trait TcClient { /// Return a sorted async iterator of all local reset proposal balances /// Only relevant for inconsistent channels - fn list_local_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + fn list_local_reset_balances(&mut self) -> AsyncOpStream<(Currency, ResetBalance)>; /// Return a sorted async iterator of all remote reset proposal balances /// Only relevant for inconsistent channels - fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, ResetBalance)>; fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; From bf2e897fe30469d2e6329c17c754d0d228fc8e6a Mon Sep 17 00:00:00 2001 From: real Date: Mon, 9 Nov 2020 14:35:12 +0200 Subject: [PATCH 166/478] funder: Derived Debug for some types --- components/funder/src/token_channel/types.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 332e55d1c..8e9c63b41 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -24,6 +24,7 @@ pub type TcOpSenderResult = oneshot::Sender>; // TODO: Might move to proto in the future: /// Balances for resetting a currency +#[derive(Debug)] pub struct ResetBalance { pub balance: i128, pub in_fees: U256, @@ -32,6 +33,7 @@ pub struct ResetBalance { // TODO: Might move to proto in the future: /// Reset terms for a token channel +#[derive(Debug)] pub struct ResetTerms { pub reset_token: Signature, pub move_token_counter: u128, @@ -39,6 +41,7 @@ pub struct ResetTerms { } /// Status of a TokenChannel. Could be either outgoing, incoming or inconsistent. +#[derive(Debug)] pub enum TcStatus { ConsistentIn(MoveTokenHashed), // (move_token_in) ConsistentOut(MoveToken, Option), // (move_token_out, last_move_token_in) From 1c88943eae664e1000bf78e3d8e938cd40742323 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 9 Nov 2020 14:35:33 +0200 Subject: [PATCH 167/478] funder: Removed old comment --- components/funder/src/token_channel/token_channel.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 3e07d9b34..78ebd60fd 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -54,7 +54,6 @@ pub struct MoveTokenReceivedCurrency { #[derive(Debug)] pub struct MoveTokenReceived { - // pub mutations: Vec>, pub currencies: Vec, pub relays_diff: Vec>, } From ae726ff7c4a1857a67586c7a0dda84e63ef50275 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 9 Nov 2020 14:36:44 +0200 Subject: [PATCH 168/478] funder: Updated comment --- .../funder/src/token_channel/token_channel.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 78ebd60fd..d9588bfb8 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -271,6 +271,13 @@ where } } +// TODO: Think abou the security implications of the implementation here. +// Some previous ideas: +// - Use a random generator to randomly generate an identity client. +// - Sign over a blob that contains: +// - hash(prefix ("SOME_STRING")) +// - Both public keys. +// - local_reset_move_token_counter /// Generate a reset token, to be used by remote side if he wants to accept the reset terms. async fn create_reset_token( identity_client: &mut IdentityClient, @@ -278,12 +285,6 @@ async fn create_reset_token( remote_public_key: &PublicKey, move_token_counter: u128, ) -> Result { - // Some ideas: - // - Use a random generator to randomly generate an identity client. - // - Sign over a blob that contains: - // - hash(prefix ("SOME_STRING")) - // - Both public keys. - // - local_reset_move_token_counter let sign_buffer = reset_token_signature_buff(local_public_key, remote_public_key, move_token_counter); Ok(identity_client From ff25dbf93c6f14cdd9c5eb60b9aba794b15b64fc Mon Sep 17 00:00:00 2001 From: real Date: Mon, 9 Nov 2020 16:31:59 +0200 Subject: [PATCH 169/478] funder: Full list of currencies is returned with reset terms --- .../funder/src/token_channel/token_channel.rs | 65 +++++++++++++------ 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index d9588bfb8..e4c77a652 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -42,6 +42,7 @@ pub enum TokenChannelError { CanNotRemoveCurrencyInUse, InvalidTokenChannelStatus, RequestSignatureError, + InvalidDbState, OpError(OpError), QueueOperationError(QueueOperationError), } @@ -64,7 +65,7 @@ pub enum ReceiveMoveTokenOutput { Duplicate, RetransmitOutgoing(MoveToken), Received(MoveTokenReceived), - ChainInconsistent(Signature, u128), // (local_reset_token, local_reset_move_token_counter) + ChainInconsistent(ResetTerms), // (local_reset_token, local_reset_move_token_counter) } /// Create a token from a public key @@ -155,6 +156,21 @@ fn reset_balance_to_mc_balance(reset_balance: ResetBalance) -> McBalance { } } +/// Extract all local balances for reset as a map: +async fn local_balances_for_reset( + tc_client: &mut impl TcClient, +) -> Result, TokenChannelError> { + let mut balances = HashMap::new(); + let mut reset_balances = tc_client.list_local_reset_balances(); + while let Some(item) = reset_balances.next().await { + let (currency, reset_balance) = item?; + if let Some(_) = balances.insert(currency, reset_balance) { + return Err(TokenChannelError::InvalidDbState); + } + } + Ok(balances) +} + pub async fn handle_in_move_token( tc_client: &mut C, identity_client: &mut IdentityClient, @@ -255,17 +271,19 @@ where } IncomingTokenMatchOutput::InvalidIncoming(_) => { // In this case the transaction was not committed: - Ok(ReceiveMoveTokenOutput::ChainInconsistent( - local_reset_token, - local_reset_move_token_counter, - )) + Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { + reset_token: local_reset_token, + move_token_counter: local_reset_move_token_counter, + balances_for_reset: local_balances_for_reset(tc_client).await?, + })) } } } else { - Ok(ReceiveMoveTokenOutput::ChainInconsistent( - local_reset_token, - local_reset_move_token_counter, - )) + Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { + reset_token: local_reset_token, + move_token_counter: local_reset_move_token_counter, + balances_for_reset: local_balances_for_reset(tc_client).await?, + })) } } } @@ -278,6 +296,7 @@ where // - hash(prefix ("SOME_STRING")) // - Both public keys. // - local_reset_move_token_counter + /// Generate a reset token, to be used by remote side if he wants to accept the reset terms. async fn create_reset_token( identity_client: &mut IdentityClient, @@ -353,10 +372,12 @@ where remote_public_key, ) .await?; - Ok(ReceiveMoveTokenOutput::ChainInconsistent( - local_reset_token, - local_reset_move_token_counter, - )) + + Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { + reset_token: local_reset_token, + move_token_counter: local_reset_move_token_counter, + balances_for_reset: local_balances_for_reset(tc_client).await?, + })) } } @@ -415,10 +436,11 @@ where remote_public_key, ) .await?; - Ok(ReceiveMoveTokenOutput::ChainInconsistent( - local_reset_token, - local_reset_move_token_counter, - )) + Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { + reset_token: local_reset_token, + move_token_counter: local_reset_move_token_counter, + balances_for_reset: local_balances_for_reset(tc_client).await?, + })) } } // self.outgoing_to_incoming(friend_move_token, new_move_token) @@ -436,10 +458,11 @@ where remote_public_key, ) .await?; - Ok(ReceiveMoveTokenOutput::ChainInconsistent( - local_reset_token, - local_reset_move_token_counter, - )) + Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { + reset_token: local_reset_token, + move_token_counter: local_reset_move_token_counter, + balances_for_reset: local_balances_for_reset(tc_client).await?, + })) } } From 19bb94ef77e02c7615c20eaf245bc698521f6604 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 9 Nov 2020 16:34:58 +0200 Subject: [PATCH 170/478] funder: load_remote_reset_terms() now returns local reset terms --- .../funder/src/token_channel/token_channel.rs | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index e4c77a652..b14b1093a 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -861,20 +861,24 @@ pub async fn load_remote_reset_terms( remote_reset_balances: impl IntoIterator, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> Result, TokenChannelError> { +) -> Result, TokenChannelError> { // Check our current state: let ret_val = match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(_) | TcStatus::ConsistentOut(_, _) => { // Change our token channel status to inconsistent: - Some( - set_inconsistent( - tc_client, - identity_client, - local_public_key, - remote_public_key, - ) - .await?, + let (local_reset_token, local_reset_move_token_counter) = set_inconsistent( + tc_client, + identity_client, + local_public_key, + remote_public_key, ) + .await?; + + Some(ResetTerms { + reset_token: local_reset_token, + move_token_counter: local_reset_move_token_counter, + balances_for_reset: local_balances_for_reset(tc_client).await?, + }) } TcStatus::Inconsistent(_, _, _) => None, }; From f15d6aed623428e8e2709081cbf8f75692e78d18 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 9 Nov 2020 16:39:33 +0200 Subject: [PATCH 171/478] funder: Enhanced match statements --- .../funder/src/token_channel/token_channel.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index b14b1093a..c6081fa12 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -678,14 +678,7 @@ where // We expect that our current state is incoming: let move_token_in = match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => move_token_in, - TcStatus::ConsistentOut(_move_token_out, _opt_move_token_in) => { - return Err(TokenChannelError::InvalidTokenChannelStatus) - } - TcStatus::Inconsistent( - _local_reset_token, - _local_reset_move_token_counter, - _opt_remote, - ) => { + TcStatus::ConsistentOut(..) | TcStatus::Inconsistent(..) => { return Err(TokenChannelError::InvalidTokenChannelStatus); } }; @@ -801,8 +794,8 @@ where // and that the remote side has already sent his reset terms: let (remote_reset_token, remote_reset_move_token_counter) = match tc_client.get_tc_status().await? { - TcStatus::ConsistentIn(_) - | TcStatus::ConsistentOut(_, _) + TcStatus::ConsistentIn(..) + | TcStatus::ConsistentOut(..) | TcStatus::Inconsistent(_, _, None) => { // We don't have the remote side's reset terms yet: return Err(TokenChannelError::InvalidTokenChannelStatus); @@ -864,7 +857,7 @@ pub async fn load_remote_reset_terms( ) -> Result, TokenChannelError> { // Check our current state: let ret_val = match tc_client.get_tc_status().await? { - TcStatus::ConsistentIn(_) | TcStatus::ConsistentOut(_, _) => { + TcStatus::ConsistentIn(..) | TcStatus::ConsistentOut(..) => { // Change our token channel status to inconsistent: let (local_reset_token, local_reset_move_token_counter) = set_inconsistent( tc_client, @@ -880,7 +873,7 @@ pub async fn load_remote_reset_terms( balances_for_reset: local_balances_for_reset(tc_client).await?, }) } - TcStatus::Inconsistent(_, _, _) => None, + TcStatus::Inconsistent(..) => None, }; // Set remote reset terms: From ee2e5d22a902369f6d38940bcb1355afefab47f6 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 9 Nov 2020 22:14:38 +0200 Subject: [PATCH 172/478] funder: Work on token_channel and tests --- .../funder/src/token_channel/tests/utils.rs | 124 ++++++++++++++---- .../funder/src/token_channel/token_channel.rs | 34 +++-- components/funder/src/token_channel/types.rs | 17 ++- 3 files changed, 126 insertions(+), 49 deletions(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 28246b996..f7cfa8910 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -3,6 +3,8 @@ use std::collections::{HashMap, HashSet}; use futures::future; use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; +use common::safe_arithmetic::SafeSignedArithmetic; +use common::u256::U256; use proto::crypto::Signature; use proto::funder::messages::{Currency, McBalance, MoveToken}; @@ -10,24 +12,10 @@ use proto::funder::messages::{Currency, McBalance, MoveToken}; use database::interface::funder::CurrencyConfig; use crate::mutual_credit::tests::MockMutualCredit; -use crate::token_channel::types::{ResetBalance, TcStatus}; +use crate::token_channel::types::{ResetBalance, ResetTerms, TcStatus}; use crate::token_channel::TcClient; use crate::types::MoveTokenHashed; -#[derive(Debug)] -pub struct MockLocalResetTerms { - reset_token: Signature, - reset_move_token_counter: u128, - reset_balances: Vec<(Currency, McBalance)>, -} - -#[derive(Debug)] -pub struct MockRemoteResetTerms { - reset_token: Signature, - reset_move_token_counter: u128, - reset_balances: Vec<(Currency, McBalance)>, -} - #[derive(Debug)] pub enum MockTcDirection { In(MoveTokenHashed), @@ -38,6 +26,7 @@ pub enum MockTcDirection { pub struct TcConsistent { mutual_credits: HashMap, direction: MockTcDirection, + move_token_counter: u128, local_currencies: HashSet, remote_currencies: HashSet, } @@ -45,7 +34,7 @@ pub struct TcConsistent { #[derive(Debug)] pub enum MockTcStatus { Consistent(TcConsistent), - Inconsistent(MockLocalResetTerms, Option), + Inconsistent(ResetTerms, Option), } #[derive(Debug)] @@ -53,6 +42,29 @@ pub struct MockTokenChannel { status: MockTcStatus, } +/// Calculate ResetBalance for a specific mutual credit +fn calc_reset_balance(mock_token_channel: &MockMutualCredit) -> ResetBalance { + let mc_balance = &mock_token_channel.balance; + + // Calculate in_fees, adding fees from remote pending requests: + let mut in_fees = mc_balance.in_fees; + for (_uid, pending_transaction) in &mock_token_channel.pending_transactions.remote { + in_fees + .checked_add(U256::from(pending_transaction.left_fees)) + .unwrap(); + } + + ResetBalance { + // Calculate reset balance, including pending debt + balance: mc_balance + .balance + .checked_add_unsigned(mc_balance.remote_pending_debt) + .unwrap(), + in_fees, + out_fees: mc_balance.out_fees, + } +} + impl TcClient for MockTokenChannel where B: Clone + Send, @@ -79,11 +91,11 @@ where MockTcStatus::Inconsistent(local_reset_terms, opt_remote_reset_terms) => { TcStatus::Inconsistent( local_reset_terms.reset_token.clone(), - local_reset_terms.reset_move_token_counter, + local_reset_terms.move_token_counter, opt_remote_reset_terms.as_ref().map(|remote_reset_terms| { ( remote_reset_terms.reset_token.clone(), - remote_reset_terms.reset_move_token_counter.clone(), + remote_reset_terms.move_token_counter.clone(), ) }), ) @@ -102,12 +114,19 @@ where Box::pin(future::ready(Ok(()))) } - fn set_direction_outgoing(&mut self, move_token: MoveToken) -> AsyncOpResult<()> { + fn set_direction_outgoing( + &mut self, + move_token: MoveToken, + move_token_counter: u128, + ) -> AsyncOpResult<()> { let tc_consistent = match &mut self.status { MockTcStatus::Consistent(tc_consistent) => tc_consistent, _ => unreachable!(), }; + // Set `move_token_counter`: + tc_consistent.move_token_counter = move_token_counter; + let last_move_token_in = match &tc_consistent.direction { MockTcDirection::In(move_token_in) => move_token_in.clone(), _ => unreachable!(), @@ -120,6 +139,7 @@ where fn set_direction_outgoing_empty_incoming( &mut self, move_token: MoveToken, + move_token_counter: u128, ) -> AsyncOpResult<()> { let tc_consistent = match &mut self.status { MockTcStatus::Consistent(tc_consistent) => tc_consistent, @@ -130,13 +150,33 @@ where Box::pin(future::ready(Ok(()))) } - // TODO: How do remote side sets reset terms? fn set_inconsistent( &mut self, local_reset_token: Signature, local_reset_move_token_counter: u128, ) -> AsyncOpResult<()> { - todo!(); + // Calculate `reset_balances`: + let reset_balances: HashMap<_, _> = match &mut self.status { + MockTcStatus::Consistent(tc_consistent) => tc_consistent + .mutual_credits + .iter() + .map(|(currency, mock_mutual_credit)| { + (currency.clone(), calc_reset_balance(&mock_mutual_credit)) + }) + .collect(), + MockTcStatus::Inconsistent(..) => unreachable!(), + }; + + // Change status to inconsistent: + self.status = MockTcStatus::Inconsistent( + ResetTerms { + reset_token: local_reset_token, + move_token_counter: local_reset_move_token_counter, + reset_balances, + }, + None, + ); + Box::pin(future::ready(Ok(()))) } /// Set remote terms for reset. Can only be called if we are in inconsistent state. @@ -145,7 +185,22 @@ where remote_reset_token: Signature, remote_reset_move_token_counter: u128, ) -> AsyncOpResult<()> { - todo!(); + let local_reset_terms = match &self.status { + MockTcStatus::Consistent(..) | MockTcStatus::Inconsistent(_, Some(_)) => unreachable!(), + MockTcStatus::Inconsistent(local_reset_terms, None) => local_reset_terms.clone(), + }; + + self.status = MockTcStatus::Inconsistent( + local_reset_terms, + Some(ResetTerms { + reset_token: remote_reset_token, + move_token_counter: remote_reset_move_token_counter, + // Note that reset_balances is currently empty, and needs to filled. + reset_balances: HashMap::new(), + }), + ); + + Box::pin(future::ready(Ok(()))) } fn add_remote_reset_balance( @@ -153,7 +208,21 @@ where currency: Currency, reset_balance: ResetBalance, ) -> AsyncOpResult<()> { - todo!(); + let remote_reset_terms = match &mut self.status { + MockTcStatus::Consistent(..) | MockTcStatus::Inconsistent(_, None) => unreachable!(), + MockTcStatus::Inconsistent(local_reset_terms, Some(remote_reset_terms)) => { + remote_reset_terms + } + }; + + if let Some(_) = remote_reset_terms + .reset_balances + .insert(currency, reset_balance) + { + unreachable!(); + } + + Box::pin(future::ready(Ok(()))) } /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) @@ -170,10 +239,13 @@ where } fn get_move_token_counter(&mut self) -> AsyncOpResult { - todo!(); - } + /* + let local_reset_terms = match &self.status { + MockTcStatus::Consistent(..) + MockTcStatus::Inconsistent(..) => unreachable!(), + }; + */ - fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()> { todo!(); } diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index c6081fa12..145fa793d 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -121,14 +121,15 @@ pub async fn init_token_channel( where B: CanonicalSerialize + Clone, { + let move_token_counter = 0; Ok( if compare_public_key(&local_public_key, &remote_public_key) == Ordering::Less { // We are the first sender tc_client - .set_direction_outgoing_empty_incoming(initial_move_token( - local_public_key, - remote_public_key, - )) + .set_direction_outgoing_empty_incoming( + initial_move_token(local_public_key, remote_public_key), + move_token_counter, + ) .await? } else { // We are the second sender @@ -136,7 +137,7 @@ where let token_info = TokenInfo { // No balances yet: balances_hash: hash_buffer(&[]), - move_token_counter: 0, + move_token_counter, }; tc_client .set_direction_incoming(create_hashed::(&move_token_in, &token_info)) @@ -146,7 +147,7 @@ where } /// Create a new McBalance (with zero pending fees) based on a given ResetBalance -fn reset_balance_to_mc_balance(reset_balance: ResetBalance) -> McBalance { +pub fn reset_balance_to_mc_balance(reset_balance: ResetBalance) -> McBalance { McBalance { balance: reset_balance.balance, local_pending_debt: 0, @@ -274,7 +275,7 @@ where Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { reset_token: local_reset_token, move_token_counter: local_reset_move_token_counter, - balances_for_reset: local_balances_for_reset(tc_client).await?, + reset_balances: local_balances_for_reset(tc_client).await?, })) } } @@ -282,7 +283,7 @@ where Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { reset_token: local_reset_token, move_token_counter: local_reset_move_token_counter, - balances_for_reset: local_balances_for_reset(tc_client).await?, + reset_balances: local_balances_for_reset(tc_client).await?, })) } } @@ -376,7 +377,7 @@ where Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { reset_token: local_reset_token, move_token_counter: local_reset_move_token_counter, - balances_for_reset: local_balances_for_reset(tc_client).await?, + reset_balances: local_balances_for_reset(tc_client).await?, })) } } @@ -439,7 +440,7 @@ where Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { reset_token: local_reset_token, move_token_counter: local_reset_move_token_counter, - balances_for_reset: local_balances_for_reset(tc_client).await?, + reset_balances: local_balances_for_reset(tc_client).await?, })) } } @@ -461,7 +462,7 @@ where Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { reset_token: local_reset_token, move_token_counter: local_reset_move_token_counter, - balances_for_reset: local_balances_for_reset(tc_client).await?, + reset_balances: local_balances_for_reset(tc_client).await?, })) } } @@ -647,11 +648,6 @@ where )); } - // Update move_token_counter: - tc_client - .set_move_token_counter(new_move_token_counter) - .await?; - // Set direction to outgoing, with the newly received move token: let new_move_token_hashed = create_hashed(&new_move_token, &token_info); tc_client @@ -771,7 +767,9 @@ where // Set the direction to be outgoing: // TODO: This should also save the last incoming move token, in an atomic way. // Should probably be implemented inside the database code. - tc_client.set_direction_outgoing(move_token.clone()).await?; + tc_client + .set_direction_outgoing(move_token.clone(), new_move_token_counter) + .await?; Ok(move_token) } @@ -870,7 +868,7 @@ pub async fn load_remote_reset_terms( Some(ResetTerms { reset_token: local_reset_token, move_token_counter: local_reset_move_token_counter, - balances_for_reset: local_balances_for_reset(tc_client).await?, + reset_balances: local_balances_for_reset(tc_client).await?, }) } TcStatus::Inconsistent(..) => None, diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 8e9c63b41..9fe75b3d7 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -24,20 +24,22 @@ pub type TcOpSenderResult = oneshot::Sender>; // TODO: Might move to proto in the future: /// Balances for resetting a currency -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ResetBalance { pub balance: i128, pub in_fees: U256, pub out_fees: U256, } +// TODO: Maybe shouldn't be cloneable (because reset balances could be large) // TODO: Might move to proto in the future: /// Reset terms for a token channel -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ResetTerms { pub reset_token: Signature, pub move_token_counter: u128, - pub balances_for_reset: HashMap, + // TODO: Rename: + pub reset_balances: HashMap, } /// Status of a TokenChannel. Could be either outgoing, incoming or inconsistent. @@ -55,10 +57,15 @@ pub trait TcClient { fn get_tc_status(&mut self) -> AsyncOpResult>; fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; - fn set_direction_outgoing(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; + fn set_direction_outgoing( + &mut self, + move_token: MoveToken, + move_token_counter: u128, + ) -> AsyncOpResult<()>; fn set_direction_outgoing_empty_incoming( &mut self, move_token: MoveToken, + move_token_counter: u128, ) -> AsyncOpResult<()>; fn set_inconsistent( &mut self, @@ -91,7 +98,7 @@ pub trait TcClient { ) -> AsyncOpResult<()>; fn get_move_token_counter(&mut self) -> AsyncOpResult; - fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; + // fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult; From e60db2b108b79ef8d4de4bd16372076f11727f91 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 9 Nov 2020 22:35:29 +0200 Subject: [PATCH 173/478] funder: Some work on implementing MockTokenChannel --- .../tests/request_cancel_send_funds.rs | 2 +- .../tests/request_response_send_funds.rs | 2 +- .../funder/src/mutual_credit/tests/utils.rs | 4 +- .../funder/src/token_channel/tests/utils.rs | 82 ++++++++++++++----- .../funder/src/token_channel/token_channel.rs | 5 +- components/funder/src/token_channel/types.rs | 11 +-- 6 files changed, 74 insertions(+), 32 deletions(-) diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index a480799f7..889cbe630 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -30,7 +30,7 @@ async fn task_request_cancel_send_funds() { let remote_public_key = public_key_b.clone(); let balance = 0; - let mut mc_transaction = MockMutualCredit::new(¤cy, balance); + let mut mc_transaction = MockMutualCredit::new(currency.clone(), balance); // -----[RequestSendFunds]-------- // ----------------------------- diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index 9f8f6da68..e5aa2934e 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -27,7 +27,7 @@ async fn task_request_response_send_funds() { let remote_public_key = PublicKey::from(&[0xbb; PublicKey::len()]); let balance = 0; - let mut mc_transaction = MockMutualCredit::new(¤cy, balance); + let mut mc_transaction = MockMutualCredit::new(currency.clone(), balance); // -----[RequestSendFunds]-------- // ----------------------------- diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index 096c4e2a1..860943184 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -39,11 +39,11 @@ pub struct MockMutualCredit { impl MockMutualCredit { pub fn new( // TODO: Should we move instead of take a reference here? - currency: &Currency, + currency: Currency, balance: i128, ) -> MockMutualCredit { MockMutualCredit { - currency: currency.clone(), + currency, balance: McBalance::new(balance), pending_transactions: McPendingTransactions::new(), } diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index f7cfa8910..7b8764d64 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -40,6 +40,9 @@ pub enum MockTcStatus { #[derive(Debug)] pub struct MockTokenChannel { status: MockTcStatus, + /// Remote max debt, configured for each currency + /// (And possibly for currencies that are not yet active) + remote_max_debts: HashMap, } /// Calculate ResetBalance for a specific mutual credit @@ -239,18 +242,17 @@ where } fn get_move_token_counter(&mut self) -> AsyncOpResult { - /* - let local_reset_terms = match &self.status { - MockTcStatus::Consistent(..) + Box::pin(future::ready(Ok(match &self.status { + MockTcStatus::Consistent(tc_consistent) => tc_consistent.move_token_counter, MockTcStatus::Inconsistent(..) => unreachable!(), - }; - */ - - todo!(); + }))) } - fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult { - todo!(); + fn get_remote_max_debt(&mut self, currency: Currency) -> AsyncOpResult { + Box::pin(future::ready(Ok(*self + .remote_max_debts + .get(¤cy) + .unwrap()))) } /// Return a sorted async iterator of all balances @@ -271,30 +273,70 @@ where } fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult { - todo!(); + let local_currencies = match &self.status { + MockTcStatus::Consistent(tc_consistent) => &tc_consistent.local_currencies, + MockTcStatus::Inconsistent(..) => unreachable!(), + }; + Box::pin(future::ready(Ok(local_currencies.contains(¤cy)))) } fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult { - todo!(); + let remote_currencies = match &self.status { + MockTcStatus::Consistent(tc_consistent) => &tc_consistent.remote_currencies, + MockTcStatus::Inconsistent(..) => unreachable!(), + }; + Box::pin(future::ready(Ok(remote_currencies.contains(¤cy)))) } - fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()> { - todo!(); + fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult { + Box::pin(future::ready(Ok(match &mut self.status { + MockTcStatus::Consistent(tc_consistent) => { + tc_consistent.local_currencies.insert(currency) + } + MockTcStatus::Inconsistent(..) => unreachable!(), + }))) } - fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()> { - todo!(); + fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult { + Box::pin(future::ready(Ok(match &mut self.status { + MockTcStatus::Consistent(tc_consistent) => { + tc_consistent.local_currencies.remove(¤cy) + } + MockTcStatus::Inconsistent(..) => unreachable!(), + }))) } - fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()> { - todo!(); + fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult { + Box::pin(future::ready(Ok(match &mut self.status { + MockTcStatus::Consistent(tc_consistent) => { + tc_consistent.remote_currencies.remove(¤cy) + } + MockTcStatus::Inconsistent(..) => unreachable!(), + }))) } - fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()> { - todo!(); + fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult { + Box::pin(future::ready(Ok(match &mut self.status { + MockTcStatus::Consistent(tc_consistent) => { + tc_consistent.remote_currencies.remove(¤cy) + } + MockTcStatus::Inconsistent(..) => unreachable!(), + }))) } fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()> { - todo!(); + let balance = 0; + match &mut self.status { + MockTcStatus::Consistent(tc_consistent) => { + let res = tc_consistent + .mutual_credits + .insert(currency.clone(), MockMutualCredit::new(currency, balance)); + if let Some(_) = res { + unreachable!(); + } + } + MockTcStatus::Inconsistent(..) => unreachable!(), + }; + Box::pin(future::ready(Ok(()))) } } diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 145fa793d..e399cf253 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -589,9 +589,8 @@ where // Attempt to apply operations for every currency: for currency_operations in &new_move_token.currencies_operations { let remote_max_debt = tc_client - .get_currency_config(currency_operations.currency.clone()) - .await? - .remote_max_debt; + .get_remote_max_debt(currency_operations.currency.clone()) + .await?; let res = process_operations_list( tc_client.mc_client(currency_operations.currency.clone()), diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 9fe75b3d7..597768468 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -100,7 +100,8 @@ pub trait TcClient { fn get_move_token_counter(&mut self) -> AsyncOpResult; // fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; - fn get_currency_config(&mut self, currency: Currency) -> AsyncOpResult; + /// Get currency's configured remote max debt + fn get_remote_max_debt(&mut self, currency: Currency) -> AsyncOpResult; /// Return a sorted async iterator of all balances fn list_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; @@ -116,11 +117,11 @@ pub trait TcClient { fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; - fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; - fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult; + fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult; - fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; - fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; + fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()>; } From c08fb4dbeda27f94be5fa38650a825e7bd10471d Mon Sep 17 00:00:00 2001 From: real Date: Mon, 9 Nov 2020 23:15:19 +0200 Subject: [PATCH 174/478] funder: Initial work on set_outgoing_from_inconsistent() mock impl --- components/funder/src/token_channel/mod.rs | 2 +- .../funder/src/token_channel/tests/utils.rs | 39 ++++++++++++++++++- .../funder/src/token_channel/token_channel.rs | 1 + 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/components/funder/src/token_channel/mod.rs b/components/funder/src/token_channel/mod.rs index 39a34044a..1a9bbcee3 100644 --- a/components/funder/src/token_channel/mod.rs +++ b/components/funder/src/token_channel/mod.rs @@ -6,7 +6,7 @@ mod tests; pub use self::token_channel::{ accept_remote_reset, handle_in_move_token, handle_out_move_token, init_token_channel, - TokenChannelError, + reset_balance_to_mc_balance, TokenChannelError, }; pub use types::TcClient; diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 7b8764d64..9a4ac940f 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -13,7 +13,7 @@ use database::interface::funder::CurrencyConfig; use crate::mutual_credit::tests::MockMutualCredit; use crate::token_channel::types::{ResetBalance, ResetTerms, TcStatus}; -use crate::token_channel::TcClient; +use crate::token_channel::{reset_balance_to_mc_balance, TcClient}; use crate::types::MoveTokenHashed; #[derive(Debug)] @@ -230,6 +230,43 @@ where /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()> { + // TODO: + // Allow to initialize MockMutualCredit using in_fees and out_fees too. + // Currently `in_fees` and `out_fees` are always initially zero. + + /* + let local_reset_terms = match &self.status { + MockTcStatus::Consistent(..) => unreachable!(), + MockTcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { + local_reset_terms.clone() + } + }; + + let mutual_credits = local_reset_terms + .reset_balances + .iter() + .map(|(currency, reset_balance)| { + ( + currency.clone(), + MockMutualCredit::new(reset_balance_to_mc_balance(reset_balance.clone()), + ) + }) + .collect(); + let currencies_set = local_reset_terms + .reset_balances + .iter() + .map(|(currency, _)| currency) + .cloned() + .collect(); + self.status = MockTcStatus::Consistent(TcConsistent { + mutual_credits, + direction: MockTcDirection::Out(move_token, None), + move_token_counter: local_reset_terms.move_token_counter.checked_sub(1).unwrap(), + local_currencies: currencies_set, + remote_currencies: currencies_set, + }); + */ + todo!(); } diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index e399cf253..11f61614c 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -146,6 +146,7 @@ where ) } +// TODO: Possibly have this function as a method on the ResetBalance struct. /// Create a new McBalance (with zero pending fees) based on a given ResetBalance pub fn reset_balance_to_mc_balance(reset_balance: ResetBalance) -> McBalance { McBalance { From c38f6d1c403739f418b0d4b29fe22c57ad1555b8 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 10 Nov 2020 16:20:46 +0200 Subject: [PATCH 175/478] funder: Extended MockMutualCredit constructors --- .../src/mutual_credit/tests/request_cancel_send_funds.rs | 5 +++-- .../mutual_credit/tests/request_response_send_funds.rs | 5 +++-- components/funder/src/mutual_credit/tests/utils.rs | 4 +++- components/funder/src/token_channel/tests/utils.rs | 9 ++++++--- components/proto/src/funder/messages.rs | 6 +++--- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index 889cbe630..5ac23cc85 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -29,8 +29,9 @@ async fn task_request_cancel_send_funds() { let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); let remote_public_key = public_key_b.clone(); let balance = 0; - - let mut mc_transaction = MockMutualCredit::new(currency.clone(), balance); + let in_fees = 0.into(); + let out_fees = 0.into(); + let mut mc_transaction = MockMutualCredit::new(currency.clone(), balance, in_fees, out_fees); // -----[RequestSendFunds]-------- // ----------------------------- diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index e5aa2934e..d0603b37d 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -26,8 +26,9 @@ async fn task_request_response_send_funds() { let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); let remote_public_key = PublicKey::from(&[0xbb; PublicKey::len()]); let balance = 0; - - let mut mc_transaction = MockMutualCredit::new(currency.clone(), balance); + let in_fees = 0.into(); + let out_fees = 0.into(); + let mut mc_transaction = MockMutualCredit::new(currency.clone(), balance, in_fees, out_fees); // -----[RequestSendFunds]-------- // ----------------------------- diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index 860943184..0fd116ccb 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -41,10 +41,12 @@ impl MockMutualCredit { // TODO: Should we move instead of take a reference here? currency: Currency, balance: i128, + in_fees: U256, + out_fees: U256, ) -> MockMutualCredit { MockMutualCredit { currency, - balance: McBalance::new(balance), + balance: McBalance::new(balance, in_fees, out_fees), pending_transactions: McPendingTransactions::new(), } } diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 9a4ac940f..b1995c65c 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -363,11 +363,14 @@ where fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()> { let balance = 0; + let in_fees = 0.into(); + let out_fees = 0.into(); match &mut self.status { MockTcStatus::Consistent(tc_consistent) => { - let res = tc_consistent - .mutual_credits - .insert(currency.clone(), MockMutualCredit::new(currency, balance)); + let res = tc_consistent.mutual_credits.insert( + currency.clone(), + MockMutualCredit::new(currency, balance, in_fees, out_fees), + ); if let Some(_) = res { unreachable!(); } diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 776a72df5..3ebaa44df 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -201,13 +201,13 @@ pub struct McBalance { } impl McBalance { - pub fn new(balance: i128) -> McBalance { + pub fn new(balance: i128, in_fees: U256, out_fees: U256) -> McBalance { McBalance { balance, local_pending_debt: 0, remote_pending_debt: 0, - in_fees: 0.into(), - out_fees: 0.into(), + in_fees, + out_fees, } } From b6aa0a52e5b968af87f58b83f0b2ea37fca90984 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 10 Nov 2020 16:31:41 +0200 Subject: [PATCH 176/478] funder: tests: impl set_outgoing_from_inconsistent() --- .../funder/src/token_channel/tests/utils.rs | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index b1995c65c..fc05f1f08 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -230,11 +230,6 @@ where /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()> { - // TODO: - // Allow to initialize MockMutualCredit using in_fees and out_fees too. - // Currently `in_fees` and `out_fees` are always initially zero. - - /* let local_reset_terms = match &self.status { MockTcStatus::Consistent(..) => unreachable!(), MockTcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { @@ -248,26 +243,32 @@ where .map(|(currency, reset_balance)| { ( currency.clone(), - MockMutualCredit::new(reset_balance_to_mc_balance(reset_balance.clone()), + MockMutualCredit::new( + currency.clone(), + reset_balance.balance, + reset_balance.in_fees, + reset_balance.out_fees, + ), ) }) .collect(); - let currencies_set = local_reset_terms + + let currencies_set: HashSet<_> = local_reset_terms .reset_balances .iter() .map(|(currency, _)| currency) .cloned() .collect(); + self.status = MockTcStatus::Consistent(TcConsistent { mutual_credits, direction: MockTcDirection::Out(move_token, None), move_token_counter: local_reset_terms.move_token_counter.checked_sub(1).unwrap(), - local_currencies: currencies_set, + local_currencies: currencies_set.clone(), remote_currencies: currencies_set, }); - */ - todo!(); + Box::pin(future::ready(Ok(()))) } /// Simulate incoming token, to be used before an outgoing reset move token (a local reset) From 21f446ec3dfb9ea377819d7cbeac23487d7a5a7e Mon Sep 17 00:00:00 2001 From: real Date: Tue, 10 Nov 2020 20:11:33 +0200 Subject: [PATCH 177/478] funder: impl set_incoming_from_inconsistent() --- .../funder/src/token_channel/tests/utils.rs | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index fc05f1f08..392991d62 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -276,7 +276,50 @@ where &mut self, move_token_hashed: MoveTokenHashed, ) -> AsyncOpResult<()> { - todo!(); + let remote_reset_terms = match &self.status { + MockTcStatus::Consistent(..) => unreachable!(), + MockTcStatus::Inconsistent(_, None) => unreachable!(), + MockTcStatus::Inconsistent(local_reset_terms, Some(remote_reset_terms)) => { + remote_reset_terms.clone() + } + }; + + let mutual_credits = remote_reset_terms + .reset_balances + .iter() + .map(|(currency, reset_balance)| { + ( + currency.clone(), + MockMutualCredit::new( + currency.clone(), + // Note: direction is flipped: + reset_balance.balance.checked_neg().unwrap(), + reset_balance.out_fees, + reset_balance.in_fees, + ), + ) + }) + .collect(); + + let currencies_set: HashSet<_> = remote_reset_terms + .reset_balances + .iter() + .map(|(currency, _)| currency) + .cloned() + .collect(); + + self.status = MockTcStatus::Consistent(TcConsistent { + mutual_credits, + direction: MockTcDirection::In(move_token_hashed), + move_token_counter: remote_reset_terms + .move_token_counter + .checked_sub(1) + .unwrap(), + local_currencies: currencies_set.clone(), + remote_currencies: currencies_set, + }); + + Box::pin(future::ready(Ok(()))) } fn get_move_token_counter(&mut self) -> AsyncOpResult { From 709496472fd4087916dd3dbe5d011ee14cafa571 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 10 Nov 2020 20:26:06 +0200 Subject: [PATCH 178/478] funder: Initial impl of TcClient for MockTokenChannel --- .../funder/src/token_channel/tests/utils.rs | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 392991d62..67fbfec99 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -1,6 +1,6 @@ use std::collections::{HashMap, HashSet}; -use futures::future; +use futures::{future, stream}; use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; use common::safe_arithmetic::SafeSignedArithmetic; @@ -338,19 +338,53 @@ where /// Return a sorted async iterator of all balances fn list_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)> { - todo!(); + let tc_consistent = match &self.status { + MockTcStatus::Consistent(tc_consistent) => tc_consistent, + MockTcStatus::Inconsistent(..) => unreachable!(), + }; + + let iter = tc_consistent + .mutual_credits + .iter() + .map(|(currency, mutual_credit)| Ok((currency.clone(), mutual_credit.balance.clone()))); + + Box::pin(stream::iter(iter)) } /// Return a sorted async iterator of all local reset proposal balances /// Only relevant for inconsistent channels fn list_local_reset_balances(&mut self) -> AsyncOpStream<(Currency, ResetBalance)> { - todo!(); + let local_reset_terms = match &self.status { + MockTcStatus::Consistent(..) => unreachable!(), + MockTcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { + local_reset_terms + } + }; + + let iter = local_reset_terms + .reset_balances + .iter() + .map(|(currency, reset_balance)| Ok((currency.clone(), reset_balance.clone()))); + + Box::pin(stream::iter(iter)) } /// Return a sorted async iterator of all remote reset proposal balances /// Only relevant for inconsistent channels fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, ResetBalance)> { - todo!(); + let remote_reset_terms = match &self.status { + MockTcStatus::Consistent(..) | MockTcStatus::Inconsistent(_, None) => unreachable!(), + MockTcStatus::Inconsistent(_local_reset_terms, Some(remote_reset_terms)) => { + remote_reset_terms + } + }; + + let iter = remote_reset_terms + .reset_balances + .iter() + .map(|(currency, reset_balance)| Ok((currency.clone(), reset_balance.clone()))); + + Box::pin(stream::iter(iter)) } fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult { From 13a413437d2d3bd035e10c6327b5b739b33c5251 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 10 Nov 2020 21:39:35 +0200 Subject: [PATCH 179/478] funder: Work on initialization of a token channel --- components/funder/src/token_channel/mod.rs | 4 +- .../funder/src/token_channel/tests/mod.rs | 1 + .../token_channel/tests/move_token_basic.rs | 55 +++++++++++++++++ .../funder/src/token_channel/tests/utils.rs | 59 +++++++++++++++++-- .../funder/src/token_channel/token_channel.rs | 7 ++- 5 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 components/funder/src/token_channel/tests/move_token_basic.rs diff --git a/components/funder/src/token_channel/mod.rs b/components/funder/src/token_channel/mod.rs index 1a9bbcee3..3039daca7 100644 --- a/components/funder/src/token_channel/mod.rs +++ b/components/funder/src/token_channel/mod.rs @@ -5,8 +5,8 @@ mod types; mod tests; pub use self::token_channel::{ - accept_remote_reset, handle_in_move_token, handle_out_move_token, init_token_channel, + accept_remote_reset, handle_in_move_token, handle_out_move_token, initial_move_token, reset_balance_to_mc_balance, TokenChannelError, }; -pub use types::TcClient; +pub use types::{TcClient, TcStatus}; diff --git a/components/funder/src/token_channel/tests/mod.rs b/components/funder/src/token_channel/tests/mod.rs index 95adf51c8..04205590d 100644 --- a/components/funder/src/token_channel/tests/mod.rs +++ b/components/funder/src/token_channel/tests/mod.rs @@ -1 +1,2 @@ +mod move_token_basic; mod utils; diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs new file mode 100644 index 000000000..9ff5d091b --- /dev/null +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -0,0 +1,55 @@ +use std::convert::TryFrom; + +use common::test_executor::TestExecutor; + +use crypto::identity::{Identity, SoftwareEd25519Identity}; +use crypto::rand::RandGen; +use crypto::test_utils::DummyRandom; + +use proto::crypto::{PrivateKey, PublicKey}; +use proto::funder::messages::Currency; + +use crate::token_channel::tests::utils::MockTokenChannel; +use crate::token_channel::{ + accept_remote_reset, handle_in_move_token, handle_out_move_token, reset_balance_to_mc_balance, + TcClient, TcStatus, TokenChannelError, +}; + +async fn task_move_token_basic(test_executor: TestExecutor) { + let currency = Currency::try_from("FST".to_owned()).unwrap(); + + let mut rng_a = DummyRandom::new(&[0xau8]); + let pkcs8 = PrivateKey::rand_gen(&mut rng_a); + let identity_a = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); + + let mut rng_b = DummyRandom::new(&[0xbu8]); + let pkcs8 = PrivateKey::rand_gen(&mut rng_b); + let identity_b = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); + + let pk_a = PublicKey::from(&[0xaa; PublicKey::len()]); + let pk_b = PublicKey::from(&[0xbb; PublicKey::len()]); + let mut tc_a_b = MockTokenChannel::::new(&pk_a, &pk_b); + let mut tc_b_a = MockTokenChannel::::new(&pk_b, &pk_a); + + // Sort `a` and `b` entities, to have always have `a` as the first sender. + let (pk_a, pk_b, identity_a, identity_b, tc_a_b, tc_b_a) = + match tc_a_b.get_tc_status().await.unwrap() { + TcStatus::ConsistentOut(..) => (pk_a, pk_b, identity_a, identity_b, tc_a_b, tc_b_a), + TcStatus::ConsistentIn(..) => (pk_b, pk_a, identity_b, identity_a, tc_b_a, tc_a_b), + TcStatus::Inconsistent(..) => unreachable!(), + }; + + /* + let currencies_operations = Vec::new(); + let relays_diff = Vec::new(); + let currencies_diff = vec![currency]; + handle_out_move_token(&mut tc_a_b, identity_a, currencies_operations, relays_diff + */ +} + +#[test] +fn test_move_token_basic() { + let test_executor = TestExecutor::new(); + let res = test_executor.run(task_move_token_basic(test_executor.clone())); + assert!(res.is_output()); +} diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 67fbfec99..65d8f6335 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; use futures::{future, stream}; @@ -6,15 +7,20 @@ use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; use common::safe_arithmetic::SafeSignedArithmetic; use common::u256::U256; -use proto::crypto::Signature; -use proto::funder::messages::{Currency, McBalance, MoveToken}; +use proto::crypto::{PublicKey, Signature}; +use proto::funder::messages::{Currency, McBalance, MoveToken, TokenInfo}; + +use signature::canonical::CanonicalSerialize; use database::interface::funder::CurrencyConfig; +use crypto::hash::hash_buffer; +use crypto::identity::compare_public_key; + use crate::mutual_credit::tests::MockMutualCredit; use crate::token_channel::types::{ResetBalance, ResetTerms, TcStatus}; -use crate::token_channel::{reset_balance_to_mc_balance, TcClient}; -use crate::types::MoveTokenHashed; +use crate::token_channel::{initial_move_token, reset_balance_to_mc_balance, TcClient}; +use crate::types::{create_hashed, MoveTokenHashed}; #[derive(Debug)] pub enum MockTcDirection { @@ -45,6 +51,51 @@ pub struct MockTokenChannel { remote_max_debts: HashMap, } +impl MockTokenChannel +where + B: CanonicalSerialize + Clone, +{ + pub fn new(local_public_key: &PublicKey, remote_public_key: &PublicKey) -> Self { + // First move token message for both sides + let move_token_counter = 0; + if compare_public_key(&local_public_key, &remote_public_key) == Ordering::Less { + // We are the first sender + MockTokenChannel { + status: MockTcStatus::Consistent(TcConsistent { + mutual_credits: HashMap::new(), + direction: MockTcDirection::Out( + initial_move_token(local_public_key, remote_public_key), + None, + ), + move_token_counter, + local_currencies: HashSet::new(), + remote_currencies: HashSet::new(), + }), + remote_max_debts: HashMap::new(), + } + } else { + // We are the second sender + let move_token_in = initial_move_token(remote_public_key, local_public_key); + let token_info = TokenInfo { + // No balances yet: + balances_hash: hash_buffer(&[]), + move_token_counter, + }; + + MockTokenChannel { + status: MockTcStatus::Consistent(TcConsistent { + mutual_credits: HashMap::new(), + direction: MockTcDirection::In(create_hashed::(&move_token_in, &token_info)), + move_token_counter, + local_currencies: HashSet::new(), + remote_currencies: HashSet::new(), + }), + remote_max_debts: HashMap::new(), + } + } + } +} + /// Calculate ResetBalance for a specific mutual credit fn calc_reset_balance(mock_token_channel: &MockMutualCredit) -> ResetBalance { let mc_balance = &mock_token_channel.balance; diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 11f61614c..ce9b1e67c 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -85,7 +85,10 @@ fn token_from_public_key(public_key: &PublicKey) -> Signature { /// Create an initial move token in the relationship between two public keys. /// To canonicalize the initial move token (Having an equal move token for both sides), we sort the /// two public keys in some way. -fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKey) -> MoveToken { +pub fn initial_move_token( + low_public_key: &PublicKey, + high_public_key: &PublicKey, +) -> MoveToken { let token_info = TokenInfo { // No balances yet: balances_hash: hash_buffer(&[]), @@ -109,6 +112,7 @@ fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKey move_token_out } +/* /// Create a new token channel, and determines the initial state for the local side. /// The initial state is determined according to the order between the two provided public keys. /// Note that this function does not affect the database, it only returns a new state for the token @@ -145,6 +149,7 @@ where }, ) } +*/ // TODO: Possibly have this function as a method on the ResetBalance struct. /// Create a new McBalance (with zero pending fees) based on a given ResetBalance From faba42d848980cc3dd30d16b5fea1e3242ed264a Mon Sep 17 00:00:00 2001 From: real Date: Tue, 10 Nov 2020 21:48:39 +0200 Subject: [PATCH 180/478] funder: Failed token channel test --- .../token_channel/tests/move_token_basic.rs | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index 9ff5d091b..d2284fb87 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -1,5 +1,8 @@ use std::convert::TryFrom; +use futures::task::SpawnExt; +use futures::{future, FutureExt}; + use common::test_executor::TestExecutor; use crypto::identity::{Identity, SoftwareEd25519Identity}; @@ -9,6 +12,8 @@ use crypto::test_utils::DummyRandom; use proto::crypto::{PrivateKey, PublicKey}; use proto::funder::messages::Currency; +use identity::{create_identity, IdentityClient}; + use crate::token_channel::tests::utils::MockTokenChannel; use crate::token_channel::{ accept_remote_reset, handle_in_move_token, handle_out_move_token, reset_balance_to_mc_balance, @@ -32,19 +37,33 @@ async fn task_move_token_basic(test_executor: TestExecutor) { let mut tc_b_a = MockTokenChannel::::new(&pk_b, &pk_a); // Sort `a` and `b` entities, to have always have `a` as the first sender. - let (pk_a, pk_b, identity_a, identity_b, tc_a_b, tc_b_a) = + let (pk_a, pk_b, identity_a, identity_b, mut tc_a_b, mut tc_b_a) = match tc_a_b.get_tc_status().await.unwrap() { TcStatus::ConsistentOut(..) => (pk_a, pk_b, identity_a, identity_b, tc_a_b, tc_b_a), TcStatus::ConsistentIn(..) => (pk_b, pk_a, identity_b, identity_a, tc_b_a, tc_a_b), TcStatus::Inconsistent(..) => unreachable!(), }; - /* + let (requests_sender_a, identity_server_a) = create_identity(identity_a); + let mut identity_client_a = IdentityClient::new(requests_sender_a); + test_executor + .spawn(identity_server_a.then(|_| future::ready(()))) + .unwrap(); + let currencies_operations = Vec::new(); let relays_diff = Vec::new(); let currencies_diff = vec![currency]; - handle_out_move_token(&mut tc_a_b, identity_a, currencies_operations, relays_diff - */ + let move_token = handle_out_move_token( + &mut tc_a_b, + &mut identity_client_a, + currencies_operations, + relays_diff, + currencies_diff, + &pk_a, + &pk_b, + ) + .await + .unwrap(); } #[test] From f21fd12bde4a8ede08fc0342d62d61c73c9d6de5 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 10 Nov 2020 21:54:28 +0200 Subject: [PATCH 181/478] funder: test_move_token_basic: Fixed directions --- .../src/token_channel/tests/move_token_basic.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index d2284fb87..83a12740b 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -44,23 +44,31 @@ async fn task_move_token_basic(test_executor: TestExecutor) { TcStatus::Inconsistent(..) => unreachable!(), }; + // Spawn identity servers: let (requests_sender_a, identity_server_a) = create_identity(identity_a); let mut identity_client_a = IdentityClient::new(requests_sender_a); test_executor .spawn(identity_server_a.then(|_| future::ready(()))) .unwrap(); + let (requests_sender_b, identity_server_b) = create_identity(identity_b); + let mut identity_client_b = IdentityClient::new(requests_sender_b); + test_executor + .spawn(identity_server_b.then(|_| future::ready(()))) + .unwrap(); + + // Send a MoveToken message from b to a: let currencies_operations = Vec::new(); let relays_diff = Vec::new(); let currencies_diff = vec![currency]; let move_token = handle_out_move_token( - &mut tc_a_b, - &mut identity_client_a, + &mut tc_b_a, + &mut identity_client_b, currencies_operations, relays_diff, currencies_diff, - &pk_a, &pk_b, + &pk_a, ) .await .unwrap(); From eb0f2f95b46302c3390ea8e0496ae613d554771b Mon Sep 17 00:00:00 2001 From: real Date: Tue, 10 Nov 2020 21:58:55 +0200 Subject: [PATCH 182/478] funder: Work on test_move_token_basic() --- .../token_channel/tests/move_token_basic.rs | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index 83a12740b..c579f5c99 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -21,7 +21,9 @@ use crate::token_channel::{ }; async fn task_move_token_basic(test_executor: TestExecutor) { - let currency = Currency::try_from("FST".to_owned()).unwrap(); + let currency1 = Currency::try_from("FST1".to_owned()).unwrap(); + let currency2 = Currency::try_from("FST2".to_owned()).unwrap(); + let currency3 = Currency::try_from("FST3".to_owned()).unwrap(); let mut rng_a = DummyRandom::new(&[0xau8]); let pkcs8 = PrivateKey::rand_gen(&mut rng_a); @@ -57,10 +59,10 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .spawn(identity_server_b.then(|_| future::ready(()))) .unwrap(); - // Send a MoveToken message from b to a: + // Send a MoveToken message from b to a, adding a currency: let currencies_operations = Vec::new(); let relays_diff = Vec::new(); - let currencies_diff = vec![currency]; + let currencies_diff = vec![currency1.clone()]; let move_token = handle_out_move_token( &mut tc_b_a, &mut identity_client_b, @@ -72,6 +74,33 @@ async fn task_move_token_basic(test_executor: TestExecutor) { ) .await .unwrap(); + + // Receive the MoveToken message at a: + handle_in_move_token( + &mut tc_a_b, + &mut identity_client_a, + move_token, + &pk_a, + &pk_b, + ) + .await + .unwrap(); + + // Send a MoveToken message from a to b, adding two currencies: + let currencies_operations = Vec::new(); + let relays_diff = Vec::new(); + let currencies_diff = vec![currency1.clone(), currency2.clone()]; + let move_token = handle_out_move_token( + &mut tc_a_b, + &mut identity_client_a, + currencies_operations, + relays_diff, + currencies_diff, + &pk_a, + &pk_b, + ) + .await + .unwrap(); } #[test] From 5196dbd2fca3c708e33607dc0543952658504a21 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 10 Nov 2020 22:11:40 +0200 Subject: [PATCH 183/478] funder: Borrow checker issues at Transaction impl for MockTokenChannel --- .../funder/src/token_channel/tests/utils.rs | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 65d8f6335..c2952748e 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -1,9 +1,11 @@ use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; +use std::mem; -use futures::{future, stream}; +use futures::{future, stream, Future}; use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; +use common::conn::BoxFuture; use common::safe_arithmetic::SafeSignedArithmetic; use common::u256::U256; @@ -13,6 +15,7 @@ use proto::funder::messages::{Currency, McBalance, MoveToken, TokenInfo}; use signature::canonical::CanonicalSerialize; use database::interface::funder::CurrencyConfig; +use database::transaction::Transaction; use crypto::hash::hash_buffer; use crypto::identity::compare_public_key; @@ -22,13 +25,13 @@ use crate::token_channel::types::{ResetBalance, ResetTerms, TcStatus}; use crate::token_channel::{initial_move_token, reset_balance_to_mc_balance, TcClient}; use crate::types::{create_hashed, MoveTokenHashed}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum MockTcDirection { In(MoveTokenHashed), Out(MoveToken, Option), } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TcConsistent { mutual_credits: HashMap, direction: MockTcDirection, @@ -37,13 +40,13 @@ pub struct TcConsistent { remote_currencies: HashSet, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum MockTcStatus { Consistent(TcConsistent), Inconsistent(ResetTerms, Option), } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct MockTokenChannel { status: MockTcStatus, /// Remote max debt, configured for each currency @@ -509,3 +512,31 @@ where Box::pin(future::ready(Ok(()))) } } + +impl Transaction for MockTokenChannel +where + B: Clone + Send, +{ + fn transaction<'a, F, FR, T>(&'a mut self, f: F) -> BoxFuture<'a, (T, bool)> + where + F: (FnOnce(&'a mut Self) -> FR) + Send + 'a, + FR: Future + Send + 'a, + T: Send + 'a, + { + Box::pin(async move { + // Save original value, before we start making modifications: + let orig_mock_token_channel = self.clone(); + match f(self).await { + (val, true) => { + // Commit transaction + (val, true) + } + (val, false) => { + // Cancel transaction + let _ = mem::replace(self, orig_mock_token_channel); + (val, false) + } + } + }) + } +} From 7357d3a53fb158f1a78298fdc97c2ad0efd1463f Mon Sep 17 00:00:00 2001 From: real Date: Sat, 14 Nov 2020 18:19:29 +0200 Subject: [PATCH 184/478] Fixed Transaction lifetime issues --- components/database/src/transaction.rs | 26 ++- .../funder/src/token_channel/tests/utils.rs | 11 +- .../funder/src/token_channel/token_channel.rs | 162 ++++++++++++------ 3 files changed, 135 insertions(+), 64 deletions(-) diff --git a/components/database/src/transaction.rs b/components/database/src/transaction.rs index c4f18c5e1..38a3b229e 100644 --- a/components/database/src/transaction.rs +++ b/components/database/src/transaction.rs @@ -1,5 +1,5 @@ use futures::future::BoxFuture; -use futures::Future; +// use futures::Future; /* /// A database transaction. Enforced using closure syntax. @@ -16,16 +16,30 @@ pub trait TransactionLegacy { } */ +/// A transaction function +pub trait TransFunc { + /// Input (Will be handed as shared reference) + type InRef; + /// Output + type Out; + /// Call invocation + fn call<'a>(self, input: &'a mut Self::InRef) -> BoxFuture<'a, Self::Out> + where + Self: 'a; +} + /// A database transaction. Enforced using closure syntax. /// Supports nested transactions. -pub trait Transaction { +pub trait Transaction +where + Self: std::marker::Sized, +{ /// Begin a new transaction. /// Transaction ends at the end of the closure scope. /// If the returned boolean is true, the transaction was successful. Otherwise, the transaction /// was canceled. - fn transaction<'a, F, FR, T>(&'a mut self, f: F) -> BoxFuture<'a, (T, bool)> + fn transaction<'a, F, T>(&'a mut self, f: F) -> BoxFuture<'a, (T, bool)> where - F: (FnOnce(&'a mut Self) -> FR) + Send + 'a, - FR: Future + Send + 'a, - T: Send + 'a; + F: TransFunc + Send + 'a, + T: Send; } diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index c2952748e..fab8b4e11 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -15,7 +15,7 @@ use proto::funder::messages::{Currency, McBalance, MoveToken, TokenInfo}; use signature::canonical::CanonicalSerialize; use database::interface::funder::CurrencyConfig; -use database::transaction::Transaction; +use database::transaction::{TransFunc, Transaction}; use crypto::hash::hash_buffer; use crypto::identity::compare_public_key; @@ -517,16 +517,15 @@ impl Transaction for MockTokenChannel where B: Clone + Send, { - fn transaction<'a, F, FR, T>(&'a mut self, f: F) -> BoxFuture<'a, (T, bool)> + fn transaction<'a, F, T>(&'a mut self, f: F) -> BoxFuture<'a, (T, bool)> where - F: (FnOnce(&'a mut Self) -> FR) + Send + 'a, - FR: Future + Send + 'a, - T: Send + 'a, + F: TransFunc + Send + 'a, + T: Send, { Box::pin(async move { // Save original value, before we start making modifications: let orig_mock_token_channel = self.clone(); - match f(self).await { + match f.call(self).await { (val, true) => { // Commit transaction (val, true) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index ce9b1e67c..b1200c421 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -1,12 +1,14 @@ use std::cmp::Ordering; use std::collections::HashMap; use std::convert::TryFrom; +use std::marker::PhantomData; use derive_more::From; use futures::{Stream, StreamExt, TryStreamExt}; use common::async_rpc::OpError; +use common::conn::BoxFuture; use crypto::hash::{hash_buffer, Hasher}; use crypto::identity::compare_public_key; @@ -23,7 +25,7 @@ use signature::signature_buff::{ }; use signature::verify::verify_move_token; -use database::transaction::Transaction; +use database::transaction::{TransFunc, Transaction}; use crate::mutual_credit::incoming::{ process_operations_list, IncomingMessage, ProcessTransListError, @@ -178,6 +180,55 @@ async fn local_balances_for_reset( Ok(balances) } +struct InconsistentTrans<'a, C, B> { + input_phantom: PhantomData, + move_token_out: MoveToken, + new_move_token: MoveToken, + local_public_key: &'a PublicKey, + remote_public_key: &'a PublicKey, +} + +impl<'b, C, B> TransFunc for InconsistentTrans<'b, C, B> +where + B: Clone + CanonicalSerialize + Send + Sync, + C: TcClient + Send, + C::McClient: Send, +{ + type InRef = C; + type Out = (Result, TokenChannelError>, bool); + + fn call<'a>(self, tc_client: &'a mut Self::InRef) -> BoxFuture<'a, Self::Out> + where + Self: 'a, + { + Box::pin(async move { + let output = async move { + tc_client + .set_outgoing_from_inconsistent(self.move_token_out.clone()) + .await?; + + // Attempt to receive an incoming token: + handle_incoming_token_match( + tc_client, + self.new_move_token, + self.local_public_key, + self.remote_public_key, + ) + .await + } + .await; + + // Decide whether we should commit the transaction + let should_commit = match &output { + Ok(IncomingTokenMatchOutput::MoveTokenReceived(_)) => true, + Ok(IncomingTokenMatchOutput::InvalidIncoming(_)) => false, + Err(_) => false, + }; + (output, should_commit) + }) + } +} + pub async fn handle_in_move_token( tc_client: &mut C, identity_client: &mut IdentityClient, @@ -242,33 +293,13 @@ where }; // Atomically attempt to handle a reset move token: - let (output, _was_committed) = tc_client - .transaction(|tc_client| { - Box::pin(async move { - let output = async move { - tc_client - .set_outgoing_from_inconsistent(move_token_out.clone()) - .await?; - - // Attempt to receive an incoming token: - handle_incoming_token_match( - tc_client, - new_move_token, - local_public_key, - remote_public_key, - ) - .await - } - .await; - - // Decide whether we should commit the transaction - let should_commit = match &output { - Ok(IncomingTokenMatchOutput::MoveTokenReceived(_)) => true, - Ok(IncomingTokenMatchOutput::InvalidIncoming(_)) => false, - Err(_) => false, - }; - (output, should_commit) - }) + let (output, was_committed) = tc_client + .transaction(InconsistentTrans { + input_phantom: PhantomData::, + move_token_out, + new_move_token, + local_public_key, + remote_public_key, }) .await; @@ -388,6 +419,50 @@ where } } +struct InMoveTokenDirOutTrans<'a, C, B> { + input_phantom: PhantomData, + new_move_token: MoveToken, + local_public_key: &'a PublicKey, + remote_public_key: &'a PublicKey, +} + +impl<'b, C, B> TransFunc for InMoveTokenDirOutTrans<'b, C, B> +where + B: Clone + CanonicalSerialize + Send + Sync, + C: TcClient + Send, + C::McClient: Send, +{ + type InRef = C; + type Out = (Result, TokenChannelError>, bool); + + fn call<'a>(self, tc_client: &'a mut Self::InRef) -> BoxFuture<'a, Self::Out> + where + Self: 'a, + { + Box::pin(async move { + let output = async move { + // Attempt to receive an incoming token: + handle_incoming_token_match( + tc_client, + self.new_move_token, + self.local_public_key, + self.remote_public_key, + ) + .await + } + .await; + + // Decide whether we should commit the transaction + let should_commit = match &output { + Ok(IncomingTokenMatchOutput::MoveTokenReceived(_)) => true, + Ok(IncomingTokenMatchOutput::InvalidIncoming(_)) => false, + Err(_) => false, + }; + (output, should_commit) + }) + } +} + async fn handle_in_move_token_dir_out( tc_client: &mut C, identity_client: &mut IdentityClient, @@ -402,30 +477,13 @@ where C::McClient: Send, { if new_move_token.old_token == move_token_out.new_token { - // Atomically attempt to handle an incoming move token: - let (output, _was_committed) = tc_client - .transaction(|tc_client| { - Box::pin(async move { - let output = async move { - // Attempt to receive an incoming token: - handle_incoming_token_match( - tc_client, - new_move_token, - local_public_key, - remote_public_key, - ) - .await - } - .await; - - // Decide whether we should commit the transaction - let should_commit = match &output { - Ok(IncomingTokenMatchOutput::MoveTokenReceived(_)) => true, - Ok(IncomingTokenMatchOutput::InvalidIncoming(_)) => false, - Err(_) => false, - }; - (output, should_commit) - }) + // Atomically attempt to handle a reset move token: + let (output, was_committed) = tc_client + .transaction(InMoveTokenDirOutTrans { + input_phantom: PhantomData::, + new_move_token, + local_public_key, + remote_public_key, }) .await; From 7e6c3f82b413f64c88c804e05ecbcc31ff22918c Mon Sep 17 00:00:00 2001 From: real Date: Sat, 14 Nov 2020 18:22:46 +0200 Subject: [PATCH 185/478] database: Added TODO comment --- components/database/src/transaction.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/database/src/transaction.rs b/components/database/src/transaction.rs index 38a3b229e..826aef173 100644 --- a/components/database/src/transaction.rs +++ b/components/database/src/transaction.rs @@ -16,6 +16,9 @@ pub trait TransactionLegacy { } */ +// TODO: This is a compromise. We would have preferred to use a closure, but the lifetimes with the +// Transaction traits seem to not work out. +// See: https://users.rust-lang.org/t/returning-this-value-requires-that-1-must-outlive-2/51417 /// A transaction function pub trait TransFunc { /// Input (Will be handed as shared reference) From 0f571207d8c78992da5a44cc56ee783b562fb547 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 14 Nov 2020 18:52:28 +0200 Subject: [PATCH 186/478] database: Updated Transaction::transaction() signature. --- components/database/src/transaction.rs | 7 +- .../funder/src/token_channel/tests/utils.rs | 15 ++-- .../funder/src/token_channel/token_channel.rs | 72 +++++++++++++------ 3 files changed, 61 insertions(+), 33 deletions(-) diff --git a/components/database/src/transaction.rs b/components/database/src/transaction.rs index 826aef173..c14d89d68 100644 --- a/components/database/src/transaction.rs +++ b/components/database/src/transaction.rs @@ -41,8 +41,9 @@ where /// Transaction ends at the end of the closure scope. /// If the returned boolean is true, the transaction was successful. Otherwise, the transaction /// was canceled. - fn transaction<'a, F, T>(&'a mut self, f: F) -> BoxFuture<'a, (T, bool)> + fn transaction<'a, F, T, E>(&'a mut self, f: F) -> BoxFuture<'a, Result> where - F: TransFunc + Send + 'a, - T: Send; + F: TransFunc> + Send + 'a, + T: Send, + E: Send; } diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index fab8b4e11..19b0076f6 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -517,23 +517,24 @@ impl Transaction for MockTokenChannel where B: Clone + Send, { - fn transaction<'a, F, T>(&'a mut self, f: F) -> BoxFuture<'a, (T, bool)> + fn transaction<'a, F, T, E>(&'a mut self, f: F) -> BoxFuture<'a, Result> where - F: TransFunc + Send + 'a, + F: TransFunc> + Send + 'a, T: Send, + E: Send, { Box::pin(async move { // Save original value, before we start making modifications: let orig_mock_token_channel = self.clone(); match f.call(self).await { - (val, true) => { - // Commit transaction - (val, true) + Ok(t) => { + // Transaction was successful + Ok(t) } - (val, false) => { + Err(e) => { // Cancel transaction let _ = mem::replace(self, orig_mock_token_channel); - (val, false) + Err(e) } } }) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index b1200c421..a1b91109f 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -188,6 +188,11 @@ struct InconsistentTrans<'a, C, B> { remote_public_key: &'a PublicKey, } +enum TransactFail { + TokenChannelError(TokenChannelError), + InvalidIncoming(InvalidIncoming), +} + impl<'b, C, B> TransFunc for InconsistentTrans<'b, C, B> where B: Clone + CanonicalSerialize + Send + Sync, @@ -195,14 +200,17 @@ where C::McClient: Send, { type InRef = C; - type Out = (Result, TokenChannelError>, bool); + // We divide the error into two types: + // Recoverable: InvalidIncoming + // Unrecoverable: TokenChannelError + type Out = Result, Result>; fn call<'a>(self, tc_client: &'a mut Self::InRef) -> BoxFuture<'a, Self::Out> where Self: 'a, { Box::pin(async move { - let output = async move { + let incoming_token_match_output = async move { tc_client .set_outgoing_from_inconsistent(self.move_token_out.clone()) .await?; @@ -216,15 +224,17 @@ where ) .await } - .await; + .await + .map_err(|e| Err(e))?; - // Decide whether we should commit the transaction - let should_commit = match &output { - Ok(IncomingTokenMatchOutput::MoveTokenReceived(_)) => true, - Ok(IncomingTokenMatchOutput::InvalidIncoming(_)) => false, - Err(_) => false, - }; - (output, should_commit) + match incoming_token_match_output { + IncomingTokenMatchOutput::MoveTokenReceived(move_token_received) => { + Ok(move_token_received) + } + IncomingTokenMatchOutput::InvalidIncoming(invalid_incoming) => { + Err(Ok(invalid_incoming)) + } + } }) } } @@ -293,7 +303,7 @@ where }; // Atomically attempt to handle a reset move token: - let (output, was_committed) = tc_client + let output = tc_client .transaction(InconsistentTrans { input_phantom: PhantomData::, move_token_out, @@ -303,11 +313,12 @@ where }) .await; - match output? { - IncomingTokenMatchOutput::MoveTokenReceived(move_token_received) => { + match output { + Ok(move_token_received) => { Ok(ReceiveMoveTokenOutput::Received(move_token_received)) } - IncomingTokenMatchOutput::InvalidIncoming(_) => { + Err(e) => { + let invalid_incoming = e?; // In this case the transaction was not committed: Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { reset_token: local_reset_token, @@ -433,14 +444,17 @@ where C::McClient: Send, { type InRef = C; - type Out = (Result, TokenChannelError>, bool); + // We divide the error into two types: + // Recoverable: InvalidIncoming + // Unrecoverable: TokenChannelError + type Out = Result, Result>; fn call<'a>(self, tc_client: &'a mut Self::InRef) -> BoxFuture<'a, Self::Out> where Self: 'a, { Box::pin(async move { - let output = async move { + let incoming_token_match_output = async move { // Attempt to receive an incoming token: handle_incoming_token_match( tc_client, @@ -450,8 +464,19 @@ where ) .await } - .await; + .await + .map_err(|e| Err(e))?; + match incoming_token_match_output { + IncomingTokenMatchOutput::MoveTokenReceived(move_token_received) => { + Ok(move_token_received) + } + IncomingTokenMatchOutput::InvalidIncoming(invalid_incoming) => { + Err(Ok(invalid_incoming)) + } + } + + /* // Decide whether we should commit the transaction let should_commit = match &output { Ok(IncomingTokenMatchOutput::MoveTokenReceived(_)) => true, @@ -459,6 +484,7 @@ where Err(_) => false, }; (output, should_commit) + */ }) } } @@ -478,7 +504,7 @@ where { if new_move_token.old_token == move_token_out.new_token { // Atomically attempt to handle a reset move token: - let (output, was_committed) = tc_client + let output = tc_client .transaction(InMoveTokenDirOutTrans { input_phantom: PhantomData::, new_move_token, @@ -487,11 +513,10 @@ where }) .await; - match output? { - IncomingTokenMatchOutput::MoveTokenReceived(move_token_received) => { - return Ok(ReceiveMoveTokenOutput::Received(move_token_received)) - } - IncomingTokenMatchOutput::InvalidIncoming(_) => { + match output { + Ok(move_token_received) => Ok(ReceiveMoveTokenOutput::Received(move_token_received)), + Err(e) => { + let invalid_incoming = e?; // Inconsistency // In this case the transaction was not committed: let (local_reset_token, local_reset_move_token_counter) = set_inconsistent( @@ -508,6 +533,7 @@ where })) } } + // self.outgoing_to_incoming(friend_move_token, new_move_token) } else if move_token_out.old_token == new_move_token.new_token { // We should retransmit our move token message to the remote side. From 05e838bed628f277c14f81d68301d3c6109931da Mon Sep 17 00:00:00 2001 From: real Date: Sat, 14 Nov 2020 18:56:04 +0200 Subject: [PATCH 187/478] database: Removed old comment --- components/database/src/transaction.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/components/database/src/transaction.rs b/components/database/src/transaction.rs index c14d89d68..35e461444 100644 --- a/components/database/src/transaction.rs +++ b/components/database/src/transaction.rs @@ -1,21 +1,6 @@ use futures::future::BoxFuture; // use futures::Future; -/* -/// A database transaction. Enforced using closure syntax. -/// Supports nested transactions. -pub trait TransactionLegacy { - /// Begin a new transaction. - /// Transaction ends at the end of the closure scope. - fn transaction<'a, F, FR, T, E>(&'a mut self, f: F) -> BoxFuture<'a, Result> - where - F: (FnOnce(&'a mut Self) -> FR) + Send + 'a, - FR: Future> + Send + 'a, - T: Send + 'a, - E: Debug + Send + 'a; -} -*/ - // TODO: This is a compromise. We would have preferred to use a closure, but the lifetimes with the // Transaction traits seem to not work out. // See: https://users.rust-lang.org/t/returning-this-value-requires-that-1-must-outlive-2/51417 From 1364f595faf9f73c3e5282cada5eacc42ffde31a Mon Sep 17 00:00:00 2001 From: real Date: Sat, 14 Nov 2020 19:08:39 +0200 Subject: [PATCH 188/478] funder: Removed old comment --- components/database/src/transaction.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/database/src/transaction.rs b/components/database/src/transaction.rs index 35e461444..386749dfb 100644 --- a/components/database/src/transaction.rs +++ b/components/database/src/transaction.rs @@ -1,5 +1,4 @@ use futures::future::BoxFuture; -// use futures::Future; // TODO: This is a compromise. We would have preferred to use a closure, but the lifetimes with the // Transaction traits seem to not work out. From de86c18b17b4a07747e80e66ccab7531bec64da8 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 14 Nov 2020 20:26:16 +0200 Subject: [PATCH 189/478] funder: Removed old comment --- components/funder/src/token_channel/token_channel.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index a1b91109f..2496ccb7a 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -475,16 +475,6 @@ where Err(Ok(invalid_incoming)) } } - - /* - // Decide whether we should commit the transaction - let should_commit = match &output { - Ok(IncomingTokenMatchOutput::MoveTokenReceived(_)) => true, - Ok(IncomingTokenMatchOutput::InvalidIncoming(_)) => false, - Err(_) => false, - }; - (output, should_commit) - */ }) } } From f1a6dfbc1c021d35d226c2f05eff0f797cfb3790 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 14 Nov 2020 23:20:06 +0200 Subject: [PATCH 190/478] signature: Corrected array's length for serializing U256 --- components/signature/src/canonical.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/signature/src/canonical.rs b/components/signature/src/canonical.rs index 371d8124e..4d1a13172 100644 --- a/components/signature/src/canonical.rs +++ b/components/signature/src/canonical.rs @@ -348,7 +348,7 @@ impl CanonicalSerialize for McBalance { .unwrap(); // Write in/out fees as big endian: - let mut temp_array = [0u8; 16]; + let mut temp_array = [0u8; 32]; self.in_fees.to_big_endian(&mut temp_array); res_bytes.extend_from_slice(&temp_array); self.out_fees.to_big_endian(&mut temp_array); From 2a29cfbb604fb0262464fee1f38aec8bd2aa6d7c Mon Sep 17 00:00:00 2001 From: real Date: Sat, 14 Nov 2020 23:20:41 +0200 Subject: [PATCH 191/478] funder: Require B: Debug for functions in token_channel --- components/funder/src/token_channel/token_channel.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 2496ccb7a..641edaa93 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -1,6 +1,7 @@ use std::cmp::Ordering; use std::collections::HashMap; use std::convert::TryFrom; +use std::fmt::Debug; use std::marker::PhantomData; use derive_more::From; @@ -195,7 +196,7 @@ enum TransactFail { impl<'b, C, B> TransFunc for InconsistentTrans<'b, C, B> where - B: Clone + CanonicalSerialize + Send + Sync, + B: Debug + Clone + CanonicalSerialize + Send + Sync, C: TcClient + Send, C::McClient: Send, { @@ -248,7 +249,7 @@ pub async fn handle_in_move_token( ) -> Result, TokenChannelError> where // TODO: Can we somehow get rid of the Sync requirement for `B`? - B: CanonicalSerialize + Clone + Send + Sync, + B: Debug + CanonicalSerialize + Clone + Send + Sync, C: TcClient + Transaction + Send, C::McClient: Send, { @@ -439,7 +440,7 @@ struct InMoveTokenDirOutTrans<'a, C, B> { impl<'b, C, B> TransFunc for InMoveTokenDirOutTrans<'b, C, B> where - B: Clone + CanonicalSerialize + Send + Sync, + B: Debug + Clone + CanonicalSerialize + Send + Sync, C: TcClient + Send, C::McClient: Send, { @@ -488,7 +489,7 @@ async fn handle_in_move_token_dir_out( remote_public_key: &PublicKey, ) -> Result, TokenChannelError> where - B: Clone + CanonicalSerialize + Send + Sync, + B: Debug + Clone + CanonicalSerialize + Send + Sync, C: TcClient + Transaction + Send, C::McClient: Send, { @@ -590,7 +591,7 @@ async fn handle_incoming_token_match( remote_public_key: &PublicKey, ) -> Result, TokenChannelError> where - B: Clone + CanonicalSerialize, + B: Debug + Clone + CanonicalSerialize, { // Verify signature: // Note that we only verify the signature here, and not at the Incoming part. From 45a8043e964b79d4f462e456584bb4776d697186 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 14 Nov 2020 23:21:09 +0200 Subject: [PATCH 192/478] funder: Fixed test_move_token_basic() test --- .../src/token_channel/tests/move_token_basic.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index c579f5c99..cc39e38e6 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -28,13 +28,13 @@ async fn task_move_token_basic(test_executor: TestExecutor) { let mut rng_a = DummyRandom::new(&[0xau8]); let pkcs8 = PrivateKey::rand_gen(&mut rng_a); let identity_a = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); + let pk_a = identity_a.get_public_key(); let mut rng_b = DummyRandom::new(&[0xbu8]); let pkcs8 = PrivateKey::rand_gen(&mut rng_b); let identity_b = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); + let pk_b = identity_b.get_public_key(); - let pk_a = PublicKey::from(&[0xaa; PublicKey::len()]); - let pk_b = PublicKey::from(&[0xbb; PublicKey::len()]); let mut tc_a_b = MockTokenChannel::::new(&pk_a, &pk_b); let mut tc_b_a = MockTokenChannel::::new(&pk_b, &pk_a); @@ -101,6 +101,17 @@ async fn task_move_token_basic(test_executor: TestExecutor) { ) .await .unwrap(); + + // Receive the MoveToken message at b: + handle_in_move_token( + &mut tc_b_a, + &mut identity_client_a, + move_token, + &pk_b, + &pk_a, + ) + .await + .unwrap(); } #[test] From 63cab6a13411eb6426bd6c6be6ff60c896e106b5 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 14 Nov 2020 23:23:48 +0200 Subject: [PATCH 193/478] funder: TODO comment --- components/funder/src/token_channel/tests/move_token_basic.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index cc39e38e6..548ca43f2 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -112,6 +112,8 @@ async fn task_move_token_basic(test_executor: TestExecutor) { ) .await .unwrap(); + + // TODO: Continue here. } #[test] From a269022af7d40a1d8d3adca4d0abafd2dc7a73a1 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 12:03:37 +0200 Subject: [PATCH 194/478] funder: token_channel: tests utils: Added missing move_token_counter update --- components/funder/src/token_channel/tests/utils.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 19b0076f6..f45ce149f 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -167,6 +167,7 @@ where _ => unreachable!(), }; + tc_consistent.move_token_counter = move_token_hashed.token_info.move_token_counter; tc_consistent.direction = MockTcDirection::In(move_token_hashed); Box::pin(future::ready(Ok(()))) } From 4e8aec94f0a8fe5a0d073a594428fe6eadab56db Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 12:04:20 +0200 Subject: [PATCH 195/478] funder: token_channel: tests: Added sorting for all 'list...' methods --- .../funder/src/token_channel/tests/utils.rs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index f45ce149f..c5d6d196c 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -398,12 +398,14 @@ where MockTcStatus::Inconsistent(..) => unreachable!(), }; - let iter = tc_consistent + let mut balances_vec: Vec<_> = tc_consistent .mutual_credits .iter() - .map(|(currency, mutual_credit)| Ok((currency.clone(), mutual_credit.balance.clone()))); + .map(|(currency, mutual_credit)| (currency.clone(), mutual_credit.balance.clone())) + .collect(); - Box::pin(stream::iter(iter)) + balances_vec.sort_by(|(currency1, _), (currency2, _)| currency1.cmp(currency2)); + Box::pin(stream::iter(balances_vec.into_iter().map(|item| Ok(item)))) } /// Return a sorted async iterator of all local reset proposal balances @@ -416,12 +418,14 @@ where } }; - let iter = local_reset_terms + let mut balances_vec: Vec<_> = local_reset_terms .reset_balances .iter() - .map(|(currency, reset_balance)| Ok((currency.clone(), reset_balance.clone()))); + .map(|(currency, reset_balance)| (currency.clone(), reset_balance.clone())) + .collect(); - Box::pin(stream::iter(iter)) + balances_vec.sort_by(|(currency1, _), (currency2, _)| currency1.cmp(currency2)); + Box::pin(stream::iter(balances_vec.into_iter().map(|item| Ok(item)))) } /// Return a sorted async iterator of all remote reset proposal balances @@ -434,12 +438,14 @@ where } }; - let iter = remote_reset_terms + let mut balances_vec: Vec<_> = remote_reset_terms .reset_balances .iter() - .map(|(currency, reset_balance)| Ok((currency.clone(), reset_balance.clone()))); + .map(|(currency, reset_balance)| (currency.clone(), reset_balance.clone())) + .collect(); - Box::pin(stream::iter(iter)) + balances_vec.sort_by(|(currency1, _), (currency2, _)| currency1.cmp(currency2)); + Box::pin(stream::iter(balances_vec.into_iter().map(|item| Ok(item)))) } fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult { From f095627a4cade206c51744aad9ecd8e34ddb6497 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 12:05:38 +0200 Subject: [PATCH 196/478] funder: Added assertions to test_move_token_basic() --- .../token_channel/tests/move_token_basic.rs | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index 548ca43f2..357e1f6e1 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -17,7 +17,7 @@ use identity::{create_identity, IdentityClient}; use crate::token_channel::tests::utils::MockTokenChannel; use crate::token_channel::{ accept_remote_reset, handle_in_move_token, handle_out_move_token, reset_balance_to_mc_balance, - TcClient, TcStatus, TokenChannelError, + ReceiveMoveTokenOutput, TcClient, TcStatus, TokenChannelError, }; async fn task_move_token_basic(test_executor: TestExecutor) { @@ -76,15 +76,17 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .unwrap(); // Receive the MoveToken message at a: - handle_in_move_token( - &mut tc_a_b, - &mut identity_client_a, - move_token, - &pk_a, - &pk_b, - ) - .await - .unwrap(); + assert!(matches!( + handle_in_move_token( + &mut tc_a_b, + &mut identity_client_a, + move_token, + &pk_a, + &pk_b, + ) + .await, + Ok(ReceiveMoveTokenOutput::Received(_)) + )); // Send a MoveToken message from a to b, adding two currencies: let currencies_operations = Vec::new(); @@ -103,15 +105,17 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .unwrap(); // Receive the MoveToken message at b: - handle_in_move_token( - &mut tc_b_a, - &mut identity_client_a, - move_token, - &pk_b, - &pk_a, - ) - .await - .unwrap(); + assert!(matches!( + handle_in_move_token( + &mut tc_b_a, + &mut identity_client_b, + move_token, + &pk_b, + &pk_a, + ) + .await, + Ok(ReceiveMoveTokenOutput::Received(_)) + )); // TODO: Continue here. } From 702edd943fe1c7fe00e7a1754578c17484e52406 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 12:39:12 +0200 Subject: [PATCH 197/478] crypto: Added empty hasher test --- components/crypto/src/hash.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/crypto/src/hash.rs b/components/crypto/src/hash.rs index dd5d96418..6abbba6c7 100644 --- a/components/crypto/src/hash.rs +++ b/components/crypto/src/hash.rs @@ -56,4 +56,13 @@ mod tests { assert_eq!(hash_res.as_ref(), expected); } + + #[test] + fn hasher_empty() { + let x = Hasher::new().finalize(); + let y = Hasher::new().finalize(); + let z = Hasher::new().finalize(); + assert_eq!(x, y); + assert_eq!(y, z); + } } From 25182b805078483838938626a5ca2a103f98c032 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 12:40:00 +0200 Subject: [PATCH 198/478] funder: token_channel tests: Fixed add_remote_currency impl --- components/funder/src/token_channel/tests/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index c5d6d196c..0c2eb204e 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -485,7 +485,7 @@ where fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult { Box::pin(future::ready(Ok(match &mut self.status { MockTcStatus::Consistent(tc_consistent) => { - tc_consistent.remote_currencies.remove(¤cy) + tc_consistent.remote_currencies.insert(currency) } MockTcStatus::Inconsistent(..) => unreachable!(), }))) From 34a26bbfc9794efe538d9ba1d95fb69860d72219 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 12:40:35 +0200 Subject: [PATCH 199/478] funder: Added missing import --- components/funder/src/token_channel/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/funder/src/token_channel/mod.rs b/components/funder/src/token_channel/mod.rs index 3039daca7..756e670c7 100644 --- a/components/funder/src/token_channel/mod.rs +++ b/components/funder/src/token_channel/mod.rs @@ -6,7 +6,7 @@ mod tests; pub use self::token_channel::{ accept_remote_reset, handle_in_move_token, handle_out_move_token, initial_move_token, - reset_balance_to_mc_balance, TokenChannelError, + reset_balance_to_mc_balance, ReceiveMoveTokenOutput, TokenChannelError, }; pub use types::{TcClient, TcStatus}; From e0c103690ec2dddb34b95d352195812021648c7f Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 13:28:06 +0200 Subject: [PATCH 200/478] signature: TODO comment --- components/signature/src/signature_buff.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index 40cb3fd20..dd4e04bf6 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -15,6 +15,9 @@ use crate::canonical::CanonicalSerialize; pub const FUNDS_RESPONSE_PREFIX: &[u8] = b"FUND_RESPONSE"; pub const FUNDS_CANCEL_PREFIX: &[u8] = b"FUND_CANCEL"; +// TODO: +// - We probably don't need the "unsigned" version, +// - Take response_send_funds as a reference. /// Create the buffer we sign over at the Response funds. /// Note that the signature is not just over the Response funds bytes. The signed buffer also /// contains information from the Request funds. From e088269d6e8a5d86c9d98e8850395cb01d495813 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 13:28:50 +0200 Subject: [PATCH 201/478] funder: token_channel: Added to test_move_token_basic() --- components/funder/src/token_channel/mod.rs | 2 +- .../token_channel/tests/move_token_basic.rs | 149 +++++++++++++++++- .../funder/src/token_channel/tests/utils.rs | 2 +- 3 files changed, 147 insertions(+), 6 deletions(-) diff --git a/components/funder/src/token_channel/mod.rs b/components/funder/src/token_channel/mod.rs index 756e670c7..6a49ff74f 100644 --- a/components/funder/src/token_channel/mod.rs +++ b/components/funder/src/token_channel/mod.rs @@ -6,7 +6,7 @@ mod tests; pub use self::token_channel::{ accept_remote_reset, handle_in_move_token, handle_out_move_token, initial_move_token, - reset_balance_to_mc_balance, ReceiveMoveTokenOutput, TokenChannelError, + reset_balance_to_mc_balance, MoveTokenReceived, ReceiveMoveTokenOutput, TokenChannelError, }; pub use types::{TcClient, TcStatus}; diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index 357e1f6e1..ce0da0002 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -5,20 +5,29 @@ use futures::{future, FutureExt}; use common::test_executor::TestExecutor; +use crypto::hash_lock::HashLock; use crypto::identity::{Identity, SoftwareEd25519Identity}; use crypto::rand::RandGen; use crypto::test_utils::DummyRandom; -use proto::crypto::{PrivateKey, PublicKey}; -use proto::funder::messages::Currency; +use signature::signature_buff::create_response_signature_buffer; + +use proto::crypto::{ + HashResult, HashedLock, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid, +}; +use proto::funder::messages::{ + Currency, CurrencyOperations, FriendTcOp, FriendsRoute, RequestSendFundsOp, ResponseSendFundsOp, +}; use identity::{create_identity, IdentityClient}; +use crate::mutual_credit::incoming::IncomingMessage; use crate::token_channel::tests::utils::MockTokenChannel; use crate::token_channel::{ accept_remote_reset, handle_in_move_token, handle_out_move_token, reset_balance_to_mc_balance, - ReceiveMoveTokenOutput, TcClient, TcStatus, TokenChannelError, + MoveTokenReceived, ReceiveMoveTokenOutput, TcClient, TcStatus, TokenChannelError, }; +use crate::types::create_pending_transaction; async fn task_move_token_basic(test_executor: TestExecutor) { let currency1 = Currency::try_from("FST1".to_owned()).unwrap(); @@ -60,6 +69,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .unwrap(); // Send a MoveToken message from b to a, adding a currency: + // -------------------------------------------------------- let currencies_operations = Vec::new(); let relays_diff = Vec::new(); let currencies_diff = vec![currency1.clone()]; @@ -76,6 +86,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .unwrap(); // Receive the MoveToken message at a: + // ----------------------------------- assert!(matches!( handle_in_move_token( &mut tc_a_b, @@ -89,6 +100,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { )); // Send a MoveToken message from a to b, adding two currencies: + // ------------------------------------------------------------ let currencies_operations = Vec::new(); let relays_diff = Vec::new(); let currencies_diff = vec![currency1.clone(), currency2.clone()]; @@ -105,6 +117,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .unwrap(); // Receive the MoveToken message at b: + // ----------------------------------- assert!(matches!( handle_in_move_token( &mut tc_b_a, @@ -117,7 +130,135 @@ async fn task_move_token_basic(test_executor: TestExecutor) { Ok(ReceiveMoveTokenOutput::Received(_)) )); - // TODO: Continue here. + // Send a MoveToken message from b to a, sending a request send funds message: + // --------------------------------------------------------------------------- + let src_plain_lock = PlainLock::from(&[0xaa; PlainLock::len()]); + let request_send_funds_op = RequestSendFundsOp { + request_id: Uid::from(&[0; Uid::len()]), + src_hashed_lock: src_plain_lock.hash_lock(), + route: FriendsRoute { + public_keys: vec![pk_a.clone()], + }, + dest_payment: 20u128, + total_dest_payment: 30u128, + invoice_hash: HashResult::from(&[0; HashResult::len()]), + hmac: HmacResult::from(&[0; HmacResult::len()]), + left_fees: 5u128, + }; + let pending_transaction = create_pending_transaction(&request_send_funds_op); + let currencies_operations = vec![CurrencyOperations { + currency: currency1.clone(), + operations: vec![FriendTcOp::RequestSendFunds(request_send_funds_op.clone())], + }]; + let relays_diff = Vec::new(); + let currencies_diff = vec![]; + let move_token = handle_out_move_token( + &mut tc_b_a, + &mut identity_client_b, + currencies_operations, + relays_diff, + currencies_diff, + &pk_b, + &pk_a, + ) + .await + .unwrap(); + + // Add a remote max debt to a, so that `a` will be able to receive credits from `b`: + // --------------------------------------------------------------------------------- + tc_a_b.remote_max_debts.insert(currency1.clone(), 100u128); + + // Receive the MoveToken message at a: + // ---------------------------------- + let res = handle_in_move_token( + &mut tc_a_b, + &mut identity_client_a, + move_token, + &pk_a, + &pk_b, + ) + .await + .unwrap(); + + // Make sure the the result is as expected: + let mut currencies = match res { + ReceiveMoveTokenOutput::Received(MoveTokenReceived { + currencies, + relays_diff, + }) => { + assert!(relays_diff.is_empty()); + currencies + } + _ => unreachable!(), + }; + + assert_eq!(currencies.len(), 1); + let mut move_token_received_currency = currencies.pop().unwrap(); + assert_eq!(move_token_received_currency.currency, currency1); + assert_eq!(move_token_received_currency.incoming_messages.len(), 1); + let incoming_message = move_token_received_currency + .incoming_messages + .pop() + .unwrap(); + let received_request_send_funds_op = match incoming_message { + IncomingMessage::Request(request_send_funds_op) => request_send_funds_op, + _ => unreachable!(), + }; + assert_eq!(received_request_send_funds_op, request_send_funds_op); + + // Send a MoveToken message from a to b, sending a response send funds message: + // ---------------------------------------------------------------------------- + let mut response_send_funds_op = ResponseSendFundsOp { + // Matches earlier's request_id: + request_id: Uid::from(&[0; Uid::len()]), + src_plain_lock, + serial_num: 0, + // Temporary signature value, calculated later: + signature: Signature::from(&[0; Signature::len()]), + }; + + // Sign the response: + let sign_buffer = create_response_signature_buffer( + ¤cy1, + response_send_funds_op.clone(), + &pending_transaction, + ); + response_send_funds_op.signature = identity_client_a + .request_signature(sign_buffer) + .await + .unwrap(); + + let currencies_operations = vec![CurrencyOperations { + currency: currency1.clone(), + operations: vec![FriendTcOp::ResponseSendFunds( + response_send_funds_op.clone(), + )], + }]; + let relays_diff = Vec::new(); + let currencies_diff = vec![]; + let move_token = handle_out_move_token( + &mut tc_a_b, + &mut identity_client_a, + currencies_operations, + relays_diff, + currencies_diff, + &pk_a, + &pk_b, + ) + .await + .unwrap(); + + // Receive the MoveToken message at b: + // ---------------------------------- + let res = handle_in_move_token( + &mut tc_b_a, + &mut identity_client_b, + move_token, + &pk_b, + &pk_a, + ) + .await + .unwrap(); } #[test] diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 0c2eb204e..bcdd63a27 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -51,7 +51,7 @@ pub struct MockTokenChannel { status: MockTcStatus, /// Remote max debt, configured for each currency /// (And possibly for currencies that are not yet active) - remote_max_debts: HashMap, + pub remote_max_debts: HashMap, } impl MockTokenChannel From b9e3434097756c0031b9ee1fd59b732b195a8584 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 14:05:58 +0200 Subject: [PATCH 202/478] funder: token_channel tests: Added missing remote max debt --- components/funder/src/token_channel/tests/move_token_basic.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index ce0da0002..b7ad19f66 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -248,6 +248,10 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .await .unwrap(); + // Insert remote_max_debt for currency1, to allow handling incoming operations for this currency. + // --------------------------------------------------------------------------------------------- + tc_b_a.remote_max_debts.insert(currency1.clone(), 20u128); + // Receive the MoveToken message at b: // ---------------------------------- let res = handle_in_move_token( From ee3b2a3609816f1df041c83227b61b3378eb9d4a Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 14:15:24 +0200 Subject: [PATCH 203/478] funder: test_move_token_basic(): Asserting balances --- .../token_channel/tests/move_token_basic.rs | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index b7ad19f66..e9d3616ae 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; use futures::task::SpawnExt; -use futures::{future, FutureExt}; +use futures::{future, FutureExt, StreamExt}; use common::test_executor::TestExecutor; @@ -164,6 +164,23 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .await .unwrap(); + { + // Assert balances: + let mut b_balances_iter = tc_b_a.list_balances(); + let mut b_balances = Vec::new(); + while let Some(item) = b_balances_iter.next().await { + b_balances.push(item.unwrap()); + } + assert_eq!(b_balances.len(), 1); + let (currency, mc_balance) = b_balances.pop().unwrap(); + assert_eq!(currency, currency1); + assert_eq!(mc_balance.balance, 0); + assert_eq!(mc_balance.local_pending_debt, 25); + assert_eq!(mc_balance.remote_pending_debt, 0); + assert_eq!(mc_balance.in_fees, 0.into()); + assert_eq!(mc_balance.out_fees, 0.into()); + } + // Add a remote max debt to a, so that `a` will be able to receive credits from `b`: // --------------------------------------------------------------------------------- tc_a_b.remote_max_debts.insert(currency1.clone(), 100u128); @@ -263,6 +280,38 @@ async fn task_move_token_basic(test_executor: TestExecutor) { ) .await .unwrap(); + + { + // Assert balances (b): + let mut b_balances_iter = tc_b_a.list_balances(); + let mut b_balances = Vec::new(); + while let Some(item) = b_balances_iter.next().await { + b_balances.push(item.unwrap()); + } + assert_eq!(b_balances.len(), 1); + let (currency, mc_balance) = b_balances.pop().unwrap(); + assert_eq!(currency, currency1); + assert_eq!(mc_balance.balance, -25); + assert_eq!(mc_balance.local_pending_debt, 0); + assert_eq!(mc_balance.remote_pending_debt, 0); + assert_eq!(mc_balance.in_fees, 0.into()); + assert_eq!(mc_balance.out_fees, 5.into()); + + // Assert balances (a): + let mut a_balances_iter = tc_a_b.list_balances(); + let mut a_balances = Vec::new(); + while let Some(item) = a_balances_iter.next().await { + a_balances.push(item.unwrap()); + } + assert_eq!(a_balances.len(), 1); + let (currency, mc_balance) = a_balances.pop().unwrap(); + assert_eq!(currency, currency1); + assert_eq!(mc_balance.balance, 25); + assert_eq!(mc_balance.local_pending_debt, 0); + assert_eq!(mc_balance.remote_pending_debt, 0); + assert_eq!(mc_balance.in_fees, 5.into()); + assert_eq!(mc_balance.out_fees, 0.into()); + } } #[test] From 4d2c18a0c00d141932c74b835812b2fe9b48fbd2 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 16:39:10 +0200 Subject: [PATCH 204/478] funder: token_channel: Removed old tests file --- .../funder/src/token_channel/tests/tests.rs | 354 ------------------ 1 file changed, 354 deletions(-) delete mode 100644 components/funder/src/token_channel/tests/tests.rs diff --git a/components/funder/src/token_channel/tests/tests.rs b/components/funder/src/token_channel/tests/tests.rs deleted file mode 100644 index 50d1a06aa..000000000 --- a/components/funder/src/token_channel/tests/tests.rs +++ /dev/null @@ -1,354 +0,0 @@ -use common::test_executor::TestExecutor; - -use proto::crypto::PrivateKey; -use proto::funder::messages::MoveToken; -// use proto::funder::messages::FriendTcOp; - -use crypto::identity::{Identity, SoftwareEd25519Identity}; -use crypto::rand::RandGen; -use crypto::test_utils::DummyRandom; - -use signature::signature_buff::move_token_signature_buff; - -/* -async fn task_initial_direction(executor: TestExecutor) { - init_move_token - - init_token_channel( - tc_client: tc_client, - local_public_key, - remote_public_key).await; - -} -*/ - -#[test] -fn test_initial_direction() { - let test_executor = TestExecutor::new(); - let res = test_executor.run(task_initial_direction(test_executor)); - assert!(res.is_output()); -} - -#[test] -fn test_initial_direction() { - let pk_a = PublicKey::from(&[0xaa; PublicKey::len()]); - let pk_b = PublicKey::from(&[0xbb; PublicKey::len()]); - let token_channel_a_b = TokenChannel::::new(&pk_a, &pk_b); - let token_channel_b_a = TokenChannel::::new(&pk_b, &pk_a); - - // Only one of those token channels is outgoing: - let is_a_b_outgoing = token_channel_a_b.get_outgoing().is_some(); - let is_b_a_outgoing = token_channel_b_a.get_outgoing().is_some(); - assert!(is_a_b_outgoing ^ is_b_a_outgoing); - - let (out_tc, in_tc) = if is_a_b_outgoing { - (token_channel_a_b, token_channel_b_a) - } else { - (token_channel_b_a, token_channel_a_b) - }; - - let out_hashed = match &out_tc.direction { - TcDirection::Incoming(_) => unreachable!(), - TcDirection::Outgoing(outgoing) => { - create_hashed(&outgoing.move_token_out, &outgoing.token_info) - } - }; - - let in_hashed = match &in_tc.direction { - TcDirection::Outgoing(_) => unreachable!(), - TcDirection::Incoming(incoming) => &incoming.move_token_in, - }; - - assert_eq!(&out_hashed, in_hashed); - - // assert_eq!(create_hashed(&out_tc.move_token_out), in_tc.move_token_in); - // assert_eq!(out_tc.get_cur_move_token_hashed(), in_tc.get_cur_move_token_hashed()); - let tc_outgoing = match out_tc.get_direction() { - TcDirectionBorrow::Out(tc_out_borrow) => tc_out_borrow.tc_outgoing, - TcDirectionBorrow::In(_) => unreachable!(), - }; - assert!(tc_outgoing.opt_prev_move_token_in.is_none()); -} - -/// Sort the two identity client. -/// The result will be a pair where the first is initially configured to have outgoing message, -/// and the second is initially configured to have incoming message. -fn sort_sides(identity1: I, identity2: I) -> (I, I) -where - I: Identity, -{ - let pk1 = identity1.get_public_key(); - let pk2 = identity2.get_public_key(); - let token_channel12 = TokenChannel::::new(&pk1, &pk2); // (local, remote) - if token_channel12.get_outgoing().is_some() { - (identity1, identity2) - } else { - (identity2, identity1) - } -} -/// Before: tc1: outgoing, tc2: incoming -/// Send AddCurrency: tc2 -> tc1 -/// After: tc1: incoming, tc2: outgoing -fn add_currencies( - _identity1: &I, - identity2: &I, - tc1: &mut TokenChannel, - tc2: &mut TokenChannel, - currencies: &[Currency], -) where - I: Identity, -{ - assert!(tc1.get_outgoing().is_some()); - assert!(!tc2.get_outgoing().is_some()); - - let tc2_in_borrow = tc2.get_incoming().unwrap(); - let currencies_operations = vec![]; - - let rand_nonce = RandValue::from(&[7; RandValue::len()]); - let opt_local_relays = None; - let opt_active_currencies = Some(currencies.to_vec()); - - let SendMoveTokenOutput { - unsigned_move_token, - mutations, - token_info, - } = tc2_in_borrow - .simulate_send_move_token( - currencies_operations, - opt_local_relays, - opt_active_currencies, - rand_nonce, - ) - .unwrap(); - - for tc_mutation in mutations { - tc2.mutate(&tc_mutation); - } - - // This is the only mutation we can not produce from inside TokenChannel, because it - // requires a signature: - let friend_move_token = dummy_sign_move_token(unsigned_move_token, identity2); - let tc_mutation = TcMutation::SetDirection(SetDirection::Outgoing(( - friend_move_token.clone(), - token_info.clone(), - ))); - tc2.mutate(&tc_mutation); - - assert!(tc2.get_outgoing().is_some()); - - let receive_move_token_output = tc1 - .simulate_receive_move_token(friend_move_token.clone(), &ImHashMap::new()) - .unwrap(); - - let move_token_received = match receive_move_token_output { - ReceiveMoveTokenOutput::Received(move_token_received) => move_token_received, - _ => unreachable!(), - }; - - assert!(move_token_received.currencies.is_empty()); - - // let mut seen_mc_mutation = false; - // let mut seen_set_direction = false; - - for tc_mutation in &move_token_received.mutations { - tc1.mutate(tc_mutation); - } - - assert!(!tc1.get_outgoing().is_some()); - match &tc1.direction { - TcDirection::Outgoing(_) => unreachable!(), - TcDirection::Incoming(tc_incoming) => { - assert_eq!( - tc_incoming.move_token_in, - create_hashed(&friend_move_token, &token_info) - ); - } - }; - - for currency in currencies { - assert!(tc2.active_currencies.local.contains(currency)); - assert!(tc1.active_currencies.remote.contains(currency)); - } -} - -/* -/// Before: tc1: outgoing, tc2: incoming -/// Send SetRemoteMaxDebt: tc2 -> tc1 -/// After: tc1: incoming, tc2: outgoing -fn set_remote_max_debt21( - _identity1: &I, - identity2: &I, - tc1: &mut TokenChannel, - tc2: &mut TokenChannel, - currency: &Currency, -) where - I: Identity, -{ - assert!(tc1.get_outgoing().is_some()); - assert!(tc2.get_incoming().is_some()); - - let tc2_in_borrow = tc2.get_incoming().unwrap(); - // let mut outgoing_mc = tc2_in_borrow.create_outgoing_mc(¤cy).unwrap(); - // - // let friend_tc_op = FriendTcOp::SetRemoteMaxDebt(100); - // - // let mc_mutations = outgoing_mc.queue_operation(&friend_tc_op).unwrap(); - let currency_operations = CurrencyOperations { - currency: currency.clone(), - operations: vec![friend_tc_op], - }; - let currencies_operations = vec![currency_operations]; - - let rand_nonce = RandValue::from(&[5; RandValue::len()]); - let opt_local_relays = None; - let opt_active_currencies = None; - - let SendMoveTokenOutput { - unsigned_move_token, - mutations, - token_info, - } = tc2_in_borrow - .simulate_send_move_token( - currencies_operations, - opt_local_relays, - opt_active_currencies, - rand_nonce, - ) - .unwrap(); - - for tc_mutation in mutations { - tc2.mutate(&tc_mutation); - } - - let friend_move_token = dummy_sign_move_token(unsigned_move_token, identity2); - let tc_mutation = TcMutation::SetDirection(SetDirection::Outgoing(( - friend_move_token.clone(), - token_info.clone(), - ))); - tc2.mutate(&tc_mutation); - - assert!(tc2.get_outgoing().is_some()); - - let receive_move_token_output = tc1 - .simulate_receive_move_token(friend_move_token.clone()) - .unwrap(); - - let move_token_received = match receive_move_token_output { - ReceiveMoveTokenOutput::Received(move_token_received) => move_token_received, - _ => unreachable!(), - }; - - assert!(move_token_received.currencies[0] - .incoming_messages - .is_empty()); - assert_eq!(move_token_received.mutations.len(), 2); - - let mut seen_mc_mutation = false; - let mut seen_set_direction = false; - - for i in 0..2 { - match &move_token_received.mutations[i] { - TcMutation::McMutation(mc_mutation) => { - seen_mc_mutation = true; - assert_eq!( - mc_mutation, - &(currency.clone(), McMutation::SetLocalMaxDebt(100)) - ); - } - TcMutation::SetDirection(set_direction) => { - seen_set_direction = true; - match set_direction { - SetDirection::Incoming(incoming_friend_move_token) => assert_eq!( - &create_hashed(&friend_move_token, &token_info), - incoming_friend_move_token - ), - _ => unreachable!(), - } - } - _ => unreachable!(), - } - } - assert!(seen_mc_mutation && seen_set_direction); - - for tc_mutation in &move_token_received.mutations { - tc1.mutate(tc_mutation); - } - - assert!(!tc1.get_outgoing().is_some()); - match &tc1.direction { - TcDirection::Outgoing(_) => unreachable!(), - TcDirection::Incoming(tc_incoming) => { - assert_eq!( - tc_incoming.move_token_in, - create_hashed(&friend_move_token, &token_info) - ); - } - }; - - assert_eq!( - tc1.mutual_credits - .get(¤cy) - .unwrap() - .state() - .balance - .local_max_debt, - 100 - ); -} -*/ - -/// This tests sends a SetRemoteMaxDebt(100) in both ways. -#[test] -fn test_simulate_receive_move_token_basic() { - let currency = Currency::try_from("FST".to_owned()).unwrap(); - - let mut rng1 = DummyRandom::new(&[1u8]); - let pkcs8 = PrivateKey::rand_gen(&mut rng1); - let identity1 = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); - - let mut rng2 = DummyRandom::new(&[2u8]); - let pkcs8 = PrivateKey::rand_gen(&mut rng2); - let identity2 = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); - - let (identity1, identity2) = sort_sides(identity1, identity2); - - let pk1 = identity1.get_public_key(); - let pk2 = identity2.get_public_key(); - let mut tc1 = TokenChannel::::new(&pk1, &pk2); // (local, remote) - let mut tc2 = TokenChannel::::new(&pk2, &pk1); // (local, remote) - - // Current state: tc1 --> tc2 - // tc1: outgoing - // tc2: incoming - add_currencies( - &identity1, - &identity2, - &mut tc1, - &mut tc2, - &[currency.clone()], - ); - - // Current state: tc2 --> tc1 - // tc1: incoming - // tc2: outgoing - add_currencies( - &identity2, - &identity1, - &mut tc2, - &mut tc1, - &[currency.clone()], - ); - - // Current state: tc1 --> tc2 - // tc1: outgoing - // tc2: incoming - // set_remote_max_debt21(&identity1, &identity2, &mut tc1, &mut tc2, ¤cy); - - // Current state: tc2 --> tc1 - // tc1: incoming - // tc2: outgoing - // set_remote_max_debt21(&identity2, &identity1, &mut tc2, &mut tc1, ¤cy); -} - -// TODO: Add more tests. -// - Test behaviour of Duplicate, ChainInconsistency From 6fc992b38442097c0bd5b3be77652bc796bc5c44 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 18:00:59 +0200 Subject: [PATCH 205/478] funder: token_channel: Simplified load_remote_reset_terms() --- components/funder/src/token_channel/token_channel.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 641edaa93..897fa4e67 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -927,9 +927,7 @@ where pub async fn load_remote_reset_terms( tc_client: &mut impl TcClient, identity_client: &mut IdentityClient, - remote_reset_token: Signature, - remote_reset_move_token_counter: u128, - remote_reset_balances: impl IntoIterator, + remote_reset_terms: ResetTerms, local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result, TokenChannelError> { @@ -956,10 +954,13 @@ pub async fn load_remote_reset_terms( // Set remote reset terms: tc_client - .set_inconsistent_remote_terms(remote_reset_token, remote_reset_move_token_counter) + .set_inconsistent_remote_terms( + remote_reset_terms.reset_token, + remote_reset_terms.move_token_counter, + ) .await?; - for (currency, mc_balance) in remote_reset_balances.into_iter() { + for (currency, mc_balance) in remote_reset_terms.reset_balances.into_iter() { tc_client .add_remote_reset_balance(currency, mc_balance) .await?; From f33fa3f7db14f3860e3cfb8125edd890ea66e52d Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 18:01:49 +0200 Subject: [PATCH 206/478] funder: token_channel: Work on test_inconsistency_resolve() Test is currently failing --- components/funder/src/token_channel/mod.rs | 5 +- .../tests/inconsistency_resolve.rs | 203 ++++++++++++++++++ .../funder/src/token_channel/tests/mod.rs | 1 + components/funder/src/token_channel/types.rs | 2 +- 4 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 components/funder/src/token_channel/tests/inconsistency_resolve.rs diff --git a/components/funder/src/token_channel/mod.rs b/components/funder/src/token_channel/mod.rs index 6a49ff74f..c7a600daa 100644 --- a/components/funder/src/token_channel/mod.rs +++ b/components/funder/src/token_channel/mod.rs @@ -6,7 +6,8 @@ mod tests; pub use self::token_channel::{ accept_remote_reset, handle_in_move_token, handle_out_move_token, initial_move_token, - reset_balance_to_mc_balance, MoveTokenReceived, ReceiveMoveTokenOutput, TokenChannelError, + load_remote_reset_terms, reset_balance_to_mc_balance, MoveTokenReceived, + ReceiveMoveTokenOutput, TokenChannelError, }; -pub use types::{TcClient, TcStatus}; +pub use types::{ResetBalance, TcClient, TcStatus}; diff --git a/components/funder/src/token_channel/tests/inconsistency_resolve.rs b/components/funder/src/token_channel/tests/inconsistency_resolve.rs new file mode 100644 index 000000000..440eead42 --- /dev/null +++ b/components/funder/src/token_channel/tests/inconsistency_resolve.rs @@ -0,0 +1,203 @@ +use std::convert::TryFrom; + +use futures::task::SpawnExt; +use futures::{future, FutureExt, StreamExt}; + +use common::test_executor::TestExecutor; + +use crypto::hash_lock::HashLock; +use crypto::identity::{Identity, SoftwareEd25519Identity}; +use crypto::rand::RandGen; +use crypto::test_utils::DummyRandom; + +use signature::signature_buff::create_response_signature_buffer; + +use proto::crypto::{ + HashResult, HashedLock, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid, +}; +use proto::funder::messages::{ + Currency, CurrencyOperations, FriendTcOp, FriendsRoute, RequestSendFundsOp, ResponseSendFundsOp, +}; + +use identity::{create_identity, IdentityClient}; + +use crate::mutual_credit::incoming::IncomingMessage; +use crate::token_channel::tests::utils::MockTokenChannel; +use crate::token_channel::{ + accept_remote_reset, handle_in_move_token, handle_out_move_token, load_remote_reset_terms, + reset_balance_to_mc_balance, MoveTokenReceived, ReceiveMoveTokenOutput, ResetBalance, TcClient, + TcStatus, TokenChannelError, +}; +use crate::types::create_pending_transaction; + +async fn task_inconsistency_resolve(test_executor: TestExecutor) { + let currency1 = Currency::try_from("FST1".to_owned()).unwrap(); + let currency2 = Currency::try_from("FST2".to_owned()).unwrap(); + let currency3 = Currency::try_from("FST3".to_owned()).unwrap(); + + let mut rng_a = DummyRandom::new(&[0xau8]); + let pkcs8 = PrivateKey::rand_gen(&mut rng_a); + let identity_a = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); + let pk_a = identity_a.get_public_key(); + + let mut rng_b = DummyRandom::new(&[0xbu8]); + let pkcs8 = PrivateKey::rand_gen(&mut rng_b); + let identity_b = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); + let pk_b = identity_b.get_public_key(); + + let mut tc_a_b = MockTokenChannel::::new(&pk_a, &pk_b); + let mut tc_b_a = MockTokenChannel::::new(&pk_b, &pk_a); + + // Sort `a` and `b` entities, to have always have `a` as the first sender. + let (pk_a, pk_b, identity_a, identity_b, mut tc_a_b, mut tc_b_a) = + match tc_a_b.get_tc_status().await.unwrap() { + TcStatus::ConsistentOut(..) => (pk_a, pk_b, identity_a, identity_b, tc_a_b, tc_b_a), + TcStatus::ConsistentIn(..) => (pk_b, pk_a, identity_b, identity_a, tc_b_a, tc_a_b), + TcStatus::Inconsistent(..) => unreachable!(), + }; + + // Spawn identity servers: + let (requests_sender_a, identity_server_a) = create_identity(identity_a); + let mut identity_client_a = IdentityClient::new(requests_sender_a); + test_executor + .spawn(identity_server_a.then(|_| future::ready(()))) + .unwrap(); + + let (requests_sender_b, identity_server_b) = create_identity(identity_b); + let mut identity_client_b = IdentityClient::new(requests_sender_b); + test_executor + .spawn(identity_server_b.then(|_| future::ready(()))) + .unwrap(); + + // Send a MoveToken message from b to a, adding a currency: + // -------------------------------------------------------- + let currencies_operations = Vec::new(); + let relays_diff = Vec::new(); + let currencies_diff = vec![currency1.clone()]; + let move_token = handle_out_move_token( + &mut tc_b_a, + &mut identity_client_b, + currencies_operations, + relays_diff, + currencies_diff, + &pk_b, + &pk_a, + ) + .await + .unwrap(); + + // Receive the MoveToken message at a: + // ----------------------------------- + assert!(matches!( + handle_in_move_token( + &mut tc_a_b, + &mut identity_client_a, + move_token, + &pk_a, + &pk_b, + ) + .await, + Ok(ReceiveMoveTokenOutput::Received(_)) + )); + + // Assert current counter value: + assert_eq!(tc_a_b.get_move_token_counter().await.unwrap(), 1); + assert_eq!(tc_b_a.get_move_token_counter().await.unwrap(), 1); + + // Send a MoveToken message from a to b, adding two currencies, + // and set incorrect token info hash. + // ------------------------------------------------------------ + let currencies_operations = Vec::new(); + let relays_diff = Vec::new(); + let currencies_diff = vec![currency1.clone(), currency2.clone()]; + let move_token = handle_out_move_token( + &mut tc_a_b, + &mut identity_client_a, + currencies_operations, + relays_diff, + currencies_diff, + &pk_a, + &pk_b, + ) + .await + .unwrap(); + + assert_eq!(tc_a_b.get_move_token_counter().await.unwrap(), 2); + assert_eq!(tc_b_a.get_move_token_counter().await.unwrap(), 1); + + // b is reset, this is done to simulate inconsistency: + // --------------------------------------------------- + let mut tc_b_a = MockTokenChannel::::new(&pk_b, &pk_a); + assert_eq!(tc_b_a.get_move_token_counter().await.unwrap(), 0); + + // Receive the MoveToken message at b: + // ----------------------------------- + let res = handle_in_move_token( + &mut tc_b_a, + &mut identity_client_b, + move_token, + &pk_b, + &pk_a, + ) + .await + .unwrap(); + + let reset_terms_b = match res { + ReceiveMoveTokenOutput::ChainInconsistent(reset_terms) => { + assert_eq!(reset_terms.move_token_counter, 0 + 2); + assert!(reset_terms.reset_balances.is_empty()); + reset_terms + } + _ => unreachable!(), + }; + + // Set a to be inconsistent, and get a's reset terms: + // ------------------------------------------------- + let reset_terms_a = load_remote_reset_terms( + &mut tc_a_b, + &mut identity_client_a, + reset_terms_b, + &pk_a, + &pk_b, + ) + .await + .unwrap() + .unwrap(); + + // Assert a's reset terms: + assert_eq!(reset_terms_a.move_token_counter, 2 + 2); + assert_eq!(reset_terms_a.reset_balances.len(), 1); + let expected_reset_balance = ResetBalance { + balance: 0, + in_fees: 0.into(), + out_fees: 0.into(), + }; + assert_eq!( + reset_terms_a.reset_balances.get(¤cy1), + Some(&expected_reset_balance) + ); + + // b accepts a's reset terms: + // -------------------------- + let currencies_operations = Vec::new(); + let relays_diff = Vec::new(); + let currencies_diff = Vec::new(); + let move_token = accept_remote_reset( + &mut tc_b_a, + &mut identity_client_b, + currencies_operations, + relays_diff, + currencies_diff, + &pk_b, + &pk_a, + ) + .await + .unwrap(); +} + +#[test] +fn test_inconsistency_resolve() { + let test_executor = TestExecutor::new(); + let res = test_executor.run(task_inconsistency_resolve(test_executor.clone())); + assert!(res.is_output()); +} diff --git a/components/funder/src/token_channel/tests/mod.rs b/components/funder/src/token_channel/tests/mod.rs index 04205590d..9d046f2c5 100644 --- a/components/funder/src/token_channel/tests/mod.rs +++ b/components/funder/src/token_channel/tests/mod.rs @@ -1,2 +1,3 @@ +mod inconsistency_resolve; mod move_token_basic; mod utils; diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 597768468..2f6c36699 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -24,7 +24,7 @@ pub type TcOpSenderResult = oneshot::Sender>; // TODO: Might move to proto in the future: /// Balances for resetting a currency -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ResetBalance { pub balance: i128, pub in_fees: U256, From 013645cc6f0a0f209f5390673ec7a2bc342366aa Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 18:29:11 +0200 Subject: [PATCH 207/478] funder: token_channel: Some work on test_inconsistency_resolve() --- .../tests/inconsistency_resolve.rs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/components/funder/src/token_channel/tests/inconsistency_resolve.rs b/components/funder/src/token_channel/tests/inconsistency_resolve.rs index 440eead42..c02a13e30 100644 --- a/components/funder/src/token_channel/tests/inconsistency_resolve.rs +++ b/components/funder/src/token_channel/tests/inconsistency_resolve.rs @@ -177,6 +177,21 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { Some(&expected_reset_balance) ); + // b: load a's reset terms: + // ------------------------ + assert!(matches!( + load_remote_reset_terms( + &mut tc_b_a, + &mut identity_client_b, + reset_terms_a, + &pk_b, + &pk_a, + ) + .await + .unwrap(), + None + )); + // b accepts a's reset terms: // -------------------------- let currencies_operations = Vec::new(); @@ -193,6 +208,18 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { ) .await .unwrap(); + + // a: receive reset move token message: + // ----------------------------------- + let res = handle_in_move_token( + &mut tc_a_b, + &mut identity_client_a, + move_token, + &pk_a, + &pk_b, + ) + .await + .unwrap(); } #[test] From b189e326dab1b3b39d71cd5a8c4aac8cf662b7e2 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 15 Nov 2020 22:59:13 +0200 Subject: [PATCH 208/478] funder: Added TODO comment --- .../funder/src/token_channel/tests/inconsistency_resolve.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/funder/src/token_channel/tests/inconsistency_resolve.rs b/components/funder/src/token_channel/tests/inconsistency_resolve.rs index c02a13e30..387792a98 100644 --- a/components/funder/src/token_channel/tests/inconsistency_resolve.rs +++ b/components/funder/src/token_channel/tests/inconsistency_resolve.rs @@ -220,6 +220,8 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { ) .await .unwrap(); + + // TODO: Send an extra move token between a and b, just ot make sure channel is now consistent. } #[test] From 319e6a04dea48400bc2ff774661d8328138c8532 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 17 Nov 2020 12:34:17 +0200 Subject: [PATCH 209/478] database: Updated sent/received friend relays design --- components/database/src/create.rs | 75 ++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index b732a4029..f56d80298 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -45,10 +45,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE friends( friend_public_key BLOB NOT NULL PRIMARY KEY, - sent_local_relays BLOB NOT NULL, - -- Last local relays we have sent to the friend - remote_relays BLOB NOT NULL, - -- Friend's relays friend_name TEXT NOT NULL UNIQUE, -- Friend's name is_enabled BOOL NOT NULL, @@ -71,6 +67,51 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // Relays list we have received from the friend + // We use those relays to connect to the friend. + tx.execute( + "CREATE TABLE received_friend_relays( + friend_public_key BLOB NOT NULL, + relay_public_key BLOB NOT NULL, + port BLOB NOT NULL, + address TEXT NOT NULL, + PRIMARY KEY(friend_public_key, relay_public_key), + FOREIGN KEY(friend_public_key) + REFERENCES friends(friend_public_key) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_received_friend_relays ON received_friend_relays(friend_public_key, relay_public_key);", + params![], + )?; + + // Relays list we have sent to the friend + // The friend will use those relays to connect to us + tx.execute( + "CREATE TABLE sent_friend_relays( + friend_public_key BLOB NOT NULL, + relay_public_key BLOB NOT NULL, + port BLOB NOT NULL, + address TEXT NOT NULL, + is_removed BOOL NOT NULL + DEFAULT false, + -- Marked for removal upon the next ack + PRIMARY KEY(friend_public_key, relay_public_key), + FOREIGN KEY(friend_public_key) + REFERENCES friends(friend_public_key) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_sent_friend_relays ON sent_friend_relays(friend_public_key, relay_public_key);", + params![], + )?; + tx.execute( "CREATE TABLE currency_configs( friend_public_key BLOB NOT NULL, @@ -529,29 +570,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - tx.execute( - "CREATE TABLE friend_relays( - friend_public_key BLOB NOT NULL, - relay_public_key BLOB NOT NULL, - address TEXT, - PRIMARY KEY(friend_public_key, relay_public_key), - FOREIGN KEY(friend_public_key) - REFERENCES friends(friend_public_key) - ON DELETE CASCADE - );", - params![], - )?; - - tx.execute( - "CREATE UNIQUE INDEX idx_friend_relays ON friend_relays(friend_public_key, relay_public_key);", - params![], - )?; - tx.execute( "CREATE TABLE relays( relay_public_key BLOB NOT NULL PRIMARY KEY, - address TEXT, - relay_name TEXT + address TEXT NOT NULL, + relay_name TEXT NOT NULL );", params![], )?; @@ -564,8 +587,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE index_servers( index_public_key BLOB NOT NULL PRIMARY KEY, - address TEXT, - index_name TEXT + address TEXT NOT NULL, + index_name TEXT NOT NULL );", params![], )?; From 5f9f40e83a723ffc1224a0b98e9aca2933dccb4a Mon Sep 17 00:00:00 2001 From: real Date: Tue, 24 Nov 2020 13:31:16 +0200 Subject: [PATCH 210/478] funder + proto: Moved relays outside of move token message --- .../tests/inconsistency_resolve.rs | 12 +- .../token_channel/tests/move_token_basic.rs | 20 +-- .../funder/src/token_channel/tests/utils.rs | 41 +++--- .../funder/src/token_channel/token_channel.rs | 126 +++++++----------- components/funder/src/token_channel/types.rs | 16 +-- components/funder/src/types.rs | 7 +- components/proto/src/funder/messages.rs | 17 ++- components/proto/src/schema/funder.capnp | 17 +-- components/signature/src/signature_buff.rs | 5 +- components/signature/src/verify.rs | 5 +- 10 files changed, 103 insertions(+), 163 deletions(-) diff --git a/components/funder/src/token_channel/tests/inconsistency_resolve.rs b/components/funder/src/token_channel/tests/inconsistency_resolve.rs index 387792a98..8b77e172a 100644 --- a/components/funder/src/token_channel/tests/inconsistency_resolve.rs +++ b/components/funder/src/token_channel/tests/inconsistency_resolve.rs @@ -45,8 +45,8 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { let identity_b = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); let pk_b = identity_b.get_public_key(); - let mut tc_a_b = MockTokenChannel::::new(&pk_a, &pk_b); - let mut tc_b_a = MockTokenChannel::::new(&pk_b, &pk_a); + let mut tc_a_b = MockTokenChannel::new(&pk_a, &pk_b); + let mut tc_b_a = MockTokenChannel::new(&pk_b, &pk_a); // Sort `a` and `b` entities, to have always have `a` as the first sender. let (pk_a, pk_b, identity_a, identity_b, mut tc_a_b, mut tc_b_a) = @@ -72,13 +72,11 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { // Send a MoveToken message from b to a, adding a currency: // -------------------------------------------------------- let currencies_operations = Vec::new(); - let relays_diff = Vec::new(); let currencies_diff = vec![currency1.clone()]; let move_token = handle_out_move_token( &mut tc_b_a, &mut identity_client_b, currencies_operations, - relays_diff, currencies_diff, &pk_b, &pk_a, @@ -108,13 +106,11 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { // and set incorrect token info hash. // ------------------------------------------------------------ let currencies_operations = Vec::new(); - let relays_diff = Vec::new(); let currencies_diff = vec![currency1.clone(), currency2.clone()]; let move_token = handle_out_move_token( &mut tc_a_b, &mut identity_client_a, currencies_operations, - relays_diff, currencies_diff, &pk_a, &pk_b, @@ -127,7 +123,7 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { // b is reset, this is done to simulate inconsistency: // --------------------------------------------------- - let mut tc_b_a = MockTokenChannel::::new(&pk_b, &pk_a); + let mut tc_b_a = MockTokenChannel::new(&pk_b, &pk_a); assert_eq!(tc_b_a.get_move_token_counter().await.unwrap(), 0); // Receive the MoveToken message at b: @@ -195,13 +191,11 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { // b accepts a's reset terms: // -------------------------- let currencies_operations = Vec::new(); - let relays_diff = Vec::new(); let currencies_diff = Vec::new(); let move_token = accept_remote_reset( &mut tc_b_a, &mut identity_client_b, currencies_operations, - relays_diff, currencies_diff, &pk_b, &pk_a, diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index e9d3616ae..42b77c41e 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -44,8 +44,8 @@ async fn task_move_token_basic(test_executor: TestExecutor) { let identity_b = SoftwareEd25519Identity::from_private_key(&pkcs8).unwrap(); let pk_b = identity_b.get_public_key(); - let mut tc_a_b = MockTokenChannel::::new(&pk_a, &pk_b); - let mut tc_b_a = MockTokenChannel::::new(&pk_b, &pk_a); + let mut tc_a_b = MockTokenChannel::new(&pk_a, &pk_b); + let mut tc_b_a = MockTokenChannel::new(&pk_b, &pk_a); // Sort `a` and `b` entities, to have always have `a` as the first sender. let (pk_a, pk_b, identity_a, identity_b, mut tc_a_b, mut tc_b_a) = @@ -71,13 +71,11 @@ async fn task_move_token_basic(test_executor: TestExecutor) { // Send a MoveToken message from b to a, adding a currency: // -------------------------------------------------------- let currencies_operations = Vec::new(); - let relays_diff = Vec::new(); let currencies_diff = vec![currency1.clone()]; let move_token = handle_out_move_token( &mut tc_b_a, &mut identity_client_b, currencies_operations, - relays_diff, currencies_diff, &pk_b, &pk_a, @@ -102,13 +100,11 @@ async fn task_move_token_basic(test_executor: TestExecutor) { // Send a MoveToken message from a to b, adding two currencies: // ------------------------------------------------------------ let currencies_operations = Vec::new(); - let relays_diff = Vec::new(); let currencies_diff = vec![currency1.clone(), currency2.clone()]; let move_token = handle_out_move_token( &mut tc_a_b, &mut identity_client_a, currencies_operations, - relays_diff, currencies_diff, &pk_a, &pk_b, @@ -150,13 +146,11 @@ async fn task_move_token_basic(test_executor: TestExecutor) { currency: currency1.clone(), operations: vec![FriendTcOp::RequestSendFunds(request_send_funds_op.clone())], }]; - let relays_diff = Vec::new(); let currencies_diff = vec![]; let move_token = handle_out_move_token( &mut tc_b_a, &mut identity_client_b, currencies_operations, - relays_diff, currencies_diff, &pk_b, &pk_a, @@ -199,13 +193,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { // Make sure the the result is as expected: let mut currencies = match res { - ReceiveMoveTokenOutput::Received(MoveTokenReceived { - currencies, - relays_diff, - }) => { - assert!(relays_diff.is_empty()); - currencies - } + ReceiveMoveTokenOutput::Received(MoveTokenReceived { currencies }) => currencies, _ => unreachable!(), }; @@ -251,13 +239,11 @@ async fn task_move_token_basic(test_executor: TestExecutor) { response_send_funds_op.clone(), )], }]; - let relays_diff = Vec::new(); let currencies_diff = vec![]; let move_token = handle_out_move_token( &mut tc_a_b, &mut identity_client_a, currencies_operations, - relays_diff, currencies_diff, &pk_a, &pk_b, diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index bcdd63a27..a836312aa 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -26,38 +26,35 @@ use crate::token_channel::{initial_move_token, reset_balance_to_mc_balance, TcCl use crate::types::{create_hashed, MoveTokenHashed}; #[derive(Debug, Clone)] -pub enum MockTcDirection { +pub enum MockTcDirection { In(MoveTokenHashed), - Out(MoveToken, Option), + Out(MoveToken, Option), } #[derive(Debug, Clone)] -pub struct TcConsistent { +pub struct TcConsistent { mutual_credits: HashMap, - direction: MockTcDirection, + direction: MockTcDirection, move_token_counter: u128, local_currencies: HashSet, remote_currencies: HashSet, } #[derive(Debug, Clone)] -pub enum MockTcStatus { - Consistent(TcConsistent), +pub enum MockTcStatus { + Consistent(TcConsistent), Inconsistent(ResetTerms, Option), } #[derive(Debug, Clone)] -pub struct MockTokenChannel { - status: MockTcStatus, +pub struct MockTokenChannel { + status: MockTcStatus, /// Remote max debt, configured for each currency /// (And possibly for currencies that are not yet active) pub remote_max_debts: HashMap, } -impl MockTokenChannel -where - B: CanonicalSerialize + Clone, -{ +impl MockTokenChannel { pub fn new(local_public_key: &PublicKey, remote_public_key: &PublicKey) -> Self { // First move token message for both sides let move_token_counter = 0; @@ -88,7 +85,7 @@ where MockTokenChannel { status: MockTcStatus::Consistent(TcConsistent { mutual_credits: HashMap::new(), - direction: MockTcDirection::In(create_hashed::(&move_token_in, &token_info)), + direction: MockTcDirection::In(create_hashed(&move_token_in, &token_info)), move_token_counter, local_currencies: HashSet::new(), remote_currencies: HashSet::new(), @@ -122,10 +119,7 @@ fn calc_reset_balance(mock_token_channel: &MockMutualCredit) -> ResetBalance { } } -impl TcClient for MockTokenChannel -where - B: Clone + Send, -{ +impl TcClient for MockTokenChannel { type McClient = MockMutualCredit; fn mc_client(&mut self, currency: Currency) -> &mut Self::McClient { @@ -137,7 +131,7 @@ where } } - fn get_tc_status(&mut self) -> AsyncOpResult> { + fn get_tc_status(&mut self) -> AsyncOpResult { let res = Ok(match &self.status { MockTcStatus::Consistent(tc_consistent) => match &tc_consistent.direction { MockTcDirection::In(move_token_in) => TcStatus::ConsistentIn(move_token_in.clone()), @@ -174,7 +168,7 @@ where fn set_direction_outgoing( &mut self, - move_token: MoveToken, + move_token: MoveToken, move_token_counter: u128, ) -> AsyncOpResult<()> { let tc_consistent = match &mut self.status { @@ -196,7 +190,7 @@ where fn set_direction_outgoing_empty_incoming( &mut self, - move_token: MoveToken, + move_token: MoveToken, move_token_counter: u128, ) -> AsyncOpResult<()> { let tc_consistent = match &mut self.status { @@ -284,7 +278,7 @@ where } /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) - fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()> { + fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()> { let local_reset_terms = match &self.status { MockTcStatus::Consistent(..) => unreachable!(), MockTcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { @@ -520,10 +514,7 @@ where } } -impl Transaction for MockTokenChannel -where - B: Clone + Send, -{ +impl Transaction for MockTokenChannel { fn transaction<'a, F, T, E>(&'a mut self, f: F) -> BoxFuture<'a, Result> where F: TransFunc> + Send + 'a, diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 897fa4e67..178898bae 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -57,17 +57,16 @@ pub struct MoveTokenReceivedCurrency { } #[derive(Debug)] -pub struct MoveTokenReceived { +pub struct MoveTokenReceived { pub currencies: Vec, - pub relays_diff: Vec>, } #[allow(clippy::large_enum_variant)] #[derive(Debug)] -pub enum ReceiveMoveTokenOutput { +pub enum ReceiveMoveTokenOutput { Duplicate, - RetransmitOutgoing(MoveToken), - Received(MoveTokenReceived), + RetransmitOutgoing(MoveToken), + Received(MoveTokenReceived), ChainInconsistent(ResetTerms), // (local_reset_token, local_reset_move_token_counter) } @@ -88,10 +87,7 @@ fn token_from_public_key(public_key: &PublicKey) -> Signature { /// Create an initial move token in the relationship between two public keys. /// To canonicalize the initial move token (Having an equal move token for both sides), we sort the /// two public keys in some way. -pub fn initial_move_token( - low_public_key: &PublicKey, - high_public_key: &PublicKey, -) -> MoveToken { +pub fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKey) -> MoveToken { let token_info = TokenInfo { // No balances yet: balances_hash: hash_buffer(&[]), @@ -103,10 +99,9 @@ pub fn initial_move_token( // We do this because we want to have synchronization between the two sides of the token // channel, however, the remote side has no means of generating the signature (Because he // doesn't have the private key). Therefore we use a dummy new_token instead. - let move_token_out = MoveToken:: { + let move_token_out = MoveToken { old_token: token_from_public_key(&low_public_key), currencies_operations: Vec::new(), - relays_diff: Vec::new(), currencies_diff: Vec::new(), info_hash: hash_token_info(&low_public_key, &high_public_key, &token_info), new_token: token_from_public_key(&high_public_key), @@ -167,8 +162,8 @@ pub fn reset_balance_to_mc_balance(reset_balance: ResetBalance) -> McBalance { } /// Extract all local balances for reset as a map: -async fn local_balances_for_reset( - tc_client: &mut impl TcClient, +async fn local_balances_for_reset( + tc_client: &mut impl TcClient, ) -> Result, TokenChannelError> { let mut balances = HashMap::new(); let mut reset_balances = tc_client.list_local_reset_balances(); @@ -181,10 +176,10 @@ async fn local_balances_for_reset( Ok(balances) } -struct InconsistentTrans<'a, C, B> { +struct InconsistentTrans<'a, C> { input_phantom: PhantomData, - move_token_out: MoveToken, - new_move_token: MoveToken, + move_token_out: MoveToken, + new_move_token: MoveToken, local_public_key: &'a PublicKey, remote_public_key: &'a PublicKey, } @@ -194,17 +189,16 @@ enum TransactFail { InvalidIncoming(InvalidIncoming), } -impl<'b, C, B> TransFunc for InconsistentTrans<'b, C, B> +impl<'b, C> TransFunc for InconsistentTrans<'b, C> where - B: Debug + Clone + CanonicalSerialize + Send + Sync, - C: TcClient + Send, + C: TcClient + Send, C::McClient: Send, { type InRef = C; // We divide the error into two types: // Recoverable: InvalidIncoming // Unrecoverable: TokenChannelError - type Out = Result, Result>; + type Out = Result>; fn call<'a>(self, tc_client: &'a mut Self::InRef) -> BoxFuture<'a, Self::Out> where @@ -240,17 +234,16 @@ where } } -pub async fn handle_in_move_token( +pub async fn handle_in_move_token( tc_client: &mut C, identity_client: &mut IdentityClient, - new_move_token: MoveToken, + new_move_token: MoveToken, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> Result, TokenChannelError> +) -> Result where // TODO: Can we somehow get rid of the Sync requirement for `B`? - B: Debug + CanonicalSerialize + Clone + Send + Sync, - C: TcClient + Transaction + Send, + C: TcClient + Transaction + Send, C::McClient: Send, { match tc_client.get_tc_status().await? { @@ -297,7 +290,6 @@ where let move_token_out = MoveToken { old_token: Signature::from(&[0; Signature::len()]), currencies_operations: Vec::new(), - relays_diff: Vec::new(), currencies_diff: Vec::new(), info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), new_token: local_reset_token.clone(), @@ -364,8 +356,8 @@ async fn create_reset_token( /// Set token channel to be inconsistent /// Local reset terms are automatically calculated -async fn set_inconsistent( - tc_client: &mut impl TcClient, +async fn set_inconsistent( + tc_client: &mut impl TcClient, identity_client: &mut IdentityClient, local_public_key: &PublicKey, remote_public_key: &PublicKey, @@ -399,17 +391,14 @@ async fn set_inconsistent( Ok((local_reset_token, local_reset_move_token_counter)) } -async fn handle_in_move_token_dir_in( - tc_client: &mut impl TcClient, +async fn handle_in_move_token_dir_in( + tc_client: &mut impl TcClient, identity_client: &mut IdentityClient, local_public_key: &PublicKey, remote_public_key: &PublicKey, move_token_in: MoveTokenHashed, - new_move_token: MoveToken, -) -> Result, TokenChannelError> -where - B: CanonicalSerialize + Clone, -{ + new_move_token: MoveToken, +) -> Result { if move_token_in == create_hashed(&new_move_token, &move_token_in.token_info) { // Duplicate Ok(ReceiveMoveTokenOutput::Duplicate) @@ -431,24 +420,23 @@ where } } -struct InMoveTokenDirOutTrans<'a, C, B> { +struct InMoveTokenDirOutTrans<'a, C> { input_phantom: PhantomData, - new_move_token: MoveToken, + new_move_token: MoveToken, local_public_key: &'a PublicKey, remote_public_key: &'a PublicKey, } -impl<'b, C, B> TransFunc for InMoveTokenDirOutTrans<'b, C, B> +impl<'b, C> TransFunc for InMoveTokenDirOutTrans<'b, C> where - B: Debug + Clone + CanonicalSerialize + Send + Sync, - C: TcClient + Send, + C: TcClient + Send, C::McClient: Send, { type InRef = C; // We divide the error into two types: // Recoverable: InvalidIncoming // Unrecoverable: TokenChannelError - type Out = Result, Result>; + type Out = Result>; fn call<'a>(self, tc_client: &'a mut Self::InRef) -> BoxFuture<'a, Self::Out> where @@ -480,17 +468,16 @@ where } } -async fn handle_in_move_token_dir_out( +async fn handle_in_move_token_dir_out( tc_client: &mut C, identity_client: &mut IdentityClient, - move_token_out: MoveToken, - new_move_token: MoveToken, + move_token_out: MoveToken, + new_move_token: MoveToken, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> Result, TokenChannelError> +) -> Result where - B: Debug + Clone + CanonicalSerialize + Send + Sync, - C: TcClient + Transaction + Send, + C: TcClient + Transaction + Send, C::McClient: Send, { if new_move_token.old_token == move_token_out.new_token { @@ -579,20 +566,17 @@ enum InvalidIncoming { } #[derive(Debug)] -enum IncomingTokenMatchOutput { - MoveTokenReceived(MoveTokenReceived), +enum IncomingTokenMatchOutput { + MoveTokenReceived(MoveTokenReceived), InvalidIncoming(InvalidIncoming), } -async fn handle_incoming_token_match( - tc_client: &mut impl TcClient, - new_move_token: MoveToken, // remote_max_debts: &ImHashMap, +async fn handle_incoming_token_match( + tc_client: &mut impl TcClient, + new_move_token: MoveToken, // remote_max_debts: &ImHashMap, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> Result, TokenChannelError> -where - B: Debug + Clone + CanonicalSerialize, -{ +) -> Result { // Verify signature: // Note that we only verify the signature here, and not at the Incoming part. // This allows the genesis move token to occur smoothly, even though its signature @@ -607,7 +591,6 @@ where // Aggregate results for every currency: let mut move_token_received = MoveTokenReceived { currencies: Vec::new(), - relays_diff: new_move_token.relays_diff.clone(), }; // Handle active currencies: @@ -739,18 +722,14 @@ where )) } -pub async fn handle_out_move_token( - tc_client: &mut impl TcClient, +pub async fn handle_out_move_token( + tc_client: &mut impl TcClient, identity_client: &mut IdentityClient, currencies_operations: Vec, - relays_diff: Vec>, currencies_diff: Vec, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> Result, TokenChannelError> -where - B: CanonicalSerialize + Clone, -{ +) -> Result { // We expect that our current state is incoming: let move_token_in = match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => move_token_in, @@ -830,7 +809,6 @@ where let mut move_token = MoveToken { old_token: move_token_in.new_token, currencies_operations, - relays_diff, currencies_diff, info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), // Still not known: @@ -856,18 +834,14 @@ where /// Apply a token channel reset, accepting remote side's /// reset terms. -pub async fn accept_remote_reset( - tc_client: &mut impl TcClient, +pub async fn accept_remote_reset( + tc_client: &mut impl TcClient, identity_client: &mut IdentityClient, currencies_operations: Vec, - relays_diff: Vec>, currencies_diff: Vec, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> Result, TokenChannelError> -where - B: CanonicalSerialize + Clone, -{ +) -> Result { // Make sure that we are in inconsistent state, // and that the remote side has already sent his reset terms: let (remote_reset_token, remote_reset_move_token_counter) = @@ -896,10 +870,9 @@ where .ok_or(TokenChannelError::MoveTokenCounterOverflow)?, }; - let move_token_in = MoveToken:: { + let move_token_in = MoveToken { old_token: Signature::from(&[0; Signature::len()]), currencies_operations: Vec::new(), - relays_diff: Vec::new(), currencies_diff: Vec::new(), info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), new_token: remote_reset_token.clone(), @@ -914,7 +887,6 @@ where tc_client, identity_client, currencies_operations, - relays_diff, currencies_diff, local_public_key, remote_public_key, @@ -924,8 +896,8 @@ where /// Load the remote reset terms information from a remote side's inconsistency message /// Optionally returns local reset terms (If not already inconsistent) -pub async fn load_remote_reset_terms( - tc_client: &mut impl TcClient, +pub async fn load_remote_reset_terms( + tc_client: &mut impl TcClient, identity_client: &mut IdentityClient, remote_reset_terms: ResetTerms, local_public_key: &PublicKey, diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 2f6c36699..72684d4de 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -44,27 +44,27 @@ pub struct ResetTerms { /// Status of a TokenChannel. Could be either outgoing, incoming or inconsistent. #[derive(Debug)] -pub enum TcStatus { - ConsistentIn(MoveTokenHashed), // (move_token_in) - ConsistentOut(MoveToken, Option), // (move_token_out, last_move_token_in) +pub enum TcStatus { + ConsistentIn(MoveTokenHashed), // (move_token_in) + ConsistentOut(MoveToken, Option), // (move_token_out, last_move_token_in) Inconsistent(Signature, u128, Option<(Signature, u128)>), // (local_reset_token, local_reset_move_token_counter, Option<(remote_reset_token, remote_reset_move_token_counter)>) } -pub trait TcClient { +pub trait TcClient { type McClient: McClient; fn mc_client(&mut self, currency: Currency) -> &mut Self::McClient; - fn get_tc_status(&mut self) -> AsyncOpResult>; + fn get_tc_status(&mut self) -> AsyncOpResult; fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; fn set_direction_outgoing( &mut self, - move_token: MoveToken, + move_token: MoveToken, move_token_counter: u128, ) -> AsyncOpResult<()>; fn set_direction_outgoing_empty_incoming( &mut self, - move_token: MoveToken, + move_token: MoveToken, move_token_counter: u128, ) -> AsyncOpResult<()>; fn set_inconsistent( @@ -89,7 +89,7 @@ pub trait TcClient { ) -> AsyncOpResult<()>; /// Simulate outgoing token, to be used before an incoming reset move token (a remote reset) - fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; + fn set_outgoing_from_inconsistent(&mut self, move_token: MoveToken) -> AsyncOpResult<()>; /// Simulate incoming token, to be used before an outgoing reset move token (a local reset) fn set_incoming_from_inconsistent( diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 2a14ad0e4..94b09dc80 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -1,5 +1,3 @@ -use signature::canonical::CanonicalSerialize; - use common::ser_utils::ser_b64; use proto::crypto::{PlainLock, PublicKey, Signature, Uid}; @@ -143,10 +141,7 @@ where /// Create a hashed version of the MoveToken. /// Hashed version contains the hash of the operations instead of the operations themselves, /// hence it is usually shorter. -pub fn create_hashed(move_token: &MoveToken, token_info: &TokenInfo) -> MoveTokenHashed -where - B: CanonicalSerialize + Clone, -{ +pub fn create_hashed(move_token: &MoveToken, token_info: &TokenInfo) -> MoveTokenHashed { MoveTokenHashed { old_token: move_token.old_token.clone(), token_info: token_info.clone(), diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 3ebaa44df..ebf61013b 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -245,11 +245,10 @@ pub struct CurrencyOperations { #[capnp_conv(crate::funder_capnp::move_token)] #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct MoveToken { +pub struct MoveToken { #[serde(with = "ser_b64")] pub old_token: Signature, pub currencies_operations: Vec, - pub relays_diff: Vec>, pub currencies_diff: Vec, #[serde(with = "ser_b64")] pub info_hash: HashResult, @@ -371,18 +370,26 @@ pub struct ResetTerms { #[capnp_conv(crate::funder_capnp::move_token_request)] #[derive(Arbitrary, PartialEq, Eq, Clone, Serialize, Debug)] -pub struct MoveTokenRequest { - pub move_token: MoveToken, +pub struct MoveTokenRequest { + pub move_token: MoveToken, // Do we want the remote side to return the token: pub token_wanted: bool, } +#[capnp_conv(crate::funder_capnp::relays_update)] +#[derive(Arbitrary, PartialEq, Eq, Clone, Serialize, Debug)] +pub struct RelaysUpdate { + pub update_id: Uid, + pub relays: Vec>, +} + #[capnp_conv(crate::funder_capnp::friend_message)] #[allow(clippy::large_enum_variant)] #[derive(PartialEq, Eq, Debug, Clone)] pub enum FriendMessage { - MoveTokenRequest(MoveTokenRequest), + MoveTokenRequest(MoveTokenRequest), InconsistencyError(ResetTerms), + RelaysUpdate(RelaysUpdate), } /// A `Receipt` is received if a `RequestSendFunds` is successful. diff --git a/components/proto/src/schema/funder.capnp b/components/proto/src/schema/funder.capnp index 65782f926..399fea5ed 100644 --- a/components/proto/src/schema/funder.capnp +++ b/components/proto/src/schema/funder.capnp @@ -34,17 +34,12 @@ struct MoveToken { # Operations that should be applied to various currencies. # For every currency, ordered batched operations are provided. # First operation should be applied first. - relaysDiff @2: List(RelayAddress); - # Exclusive-Or difference between previous list of relays and new list of relays. - # Should be empty if nothing has changed. - # TODO: We might be able to make this more efficient, as RelayAddress - # might be too much information for removing an entry. - currenciesDiff @3: List(Currency); + currenciesDiff @2: List(Currency); # Exclusive-Or difference between previous list of currencies and new list of currencies. # Should be empty if nothing has changed. - infoHash @4: HashResult; + infoHash @3: HashResult; # Current information about the channel that both sides implicitly agree upon. - newToken @5 : Signature; + newToken @4 : Signature; # A signature over all the previous fields. } @@ -68,12 +63,18 @@ struct ResetTerms { # List of expected balance for each currency } +struct RelaysUpdate { + updateId @0: Uid; + relays @1: List(RelayAddress); +} + # A message sent between friends. struct FriendMessage { union { moveTokenRequest @0: MoveTokenRequest; inconsistencyError @1: ResetTerms; + relaysUpdate @2: RelaysUpdate; } } diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index dd4e04bf6..a582b8a6d 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -130,10 +130,7 @@ where } */ -pub fn move_token_signature_buff(move_token: &MoveToken) -> Vec -where - B: CanonicalSerialize + Clone, -{ +pub fn move_token_signature_buff(move_token: &MoveToken) -> Vec { let mut sig_buffer = Vec::new(); sig_buffer.extend_from_slice(&hash::hash_buffer(TOKEN_NEXT)); sig_buffer.extend_from_slice(&move_token.old_token); diff --git a/components/signature/src/verify.rs b/components/signature/src/verify.rs index 547f63fd9..d9cddc3eb 100644 --- a/components/signature/src/verify.rs +++ b/components/signature/src/verify.rs @@ -62,10 +62,7 @@ pub fn verify_commit(commit: &Commit, local_public_key: &PublicKey) -> bool { } /// Verify that new_token is a valid signature over the rest of the fields. -pub fn verify_move_token(move_token: &MoveToken, public_key: &PublicKey) -> bool -where - B: CanonicalSerialize + Clone, -{ +pub fn verify_move_token(move_token: &MoveToken, public_key: &PublicKey) -> bool { let sig_buffer = move_token_signature_buff(move_token); verify_signature(&sig_buffer, public_key, &move_token.new_token) } From 2122b5705117ac3351c305376cec712787babdaf Mon Sep 17 00:00:00 2001 From: real Date: Wed, 25 Nov 2020 11:56:58 +0200 Subject: [PATCH 211/478] database: Updated payment_events table --- components/database/src/create.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index f56d80298..c719c2512 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -740,11 +740,16 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { event_type TEXT CHECK (event_type = 'P') DEFAULT 'P' NOT NULL, - payment_id BLOB NOT NULL UNIQUE, + response_hash BLOB NOT NULL, + dest_public_key BLOB NOT NULL, + serial_num BLOB NOT NULL, + invoice_id BLOB NOT NULL, currency TEXT NOT NULL, - total_amount BLOB NOT NULL, amount BLOB NOT NULL, description TEXT NOT NULL, + data_hash BLOB NOT NULL, + UNIQUE (dest_public_key, serial_num), + -- A node can not issue the same invoice sequence number twice FOREIGN KEY(counter, event_type) REFERENCES events(counter, event_type) ON DELETE CASCADE @@ -752,6 +757,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // TODO: Add relevant indexes? + // - Search using description? + // - Search using counter? + // - How to make interface more flexible? + // Allowing user to make interesting queries? + tx.execute( "CREATE TABLE invoice_events ( counter BLOB NOT NULL PRIMARY KEY, From 8cb60a7795d579b8c67641635a2e20ef2dfd0fbe Mon Sep 17 00:00:00 2001 From: real Date: Wed, 25 Nov 2020 12:01:14 +0200 Subject: [PATCH 212/478] database: invoice_events: Added data_hash column --- components/database/src/create.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index c719c2512..870661db9 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -769,10 +769,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { event_type TEXT CHECK (event_type = 'I') DEFAULT 'I' NOT NULL, + serial_num BLOB NOT NULL UNIQUE, currency TEXT NOT NULL, amount BLOB NOT NULL, description TEXT NOT NULL, - serial_num BLOB NOT NULL UNIQUE, + data_hash BLOB NOT NULL, FOREIGN KEY(counter, event_type) REFERENCES events(counter, event_type) ON DELETE CASCADE From e904b183269ff31b8a8d96b85ff1809e46464d51 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 25 Nov 2020 12:04:26 +0200 Subject: [PATCH 213/478] database: payment_events: Added signature column --- components/database/src/create.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 870661db9..2ebedfe3a 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -748,6 +748,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { amount BLOB NOT NULL, description TEXT NOT NULL, data_hash BLOB NOT NULL, + signature BLOB NOT NULL, UNIQUE (dest_public_key, serial_num), -- A node can not issue the same invoice sequence number twice FOREIGN KEY(counter, event_type) From fd3254b4bdf9bf4d4e6436c315ab538814c105d8 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 25 Nov 2020 15:45:26 +0200 Subject: [PATCH 214/478] database: Updated sent_friend_relays table to use generations --- components/database/src/create.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 2ebedfe3a..3a468cd2d 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -96,9 +96,9 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { relay_public_key BLOB NOT NULL, port BLOB NOT NULL, address TEXT NOT NULL, - is_removed BOOL NOT NULL - DEFAULT false, - -- Marked for removal upon the next ack + remove_generation BLOB, + -- At which generation this relay was marked for removal? + -- NULL if not marked for removal PRIMARY KEY(friend_public_key, relay_public_key), FOREIGN KEY(friend_public_key) REFERENCES friends(friend_public_key) From c36b77677923bc040807cd0fc8a0c396449a2ecf Mon Sep 17 00:00:00 2001 From: real Date: Wed, 25 Nov 2020 16:25:26 +0200 Subject: [PATCH 215/478] database: Updated sent_friend_relays to include include generation for new relays --- components/database/src/create.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 3a468cd2d..98748ecb7 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -96,9 +96,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { relay_public_key BLOB NOT NULL, port BLOB NOT NULL, address TEXT NOT NULL, - remove_generation BLOB, - -- At which generation this relay was marked for removal? - -- NULL if not marked for removal + is_remove BOOL NOT NULL, + -- Is marked for removal? + generation BLOB, + -- At which generation this relay was added/removed? + -- NULL if change was already acked. + CHECK (NOT (is_remove == true AND generation == NULL)), PRIMARY KEY(friend_public_key, relay_public_key), FOREIGN KEY(friend_public_key) REFERENCES friends(friend_public_key) From cb3ab0a08689c483deed8427f9db7002d0826a27 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 25 Nov 2020 16:25:55 +0200 Subject: [PATCH 216/478] database: Using double equal operator instead of single equal operator --- components/database/src/create.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 98748ecb7..3d62d3d7f 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -35,7 +35,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // Single row is enforced in this table according to https://stackoverflow.com/a/33104119 tx.execute( "CREATE TABLE node( - id INTEGER PRIMARY KEY CHECK (id = 0), -- enforce single row + id INTEGER PRIMARY KEY CHECK (id == 0), -- enforce single row version INTEGER NOT NULL, -- Database version local_public_key BLOB NOT NULL );", @@ -139,7 +139,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE consistent_channels( friend_public_key BLOB NOT NULL PRIMARY KEY, is_consistent BOOL NOT NULL - CHECK (is_consistent = true) + CHECK (is_consistent == true) DEFAULT true, move_token_counter BLOB NOT NULL, is_incoming BOOL NOT NULL, @@ -160,7 +160,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE consistent_channels_incoming( friend_public_key BLOB NOT NULL PRIMARY KEY, is_incoming BOOL NOT NULL - CHECK (is_incoming = true) + CHECK (is_incoming == true) DEFAULT true, old_token BLOB NOT NULL, new_token BLOB NOT NULL, @@ -181,7 +181,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE consistent_channels_outgoing( friend_public_key BLOB NOT NULL PRIMARY KEY, is_incoming BOOL NOT NULL - CHECK (is_incoming = false) + CHECK (is_incoming == false) DEFAULT false, move_token_out BLOB NOT NULL, @@ -204,7 +204,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE consistent_channels_outgoing_with_incoming( friend_public_key BLOB NOT NULL PRIMARY KEY, is_with_incoming BOOL NOT NULL - CHECK (is_with_incoming = true) + CHECK (is_with_incoming == true) DEFAULT true, -- Data saved for last incoming move token. @@ -253,7 +253,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE inconsistent_channels( friend_public_key BLOB NOT NULL PRIMARY KEY, is_consistent BOOL NOT NULL - CHECK (is_consistent = false) + CHECK (is_consistent == false) DEFAULT false, -- Last seen incoming move token: opt_move_token_in BLOB, @@ -536,7 +536,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, backwards_type TEXT NOT NULL - CHECK (backwards_type = 'R') + CHECK (backwards_type == 'R') DEFAULT 'R', src_hashed_lock BLOB NOT NULL, serial_num BLOB NOT NULL, @@ -559,7 +559,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, backwards_type TEXT NOT NULL - CHECK (backwards_type = 'C') + CHECK (backwards_type == 'C') DEFAULT 'C', FOREIGN KEY(friend_public_key, currency, request_id, backwards_type) REFERENCES pending_backwards(friend_public_key, currency, request_id, backwards_type) @@ -740,7 +740,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE payment_events( counter BLOB NOT NULL PRIMARY KEY, - event_type TEXT CHECK (event_type = 'P') + event_type TEXT CHECK (event_type == 'P') DEFAULT 'P' NOT NULL, response_hash BLOB NOT NULL, @@ -770,7 +770,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE invoice_events ( counter BLOB NOT NULL PRIMARY KEY, - event_type TEXT CHECK (event_type = 'I') + event_type TEXT CHECK (event_type == 'I') DEFAULT 'I' NOT NULL, serial_num BLOB NOT NULL UNIQUE, @@ -789,7 +789,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE friend_inconsistency_events ( counter BLOB NOT NULL PRIMARY KEY, - event_type TEXT CHECK (event_type = 'F') + event_type TEXT CHECK (event_type == 'F') DEFAULT 'F' NOT NULL, friend_public_key BLOB NOT NULL, From fe2f03d0ae5128486f05a69445630634edf22ac3 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 25 Nov 2020 16:26:26 +0200 Subject: [PATCH 217/478] database: Added generation index for sent_friend_relays --- components/database/src/create.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 3d62d3d7f..4c447d7a2 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -115,6 +115,11 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + tx.execute( + "CREATE INDEX idx_sent_friend_relays_generation ON sent_friend_relays(generation);", + params![], + )?; + tx.execute( "CREATE TABLE currency_configs( friend_public_key BLOB NOT NULL, From 8fa434c97f7860a54189cef43620bf7319f00fd7 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 27 Nov 2020 17:52:56 +0200 Subject: [PATCH 218/478] database: Updated invoice columns in various tables, Introduced action_id --- components/database/src/create.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 4c447d7a2..e3af5d229 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -630,7 +630,9 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE open_invoices( invoice_id BLOB NOT NULL PRIMARY KEY, + psk BLOB NOT NULL, description TEXT NOT NULL, + data_hash BLOB NOT NULL, currency TEXT NOT NULL, opt_amount BLOB );", @@ -661,16 +663,15 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE TABLE invoice_instances( + "CREATE TABLE invoice_actions( invoice_id BLOB NOT NULL, - invoice_instance BLOB NOT NULL, + action_id BLOB NOT NULL, description TEXT NOT NULL, - payload_hash BLOB NOT NULL UNIQUE, - -- hash(invoice_instance, description, payload_hash) invoice_hash BLOB NOT NULL UNIQUE, - -- src_hashed_lock is provided by the buyer/payer during the commitment. + -- invoiceHash = sha512/256(action_id || hash(description) || data_hash) opt_src_hashed_lock BLOB, - PRIMARY KEY(invoice_id, invoice_instance), + -- src_hashed_lock is provided by the buyer/payer during the commitment. + PRIMARY KEY(invoice_id, action_id), FOREIGN KEY(invoice_id) REFERENCES open_invoices(invoice_id) ON DELETE CASCADE @@ -679,32 +680,32 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_invoice_instances ON invoice_instances(invoice_id, invoice_instance);", + "CREATE UNIQUE INDEX idx_invoice_actions ON invoice_actions(invoice_id, action_id);", params![], )?; tx.execute( - "CREATE TABLE invoice_instances_requests( + "CREATE TABLE invoice_actions_requests( invoice_id BLOB NOT NULL, - invoice_instance BLOB NOT NULL, + action_id BLOB NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, FOREIGN KEY(request_id) REFERENCES remote_open_transactions(request_id) ON DELETE RESTRICT, - FOREIGN KEY(invoice_id, invoice_instance) - REFERENCES invoice_instances(invoice_id, invoice_instance) + FOREIGN KEY(invoice_id, action_id) + REFERENCES invoice_actions(invoice_id, action_id) ON DELETE CASCADE );", params![], )?; tx.execute( - "CREATE INDEX idx_instances_requests ON invoice_instances_requests(invoice_id, invoice_instance);", + "CREATE INDEX idx_actions_requests ON invoice_actions_requests(invoice_id, action_id);", params![], )?; tx.execute( - "CREATE UNIQUE INDEX idx_instances_requests_request_id ON invoice_instances_requests(request_id);", + "CREATE UNIQUE INDEX idx_actions_requests_request_id ON invoice_actions_requests(request_id);", params![], )?; @@ -751,7 +752,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { response_hash BLOB NOT NULL, dest_public_key BLOB NOT NULL, serial_num BLOB NOT NULL, - invoice_id BLOB NOT NULL, + action_id BLOB NOT NULL, currency TEXT NOT NULL, amount BLOB NOT NULL, description TEXT NOT NULL, From 547907e218e34378127c2985f0f9dd643b2fbe7e Mon Sep 17 00:00:00 2001 From: real Date: Fri, 27 Nov 2020 18:13:59 +0200 Subject: [PATCH 219/478] database: Added friend_invites related tables --- components/database/src/create.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index e3af5d229..db5587382 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -709,6 +709,37 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // Currently open friend invites + tx.execute( + "CREATE TABLE friend_invites( + invite_id BLOB NOT NULL PRIMARY KEY, + psk BLOB NOT NULL, + friend_public_key BLOB + -- If friend_public_key == NULL, it means we haven't + -- been contacted by the friend yet, or that we have created a specific + -- friend invite. + );", + params![], + )?; + + // Relays we use to listen for friend invites + tx.execute( + "CREATE TABLE friend_invites_relays( + invite_id BLOB NOT NULL, + relay_public_key BLOB NOT NULL, + port BLOB NOT NULL, + address TEXT NOT NULL, + -- If friend_public_key == NULL, it means we haven't + -- been contacted by the friend yet, or that we have created a specific + -- friend invite. + PRIMARY KEY(invite_id, relay_public_key), + FOREIGN KEY(invite_id) + REFERENCES friend_invites(invite_id) + ON DELETE CASCADE + );", + params![], + )?; + // Documents table, allowing total order on all items payments and invoices tx.execute( "CREATE TABLE events( From a05119e73f4b942244a4b3f4d17aeb3a090115c5 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 27 Nov 2020 21:42:33 +0200 Subject: [PATCH 220/478] database: Split friend_invites into add + update tables --- components/database/src/create.rs | 33 ++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index db5587382..fc7dc40f3 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -713,11 +713,34 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE friend_invites( invite_id BLOB NOT NULL PRIMARY KEY, - psk BLOB NOT NULL, - friend_public_key BLOB - -- If friend_public_key == NULL, it means we haven't - -- been contacted by the friend yet, or that we have created a specific - -- friend invite. + psk BLOB NOT NULL + );", + params![], + )?; + + // Invites that are used to add a new friend + tx.execute( + "CREATE TABLE friend_invites_add( + invite_id BLOB NOT NULL PRIMARY KEY, + new_friend_name TEXT NOT NULL, + FOREIGN KEY(invite_id) + REFERENCES friend_invites(invite_id) + ON DELETE CASCADE + );", + params![], + )?; + + // Invites that are used to inform a remote friend about updated relays list. + tx.execute( + "CREATE TABLE friend_invites_update( + invite_id BLOB NOT NULL PRIMARY KEY, + friend_public_key TEXT NOT NULL, + FOREIGN KEY(invite_id) + REFERENCES friend_invites(invite_id) + ON DELETE CASCADE, + FOREIGN KEY(friend_public_key) + REFERENCES friends(friend_public_key) + ON DELETE CASCADE );", params![], )?; From 6e094dbe2a9a0616e606ca0200455a72e0dd0c8b Mon Sep 17 00:00:00 2001 From: real Date: Fri, 27 Nov 2020 22:34:22 +0200 Subject: [PATCH 221/478] database: Make sure every friend invite is of one of two types --- components/database/src/create.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index fc7dc40f3..2ecdf4327 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -713,7 +713,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE friend_invites( invite_id BLOB NOT NULL PRIMARY KEY, - psk BLOB NOT NULL + psk BLOB NOT NULL, + invite_type TEXT CHECK (invite_type IN ('A', 'U')) NOT NULL );", params![], )?; @@ -722,9 +723,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE friend_invites_add( invite_id BLOB NOT NULL PRIMARY KEY, + invite_type TEXT NOT NULL + CHECK (invite_type == 'A') + DEFAULT 'A', new_friend_name TEXT NOT NULL, - FOREIGN KEY(invite_id) - REFERENCES friend_invites(invite_id) + FOREIGN KEY(invite_id, invite_type) + REFERENCES friend_invites(invite_id, invite_type) ON DELETE CASCADE );", params![], @@ -734,9 +738,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE friend_invites_update( invite_id BLOB NOT NULL PRIMARY KEY, + invite_type TEXT NOT NULL + CHECK (invite_type == 'U') + DEFAULT 'U', friend_public_key TEXT NOT NULL, - FOREIGN KEY(invite_id) - REFERENCES friend_invites(invite_id) + FOREIGN KEY(invite_id, invite_type) + REFERENCES friend_invites(invite_id, invite_type) ON DELETE CASCADE, FOREIGN KEY(friend_public_key) REFERENCES friends(friend_public_key) From 13e2f5e5090768b9dc35089f3d390ee5f4161ca3 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 28 Nov 2020 19:01:15 +0200 Subject: [PATCH 222/478] database: Work on payment tables and friend invite tables --- components/database/src/create.rs | 56 +++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 2ecdf4327..2223b5043 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -18,11 +18,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { perm_buy BOOL NOT NULL, perm_sell BOOL NOT NULL, perm_config_card BOOL NOT NULL, - perm_config_access BOOL NOT NULL, - - FOREIGN KEY(app_public_key) - REFERENCES applications(app_public_key) - ON DELETE CASCADE + perm_config_access BOOL NOT NULL );", params![], )?; @@ -607,17 +603,20 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; // Ongoing payments that were not yet finalized - // TODO: Complete open payments information: - // - Pending requests/responses? - // - Stage information? (See state.rs in funder) tx.execute( "CREATE TABLE open_payments( payment_id BLOB NOT NULL PRIMARY KEY, + app_public_key BLOB NOT NULL, + app_name TEXT NOT NULL, dest_public_key BLOB NOT NULL, currency TEXT NOT NULL, amount BLOB NOT NULL, description TEXT NOT NULL, - src_plain_lock BLOB NOT NULL + src_plain_lock BLOB NOT NULL, + fees BLOB, + -- fees == NULL if we don't know the fees yet. + FOREIGN KEY(app_public_key) + REFERENCES applications(app_public_key) );", params![], )?; @@ -627,14 +626,47 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // Payments where the user accepted the proposed fees. + // Such payments can only be cancelled by the seller. + tx.execute( + "CREATE TABLE open_payments_accepted( + payment_id BLOB NOT NULL PRIMARY KEY, + fees BLOB NOT NULL + CHECK (fees != NULL), + FOREIGN KEY(payment_id, fees) + REFERENCES open_payments(payment_id, fees) + ON DELETE CASCADE + );", + params![], + )?; + + // TODO: Add indexes. Should we add an index to `request_id` here? + tx.execute( + "CREATE TABLE open_payments_requests( + payment_id BLOB NOT NULL, + request_id BLOB NOT NULL UNIQUE, + received_ack BOOL NOT NULL, + -- Have we received an acknowledgement from the seller about this request? + PRIMARY KEY(payment_id, request_id), + FOREIGN KEY(payment_id) + REFERENCES open_payments_accepted(payment_id) + ON DELETE CASCADE + );", + params![], + )?; + tx.execute( "CREATE TABLE open_invoices( invoice_id BLOB NOT NULL PRIMARY KEY, + app_public_key BLOB NOT NULL, psk BLOB NOT NULL, description TEXT NOT NULL, data_hash BLOB NOT NULL, currency TEXT NOT NULL, - opt_amount BLOB + opt_amount BLOB, + FOREIGN KEY(app_public_key) + REFERENCES applications(app_public_key) + ON DELETE RESTRICT );", params![], )?; @@ -765,11 +797,13 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { PRIMARY KEY(invite_id, relay_public_key), FOREIGN KEY(invite_id) REFERENCES friend_invites(invite_id) - ON DELETE CASCADE + ON DELETE RESTRICT );", params![], )?; + // TODO: Maybe app_public_key should be a foreign key to applications table, and should be + // nullable? // Documents table, allowing total order on all items payments and invoices tx.execute( "CREATE TABLE events( From 5dd6227a879fd5c36b399513ebda9f507f51bdaa Mon Sep 17 00:00:00 2001 From: real Date: Sat, 28 Nov 2020 20:23:04 +0200 Subject: [PATCH 223/478] database: Removed TODO comment --- components/database/src/create.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 2223b5043..3b6ad8301 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -802,8 +802,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // TODO: Maybe app_public_key should be a foreign key to applications table, and should be - // nullable? // Documents table, allowing total order on all items payments and invoices tx.execute( "CREATE TABLE events( From 094ffcf871152d1e37eb165f2c2fd982a96bfeb8 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 28 Nov 2020 23:07:56 +0200 Subject: [PATCH 224/478] database: Added app information on invites --- components/database/src/create.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 3b6ad8301..18356f6fd 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -746,7 +746,10 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE friend_invites( invite_id BLOB NOT NULL PRIMARY KEY, psk BLOB NOT NULL, - invite_type TEXT CHECK (invite_type IN ('A', 'U')) NOT NULL + invite_type TEXT CHECK (invite_type IN ('A', 'U')) NOT NULL, + -- Information about the application that created this invite + app_public_key BLOB NOT NULL, + app_name TEXT NOT NULL );", params![], )?; From ebea703df5d0fbce168b4c7c5f87177d6104e44b Mon Sep 17 00:00:00 2001 From: real Date: Sun, 29 Nov 2020 18:07:35 +0200 Subject: [PATCH 225/478] database: Updated friend_invite_update public_key field --- components/database/src/create.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 18356f6fd..6c9e3729d 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -776,7 +776,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { invite_type TEXT NOT NULL CHECK (invite_type == 'U') DEFAULT 'U', - friend_public_key TEXT NOT NULL, + friend_public_key BLOB NOT NULL UNIQUE, FOREIGN KEY(invite_id, invite_type) REFERENCES friend_invites(invite_id, invite_type) ON DELETE CASCADE, From 1eb7cf6a070d5bea0b7c112be595bcf0f1b902e4 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 3 Dec 2020 13:33:18 +0200 Subject: [PATCH 226/478] funder: Added TODO comment --- components/funder/src/token_channel/tests/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/funder/src/token_channel/tests/mod.rs b/components/funder/src/token_channel/tests/mod.rs index 9d046f2c5..d4c845de9 100644 --- a/components/funder/src/token_channel/tests/mod.rs +++ b/components/funder/src/token_channel/tests/mod.rs @@ -1,3 +1,7 @@ mod inconsistency_resolve; mod move_token_basic; mod utils; + +// TODO: Add more tests +// - Duplicate test +// - Retransmit outgoing test From e2f99eb9526671302d19b2f2e4e143afcd1b34ca Mon Sep 17 00:00:00 2001 From: real Date: Thu, 3 Dec 2020 13:35:26 +0200 Subject: [PATCH 227/478] crypto: Split to Dh{Ephemeral,Static}PrivateKey --- components/crypto/src/dh.rs | 43 +++++++++++++++++++++----- components/secure_channel/src/state.rs | 12 +++---- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/components/crypto/src/dh.rs b/components/crypto/src/dh.rs index 44dcd4401..c628d2430 100644 --- a/components/crypto/src/dh.rs +++ b/components/crypto/src/dh.rs @@ -7,14 +7,42 @@ use crate::error::CryptoError; use crate::rand::CryptoRandom; use crate::sym_encrypt::SymmetricKey; -pub const SHARED_SECRET_LEN: usize = 32; +pub struct DhEphemeralPrivateKey(x25519_dalek::EphemeralSecret); +pub struct DhStaticPrivateKey(x25519_dalek::StaticSecret); -pub struct DhPrivateKey(x25519_dalek::EphemeralSecret); +/// A diffie hellman private key that we can reuse multiple times, and save to disk. +impl DhStaticPrivateKey { + /// Create a new ephemeral private key. + pub fn new(rng: &mut R) -> Result { + Ok(DhStaticPrivateKey(x25519_dalek::StaticSecret::new(rng))) + } + + /// Compute public key from our private key. + /// The public key will be sent to remote side. + pub fn compute_public_key(&self) -> Result { + Ok(DhPublicKey::from( + x25519_dalek::PublicKey::from(&self.0).as_bytes(), + )) + } + + // TODO: Implement handshake +} + +impl From<[u8; 32]> for DhStaticPrivateKey { + /// Load a static diffie hellman private key from an array of bytes + fn from(bytes: [u8; 32]) -> Self { + DhStaticPrivateKey(x25519_dalek::StaticSecret::from(bytes)) + } +} -impl DhPrivateKey { +/// An ephemeral diffie hellman private key. Can be used only once, and should not be saved to +/// disk. +impl DhEphemeralPrivateKey { /// Create a new ephemeral private key. - pub fn new(rng: &mut R) -> Result { - Ok(DhPrivateKey(x25519_dalek::EphemeralSecret::new(rng))) + pub fn new(rng: &mut R) -> Result { + Ok(DhEphemeralPrivateKey(x25519_dalek::EphemeralSecret::new( + rng, + ))) } /// Compute public key from our private key. @@ -25,6 +53,7 @@ impl DhPrivateKey { )) } + // TODO: Maybe separate handshake and kdf part? /// Derive a symmetric key from our private key and remote's public key. pub fn derive_symmetric_key( self, @@ -77,8 +106,8 @@ mod tests { #[test] fn test_derive_symmetric_key() { let mut rng = DummyRandom::new(&[1, 2, 3, 4, 5]); - let dh_private_a = DhPrivateKey::new(&mut rng).unwrap(); - let dh_private_b = DhPrivateKey::new(&mut rng).unwrap(); + let dh_private_a = DhEphemeralPrivateKey::new(&mut rng).unwrap(); + let dh_private_b = DhEphemeralPrivateKey::new(&mut rng).unwrap(); let public_key_a = dh_private_a.compute_public_key().unwrap(); let public_key_b = dh_private_b.compute_public_key().unwrap(); diff --git a/components/secure_channel/src/state.rs b/components/secure_channel/src/state.rs index 0e6404aac..4a583f744 100644 --- a/components/secure_channel/src/state.rs +++ b/components/secure_channel/src/state.rs @@ -4,7 +4,7 @@ use byteorder::{BigEndian, ByteOrder}; use derive_more::From; -use crypto::dh::DhPrivateKey; +use crypto::dh::DhEphemeralPrivateKey; use crypto::identity::verify_signature; use crypto::rand::{CryptoRandom, RandGen}; use crypto::sym_encrypt::{Decryptor, Encryptor}; @@ -48,12 +48,12 @@ pub struct ScStateHalf { pub remote_public_key: PublicKey, local_public_key: PublicKey, local_rand_nonce: RandValue, - dh_private_key: DhPrivateKey, + dh_private_key: DhEphemeralPrivateKey, local_salt: Salt, } struct PendingRekey { - local_dh_private_key: DhPrivateKey, + local_dh_private_key: DhEphemeralPrivateKey, local_salt: Salt, } @@ -105,7 +105,7 @@ impl ScStateInitial { } let dh_private_key = - DhPrivateKey::new(&mut rng).map_err(|_| ScStateError::PrivateKeyGenFailure)?; + DhEphemeralPrivateKey::new(&mut rng).map_err(|_| ScStateError::PrivateKeyGenFailure)?; let dh_public_key = dh_private_key .compute_public_key() .map_err(|_| ScStateError::DhPublicKeyComputeFailure)?; @@ -257,7 +257,7 @@ impl ScState { if self.opt_pending_rekey.is_some() { return Err(ScStateError::RekeyInProgress); } - let dh_private_key = DhPrivateKey::new(rng).unwrap(); + let dh_private_key = DhEphemeralPrivateKey::new(rng).unwrap(); let local_salt = Salt::rand_gen(rng); let dh_public_key = dh_private_key.compute_public_key().unwrap(); let pending_rekey = PendingRekey { @@ -280,7 +280,7 @@ impl ScState { ) -> Result { match self.opt_pending_rekey.take() { None => { - let dh_private_key = DhPrivateKey::new(rng).unwrap(); + let dh_private_key = DhEphemeralPrivateKey::new(rng).unwrap(); let local_salt = Salt::rand_gen(rng); let dh_public_key = dh_private_key.compute_public_key().unwrap(); From db7eec5fc830bb3b6f77b3f4825ea6491043c5c0 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 3 Dec 2020 13:35:49 +0200 Subject: [PATCH 228/478] funder: Initial definition of RelayClient trait --- components/funder/src/lib.rs | 3 +++ components/funder/src/relay_client.rs | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 components/funder/src/relay_client.rs diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 293488f9b..4cb1c0c0e 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -34,6 +34,9 @@ mod token_channel; pub mod types; +// TODO: Later move outside of this module, to a relay related module +pub mod relay_client; + // #[cfg(test)] // mod tests; diff --git a/components/funder/src/relay_client.rs b/components/funder/src/relay_client.rs new file mode 100644 index 000000000..af95d9961 --- /dev/null +++ b/components/funder/src/relay_client.rs @@ -0,0 +1,22 @@ +use common::conn::{BoxFuture, BoxStream, ConnPairVec}; +use crypto::dh::DhStaticPrivateKey; + +use proto::app_server::messages::RelayAddress; +use proto::crypto::DhPublicKey; + +#[derive(Debug)] +struct RelayClientError; + +trait RelayClient { + fn connect( + &mut self, + relay: RelayAddress, + port: DhPublicKey, + ) -> BoxFuture<'_, Result>; + + fn listen( + &mut self, + relay: RelayAddress, + port_private: DhStaticPrivateKey, + ) -> BoxStream<'_, ConnPairVec>; +} From 1f04f2340f19424b9445c4a2544db6cf83ce4076 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 3 Dec 2020 13:43:19 +0200 Subject: [PATCH 229/478] funder: Moved RelayClient trait to types submodule --- components/funder/src/lib.rs | 3 --- components/funder/src/relay_client.rs | 22 ---------------------- components/funder/src/types.rs | 22 +++++++++++++++++++++- 3 files changed, 21 insertions(+), 26 deletions(-) delete mode 100644 components/funder/src/relay_client.rs diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 4cb1c0c0e..293488f9b 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -34,9 +34,6 @@ mod token_channel; pub mod types; -// TODO: Later move outside of this module, to a relay related module -pub mod relay_client; - // #[cfg(test)] // mod tests; diff --git a/components/funder/src/relay_client.rs b/components/funder/src/relay_client.rs deleted file mode 100644 index af95d9961..000000000 --- a/components/funder/src/relay_client.rs +++ /dev/null @@ -1,22 +0,0 @@ -use common::conn::{BoxFuture, BoxStream, ConnPairVec}; -use crypto::dh::DhStaticPrivateKey; - -use proto::app_server::messages::RelayAddress; -use proto::crypto::DhPublicKey; - -#[derive(Debug)] -struct RelayClientError; - -trait RelayClient { - fn connect( - &mut self, - relay: RelayAddress, - port: DhPublicKey, - ) -> BoxFuture<'_, Result>; - - fn listen( - &mut self, - relay: RelayAddress, - port_private: DhStaticPrivateKey, - ) -> BoxStream<'_, ConnPairVec>; -} diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 94b09dc80..09cad180d 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -1,6 +1,7 @@ +use common::conn::{BoxFuture, BoxStream, ConnPairVec}; use common::ser_utils::ser_b64; -use proto::crypto::{PlainLock, PublicKey, Signature, Uid}; +use proto::crypto::{DhPublicKey, PlainLock, PublicKey, Signature, Uid}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ @@ -13,6 +14,25 @@ use signature::signature_buff::create_response_signature_buffer; use identity::IdentityClient; +use crypto::dh::DhStaticPrivateKey; + +#[derive(Debug)] +struct RelayClientError; + +trait RelayClient { + fn connect( + &mut self, + relay: RelayAddress, + port: DhPublicKey, + ) -> BoxFuture<'_, Result>; + + fn listen( + &mut self, + relay: RelayAddress, + port_private: DhStaticPrivateKey, + ) -> BoxStream<'_, ConnPairVec>; +} + pub async fn create_response_send_funds<'a>( currency: &Currency, pending_transaction: &'a PendingTransaction, From e6b2c3816a6721c780a31b0a1e80bc5dbd877cd0 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 3 Dec 2020 13:43:59 +0200 Subject: [PATCH 230/478] funder: Removed legacy code --- components/funder/src/freeze_guard_legacy.rs | 528 ------------------- 1 file changed, 528 deletions(-) delete mode 100644 components/funder/src/freeze_guard_legacy.rs diff --git a/components/funder/src/freeze_guard_legacy.rs b/components/funder/src/freeze_guard_legacy.rs deleted file mode 100644 index 2e56fde2e..000000000 --- a/components/funder/src/freeze_guard_legacy.rs +++ /dev/null @@ -1,528 +0,0 @@ -/* -use std::collections::HashMap as ImHashMap; - -use num_bigint::BigUint; - -use crypto::identity::PublicKey; -use crypto::hash::{HashResult, sha_512_256}; - -use common::int_convert::usize_to_u32; -use signature::canonical::CanonicalSerialize; - -use proto::funder::messages::{Ratio, FriendsRoute, FreezeLink}; - -use crate::credit_calc::CreditCalculator; -use crate::state::FunderState; -use crate::friend::ChannelStatus; - - -#[derive(Clone)] -struct FriendFreezeGuard { - frozen_credits_from: ImHashMap> - // ^-A ^-hash(route) ^-frozen -} - -impl FriendFreezeGuard { - fn new() -> FriendFreezeGuard { - FriendFreezeGuard { - frozen_credits_from: ImHashMap::new(), - } - } -} - -#[derive(Clone)] -pub struct FreezeGuard { - local_public_key: PublicKey, - // Total amount of credits frozen from A to B through this Offset node. - // ``` - // A --> ... --> X --> B - // ``` - // A could be any node, B must be a friend of this Offset node. - frozen_to: ImHashMap, - // ^ B -} - -#[derive(Debug)] -pub enum FreezeGuardMutation { - AddFrozenCredit((FriendsRoute, u128)), // (friends_route, dest_payment) - SubFrozenCredit((FriendsRoute, u128)), // (friends_route, dest_payment) -} - -fn hash_subroute(subroute: &[PublicKey]) -> HashResult { - let mut hash_buffer = Vec::new(); - - for public_key in subroute { - hash_buffer.extend_from_slice(&public_key); - } - sha_512_256(&hash_buffer) -} - -impl FreezeGuard { - pub fn new(local_public_key: &PublicKey) -> FreezeGuard { - FreezeGuard { - local_public_key: local_public_key.clone(), - frozen_to: ImHashMap::new(), - } - } - - pub fn mutate(&mut self, mutation: &FreezeGuardMutation) { - match mutation { - FreezeGuardMutation::AddFrozenCredit((friends_route, dest_payment)) => - self.add_frozen_credit(friends_route, *dest_payment), - FreezeGuardMutation::SubFrozenCredit((friends_route, dest_payment)) => - self.sub_frozen_credit(friends_route, *dest_payment), - } - } - - // TODO: Should be moved outside of this structure implementation. - // The only public function that allows mutation FreezeGuard should be mutate. - pub fn load_funder_state(mut self, funder_state: &FunderState) -> FreezeGuard - where - A: CanonicalSerialize + Clone, - { - // Local public key should match: - assert_eq!(self.local_public_key, funder_state.local_public_key); - for (_friend_public_key, friend) in &funder_state.friends { - if let ChannelStatus::Consistent(token_channel) = &friend.channel_status { - let pending_local_requests = &token_channel - .get_mutual_credit() - .state() - .pending_requests - .pending_local_requests; - for (_request_id, pending_request) in pending_local_requests { - self.add_frozen_credit(&pending_request.route, pending_request.dest_payment); - } - } - } - self - } - // TODO: Possibly refactor similar code of add/sub frozen credit to be one function that - // returns an iterator? - /// ```text - /// A -- ... -- X -- B - /// ``` - /// On the image: X is the local public key, B is a direct friend of X. - /// For every node Y along the route, we add the credits Y needs to freeze because of the route - /// from A to B. - fn add_frozen_credit(&mut self, route: &FriendsRoute, dest_payment: u128) { - assert!(route.public_keys.contains(&self.local_public_key)); - if &self.local_public_key == route.public_keys.last().unwrap() { - // We are the destination. Nothing to do here. - return; - } - - let my_index = route.pk_to_index(&self.local_public_key).unwrap(); - - let route_len = usize_to_u32(route.len()).unwrap(); - let credit_calc = CreditCalculator::new(route_len, dest_payment); - - let next_index = my_index.checked_add(1).unwrap(); - let next_public_key = route.index_to_pk(next_index).unwrap().clone(); - let friend_freeze_guard = self.frozen_to - .entry(next_public_key) - .or_insert_with(FriendFreezeGuard::new); - - // Iterate over all nodes from the beginning of the route until our index: - for node_index in 0 ..= my_index { - let node_public_key = route.index_to_pk(node_index).unwrap(); - - let next_node_index = usize_to_u32(node_index.checked_add(1).unwrap()).unwrap(); - let credits_to_freeze = credit_calc.credits_to_freeze(next_node_index).unwrap(); - let routes_map = friend_freeze_guard - .frozen_credits_from - .entry(node_public_key.clone()) - .or_insert_with(ImHashMap::new); - - let route_hash = hash_subroute(&route.public_keys[node_index ..= next_index]); - let route_entry = routes_map - .entry(route_hash.clone()) - .or_insert(0); - - *route_entry = (*route_entry).checked_add(credits_to_freeze).unwrap(); - } - } - - /// ```text - /// A -- ... -- X -- B - /// ``` - /// On the image: X is the local public key, B is a direct friend of X. - /// For every node Y along the route, we subtract the credits Y needs to freeze because of the - /// route from A to B. In other words, this method unfreezes frozen credits along this route. - fn sub_frozen_credit(&mut self, route: &FriendsRoute, dest_payment: u128) { - assert!(route.public_keys.contains(&self.local_public_key)); - if &self.local_public_key == route.public_keys.last().unwrap() { - // We are the destination. Nothing to do here. - return; - } - - let my_index = route.pk_to_index(&self.local_public_key).unwrap(); - - let route_len = usize_to_u32(route.len()).unwrap(); - let credit_calc = CreditCalculator::new(route_len, dest_payment); - - let next_index = my_index.checked_add(1).unwrap(); - let next_public_key = route - .index_to_pk(next_index).unwrap().clone(); - let friend_freeze_guard = self.frozen_to - .get_mut(&next_public_key) - .unwrap(); - - // Iterate over all nodes from the beginning of the route until our index: - for node_index in 0 ..= my_index { - let node_public_key = route - .index_to_pk(node_index) - .unwrap(); - - let next_node_index = usize_to_u32(node_index.checked_add(1).unwrap()).unwrap(); - let credits_to_freeze = credit_calc.credits_to_freeze(next_node_index).unwrap(); - let routes_map = friend_freeze_guard - .frozen_credits_from - .get_mut(&node_public_key) - .unwrap(); - - let route_hash = hash_subroute(&route.public_keys[node_index ..= next_index]); - let route_entry = routes_map - .get_mut(&route_hash) - .unwrap(); - - *route_entry = (*route_entry).checked_sub(credits_to_freeze).unwrap(); - // Cleanup: - if *route_entry == 0 { - routes_map.remove(&route_hash); - } - - // Cleanup: - if routes_map.is_empty() { - friend_freeze_guard.frozen_credits_from.remove(&node_public_key); - } - } - - // Cleanup: - if friend_freeze_guard.frozen_credits_from.is_empty() { - self.frozen_to.remove(&next_public_key); - } - } - - /// Get the amount of credits frozen from to going through this sub-route, - /// where is a friend of this Offset node. - fn get_frozen(&self, subroute: &[PublicKey]) -> u128 { - if subroute.len() < 2 { - unreachable!(); - } - let from_pk = &subroute[0]; - let to_pk = &subroute[subroute.len().checked_sub(1).unwrap()]; - - self.frozen_to.get(to_pk) - .and_then(|ref friend_freeze_guard| - friend_freeze_guard.frozen_credits_from.get(from_pk)) - .and_then(|ref routes_map| - routes_map.get(&hash_subroute(subroute)).cloned()) - .unwrap_or(0u128) - } - - /// ```text - /// A -- ... -- X -- B - /// ``` - /// X is the local public key. B is a direct friend of X. - /// For any node Y along the route from A to X, we make sure that B does not freeze too many - /// credits for this node. In other words, we save Y from freezing too many credits for B. - pub fn verify_freezing_links(&self, route: &FriendsRoute, - dest_payment: u128, - freeze_links: &[FreezeLink]) -> Option<()> { - assert!(freeze_links.len().checked_add(1).unwrap() <= route.len()); - let my_index = route.pk_to_index(&self.local_public_key).unwrap(); - // TODO: Do we ever get here as the destination of the route? - let next_index = my_index.checked_add(1).unwrap(); - assert_eq!(next_index, freeze_links.len()); - - let route_len = usize_to_u32(route.len()).unwrap(); - let credit_calc = CreditCalculator::new(route_len, dest_payment); - - let two_pow_128 = BigUint::new(vec![0x0u32, 0x0u32, 0x0u32, 0x0u32, 0x1u32]); - assert_eq!(two_pow_128, BigUint::from(0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffffu128) + BigUint::from(1u128)); - - // Verify previous freezing links - for node_findex in 0 .. freeze_links.len() { - let first_freeze_link = &freeze_links[node_findex]; - let mut allowed_credits: BigUint = first_freeze_link.shared_credits.into(); - for freeze_link in &freeze_links[ - node_findex .. freeze_links.len()] { - - allowed_credits = match freeze_link.usable_ratio { - Ratio::One => allowed_credits, - Ratio::Numerator(num) => { - let b_num = BigUint::from(num); - allowed_credits * b_num / &two_pow_128 - }, - }; - } - - let subroute = &route - .public_keys[node_findex ..= next_index]; - let old_frozen = self.get_frozen(subroute); - - let node_findex = usize_to_u32(node_findex).unwrap(); - let next_node_findex = node_findex.checked_add(1).unwrap(); - let new_frozen = credit_calc.credits_to_freeze(next_node_findex)? - .checked_add(old_frozen).unwrap(); - if allowed_credits < new_frozen.into() { - return None; - } - } - Some(()) - } -} - - -#[cfg(test)] -mod tests { - use super::*; - use crypto::identity::{PublicKey, PublicKey::len()}; - - /// Get the amount of credits to be frozen on a route of a certain length - /// with certain amount to pay. - /// index is the location of the next node. For example, index = 1 will return the amount of - /// credits node 0 should freeze. - fn credit_freeze(route_len: u32, dest_payment: u128, index: u32) -> u128 { - CreditCalculator::new(route_len, dest_payment).credits_to_freeze(index).unwrap() - } - - #[test] - fn test_get_frozen_basic() { - /* - * a -- b -- (c) -- d - */ - - let pk_a = PublicKey::from(&[0xaa; PublicKey::len()]); - let pk_b = PublicKey::from(&[0xbb; PublicKey::len()]); - let pk_c = PublicKey::from(&[0xcc; PublicKey::len()]); - let pk_d = PublicKey::from(&[0xdd; PublicKey::len()]); - - let mut freeze_guard = FreezeGuard::new(&pk_c); - freeze_guard.add_frozen_credit(&FriendsRoute - {public_keys: vec![pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]}, 19); - - let guard_frozen = freeze_guard.get_frozen(&[pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,19,1), guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,19,2), guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,19,3), guard_frozen); - - freeze_guard.sub_frozen_credit(&FriendsRoute - {public_keys: vec![pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]}, 19); - let guard_frozen = freeze_guard.get_frozen(&[pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(guard_frozen, 0); - - let guard_frozen = freeze_guard.get_frozen(&[pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(guard_frozen, 0); - - let guard_frozen = freeze_guard.get_frozen(&[pk_c.clone(), pk_d.clone()]); - assert_eq!(guard_frozen, 0); - } - - #[test] - fn test_get_frozen_multiple_requests() { - /* - * a -- b -- (c) -- d - */ - - let pk_a = PublicKey::from(&[0xaa; PublicKey::len()]); - let pk_b = PublicKey::from(&[0xbb; PublicKey::len()]); - let pk_c = PublicKey::from(&[0xcc; PublicKey::len()]); - let pk_d = PublicKey::from(&[0xdd; PublicKey::len()]); - - let mut freeze_guard = FreezeGuard::new(&pk_c); - freeze_guard.add_frozen_credit(&FriendsRoute - {public_keys: vec![pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]}, 11); - freeze_guard.add_frozen_credit(&FriendsRoute - {public_keys: vec![pk_b.clone(), pk_c.clone(), pk_d.clone()]}, 17); - - let guard_frozen = freeze_guard.get_frozen(&[pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,11,1), guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,11,2) + credit_freeze(3,17,1), guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,11,3) + credit_freeze(3,17,2), guard_frozen); - - freeze_guard.sub_frozen_credit(&FriendsRoute - {public_keys: vec![pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]}, 11); - - let guard_frozen = freeze_guard.get_frozen(&[pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(0, guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(3,17,1), guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(3,17,2), guard_frozen); - - freeze_guard.sub_frozen_credit(&FriendsRoute - {public_keys: vec![pk_b.clone(), pk_c.clone(), pk_d.clone()]}, 17); - - let guard_frozen = freeze_guard.get_frozen(&[pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(0, guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(0, guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_c.clone(), pk_d.clone()]); - assert_eq!(0, guard_frozen); - } - - #[test] - fn test_get_frozen_branch_out() { - /* - * a -- b -- (c) -- d - * | - * e - */ - - let pk_a = PublicKey::from(&[0xaa; PublicKey::len()]); - let pk_b = PublicKey::from(&[0xbb; PublicKey::len()]); - let pk_c = PublicKey::from(&[0xcc; PublicKey::len()]); - let pk_d = PublicKey::from(&[0xdd; PublicKey::len()]); - let pk_e = PublicKey::from(&[0xee; PublicKey::len()]); - - let mut freeze_guard = FreezeGuard::new(&pk_c); - freeze_guard.add_frozen_credit(&FriendsRoute - {public_keys: vec![pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]}, 11); - freeze_guard.add_frozen_credit(&FriendsRoute - {public_keys: vec![pk_e.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]}, 17); - - let guard_frozen = freeze_guard.get_frozen(&[pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,11,1), guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_e.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,17,1), guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,11,2) + credit_freeze(4,17,2), guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,11,3) + credit_freeze(4,17,3), guard_frozen); - - freeze_guard.sub_frozen_credit(&FriendsRoute - {public_keys: vec![pk_e.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]}, 17); - - let guard_frozen = freeze_guard.get_frozen(&[pk_e.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(0, guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,11,1), guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,11,2), guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_c.clone(), pk_d.clone()]); - assert_eq!(credit_freeze(4,11,3), guard_frozen); - - freeze_guard.sub_frozen_credit(&FriendsRoute - {public_keys: vec![pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]}, 11); - - let guard_frozen = freeze_guard.get_frozen(&[pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(0, guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_b.clone(), pk_c.clone(), pk_d.clone()]); - assert_eq!(0, guard_frozen); - - let guard_frozen = freeze_guard.get_frozen(&[pk_c.clone(), pk_d.clone()]); - assert_eq!(0, guard_frozen); - } - - #[test] - fn test_verify_freezing_links_basic() { - /* - * a -- b -- (c) -- d - * | - * e - */ - - let pk_a = PublicKey::from(&[0xaa; PublicKey::len()]); - let pk_b = PublicKey::from(&[0xbb; PublicKey::len()]); - let pk_c = PublicKey::from(&[0xcc; PublicKey::len()]); - let pk_d = PublicKey::from(&[0xdd; PublicKey::len()]); - let pk_e = PublicKey::from(&[0xee; PublicKey::len()]); - - let mut freeze_guard = FreezeGuard::new(&pk_c); - freeze_guard.add_frozen_credit(&FriendsRoute - {public_keys: vec![pk_a.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]}, 11); - freeze_guard.add_frozen_credit(&FriendsRoute - {public_keys: vec![pk_e.clone(), pk_b.clone(), pk_c.clone(), pk_d.clone()]}, 17); - - let frozen_b = freeze_guard.get_frozen(&[pk_b.clone(), pk_c.clone(), pk_d.clone()]); - let frozen_c = freeze_guard.get_frozen(&[pk_c.clone(), pk_d.clone()]); - let half = Ratio::Numerator(0x8000_0000_0000_0000_0000_0000_0000_0000); - - - // -- Freezing not allowed, c -- d - let route = FriendsRoute {public_keys: vec![pk_c.clone(), pk_d.clone()]}; - let freeze_link_c = FreezeLink { - shared_credits: (frozen_c + credit_freeze(2,9,1) - 1)* 2, - usable_ratio: half.clone(), // Half - }; - let freeze_links = vec![freeze_link_c]; - let res = freeze_guard.verify_freezing_links(&route, 9, &freeze_links); - assert!(res.is_none()); - - - // -- Freezing allowed: c -- d - let route = FriendsRoute {public_keys: vec![pk_c.clone(), pk_d.clone()]}; - let freeze_link_c = FreezeLink { - shared_credits: (frozen_c + credit_freeze(2,9,1)) * 2, - usable_ratio: half.clone(), // Half - }; - let freeze_links = vec![freeze_link_c]; - let res = freeze_guard.verify_freezing_links(&route, 9, &freeze_links); - assert!(res.is_some()); - - - // -- Freezing not allowed: b -- c -- d - let route = FriendsRoute {public_keys: vec![pk_b.clone(), pk_c.clone(), pk_d.clone()]}; - let freeze_link_b = FreezeLink { - shared_credits: (frozen_b + credit_freeze(3,9,1) - 1) * 4, // <-- should be not enough - usable_ratio: half.clone(), // Half - }; - let freeze_link_c = FreezeLink { - shared_credits: (frozen_c + credit_freeze(3,9,2)) * 2, - usable_ratio: half.clone(), // Half - }; - let freeze_links = vec![freeze_link_b, freeze_link_c]; - let res = freeze_guard.verify_freezing_links(&route, 9, &freeze_links); - assert!(res.is_none()); - - // -- Freezing not allowed: b -- c -- d - let route = FriendsRoute {public_keys: vec![pk_b.clone(), pk_c.clone(), pk_d.clone()]}; - let freeze_link_b = FreezeLink { - shared_credits: (frozen_b + credit_freeze(3,9,1)) * 4, - usable_ratio: half.clone(), // Half - }; - let freeze_link_c = FreezeLink { - shared_credits: (frozen_c + credit_freeze(3,9,2) - 1) * 2, // <-- should be not enough - usable_ratio: half.clone(), // Half - }; - let freeze_links = vec![freeze_link_b, freeze_link_c]; - let res = freeze_guard.verify_freezing_links(&route, 9, &freeze_links); - assert!(res.is_none()); - - - // -- Freezing allowed: b -- c -- d - let route = FriendsRoute {public_keys: vec![pk_b.clone(), pk_c.clone(), pk_d.clone()]}; - let freeze_link_b = FreezeLink { - shared_credits: (frozen_b + credit_freeze(3,9,1)) * 4, - usable_ratio: half.clone(), // Half - }; - let freeze_link_c = FreezeLink { - shared_credits: (frozen_c + credit_freeze(3,9,2)) * 2, - usable_ratio: half.clone(), // Half - }; - let freeze_links = vec![freeze_link_b, freeze_link_c]; - let res = freeze_guard.verify_freezing_links(&route, 9, &freeze_links); - assert!(res.is_some()); - } -} -*/ From 8a0488185d3f493275e95ea4a44e1b616d9f2a82 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 8 Dec 2020 14:49:29 +0200 Subject: [PATCH 231/478] funder: Added switch submodule empty files --- components/funder/src/lib.rs | 2 ++ components/funder/src/switch/mod.rs | 2 ++ components/funder/src/switch/switch.rs | 0 components/funder/src/switch/types.rs | 35 ++++++++++++++++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 components/funder/src/switch/mod.rs create mode 100644 components/funder/src/switch/switch.rs create mode 100644 components/funder/src/switch/types.rs diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 293488f9b..0c0add1d2 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -29,6 +29,8 @@ mod mutual_credit; // mod state; #[allow(unused)] mod token_channel; + +mod switch; // // For testing: diff --git a/components/funder/src/switch/mod.rs b/components/funder/src/switch/mod.rs new file mode 100644 index 000000000..8fee2a555 --- /dev/null +++ b/components/funder/src/switch/mod.rs @@ -0,0 +1,2 @@ +mod switch; +mod types; diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs new file mode 100644 index 000000000..e69de29bb diff --git a/components/funder/src/switch/types.rs b/components/funder/src/switch/types.rs new file mode 100644 index 000000000..6dccbe2a0 --- /dev/null +++ b/components/funder/src/switch/types.rs @@ -0,0 +1,35 @@ +/* +use common::async_rpc::AsyncOpResult; +// use common::ser_utils::ser_string; +use common::u256::U256; + +use proto::crypto::Uid; +use proto::funder::messages::{McBalance, PendingTransaction}; + +pub trait SwitchClient { + fn get_balance(&mut self) -> AsyncOpResult; + fn set_balance(&mut self, new_balance: i128) -> AsyncOpResult<()>; + fn set_local_pending_debt(&mut self, debt: u128) -> AsyncOpResult<()>; + fn set_remote_pending_debt(&mut self, debt: u128) -> AsyncOpResult<()>; + fn set_in_fees(&mut self, in_fees: U256) -> AsyncOpResult<()>; + fn set_out_fees(&mut self, out_fees: U256) -> AsyncOpResult<()>; + fn get_local_pending_transaction( + &mut self, + request_id: Uid, + ) -> AsyncOpResult>; + fn insert_local_pending_transaction( + &mut self, + pending_transaction: PendingTransaction, + ) -> AsyncOpResult<()>; + fn remove_local_pending_transaction(&mut self, request_id: Uid) -> AsyncOpResult<()>; + fn get_remote_pending_transaction( + &mut self, + request_id: Uid, + ) -> AsyncOpResult>; + fn insert_remote_pending_transaction( + &mut self, + pending_transaction: PendingTransaction, + ) -> AsyncOpResult<()>; + fn remove_remote_pending_transaction(&mut self, request_id: Uid) -> AsyncOpResult<()>; +} +*/ From 04de42d6226c387c7471966c9c47801379c33fbf Mon Sep 17 00:00:00 2001 From: real Date: Tue, 8 Dec 2020 15:40:09 +0200 Subject: [PATCH 232/478] funder: Renamed db clients --- .../funder/src/mutual_credit/incoming.rs | 12 +++---- .../funder/src/mutual_credit/outgoing.rs | 10 +++--- .../tests/request_cancel_send_funds.rs | 2 +- .../tests/request_response_send_funds.rs | 2 +- .../funder/src/mutual_credit/tests/utils.rs | 4 +-- components/funder/src/mutual_credit/types.rs | 2 +- components/funder/src/token_channel/mod.rs | 2 +- .../tests/inconsistency_resolve.rs | 4 +-- .../token_channel/tests/move_token_basic.rs | 2 +- .../funder/src/token_channel/tests/utils.rs | 8 ++--- .../funder/src/token_channel/token_channel.rs | 34 +++++++++---------- components/funder/src/token_channel/types.rs | 8 ++--- 12 files changed, 45 insertions(+), 45 deletions(-) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 5a7170f56..12a1fa444 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -16,7 +16,7 @@ use signature::signature_buff::create_response_signature_buffer; use crate::types::create_pending_transaction; -use super::types::McClient; +use super::types::McDbClient; #[derive(Debug)] pub struct IncomingResponseSendFundsOp { @@ -58,7 +58,7 @@ pub struct ProcessTransListError { } pub async fn process_operations_list( - mc_client: &mut impl McClient, + mc_client: &mut impl McDbClient, operations: Vec, currency: &Currency, remote_public_key: &PublicKey, @@ -89,7 +89,7 @@ pub async fn process_operations_list( } pub async fn process_operation( - mc_client: &mut impl McClient, + mc_client: &mut impl McDbClient, friend_tc_op: FriendTcOp, currency: &Currency, remote_public_key: &PublicKey, @@ -111,7 +111,7 @@ pub async fn process_operation( /// Process an incoming RequestSendFundsOp async fn process_request_send_funds( - mc_client: &mut impl McClient, + mc_client: &mut impl McDbClient, request_send_funds: RequestSendFundsOp, remote_max_debt: u128, ) -> Result { @@ -177,7 +177,7 @@ async fn process_request_send_funds( } async fn process_response_send_funds( - mc_client: &mut impl McClient, + mc_client: &mut impl McDbClient, response_send_funds: ResponseSendFundsOp, currency: &Currency, remote_public_key: &PublicKey, @@ -265,7 +265,7 @@ async fn process_response_send_funds( } async fn process_cancel_send_funds( - mc_client: &mut impl McClient, + mc_client: &mut impl McDbClient, cancel_send_funds: CancelSendFundsOp, ) -> Result { // Make sure that id exists in local_pending hashmap, diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 5bd8dca8b..0f3a8f77c 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -12,7 +12,7 @@ use proto::funder::messages::{ }; use signature::signature_buff::create_response_signature_buffer; -use crate::mutual_credit::types::McClient; +use crate::mutual_credit::types::McDbClient; use crate::types::create_pending_transaction; #[derive(Debug, From)] @@ -33,7 +33,7 @@ pub enum QueueOperationError { // TODO: Remove later: #[allow(unused)] pub async fn queue_operation( - mc_client: &mut impl McClient, + mc_client: &mut impl McDbClient, operation: FriendTcOp, currency: &Currency, local_public_key: &PublicKey, @@ -54,7 +54,7 @@ pub async fn queue_operation( } async fn queue_request_send_funds( - mc_client: &mut impl McClient, + mc_client: &mut impl McDbClient, request_send_funds: RequestSendFundsOp, ) -> Result<(), QueueOperationError> { if !request_send_funds.route.is_part_valid() { @@ -103,7 +103,7 @@ async fn queue_request_send_funds( } async fn queue_response_send_funds( - mc_client: &mut impl McClient, + mc_client: &mut impl McDbClient, response_send_funds: ResponseSendFundsOp, currency: &Currency, local_public_key: &PublicKey, @@ -194,7 +194,7 @@ async fn queue_response_send_funds( } async fn queue_cancel_send_funds( - mc_client: &mut impl McClient, + mc_client: &mut impl McDbClient, cancel_send_funds: CancelSendFundsOp, ) -> Result<(), QueueOperationError> { // Make sure that id exists in remote_pending hashmap, diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index 5ac23cc85..1e87d4b8d 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -13,7 +13,7 @@ use proto::funder::messages::{ }; use crate::mutual_credit::tests::utils::MockMutualCredit; -use crate::mutual_credit::types::McClient; +use crate::mutual_credit::types::McDbClient; use crate::mutual_credit::incoming::process_operations_list; use crate::mutual_credit::outgoing::queue_operation; diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index d0603b37d..d497adbff 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -14,7 +14,7 @@ use proto::funder::messages::{ use signature::signature_buff::create_response_signature_buffer; use crate::mutual_credit::tests::utils::MockMutualCredit; -use crate::mutual_credit::types::McClient; +use crate::mutual_credit::types::McDbClient; use crate::types::create_pending_transaction; use crate::mutual_credit::incoming::process_operations_list; diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index 0fd116ccb..20d219913 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -7,7 +7,7 @@ use common::u256::U256; use proto::crypto::Uid; use proto::funder::messages::{Currency, McBalance, PendingTransaction}; -use crate::mutual_credit::types::McClient; +use crate::mutual_credit::types::McDbClient; #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct McPendingTransactions { @@ -52,7 +52,7 @@ impl MockMutualCredit { } } -impl McClient for MockMutualCredit { +impl McDbClient for MockMutualCredit { fn get_balance(&mut self) -> BoxFuture<'static, Result> { let mc_balance = self.balance.clone(); Box::pin(async move { Ok(mc_balance) }) diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 4ddcfcfb0..441f3efad 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -5,7 +5,7 @@ use common::u256::U256; use proto::crypto::Uid; use proto::funder::messages::{McBalance, PendingTransaction}; -pub trait McClient { +pub trait McDbClient { fn get_balance(&mut self) -> AsyncOpResult; fn set_balance(&mut self, new_balance: i128) -> AsyncOpResult<()>; fn set_local_pending_debt(&mut self, debt: u128) -> AsyncOpResult<()>; diff --git a/components/funder/src/token_channel/mod.rs b/components/funder/src/token_channel/mod.rs index c7a600daa..63b133143 100644 --- a/components/funder/src/token_channel/mod.rs +++ b/components/funder/src/token_channel/mod.rs @@ -10,4 +10,4 @@ pub use self::token_channel::{ ReceiveMoveTokenOutput, TokenChannelError, }; -pub use types::{ResetBalance, TcClient, TcStatus}; +pub use types::{ResetBalance, TcDbClient, TcStatus}; diff --git a/components/funder/src/token_channel/tests/inconsistency_resolve.rs b/components/funder/src/token_channel/tests/inconsistency_resolve.rs index 8b77e172a..37c35cd7b 100644 --- a/components/funder/src/token_channel/tests/inconsistency_resolve.rs +++ b/components/funder/src/token_channel/tests/inconsistency_resolve.rs @@ -25,8 +25,8 @@ use crate::mutual_credit::incoming::IncomingMessage; use crate::token_channel::tests::utils::MockTokenChannel; use crate::token_channel::{ accept_remote_reset, handle_in_move_token, handle_out_move_token, load_remote_reset_terms, - reset_balance_to_mc_balance, MoveTokenReceived, ReceiveMoveTokenOutput, ResetBalance, TcClient, - TcStatus, TokenChannelError, + reset_balance_to_mc_balance, MoveTokenReceived, ReceiveMoveTokenOutput, ResetBalance, + TcDbClient, TcStatus, TokenChannelError, }; use crate::types::create_pending_transaction; diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index 42b77c41e..e9f457900 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -25,7 +25,7 @@ use crate::mutual_credit::incoming::IncomingMessage; use crate::token_channel::tests::utils::MockTokenChannel; use crate::token_channel::{ accept_remote_reset, handle_in_move_token, handle_out_move_token, reset_balance_to_mc_balance, - MoveTokenReceived, ReceiveMoveTokenOutput, TcClient, TcStatus, TokenChannelError, + MoveTokenReceived, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; use crate::types::create_pending_transaction; diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index a836312aa..85690c58c 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -22,7 +22,7 @@ use crypto::identity::compare_public_key; use crate::mutual_credit::tests::MockMutualCredit; use crate::token_channel::types::{ResetBalance, ResetTerms, TcStatus}; -use crate::token_channel::{initial_move_token, reset_balance_to_mc_balance, TcClient}; +use crate::token_channel::{initial_move_token, reset_balance_to_mc_balance, TcDbClient}; use crate::types::{create_hashed, MoveTokenHashed}; #[derive(Debug, Clone)] @@ -119,10 +119,10 @@ fn calc_reset_balance(mock_token_channel: &MockMutualCredit) -> ResetBalance { } } -impl TcClient for MockTokenChannel { - type McClient = MockMutualCredit; +impl TcDbClient for MockTokenChannel { + type McDbClient = MockMutualCredit; - fn mc_client(&mut self, currency: Currency) -> &mut Self::McClient { + fn mc_client(&mut self, currency: Currency) -> &mut Self::McDbClient { match &mut self.status { MockTcStatus::Consistent(tc_consistent) => { tc_consistent.mutual_credits.get_mut(¤cy).unwrap() diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 178898bae..0024247e6 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -32,9 +32,9 @@ use crate::mutual_credit::incoming::{ process_operations_list, IncomingMessage, ProcessTransListError, }; use crate::mutual_credit::outgoing::{queue_operation, QueueOperationError}; -use crate::mutual_credit::types::McClient; +use crate::mutual_credit::types::McDbClient; -use crate::token_channel::types::{ResetBalance, ResetTerms, TcClient, TcStatus}; +use crate::token_channel::types::{ResetBalance, ResetTerms, TcDbClient, TcStatus}; use crate::types::{create_hashed, MoveTokenHashed}; /// Unrecoverable TokenChannel error @@ -163,7 +163,7 @@ pub fn reset_balance_to_mc_balance(reset_balance: ResetBalance) -> McBalance { /// Extract all local balances for reset as a map: async fn local_balances_for_reset( - tc_client: &mut impl TcClient, + tc_client: &mut impl TcDbClient, ) -> Result, TokenChannelError> { let mut balances = HashMap::new(); let mut reset_balances = tc_client.list_local_reset_balances(); @@ -191,8 +191,8 @@ enum TransactFail { impl<'b, C> TransFunc for InconsistentTrans<'b, C> where - C: TcClient + Send, - C::McClient: Send, + C: TcDbClient + Send, + C::McDbClient: Send, { type InRef = C; // We divide the error into two types: @@ -243,8 +243,8 @@ pub async fn handle_in_move_token( ) -> Result where // TODO: Can we somehow get rid of the Sync requirement for `B`? - C: TcClient + Transaction + Send, - C::McClient: Send, + C: TcDbClient + Transaction + Send, + C::McDbClient: Send, { match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => { @@ -357,7 +357,7 @@ async fn create_reset_token( /// Set token channel to be inconsistent /// Local reset terms are automatically calculated async fn set_inconsistent( - tc_client: &mut impl TcClient, + tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, local_public_key: &PublicKey, remote_public_key: &PublicKey, @@ -392,7 +392,7 @@ async fn set_inconsistent( } async fn handle_in_move_token_dir_in( - tc_client: &mut impl TcClient, + tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, local_public_key: &PublicKey, remote_public_key: &PublicKey, @@ -429,8 +429,8 @@ struct InMoveTokenDirOutTrans<'a, C> { impl<'b, C> TransFunc for InMoveTokenDirOutTrans<'b, C> where - C: TcClient + Send, - C::McClient: Send, + C: TcDbClient + Send, + C::McDbClient: Send, { type InRef = C; // We divide the error into two types: @@ -477,8 +477,8 @@ async fn handle_in_move_token_dir_out( remote_public_key: &PublicKey, ) -> Result where - C: TcClient + Transaction + Send, - C::McClient: Send, + C: TcDbClient + Transaction + Send, + C::McDbClient: Send, { if new_move_token.old_token == move_token_out.new_token { // Atomically attempt to handle a reset move token: @@ -572,7 +572,7 @@ enum IncomingTokenMatchOutput { } async fn handle_incoming_token_match( - tc_client: &mut impl TcClient, + tc_client: &mut impl TcDbClient, new_move_token: MoveToken, // remote_max_debts: &ImHashMap, local_public_key: &PublicKey, remote_public_key: &PublicKey, @@ -723,7 +723,7 @@ async fn handle_incoming_token_match( } pub async fn handle_out_move_token( - tc_client: &mut impl TcClient, + tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, currencies_operations: Vec, currencies_diff: Vec, @@ -835,7 +835,7 @@ pub async fn handle_out_move_token( /// Apply a token channel reset, accepting remote side's /// reset terms. pub async fn accept_remote_reset( - tc_client: &mut impl TcClient, + tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, currencies_operations: Vec, currencies_diff: Vec, @@ -897,7 +897,7 @@ pub async fn accept_remote_reset( /// Load the remote reset terms information from a remote side's inconsistency message /// Optionally returns local reset terms (If not already inconsistent) pub async fn load_remote_reset_terms( - tc_client: &mut impl TcClient, + tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, remote_reset_terms: ResetTerms, local_public_key: &PublicKey, diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 72684d4de..aaeba54a7 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -10,7 +10,7 @@ use proto::funder::messages::{Currency, McBalance, MoveToken}; use database::interface::funder::CurrencyConfig; -use crate::mutual_credit::types::McClient; +use crate::mutual_credit::types::McDbClient; use crate::types::MoveTokenHashed; #[derive(Debug)] @@ -51,9 +51,9 @@ pub enum TcStatus { // (local_reset_token, local_reset_move_token_counter, Option<(remote_reset_token, remote_reset_move_token_counter)>) } -pub trait TcClient { - type McClient: McClient; - fn mc_client(&mut self, currency: Currency) -> &mut Self::McClient; +pub trait TcDbClient { + type McDbClient: McDbClient; + fn mc_client(&mut self, currency: Currency) -> &mut Self::McDbClient; fn get_tc_status(&mut self) -> AsyncOpResult; fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; From e323e40c5753c9df1a0e250c4e6da9a396d1f20c Mon Sep 17 00:00:00 2001 From: real Date: Tue, 8 Dec 2020 16:35:48 +0200 Subject: [PATCH 233/478] funder: Renamed trait method --- components/funder/src/token_channel/tests/utils.rs | 2 +- components/funder/src/token_channel/token_channel.rs | 8 ++++---- components/funder/src/token_channel/types.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 85690c58c..dca3a5e45 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -122,7 +122,7 @@ fn calc_reset_balance(mock_token_channel: &MockMutualCredit) -> ResetBalance { impl TcDbClient for MockTokenChannel { type McDbClient = MockMutualCredit; - fn mc_client(&mut self, currency: Currency) -> &mut Self::McDbClient { + fn mc_db_client(&mut self, currency: Currency) -> &mut Self::McDbClient { match &mut self.status { MockTcStatus::Consistent(tc_consistent) => { tc_consistent.mutual_credits.get_mut(¤cy).unwrap() diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 0024247e6..f8185344b 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -618,7 +618,7 @@ async fn handle_incoming_token_match( let is_local_currency = tc_client.is_local_currency(diff_currency.clone()).await?; if is_local_currency { let mc_balance = tc_client - .mc_client(diff_currency.clone()) + .mc_db_client(diff_currency.clone()) .get_balance() .await?; if mc_balance.balance == 0 @@ -657,7 +657,7 @@ async fn handle_incoming_token_match( .await?; let res = process_operations_list( - tc_client.mc_client(currency_operations.currency.clone()), + tc_client.mc_db_client(currency_operations.currency.clone()), currency_operations.operations.clone(), ¤cy_operations.currency, remote_public_key, @@ -753,7 +753,7 @@ pub async fn handle_out_move_token( let is_remote_currency = tc_client.is_remote_currency(diff_currency.clone()).await?; if is_remote_currency { let mc_balance = tc_client - .mc_client(diff_currency.clone()) + .mc_db_client(diff_currency.clone()) .get_balance() .await?; if mc_balance.balance == 0 @@ -785,7 +785,7 @@ pub async fn handle_out_move_token( for currency_operations in ¤cies_operations { for operation in currency_operations.operations.iter().cloned() { queue_operation( - tc_client.mc_client(currency_operations.currency.clone()), + tc_client.mc_db_client(currency_operations.currency.clone()), operation, ¤cy_operations.currency, local_public_key, diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index aaeba54a7..06e92ce71 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -53,7 +53,7 @@ pub enum TcStatus { pub trait TcDbClient { type McDbClient: McDbClient; - fn mc_client(&mut self, currency: Currency) -> &mut Self::McDbClient; + fn mc_db_client(&mut self, currency: Currency) -> &mut Self::McDbClient; fn get_tc_status(&mut self) -> AsyncOpResult; fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; From 889abeeeda8bc601251e8b228777a33576675579 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 8 Dec 2020 22:22:54 +0200 Subject: [PATCH 234/478] funder: Initial switch interface --- components/funder/src/switch/mod.rs | 1 + components/funder/src/switch/switch.rs | 107 +++++++++++++++++++++++++ components/funder/src/switch/types.rs | 40 +++------ 3 files changed, 118 insertions(+), 30 deletions(-) diff --git a/components/funder/src/switch/mod.rs b/components/funder/src/switch/mod.rs index 8fee2a555..c1f1a4952 100644 --- a/components/funder/src/switch/mod.rs +++ b/components/funder/src/switch/mod.rs @@ -1,2 +1,3 @@ +#[allow(unused)] mod switch; mod types; diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index e69de29bb..dcb931935 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -0,0 +1,107 @@ +use derive_more::From; +use std::collections::{HashMap, HashSet}; + +use common::async_rpc::OpError; + +use proto::app_server::messages::RelayAddress; +use proto::crypto::PublicKey; +use proto::funder::messages::{Currency, MoveToken, RelaysUpdate, RequestSendFundsOp}; + +use crate::switch::types::SwitchDbClient; + +#[derive(Debug, From)] +pub enum SwitchError { + OpError(OpError), +} + +/* +#[derive(Debug)] +pub struct SwitchOutput { + opt_move_tokens: HashMap, + add_connections: Vec<(u128, PublicKey)>, + remove_connections: Vec<(u128, PublicKey)>, +} +*/ + +pub async fn send_request( + _switch_db_client: &mut impl SwitchDbClient, + _request: RequestSendFundsOp, +) -> Result<(PublicKey, MoveToken), SwitchError> { + // TODO: + // - Add request to relevant user pending requests queue (According to friend on route) + // - For the relevant friend: If token is present: + // - Compose a friend move token message + // - If the token is not present: + // - Compose a request token message. + todo!(); +} + +pub async fn add_currency( + _switch_db_client: &mut impl SwitchDbClient, + _friend_public_key: PublicKey, + _currency: Currency, +) -> Result { + // TODO + todo!(); +} + +pub async fn remove_currency( + _switch_db_client: &mut impl SwitchDbClient, + _friend_public_key: PublicKey, + _currency: Currency, +) -> Result { + // TODO + todo!(); +} + +// TODO: Do we need to send an update to index client somehow? +pub async fn set_remote_max_debt( + _switch_db_client: &mut impl SwitchDbClient, + _friend_public_key: PublicKey, + _currency: Currency, + _remote_max_debt: u128, +) -> Result<(), SwitchError> { + // TODO + todo!(); +} + +// TODO: Do we need to send an update to index client somehow? +pub async fn open_currency( + _switch_db_client: &mut impl SwitchDbClient, + _friend_public_key: PublicKey, + _currency: Currency, +) -> Result<(), SwitchError> { + // TODO + todo!(); +} + +// TODO: Do we need to send an update to index client somehow? +pub async fn close_currency( + _switch_db_client: &mut impl SwitchDbClient, + _friend_public_key: PublicKey, + _currency: Currency, +) -> Result<(), SwitchError> { + // TODO + todo!(); +} + +/* +// TODO +type FriendListen = (PublicKey, RelayAddress); + +#[derive(Debug)] +pub struct UpdateLocalRelaysOutput { + // Optional outgoing "relays update" message: + opt_relays_update: Option, + add_friend_listens: HashSet, + remove_friend_listens: HashSet, +} + +pub async fn update_local_relays( + _switch_db_client: &mut impl SwitchDbClient, + _local_relays: HashMap, +) -> Result { + // TODO + todo!(); +} +*/ diff --git a/components/funder/src/switch/types.rs b/components/funder/src/switch/types.rs index 6dccbe2a0..5b50de088 100644 --- a/components/funder/src/switch/types.rs +++ b/components/funder/src/switch/types.rs @@ -1,35 +1,15 @@ -/* -use common::async_rpc::AsyncOpResult; +// use common::async_rpc::AsyncOpResult; // use common::ser_utils::ser_string; -use common::u256::U256; +// use common::u256::U256; -use proto::crypto::Uid; -use proto::funder::messages::{McBalance, PendingTransaction}; +use proto::crypto::PublicKey; +// use proto::funder::messages::{McBalance, PendingTransaction}; -pub trait SwitchClient { +pub trait SwitchDbClient { + type TcDbClient; + fn tc_db_client(&mut self, friend_public_key: PublicKey) -> &mut Self::TcDbClient; + + /* fn get_balance(&mut self) -> AsyncOpResult; - fn set_balance(&mut self, new_balance: i128) -> AsyncOpResult<()>; - fn set_local_pending_debt(&mut self, debt: u128) -> AsyncOpResult<()>; - fn set_remote_pending_debt(&mut self, debt: u128) -> AsyncOpResult<()>; - fn set_in_fees(&mut self, in_fees: U256) -> AsyncOpResult<()>; - fn set_out_fees(&mut self, out_fees: U256) -> AsyncOpResult<()>; - fn get_local_pending_transaction( - &mut self, - request_id: Uid, - ) -> AsyncOpResult>; - fn insert_local_pending_transaction( - &mut self, - pending_transaction: PendingTransaction, - ) -> AsyncOpResult<()>; - fn remove_local_pending_transaction(&mut self, request_id: Uid) -> AsyncOpResult<()>; - fn get_remote_pending_transaction( - &mut self, - request_id: Uid, - ) -> AsyncOpResult>; - fn insert_remote_pending_transaction( - &mut self, - pending_transaction: PendingTransaction, - ) -> AsyncOpResult<()>; - fn remove_remote_pending_transaction(&mut self, request_id: Uid) -> AsyncOpResult<()>; + */ } -*/ From 79abb64cbea61cf0bb405be874f21bd368e360d0 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 9 Dec 2020 17:38:19 +0200 Subject: [PATCH 235/478] funder: Some work on switch's interface --- components/funder/src/lib.rs | 4 +- components/funder/src/switch/mod.rs | 1 - components/funder/src/switch/switch.rs | 106 ++++++++++++++++++++----- components/funder/src/switch/types.rs | 10 ++- 4 files changed, 96 insertions(+), 25 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 0c0add1d2..5fbea1549 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -23,13 +23,15 @@ extern crate quickcheck_derive; // mod friend; // mod funder; // mod handler; -// mod liveness; +#[allow(unused)] +mod liveness; mod mutual_credit; // pub mod report; // mod state; #[allow(unused)] mod token_channel; +#[allow(unused)] mod switch; // // For testing: diff --git a/components/funder/src/switch/mod.rs b/components/funder/src/switch/mod.rs index c1f1a4952..8fee2a555 100644 --- a/components/funder/src/switch/mod.rs +++ b/components/funder/src/switch/mod.rs @@ -1,3 +1,2 @@ -#[allow(unused)] mod switch; mod types; diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index dcb931935..8cfe570ad 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -5,12 +5,18 @@ use common::async_rpc::OpError; use proto::app_server::messages::RelayAddress; use proto::crypto::PublicKey; -use proto::funder::messages::{Currency, MoveToken, RelaysUpdate, RequestSendFundsOp}; +use proto::funder::messages::{ + CancelSendFundsOp, Currency, MoveToken, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, +}; +use proto::index_server::messages::IndexMutation; -use crate::switch::types::SwitchDbClient; +use crate::liveness::LivenessMutation; +use crate::switch::types::{SwitchDbClient, SwitchState}; +use crate::token_channel::{TcDbClient, TcStatus}; #[derive(Debug, From)] pub enum SwitchError { + FriendAlreadyOnline, OpError(OpError), } @@ -23,10 +29,70 @@ pub struct SwitchOutput { } */ +#[derive(Debug)] +pub struct SwitchOutput { + pub outgoing_move_tokens: HashMap, + pub relays_updates: HashMap, + pub index_mutations: Vec, + pub updated_remote_relays: Vec, + pub incoming_requests: Vec, + pub incoming_responses: Vec, + pub incoming_cancels: Vec, +} + +pub async fn set_friend_online( + switch_db_client: &mut impl SwitchDbClient, + switch_state: &mut SwitchState, + friend_public_key: PublicKey, +) -> Result { + if switch_state.liveness.is_online(&friend_public_key) { + // The friend is already marked as online! + return Err(SwitchError::FriendAlreadyOnline); + } + + // TODO: Possibly resend relays updates + todo!(); + + // TODO: Attempt to reconstruct and send last outgoing message, if exists. + match switch_db_client + .tc_db_client(friend_public_key.clone()) + .get_tc_status() + .await? + { + TcStatus::ConsistentIn(_) => { + // Create an outgoing move token if we have something to send. + todo!(); + } + TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { + // Resend outgoing move token. + // Resend with "request token back = true" if we have more things to send. + todo!(); + } + TcStatus::Inconsistent(..) => { + // Resend reset terms + todo!(); + } + } + + // TODO: Maybe change liveness to work directly, without the mutations concept? + // Maybe we don't need atomicity for the liveness struct? + switch_state + .liveness + .mutate(&LivenessMutation::SetOnline(friend_public_key.clone())); +} + +pub async fn set_friend_offline( + _switch_db_client: &mut impl SwitchDbClient, + _switch_state: &mut SwitchState, + _friend_public_key: PublicKey, +) -> Result { + todo!(); +} + pub async fn send_request( _switch_db_client: &mut impl SwitchDbClient, _request: RequestSendFundsOp, -) -> Result<(PublicKey, MoveToken), SwitchError> { +) -> Result { // TODO: // - Add request to relevant user pending requests queue (According to friend on route) // - For the relevant friend: If token is present: @@ -40,7 +106,7 @@ pub async fn add_currency( _switch_db_client: &mut impl SwitchDbClient, _friend_public_key: PublicKey, _currency: Currency, -) -> Result { +) -> Result { // TODO todo!(); } @@ -49,7 +115,7 @@ pub async fn remove_currency( _switch_db_client: &mut impl SwitchDbClient, _friend_public_key: PublicKey, _currency: Currency, -) -> Result { +) -> Result { // TODO todo!(); } @@ -60,7 +126,7 @@ pub async fn set_remote_max_debt( _friend_public_key: PublicKey, _currency: Currency, _remote_max_debt: u128, -) -> Result<(), SwitchError> { +) -> Result { // TODO todo!(); } @@ -70,7 +136,7 @@ pub async fn open_currency( _switch_db_client: &mut impl SwitchDbClient, _friend_public_key: PublicKey, _currency: Currency, -) -> Result<(), SwitchError> { +) -> Result { // TODO todo!(); } @@ -80,28 +146,24 @@ pub async fn close_currency( _switch_db_client: &mut impl SwitchDbClient, _friend_public_key: PublicKey, _currency: Currency, -) -> Result<(), SwitchError> { +) -> Result { // TODO todo!(); } -/* -// TODO -type FriendListen = (PublicKey, RelayAddress); - -#[derive(Debug)] -pub struct UpdateLocalRelaysOutput { - // Optional outgoing "relays update" message: - opt_relays_update: Option, - add_friend_listens: HashSet, - remove_friend_listens: HashSet, -} - pub async fn update_local_relays( _switch_db_client: &mut impl SwitchDbClient, _local_relays: HashMap, -) -> Result { +) -> Result { + // TODO + todo!(); +} + +pub async fn incoming_move_token( + _switch_db_client: &mut impl SwitchDbClient, + _friend_public_key: PublicKey, + _move_token: MoveToken, +) -> Result { // TODO todo!(); } -*/ diff --git a/components/funder/src/switch/types.rs b/components/funder/src/switch/types.rs index 5b50de088..32117b9c7 100644 --- a/components/funder/src/switch/types.rs +++ b/components/funder/src/switch/types.rs @@ -2,14 +2,22 @@ // use common::ser_utils::ser_string; // use common::u256::U256; +use crate::liveness::Liveness; +use crate::token_channel::TcDbClient; + use proto::crypto::PublicKey; // use proto::funder::messages::{McBalance, PendingTransaction}; pub trait SwitchDbClient { - type TcDbClient; + type TcDbClient: TcDbClient; fn tc_db_client(&mut self, friend_public_key: PublicKey) -> &mut Self::TcDbClient; /* fn get_balance(&mut self) -> AsyncOpResult; */ } + +/// Switch's ephemeral state (Not saved inside the database) +pub struct SwitchState { + pub liveness: Liveness, +} From 95cd3c0728ac00f63eb8c2dcc1346525aa905493 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 13 Dec 2020 11:03:40 +0200 Subject: [PATCH 236/478] proto: Added RelaysAck message --- components/proto/src/funder/messages.rs | 1 + components/proto/src/schema/funder.capnp | 1 + 2 files changed, 2 insertions(+) diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index ebf61013b..7fea12876 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -390,6 +390,7 @@ pub enum FriendMessage { MoveTokenRequest(MoveTokenRequest), InconsistencyError(ResetTerms), RelaysUpdate(RelaysUpdate), + RelaysAck(Uid), } /// A `Receipt` is received if a `RequestSendFunds` is successful. diff --git a/components/proto/src/schema/funder.capnp b/components/proto/src/schema/funder.capnp index 399fea5ed..bc7ee8e97 100644 --- a/components/proto/src/schema/funder.capnp +++ b/components/proto/src/schema/funder.capnp @@ -75,6 +75,7 @@ struct FriendMessage { moveTokenRequest @0: MoveTokenRequest; inconsistencyError @1: ResetTerms; relaysUpdate @2: RelaysUpdate; + relaysAck @3: Uid; } } From 4693621d56605e819939c11aeb4a3676a1344325 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 13 Dec 2020 13:05:09 +0200 Subject: [PATCH 237/478] funder: Using the more general FriendMessage over MoveToken --- components/funder/src/switch/switch.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 8cfe570ad..fb8c7a6a2 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -6,7 +6,8 @@ use common::async_rpc::OpError; use proto::app_server::messages::RelayAddress; use proto::crypto::PublicKey; use proto::funder::messages::{ - CancelSendFundsOp, Currency, MoveToken, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendMessage, MoveToken, RelaysUpdate, RequestSendFundsOp, + ResponseSendFundsOp, }; use proto::index_server::messages::IndexMutation; @@ -31,8 +32,7 @@ pub struct SwitchOutput { #[derive(Debug)] pub struct SwitchOutput { - pub outgoing_move_tokens: HashMap, - pub relays_updates: HashMap, + pub friend_message: HashMap, pub index_mutations: Vec, pub updated_remote_relays: Vec, pub incoming_requests: Vec, @@ -159,10 +159,10 @@ pub async fn update_local_relays( todo!(); } -pub async fn incoming_move_token( +pub async fn incoming_friend_message( _switch_db_client: &mut impl SwitchDbClient, _friend_public_key: PublicKey, - _move_token: MoveToken, + _friend_message: FriendMessage, ) -> Result { // TODO todo!(); From 8c73f7a0c26a6322024041db37d71d4861e47fe2 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 13 Dec 2020 18:36:27 +0200 Subject: [PATCH 238/478] proto: Updated RelaysUpdate message (updateId -> generation) --- components/proto/src/funder/messages.rs | 3 ++- components/proto/src/schema/funder.capnp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 7fea12876..eca14c35d 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -379,7 +379,8 @@ pub struct MoveTokenRequest { #[capnp_conv(crate::funder_capnp::relays_update)] #[derive(Arbitrary, PartialEq, Eq, Clone, Serialize, Debug)] pub struct RelaysUpdate { - pub update_id: Uid, + #[capnp_conv(with = Wrapper)] + pub generation: u128, pub relays: Vec>, } diff --git a/components/proto/src/schema/funder.capnp b/components/proto/src/schema/funder.capnp index bc7ee8e97..4bfdbb268 100644 --- a/components/proto/src/schema/funder.capnp +++ b/components/proto/src/schema/funder.capnp @@ -64,7 +64,7 @@ struct ResetTerms { } struct RelaysUpdate { - updateId @0: Uid; + generation @0: CustomUInt128; relays @1: List(RelayAddress); } From 1618c8cac5b814a78867ed38af0b661967b70ff5 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 13 Dec 2020 18:40:39 +0200 Subject: [PATCH 239/478] funder: Work on set_friend_online(). Not done yet --- components/funder/src/liveness.rs | 39 +++++++++-------------- components/funder/src/switch/switch.rs | 44 +++++++++++++++++++++++--- components/funder/src/switch/types.rs | 21 +++++++++++- 3 files changed, 74 insertions(+), 30 deletions(-) diff --git a/components/funder/src/liveness.rs b/components/funder/src/liveness.rs index 05f626d71..21e37f22f 100644 --- a/components/funder/src/liveness.rs +++ b/components/funder/src/liveness.rs @@ -7,12 +7,6 @@ pub struct Liveness { pub friends: ImHashSet, } -#[derive(Debug)] -pub enum LivenessMutation { - SetOnline(PublicKey), - SetOffline(PublicKey), -} - impl Liveness { pub fn new() -> Liveness { Liveness { @@ -20,19 +14,16 @@ impl Liveness { } } - pub fn mutate(&mut self, mutation: &LivenessMutation) { - match mutation { - LivenessMutation::SetOnline(public_key) => { - self.friends.insert(public_key.clone()); - } - LivenessMutation::SetOffline(public_key) => { - let _ = self.friends.remove(public_key); - } - } + pub fn set_online(&mut self, public_key: PublicKey) -> bool { + self.friends.insert(public_key).is_none() + } + + pub fn set_offline(&mut self, public_key: &PublicKey) -> bool { + self.friends.remove(&public_key).is_some() } - pub fn is_online(&self, friend_public_key: &PublicKey) -> bool { - self.friends.contains(&friend_public_key) + pub fn is_online(&mut self, public_key: &PublicKey) -> bool { + self.friends.contains(public_key) } } @@ -51,37 +42,37 @@ mod tests { assert!(!liveness.is_online(&pk_b)); assert!(!liveness.is_online(&pk_c)); - liveness.mutate(&LivenessMutation::SetOnline(pk_a.clone())); + liveness.set_online(pk_a.clone()); assert!(liveness.is_online(&pk_a)); assert!(!liveness.is_online(&pk_b)); assert!(!liveness.is_online(&pk_c)); - liveness.mutate(&LivenessMutation::SetOnline(pk_a.clone())); + liveness.set_online(pk_a.clone()); assert!(liveness.is_online(&pk_a)); assert!(!liveness.is_online(&pk_b)); assert!(!liveness.is_online(&pk_c)); - liveness.mutate(&LivenessMutation::SetOnline(pk_b.clone())); + liveness.set_online(pk_b.clone()); assert!(liveness.is_online(&pk_a)); assert!(liveness.is_online(&pk_b)); assert!(!liveness.is_online(&pk_c)); - liveness.mutate(&LivenessMutation::SetOffline(pk_c.clone())); + liveness.set_offline(&pk_c); assert!(liveness.is_online(&pk_a)); assert!(liveness.is_online(&pk_b)); assert!(!liveness.is_online(&pk_c)); - liveness.mutate(&LivenessMutation::SetOffline(pk_b.clone())); + liveness.set_offline(&pk_b); assert!(liveness.is_online(&pk_a)); assert!(!liveness.is_online(&pk_b)); assert!(!liveness.is_online(&pk_c)); - liveness.mutate(&LivenessMutation::SetOffline(pk_b.clone())); + liveness.set_offline(&pk_b); assert!(liveness.is_online(&pk_a)); assert!(!liveness.is_online(&pk_b)); assert!(!liveness.is_online(&pk_c)); - liveness.mutate(&LivenessMutation::SetOffline(pk_a.clone())); + liveness.set_offline(&pk_a); assert!(!liveness.is_online(&pk_a)); assert!(!liveness.is_online(&pk_b)); assert!(!liveness.is_online(&pk_c)); diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index fb8c7a6a2..864740c08 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -11,13 +11,13 @@ use proto::funder::messages::{ }; use proto::index_server::messages::IndexMutation; -use crate::liveness::LivenessMutation; use crate::switch::types::{SwitchDbClient, SwitchState}; use crate::token_channel::{TcDbClient, TcStatus}; #[derive(Debug, From)] pub enum SwitchError { FriendAlreadyOnline, + GenerationOverflow, OpError(OpError), } @@ -30,9 +30,10 @@ pub struct SwitchOutput { } */ +// TODO: Make this structure more ergonomic to use: #[derive(Debug)] pub struct SwitchOutput { - pub friend_message: HashMap, + pub friends_messages: HashMap, pub index_mutations: Vec, pub updated_remote_relays: Vec, pub incoming_requests: Vec, @@ -50,7 +51,42 @@ pub async fn set_friend_online( return Err(SwitchError::FriendAlreadyOnline); } + if let Some(max_generation) = switch_db_client + .get_max_sent_relays_generation(friend_public_key.clone()) + .await? + { + let generation = max_generation + .checked_add(1) + .ok_or(SwitchError::GenerationOverflow)?; + + let local_relays = switch_db_client.get_local_relays().await?; + let mut relays = Vec::new(); + for local_relay in local_relays { + relays.push(RelayAddress { + public_key: local_relay.public_key, + address: local_relay.address, + // TODO: We need to randomly generate relay ports here + // Should we use u128, or a different type? How will it be json serialized? + port: todo!(), + }) + } + + let relays_update = RelaysUpdate { + generation, + relays: relays.clone(), + }; + + switch_db_client + .update_sent_relays(friend_public_key, generation, relays) + .await?; + + // Actually send relays here: + todo!(); + } + // TODO: Possibly resend relays updates + // - If there are unpacked changes to relays: + // - todo!(); // TODO: Attempt to reconstruct and send last outgoing message, if exists. @@ -76,9 +112,7 @@ pub async fn set_friend_online( // TODO: Maybe change liveness to work directly, without the mutations concept? // Maybe we don't need atomicity for the liveness struct? - switch_state - .liveness - .mutate(&LivenessMutation::SetOnline(friend_public_key.clone())); + switch_state.liveness.set_online(friend_public_key.clone()); } pub async fn set_friend_offline( diff --git a/components/funder/src/switch/types.rs b/components/funder/src/switch/types.rs index 32117b9c7..7319d7702 100644 --- a/components/funder/src/switch/types.rs +++ b/components/funder/src/switch/types.rs @@ -1,10 +1,11 @@ -// use common::async_rpc::AsyncOpResult; +use common::async_rpc::AsyncOpResult; // use common::ser_utils::ser_string; // use common::u256::U256; use crate::liveness::Liveness; use crate::token_channel::TcDbClient; +use proto::app_server::messages::{NamedRelayAddress, RelayAddress}; use proto::crypto::PublicKey; // use proto::funder::messages::{McBalance, PendingTransaction}; @@ -12,6 +13,24 @@ pub trait SwitchDbClient { type TcDbClient: TcDbClient; fn tc_db_client(&mut self, friend_public_key: PublicKey) -> &mut Self::TcDbClient; + /// Get the current list of local relays + fn get_local_relays(&mut self) -> AsyncOpResult>; + + /// Get the maximum value of sent relay generation. + /// Returns None if all relays were acked by the remote side. + fn get_max_sent_relays_generation( + &mut self, + friend_public_key: PublicKey, + ) -> AsyncOpResult>; + + /// Update sent relays for friend `friend_public_key` with the list of current local relays. + fn update_sent_relays( + &mut self, + friend_public_key: PublicKey, + generation: u128, + sent_relays: Vec, + ) -> AsyncOpResult<()>; + /* fn get_balance(&mut self) -> AsyncOpResult; */ From f9f0551527628d7d3bf5c6b8ecc384ada9eafe7b Mon Sep 17 00:00:00 2001 From: real Date: Wed, 16 Dec 2020 13:14:56 +0200 Subject: [PATCH 240/478] proto: Added RelayPort --- components/proto/src/crypto/mod.rs | 3 +++ components/proto/src/schema/common.capnp | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/components/proto/src/crypto/mod.rs b/components/proto/src/crypto/mod.rs index 9ff43bdb9..eb9998b1c 100644 --- a/components/proto/src/crypto/mod.rs +++ b/components/proto/src/crypto/mod.rs @@ -57,6 +57,9 @@ type_capnp_serde!(InvoiceId, common_capnp::invoice_id, (x0, x1, x2, x3)); define_fixed_bytes!(PaymentId, 16); type_capnp_serde!(PaymentId, common_capnp::payment_id, (x0, x1)); +define_fixed_bytes!(RelayPort, 16); +type_capnp_serde!(RelayPort, common_capnp::relay_port, (x0, x1)); + define_fixed_bytes!(RandValue, 16); type_capnp_serde!(RandValue, common_capnp::rand_value, (x0, x1)); diff --git a/components/proto/src/schema/common.capnp b/components/proto/src/schema/common.capnp index 8935a6ffb..307e67a6a 100644 --- a/components/proto/src/schema/common.capnp +++ b/components/proto/src/schema/common.capnp @@ -81,10 +81,15 @@ struct PaymentId { inner @0: Buffer128; } +struct RelayPort { + inner @0: Buffer128; +} + struct PlainLock { inner @0: Buffer256; } + struct HashedLock { inner @0: Buffer256; } From 1ecf6026af88cc59bfdd6fbaf46ca7cf15cd064c Mon Sep 17 00:00:00 2001 From: real Date: Wed, 16 Dec 2020 13:20:08 +0200 Subject: [PATCH 241/478] proto: Renamed RelayPort -> NodePort --- components/proto/src/crypto/mod.rs | 4 ++-- components/proto/src/schema/common.capnp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/proto/src/crypto/mod.rs b/components/proto/src/crypto/mod.rs index eb9998b1c..4820f6ada 100644 --- a/components/proto/src/crypto/mod.rs +++ b/components/proto/src/crypto/mod.rs @@ -57,8 +57,8 @@ type_capnp_serde!(InvoiceId, common_capnp::invoice_id, (x0, x1, x2, x3)); define_fixed_bytes!(PaymentId, 16); type_capnp_serde!(PaymentId, common_capnp::payment_id, (x0, x1)); -define_fixed_bytes!(RelayPort, 16); -type_capnp_serde!(RelayPort, common_capnp::relay_port, (x0, x1)); +define_fixed_bytes!(NodePort, 16); +type_capnp_serde!(NodePort, common_capnp::node_port, (x0, x1)); define_fixed_bytes!(RandValue, 16); type_capnp_serde!(RandValue, common_capnp::rand_value, (x0, x1)); diff --git a/components/proto/src/schema/common.capnp b/components/proto/src/schema/common.capnp index 307e67a6a..a8e2db1e5 100644 --- a/components/proto/src/schema/common.capnp +++ b/components/proto/src/schema/common.capnp @@ -81,7 +81,7 @@ struct PaymentId { inner @0: Buffer128; } -struct RelayPort { +struct NodePort { inner @0: Buffer128; } From b82478d51297cce9d2cd105e2d08f81cf69c3619 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 16 Dec 2020 13:20:33 +0200 Subject: [PATCH 242/478] funder: impl RangGen for NodePort --- components/crypto/src/rand.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/components/crypto/src/rand.rs b/components/crypto/src/rand.rs index 898234112..58cc6c5d5 100644 --- a/components/crypto/src/rand.rs +++ b/components/crypto/src/rand.rs @@ -5,7 +5,7 @@ use rand_core::impls; use crate::error::CryptoError; -use proto::crypto::{InvoiceId, PaymentId, PlainLock, RandValue, Salt, Uid}; +use proto::crypto::{InvoiceId, NodePort, PaymentId, PlainLock, RandValue, Salt, Uid}; // TODO: Maybe we shouldn't have Sync + Send here as bounds? pub trait CryptoRandom: RngCore + CryptoRng { @@ -141,6 +141,14 @@ impl RandGen for InvoiceId { } } +impl RandGen for NodePort { + fn rand_gen(crypt_rng: &mut impl CryptoRandom) -> Self { + let mut res = Self::default(); + crypt_rng.fill(&mut res).unwrap(); + res + } +} + impl RandGen for RandValue { fn rand_gen(crypt_rng: &mut impl CryptoRandom) -> Self { let mut res = Self::default(); From 85ac6fc503f5e578ed288899ded95cfffc57415c Mon Sep 17 00:00:00 2001 From: real Date: Wed, 16 Dec 2020 13:24:42 +0200 Subject: [PATCH 243/478] proto: NodePort is now a buffer instead of u128 --- components/proto/src/app_server/messages.rs | 12 ++++++------ components/proto/src/file.rs | 6 +++--- components/proto/src/schema/common.capnp | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/components/proto/src/app_server/messages.rs b/components/proto/src/app_server/messages.rs index c457aa9e6..f28951bbc 100644 --- a/components/proto/src/app_server/messages.rs +++ b/components/proto/src/app_server/messages.rs @@ -2,10 +2,10 @@ use serde::{Deserialize, Serialize}; use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; -use common::ser_utils::{ser_b64, ser_string}; +use common::ser_utils::ser_b64; -use crate::crypto::{InvoiceId, PaymentId, PublicKey, Uid}; -use crate::wrapper::Wrapper; +use crate::crypto::{InvoiceId, NodePort, PaymentId, PublicKey, Uid}; +// use crate::wrapper::Wrapper; use crate::funder::messages::{ AckClosePayment, AddFriend, AddInvoice, Commit, CreatePayment, CreateTransaction, Currency, @@ -36,9 +36,9 @@ pub struct RelayAddress { #[serde(with = "ser_b64")] pub public_key: PublicKey, pub address: B, - #[capnp_conv(with = Wrapper)] - #[serde(with = "ser_string")] - pub port: u128, + // #[capnp_conv(with = Wrapper)] + #[serde(with = "ser_b64")] + pub port: NodePort, } /* diff --git a/components/proto/src/file.rs b/components/proto/src/file.rs index b7a681c79..3ec8dc76f 100644 --- a/components/proto/src/file.rs +++ b/components/proto/src/file.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use crate::crypto::{PrivateKey, PublicKey}; +use crate::crypto::{NodePort, PrivateKey, PublicKey}; use mutual_from::mutual_from; @@ -35,8 +35,8 @@ pub struct RelayAddressFile { pub public_key: PublicKey, #[serde(with = "ser_string")] pub address: NetAddress, - #[serde(with = "ser_string")] - pub port: u128, + #[serde(with = "ser_b64")] + pub port: NodePort, } /// A helper structure for serialize and deserializing FriendAddress. diff --git a/components/proto/src/schema/common.capnp b/components/proto/src/schema/common.capnp index a8e2db1e5..c296fe8ac 100644 --- a/components/proto/src/schema/common.capnp +++ b/components/proto/src/schema/common.capnp @@ -116,7 +116,7 @@ struct Currency { struct RelayAddress { publicKey @0: PublicKey; address @1: NetAddress; - port @2: CustomUInt128; + port @2: NodePort; } # Authenticated named address of a Relay (Includes public key) From 26a2b0d479f01a35fc6bfb4b7e3d04dfe38dd4a5 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 16 Dec 2020 15:52:41 +0200 Subject: [PATCH 244/478] funder: switch refactor and set_friend_online() fix --- components/funder/src/switch/switch.rs | 67 +++++--------------------- components/funder/src/switch/types.rs | 63 ++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 56 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 864740c08..cc0c0b281 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -9,9 +9,8 @@ use proto::funder::messages::{ CancelSendFundsOp, Currency, FriendMessage, MoveToken, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, }; -use proto::index_server::messages::IndexMutation; -use crate::switch::types::{SwitchDbClient, SwitchState}; +use crate::switch::types::{SwitchDbClient, SwitchOutput, SwitchState}; use crate::token_channel::{TcDbClient, TcStatus}; #[derive(Debug, From)] @@ -21,26 +20,6 @@ pub enum SwitchError { OpError(OpError), } -/* -#[derive(Debug)] -pub struct SwitchOutput { - opt_move_tokens: HashMap, - add_connections: Vec<(u128, PublicKey)>, - remove_connections: Vec<(u128, PublicKey)>, -} -*/ - -// TODO: Make this structure more ergonomic to use: -#[derive(Debug)] -pub struct SwitchOutput { - pub friends_messages: HashMap, - pub index_mutations: Vec, - pub updated_remote_relays: Vec, - pub incoming_requests: Vec, - pub incoming_responses: Vec, - pub incoming_cancels: Vec, -} - pub async fn set_friend_online( switch_db_client: &mut impl SwitchDbClient, switch_state: &mut SwitchState, @@ -51,44 +30,20 @@ pub async fn set_friend_online( return Err(SwitchError::FriendAlreadyOnline); } - if let Some(max_generation) = switch_db_client - .get_max_sent_relays_generation(friend_public_key.clone()) + let mut output = SwitchOutput::new(); + + // Check if we have any relays information to send to the remote side: + if let (Some(generation), relays) = switch_db_client + .get_sent_relays(friend_public_key.clone()) .await? { - let generation = max_generation - .checked_add(1) - .ok_or(SwitchError::GenerationOverflow)?; - - let local_relays = switch_db_client.get_local_relays().await?; - let mut relays = Vec::new(); - for local_relay in local_relays { - relays.push(RelayAddress { - public_key: local_relay.public_key, - address: local_relay.address, - // TODO: We need to randomly generate relay ports here - // Should we use u128, or a different type? How will it be json serialized? - port: todo!(), - }) - } - - let relays_update = RelaysUpdate { - generation, - relays: relays.clone(), - }; - - switch_db_client - .update_sent_relays(friend_public_key, generation, relays) - .await?; - - // Actually send relays here: - todo!(); + // Add a message for sending relays: + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), + ); } - // TODO: Possibly resend relays updates - // - If there are unpacked changes to relays: - // - - todo!(); - // TODO: Attempt to reconstruct and send last outgoing message, if exists. match switch_db_client .tc_db_client(friend_public_key.clone()) diff --git a/components/funder/src/switch/types.rs b/components/funder/src/switch/types.rs index 7319d7702..5305b8a89 100644 --- a/components/funder/src/switch/types.rs +++ b/components/funder/src/switch/types.rs @@ -1,4 +1,5 @@ use common::async_rpc::AsyncOpResult; +use std::collections::HashMap; // use common::ser_utils::ser_string; // use common::u256::U256; @@ -7,6 +8,10 @@ use crate::token_channel::TcDbClient; use proto::app_server::messages::{NamedRelayAddress, RelayAddress}; use proto::crypto::PublicKey; +use proto::funder::messages::{ + CancelSendFundsOp, FriendMessage, RequestSendFundsOp, ResponseSendFundsOp, +}; +use proto::index_server::messages::IndexMutation; // use proto::funder::messages::{McBalance, PendingTransaction}; pub trait SwitchDbClient { @@ -16,12 +21,21 @@ pub trait SwitchDbClient { /// Get the current list of local relays fn get_local_relays(&mut self) -> AsyncOpResult>; + /* /// Get the maximum value of sent relay generation. /// Returns None if all relays were acked by the remote side. fn get_max_sent_relays_generation( &mut self, friend_public_key: PublicKey, ) -> AsyncOpResult>; + */ + + /// Get the last set of sent relays, together with their generation + /// Generation == None means that the sent relays were already acked + fn get_sent_relays( + &mut self, + friend_public_key: PublicKey, + ) -> AsyncOpResult<(Option, Vec)>; /// Update sent relays for friend `friend_public_key` with the list of current local relays. fn update_sent_relays( @@ -40,3 +54,52 @@ pub trait SwitchDbClient { pub struct SwitchState { pub liveness: Liveness, } + +#[derive(Debug)] +pub struct SwitchOutput { + pub friends_messages: HashMap>, + pub index_mutations: Vec, + pub updated_remote_relays: Vec, + pub incoming_requests: Vec, + pub incoming_responses: Vec, + pub incoming_cancels: Vec, +} + +impl SwitchOutput { + pub fn new() -> Self { + SwitchOutput { + friends_messages: HashMap::new(), + index_mutations: Vec::new(), + updated_remote_relays: Vec::new(), + incoming_requests: Vec::new(), + incoming_responses: Vec::new(), + incoming_cancels: Vec::new(), + } + } + + pub fn add_friend_message(&mut self, public_key: PublicKey, friend_message: FriendMessage) { + let entry = self + .friends_messages + .entry(public_key) + .or_insert(Vec::new()); + (*entry).push(friend_message); + } + + pub fn add_index_mutation(&mut self, index_mutation: IndexMutation) { + self.index_mutations.push(index_mutation); + } + + // TODO: Add updated remote relays? + + pub fn add_incoming_request(&mut self, request: RequestSendFundsOp) { + self.incoming_requests.push(request); + } + + pub fn add_incoming_response(&mut self, response: ResponseSendFundsOp) { + self.incoming_responses.push(response); + } + + pub fn add_incoming_cancel(&mut self, cancel: CancelSendFundsOp) { + self.incoming_cancels.push(cancel); + } +} From 824f03873f6d9659fc4fb8ac651583c74a335570 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 16 Dec 2020 17:31:42 +0200 Subject: [PATCH 245/478] funder: Initial idea for collect_outgoing_move_token() --- components/funder/src/switch/switch.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index cc0c0b281..208e804bc 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -20,6 +20,19 @@ pub enum SwitchError { OpError(OpError), } +/// Attempt to create an outgoing move token +pub fn collect_outgoing_move_token() -> Result, SwitchError> { + // TODO: + // - Collect any pending responses and cancels + // - Collect user pending requests + // - Collect pending requests from other queues + // - Collect requests to add currencies (Currencies that are present in the config tables but + // not in `local_currencies` table. + // - Collect requests to remove currencies + // - Question: Is this saved in the database? + todo!(); +} + pub async fn set_friend_online( switch_db_client: &mut impl SwitchDbClient, switch_state: &mut SwitchState, @@ -56,6 +69,7 @@ pub async fn set_friend_online( } TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { // Resend outgoing move token. + // Resend with "request token back = true" if we have more things to send. todo!(); } From 5172cf4789bd9624f84719018ec1be795e04c04d Mon Sep 17 00:00:00 2001 From: real Date: Wed, 16 Dec 2020 17:32:11 +0200 Subject: [PATCH 246/478] database: Work on currency removal feature --- components/database/src/create.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 6c9e3729d..45e1899e3 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -337,6 +337,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE local_currencies( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, + mark_removal BOOL NOT NULL, + -- Is marked for removal? FOREIGN KEY(friend_public_key) REFERENCES consistent_channels(friend_public_key) ON DELETE CASCADE, From 89edda4d968020fd2301129cfbe8d24882ac1e00 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 16 Dec 2020 21:48:18 +0200 Subject: [PATCH 247/478] funder: Comment --- components/funder/src/switch/switch.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 208e804bc..3919e42c4 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -26,6 +26,11 @@ pub fn collect_outgoing_move_token() -> Result, SwitchError> { // - Collect any pending responses and cancels // - Collect user pending requests // - Collect pending requests from other queues + // - Question: How to order the pending responses, cancels and requests with respect to + // currencies? + // - Round robin? + // - first in first out (How to order)? + // - What is the solution for this in Offset v1? // - Collect requests to add currencies (Currencies that are present in the config tables but // not in `local_currencies` table. // - Collect requests to remove currencies From d2f14b23cdf0fa4c2950587f897b428365bd271e Mon Sep 17 00:00:00 2001 From: real Date: Wed, 16 Dec 2020 21:53:28 +0200 Subject: [PATCH 248/478] funder: Comment update --- components/funder/src/switch/switch.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 3919e42c4..e97270995 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -28,9 +28,7 @@ pub fn collect_outgoing_move_token() -> Result, SwitchError> { // - Collect pending requests from other queues // - Question: How to order the pending responses, cancels and requests with respect to // currencies? - // - Round robin? - // - first in first out (How to order)? - // - What is the solution for this in Offset v1? + // -- first in first out // - Collect requests to add currencies (Currencies that are present in the config tables but // not in `local_currencies` table. // - Collect requests to remove currencies From f220d6ff010351f91c1be365def4486b9f61d976 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 22 Dec 2020 15:49:35 +0200 Subject: [PATCH 249/478] database: Renamed column (generation -> index) --- components/database/src/create.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 45e1899e3..7646ff0b8 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -450,7 +450,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, - generation BLOB NOT NULL UNIQUE, + index BLOB NOT NULL UNIQUE, src_hashed_lock BLOB NOT NULL, route BLOB NOT NULL, dest_payment BLOB NOT NULL, @@ -471,7 +471,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_pending_user_requests_generation ON pending_user_requests(generation);", + "CREATE UNIQUE INDEX idx_pending_user_requests_index ON pending_user_requests(index);", params![], )?; @@ -480,7 +480,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, - generation BLOB NOT NULL UNIQUE, + index BLOB NOT NULL UNIQUE, src_hashed_lock BLOB NOT NULL, route BLOB NOT NULL, dest_payment BLOB NOT NULL, @@ -501,7 +501,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_pending_requests_generation ON pending_requests(generation);", + "CREATE UNIQUE INDEX idx_pending_requests_index ON pending_requests(index);", params![], )?; @@ -510,7 +510,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, - generation BLOB NOT NULL UNIQUE, + index BLOB NOT NULL UNIQUE, backwards_type TEXT CHECK (backwards_type IN ('R', 'C')) NOT NULL, -- R: Response, C: Cancel FOREIGN KEY(friend_public_key, currency) @@ -529,7 +529,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_pending_backwards_generation ON pending_backwards(generation);", + "CREATE UNIQUE INDEX idx_pending_backwards_index ON pending_backwards(index);", params![], )?; From a6f81eac1dc706c3e887e766689508970434e8b5 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 22 Dec 2020 16:31:11 +0200 Subject: [PATCH 250/478] database: Renamed index -> queue_index (Reserved keyword) --- components/database/src/create.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 7646ff0b8..b89ea8397 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -450,7 +450,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, - index BLOB NOT NULL UNIQUE, + queue_index BLOB NOT NULL UNIQUE, src_hashed_lock BLOB NOT NULL, route BLOB NOT NULL, dest_payment BLOB NOT NULL, @@ -471,7 +471,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_pending_user_requests_index ON pending_user_requests(index);", + "CREATE UNIQUE INDEX idx_pending_user_requests_queue_index ON pending_user_requests(queue_index);", params![], )?; @@ -480,7 +480,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, - index BLOB NOT NULL UNIQUE, + queue_index BLOB NOT NULL UNIQUE, src_hashed_lock BLOB NOT NULL, route BLOB NOT NULL, dest_payment BLOB NOT NULL, @@ -501,7 +501,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_pending_requests_index ON pending_requests(index);", + "CREATE UNIQUE INDEX idx_pending_requests_queue_index ON pending_requests(queue_index);", params![], )?; @@ -510,7 +510,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, - index BLOB NOT NULL UNIQUE, + queue_index BLOB NOT NULL UNIQUE, backwards_type TEXT CHECK (backwards_type IN ('R', 'C')) NOT NULL, -- R: Response, C: Cancel FOREIGN KEY(friend_public_key, currency) @@ -529,14 +529,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_pending_backwards_index ON pending_backwards(index);", + "CREATE UNIQUE INDEX idx_pending_backwards_queue_index ON pending_backwards(queue_index);", params![], )?; tx.execute( "CREATE TABLE pending_backwards_responses( - friend_public_key BLOB NOT NULL, - currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, backwards_type TEXT NOT NULL CHECK (backwards_type == 'R') @@ -544,8 +542,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { src_hashed_lock BLOB NOT NULL, serial_num BLOB NOT NULL, signature BLOB NOT NULL, - FOREIGN KEY(friend_public_key, currency, request_id, backwards_type) - REFERENCES pending_backwards(friend_public_key, currency, request_id, backwards_type) + FOREIGN KEY(request_id, backwards_type) + REFERENCES pending_backwards(request_id, backwards_type) ON DELETE CASCADE );", params![], @@ -558,14 +556,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE pending_backwards_cancels( - friend_public_key BLOB NOT NULL, - currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, backwards_type TEXT NOT NULL CHECK (backwards_type == 'C') DEFAULT 'C', - FOREIGN KEY(friend_public_key, currency, request_id, backwards_type) - REFERENCES pending_backwards(friend_public_key, currency, request_id, backwards_type) + FOREIGN KEY(request_id, backwards_type) + REFERENCES pending_backwards(request_id, backwards_type) ON DELETE CASCADE );", params![], From a8bfb0a772f19bbf173eeaef93f3416342968055 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 22 Dec 2020 16:39:25 +0200 Subject: [PATCH 251/478] database: Split queue to multiple queues, according to friend_public_key --- components/database/src/create.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index b89ea8397..92950f83f 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -480,7 +480,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, - queue_index BLOB NOT NULL UNIQUE, + queue_index BLOB NOT NULL, src_hashed_lock BLOB NOT NULL, route BLOB NOT NULL, dest_payment BLOB NOT NULL, @@ -488,6 +488,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { invoice_hash BLOB NOT NULL, hmac BLOB NOT NULL, left_fees BLOB NOT NULL, + UNIQUE (friend_public_key, queue_index), FOREIGN KEY(friend_public_key, currency) REFERENCES mutual_credits(friend_public_key, currency) ON DELETE CASCADE @@ -501,7 +502,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_pending_requests_queue_index ON pending_requests(queue_index);", + "CREATE UNIQUE INDEX idx_pending_requests_friend_public_key_queue_index ON pending_requests(friend_public_key, queue_index);", params![], )?; @@ -513,6 +514,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { queue_index BLOB NOT NULL UNIQUE, backwards_type TEXT CHECK (backwards_type IN ('R', 'C')) NOT NULL, -- R: Response, C: Cancel + UNIQUE (friend_public_key, queue_index), FOREIGN KEY(friend_public_key, currency) REFERENCES mutual_credits(friend_public_key, currency) ON DELETE CASCADE, @@ -529,7 +531,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; tx.execute( - "CREATE UNIQUE INDEX idx_pending_backwards_queue_index ON pending_backwards(queue_index);", + "CREATE UNIQUE INDEX idx_pending_backwards_friend_public_key_queue_index ON pending_backwards(friend_public_key, queue_index);", params![], )?; From 1606ca81d1e8547f6b89518e84d76bc3606ebd78 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 22 Dec 2020 17:50:06 +0200 Subject: [PATCH 252/478] funder: derive Debug for Liveness --- components/funder/src/liveness.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/funder/src/liveness.rs b/components/funder/src/liveness.rs index 21e37f22f..13c2401d8 100644 --- a/components/funder/src/liveness.rs +++ b/components/funder/src/liveness.rs @@ -2,7 +2,7 @@ use im::hashset::HashSet as ImHashSet; use proto::crypto::PublicKey; -#[derive(Clone, Default)] +#[derive(Debug, Clone, Default)] pub struct Liveness { pub friends: ImHashSet, } From 70d14e964aca91a047bcf80bfdd9f50fa56a5cdb Mon Sep 17 00:00:00 2001 From: real Date: Tue, 22 Dec 2020 17:50:38 +0200 Subject: [PATCH 253/478] proto: Added TODO comment (Renaming) --- components/proto/src/funder/messages.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index eca14c35d..f34ea44b8 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -152,6 +152,7 @@ pub struct Commit { pub signature: Signature, } +// TODO: Possibly shorten names inside enum? #[capnp_conv(crate::funder_capnp::friend_tc_op)] #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub enum FriendTcOp { From 70805f1ae7c097fd82d0262c052b9d36688c6669 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 22 Dec 2020 17:51:52 +0200 Subject: [PATCH 254/478] funder: Some work on collect_outgoing_move_token() --- components/funder/src/switch/switch.rs | 100 ++++++++++++++++++++++--- components/funder/src/switch/types.rs | 37 +++++++-- 2 files changed, 121 insertions(+), 16 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index e97270995..5cc1ee3bc 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -3,37 +3,115 @@ use std::collections::{HashMap, HashSet}; use common::async_rpc::OpError; +use identity::IdentityClient; + use proto::app_server::messages::RelayAddress; use proto::crypto::PublicKey; use proto::funder::messages::{ - CancelSendFundsOp, Currency, FriendMessage, MoveToken, RelaysUpdate, RequestSendFundsOp, - ResponseSendFundsOp, + CancelSendFundsOp, Currency, CurrencyOperations, FriendMessage, FriendTcOp, MoveToken, + RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, }; -use crate::switch::types::{SwitchDbClient, SwitchOutput, SwitchState}; -use crate::token_channel::{TcDbClient, TcStatus}; +use crate::switch::types::{BackwardsOp, SwitchDbClient, SwitchOutput, SwitchState}; +use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; #[derive(Debug, From)] pub enum SwitchError { FriendAlreadyOnline, GenerationOverflow, + TokenChannelError(TokenChannelError), OpError(OpError), } -/// Attempt to create an outgoing move token -pub fn collect_outgoing_move_token() -> Result, SwitchError> { +fn operations_vec_to_currencies_operations( + operations_vec: Vec<(Currency, FriendTcOp)>, +) -> Vec { + let mut operations_map = HashMap::>::new(); + for (currency, tc_op) in operations_vec { + let entry = operations_map.entry(currency).or_insert(Vec::new()); + (*entry).push(tc_op); + } + + // Sort by currency, for deterministic results: + let mut currencies_operations: Vec = operations_map + .into_iter() + .map(|(currency, operations)| CurrencyOperations { + currency, + operations, + }) + .collect(); + currencies_operations.sort_by(|co_a, co_b| co_a.currency.cmp(&co_b.currency)); + currencies_operations +} + +pub async fn collect_currencies_operations( + switch_db_client: &mut impl SwitchDbClient, + friend_public_key: PublicKey, + max_operations_in_batch: usize, +) -> Result, SwitchError> { + let mut operations_vec = Vec::<(Currency, FriendTcOp)>::new(); + + // Collect any pending responses and cancels: + while let Some((currency, backwards_op)) = switch_db_client + .pop_front_pending_backwards(friend_public_key.clone()) + .await? + { + let friend_tc_op = match backwards_op { + BackwardsOp::Response(response_op) => FriendTcOp::ResponseSendFunds(response_op), + BackwardsOp::Cancel(cancel_op) => FriendTcOp::CancelSendFunds(cancel_op), + }; + operations_vec.push((currency, friend_tc_op)); + + // Make sure we do not exceed maximum amount of operations: + if operations_vec.len() >= max_operations_in_batch { + return Ok(operations_vec_to_currencies_operations(operations_vec)); + } + } + // TODO: - // - Collect any pending responses and cancels + // - Collect user pending requests // - Collect pending requests from other queues - // - Question: How to order the pending responses, cancels and requests with respect to - // currencies? - // -- first in first out + + todo!(); +} + +/// Attempt to create an outgoing move token +pub async fn collect_outgoing_move_token( + switch_db_client: &mut impl SwitchDbClient, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + friend_public_key: PublicKey, + max_operations_in_batch: usize, +) -> Result, SwitchError> { + let currencies_operations = collect_currencies_operations( + switch_db_client, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + let mut currencies_diff = Vec::new(); + + // TODO: // - Collect requests to add currencies (Currencies that are present in the config tables but // not in `local_currencies` table. // - Collect requests to remove currencies - // - Question: Is this saved in the database? + // + // Possibly pack into one function? todo!(); + + Ok(Some( + handle_out_move_token( + switch_db_client.tc_db_client(friend_public_key.clone()), + identity_client, + currencies_operations, + currencies_diff, + local_public_key, + &friend_public_key, + ) + .await?, + )) } pub async fn set_friend_online( diff --git a/components/funder/src/switch/types.rs b/components/funder/src/switch/types.rs index 5305b8a89..abb4830c5 100644 --- a/components/funder/src/switch/types.rs +++ b/components/funder/src/switch/types.rs @@ -9,10 +9,23 @@ use crate::token_channel::TcDbClient; use proto::app_server::messages::{NamedRelayAddress, RelayAddress}; use proto::crypto::PublicKey; use proto::funder::messages::{ - CancelSendFundsOp, FriendMessage, RequestSendFundsOp, ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendMessage, RequestSendFundsOp, ResponseSendFundsOp, }; use proto::index_server::messages::IndexMutation; // use proto::funder::messages::{McBalance, PendingTransaction}; +// + +/// Switch's ephemeral state (Not saved inside the database) +#[derive(Debug)] +pub struct SwitchState { + pub liveness: Liveness, +} + +#[derive(Debug)] +pub enum BackwardsOp { + Response(ResponseSendFundsOp), + Cancel(CancelSendFundsOp), +} pub trait SwitchDbClient { type TcDbClient: TcDbClient; @@ -48,11 +61,25 @@ pub trait SwitchDbClient { /* fn get_balance(&mut self) -> AsyncOpResult; */ -} -/// Switch's ephemeral state (Not saved inside the database) -pub struct SwitchState { - pub liveness: Liveness, + /* + fn peek_pending_backwards( + &mut self, + friend_public_key: PublicKey, + ) -> AsyncOpResult; + */ + + fn pop_front_pending_backwards( + &mut self, + friend_public_key: PublicKey, + ) -> AsyncOpResult>; + + fn push_back_pending_backwards( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + backwards_op: BackwardsOp, + ) -> AsyncOpResult<()>; } #[derive(Debug)] From e875dd5de2fa1159a003a728bd9e807689a8349c Mon Sep 17 00:00:00 2001 From: real Date: Tue, 22 Dec 2020 18:16:53 +0200 Subject: [PATCH 255/478] funder: Work on collect_outgoing_move_token() --- components/funder/src/switch/switch.rs | 90 ++++++++++++++++++-------- components/funder/src/switch/types.rs | 24 +++++++ 2 files changed, 88 insertions(+), 26 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 5cc1ee3bc..dc48c595f 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -44,7 +44,7 @@ fn operations_vec_to_currencies_operations( currencies_operations } -pub async fn collect_currencies_operations( +async fn collect_currencies_operations( switch_db_client: &mut impl SwitchDbClient, friend_public_key: PublicKey, max_operations_in_batch: usize, @@ -68,16 +68,53 @@ pub async fn collect_currencies_operations( } } - // TODO: + // Collect any pending user requests: + while let Some((currency, request_op)) = switch_db_client + .pop_front_pending_user_requests(friend_public_key.clone()) + .await? + { + let friend_tc_op = FriendTcOp::RequestSendFunds(request_op); + operations_vec.push((currency, friend_tc_op)); + + // Make sure we do not exceed maximum amount of operations: + if operations_vec.len() >= max_operations_in_batch { + return Ok(operations_vec_to_currencies_operations(operations_vec)); + } + } - // - Collect user pending requests - // - Collect pending requests from other queues + // Collect any pending requests: + while let Some((currency, request_op)) = switch_db_client + .pop_front_pending_requests(friend_public_key.clone()) + .await? + { + let friend_tc_op = FriendTcOp::RequestSendFunds(request_op); + operations_vec.push((currency, friend_tc_op)); + + // Make sure we do not exceed maximum amount of operations: + if operations_vec.len() >= max_operations_in_batch { + return Ok(operations_vec_to_currencies_operations(operations_vec)); + } + } + Ok(operations_vec_to_currencies_operations(operations_vec)) +} + +async fn collect_currencies_diff( + switch_db_client: &mut impl SwitchDbClient, + friend_public_key: PublicKey, +) -> Result, SwitchError> { + // TODO: + // - Collect requests to add currencies (Currencies that are present in the config tables but + // not in `local_currencies` table. + // - Collect requests to remove currencies + // + // Possibly pack into one function? todo!(); } /// Attempt to create an outgoing move token -pub async fn collect_outgoing_move_token( +/// Return Ok(None) if we have nothing to send +async fn collect_outgoing_move_token( switch_db_client: &mut impl SwitchDbClient, identity_client: &mut IdentityClient, local_public_key: &PublicKey, @@ -91,27 +128,28 @@ pub async fn collect_outgoing_move_token( ) .await?; - let mut currencies_diff = Vec::new(); - - // TODO: - // - Collect requests to add currencies (Currencies that are present in the config tables but - // not in `local_currencies` table. - // - Collect requests to remove currencies - // - // Possibly pack into one function? - todo!(); - - Ok(Some( - handle_out_move_token( - switch_db_client.tc_db_client(friend_public_key.clone()), - identity_client, - currencies_operations, - currencies_diff, - local_public_key, - &friend_public_key, - ) - .await?, - )) + let mut currencies_diff = + collect_currencies_diff(switch_db_client, friend_public_key.clone()).await?; + + Ok( + if currencies_operations.is_empty() && currencies_diff.is_empty() { + // There is nothing interesting to send to remote side + None + } else { + // We have something to send to remote side + Some( + handle_out_move_token( + switch_db_client.tc_db_client(friend_public_key.clone()), + identity_client, + currencies_operations, + currencies_diff, + local_public_key, + &friend_public_key, + ) + .await?, + ) + }, + ) } pub async fn set_friend_online( diff --git a/components/funder/src/switch/types.rs b/components/funder/src/switch/types.rs index abb4830c5..f7f6296df 100644 --- a/components/funder/src/switch/types.rs +++ b/components/funder/src/switch/types.rs @@ -80,6 +80,30 @@ pub trait SwitchDbClient { currency: Currency, backwards_op: BackwardsOp, ) -> AsyncOpResult<()>; + + fn pop_front_pending_user_requests( + &mut self, + friend_public_key: PublicKey, + ) -> AsyncOpResult>; + + fn push_back_pending_user_requests( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + request_op: RequestSendFundsOp, + ) -> AsyncOpResult<()>; + + fn pop_front_pending_requests( + &mut self, + friend_public_key: PublicKey, + ) -> AsyncOpResult>; + + fn push_back_pending_requests( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + request_op: RequestSendFundsOp, + ) -> AsyncOpResult<()>; } #[derive(Debug)] From 78954d7fcfb48b26d7d94994335b49a4c94386d4 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 22 Dec 2020 18:24:53 +0200 Subject: [PATCH 256/478] database: Updated column name --- components/database/src/create.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 92950f83f..1fb417ee3 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -337,7 +337,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE local_currencies( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, - mark_removal BOOL NOT NULL, + is_remove BOOL NOT NULL, -- Is marked for removal? FOREIGN KEY(friend_public_key) REFERENCES consistent_channels(friend_public_key) From 8384c93a29f7fb0979b327455d733dfb7c2daa42 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 22 Dec 2020 18:45:46 +0200 Subject: [PATCH 257/478] funder: Initial impl of collect_outgoing_move_token() --- components/funder/src/switch/switch.rs | 29 ++++++++++++-------------- components/funder/src/switch/types.rs | 24 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index dc48c595f..0ac5bbd5f 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -99,19 +99,6 @@ async fn collect_currencies_operations( Ok(operations_vec_to_currencies_operations(operations_vec)) } -async fn collect_currencies_diff( - switch_db_client: &mut impl SwitchDbClient, - friend_public_key: PublicKey, -) -> Result, SwitchError> { - // TODO: - // - Collect requests to add currencies (Currencies that are present in the config tables but - // not in `local_currencies` table. - // - Collect requests to remove currencies - // - // Possibly pack into one function? - todo!(); -} - /// Attempt to create an outgoing move token /// Return Ok(None) if we have nothing to send async fn collect_outgoing_move_token( @@ -128,8 +115,9 @@ async fn collect_outgoing_move_token( ) .await?; - let mut currencies_diff = - collect_currencies_diff(switch_db_client, friend_public_key.clone()).await?; + let mut currencies_diff = switch_db_client + .currencies_diff(friend_public_key.clone()) + .await?; Ok( if currencies_operations.is_empty() && currencies_diff.is_empty() { @@ -233,7 +221,16 @@ pub async fn add_currency( todo!(); } -pub async fn remove_currency( +pub async fn set_remove_currency( + _switch_db_client: &mut impl SwitchDbClient, + _friend_public_key: PublicKey, + _currency: Currency, +) -> Result { + // TODO + todo!(); +} + +pub async fn unset_remove_currency( _switch_db_client: &mut impl SwitchDbClient, _friend_public_key: PublicKey, _currency: Currency, diff --git a/components/funder/src/switch/types.rs b/components/funder/src/switch/types.rs index f7f6296df..3cae155aa 100644 --- a/components/funder/src/switch/types.rs +++ b/components/funder/src/switch/types.rs @@ -104,6 +104,30 @@ pub trait SwitchDbClient { currency: Currency, request_op: RequestSendFundsOp, ) -> AsyncOpResult<()>; + + /* + /// Get a list of configured currencies that were not yet added as local currencies + fn currencies_to_add(&mut self, friend_public_key: PublicKey) -> AsyncOpResult>; + + /// Get a list of local currencies that can be removed at the moment. Options: + /// - Not present in remote currencies + /// - Present in remote currencies but have a zero balance + fn currencies_to_remove( + &mut self, + friend_public_key: PublicKey, + ) -> AsyncOpResult>; + */ + + /// Add currencies + /// -------------- + /// Get a list of configured currencies that were not yet added as local currencies + /// + /// Remove currencies + /// ----------------- + /// Get a list of local currencies that can be removed at the moment. Options: + /// - Not present in remote currencies + /// - Present in remote currencies but have a zero balance + fn currencies_diff(&mut self, friend_public_key: PublicKey) -> AsyncOpResult>; } #[derive(Debug)] From 044eff13a24e2a7a9a397b67998399e2976d552c Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 11:24:22 +0200 Subject: [PATCH 258/478] funder: Work on collect_outgoing_move_token() --- components/funder/src/switch/switch.rs | 49 ++++++++++++++++++-------- components/funder/src/switch/types.rs | 21 +++++++---- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 0ac5bbd5f..10c33a0fc 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -9,7 +9,7 @@ use proto::app_server::messages::RelayAddress; use proto::crypto::PublicKey; use proto::funder::messages::{ CancelSendFundsOp, Currency, CurrencyOperations, FriendMessage, FriendTcOp, MoveToken, - RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, + MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, }; use crate::switch::types::{BackwardsOp, SwitchDbClient, SwitchOutput, SwitchState}; @@ -53,7 +53,7 @@ async fn collect_currencies_operations( // Collect any pending responses and cancels: while let Some((currency, backwards_op)) = switch_db_client - .pop_front_pending_backwards(friend_public_key.clone()) + .pending_backwards_pop_front(friend_public_key.clone()) .await? { let friend_tc_op = match backwards_op { @@ -70,7 +70,7 @@ async fn collect_currencies_operations( // Collect any pending user requests: while let Some((currency, request_op)) = switch_db_client - .pop_front_pending_user_requests(friend_public_key.clone()) + .pending_user_requests_pop_front(friend_public_key.clone()) .await? { let friend_tc_op = FriendTcOp::RequestSendFunds(request_op); @@ -84,7 +84,7 @@ async fn collect_currencies_operations( // Collect any pending requests: while let Some((currency, request_op)) = switch_db_client - .pop_front_pending_requests(friend_public_key.clone()) + .pending_requests_pop_front(friend_public_key.clone()) .await? { let friend_tc_op = FriendTcOp::RequestSendFunds(request_op); @@ -99,6 +99,22 @@ async fn collect_currencies_operations( Ok(operations_vec_to_currencies_operations(operations_vec)) } +/// Do we have more pending currencies operations? +async fn is_pending_currencies_operations( + switch_db_client: &mut impl SwitchDbClient, + friend_public_key: PublicKey, +) -> Result { + Ok(!switch_db_client + .pending_backwards_is_empty(friend_public_key.clone()) + .await? + || !switch_db_client + .pending_user_requests_is_empty(friend_public_key.clone()) + .await? + || !switch_db_client + .pending_requests_is_empty(friend_public_key.clone()) + .await?) +} + /// Attempt to create an outgoing move token /// Return Ok(None) if we have nothing to send async fn collect_outgoing_move_token( @@ -107,7 +123,7 @@ async fn collect_outgoing_move_token( local_public_key: &PublicKey, friend_public_key: PublicKey, max_operations_in_batch: usize, -) -> Result, SwitchError> { +) -> Result, SwitchError> { let currencies_operations = collect_currencies_operations( switch_db_client, friend_public_key.clone(), @@ -125,17 +141,20 @@ async fn collect_outgoing_move_token( None } else { // We have something to send to remote side - Some( - handle_out_move_token( - switch_db_client.tc_db_client(friend_public_key.clone()), - identity_client, - currencies_operations, - currencies_diff, - local_public_key, - &friend_public_key, - ) - .await?, + let move_token = handle_out_move_token( + switch_db_client.tc_db_client(friend_public_key.clone()), + identity_client, + currencies_operations, + currencies_diff, + local_public_key, + &friend_public_key, ) + .await?; + Some(MoveTokenRequest { + move_token, + token_wanted: is_pending_currencies_operations(switch_db_client, friend_public_key) + .await?, + }) }, ) } diff --git a/components/funder/src/switch/types.rs b/components/funder/src/switch/types.rs index 3cae155aa..5f4e11137 100644 --- a/components/funder/src/switch/types.rs +++ b/components/funder/src/switch/types.rs @@ -69,42 +69,51 @@ pub trait SwitchDbClient { ) -> AsyncOpResult; */ - fn pop_front_pending_backwards( + fn pending_backwards_pop_front( &mut self, friend_public_key: PublicKey, ) -> AsyncOpResult>; - fn push_back_pending_backwards( + fn pending_backwards_push_back( &mut self, friend_public_key: PublicKey, currency: Currency, backwards_op: BackwardsOp, ) -> AsyncOpResult<()>; - fn pop_front_pending_user_requests( + fn pending_backwards_is_empty(&mut self, friend_public_key: PublicKey) -> AsyncOpResult; + + fn pending_user_requests_pop_front( &mut self, friend_public_key: PublicKey, ) -> AsyncOpResult>; - fn push_back_pending_user_requests( + fn pending_user_requests_push_back( &mut self, friend_public_key: PublicKey, currency: Currency, request_op: RequestSendFundsOp, ) -> AsyncOpResult<()>; - fn pop_front_pending_requests( + fn pending_user_requests_is_empty( + &mut self, + friend_public_key: PublicKey, + ) -> AsyncOpResult; + + fn pending_requests_pop_front( &mut self, friend_public_key: PublicKey, ) -> AsyncOpResult>; - fn push_back_pending_requests( + fn pending_requests_push_back( &mut self, friend_public_key: PublicKey, currency: Currency, request_op: RequestSendFundsOp, ) -> AsyncOpResult<()>; + fn pending_requests_is_empty(&mut self, friend_public_key: PublicKey) -> AsyncOpResult; + /* /// Get a list of configured currencies that were not yet added as local currencies fn currencies_to_add(&mut self, friend_public_key: PublicKey) -> AsyncOpResult>; From 4f6106da7b4f34ac96a58817a97b284449fe71a4 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 12:01:25 +0200 Subject: [PATCH 259/478] funder: Some work on set_friend_online() --- components/funder/src/switch/switch.rs | 58 ++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 10c33a0fc..96db47dbe 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -159,15 +159,34 @@ async fn collect_outgoing_move_token( ) } +/// Check if we have anything to send to a remove friend on a move token message, +/// without performing any data mutations +async fn is_pending_move_token( + switch_db_client: &mut impl SwitchDbClient, + friend_public_key: PublicKey, +) -> Result { + Ok( + is_pending_currencies_operations(switch_db_client, friend_public_key.clone()).await? + || !switch_db_client + .currencies_diff(friend_public_key.clone()) + .await? + .is_empty(), + ) +} + pub async fn set_friend_online( switch_db_client: &mut impl SwitchDbClient, switch_state: &mut SwitchState, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, friend_public_key: PublicKey, + max_operations_in_batch: usize, ) -> Result { if switch_state.liveness.is_online(&friend_public_key) { // The friend is already marked as online! return Err(SwitchError::FriendAlreadyOnline); } + switch_state.liveness.set_online(friend_public_key.clone()); let mut output = SwitchOutput::new(); @@ -183,7 +202,6 @@ pub async fn set_friend_online( ); } - // TODO: Attempt to reconstruct and send last outgoing message, if exists. match switch_db_client .tc_db_client(friend_public_key.clone()) .get_tc_status() @@ -191,13 +209,37 @@ pub async fn set_friend_online( { TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. - todo!(); + let opt_move_token_request = collect_outgoing_move_token( + switch_db_client, + identity_client, + local_public_key, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + if let Some(move_token_request) = opt_move_token_request { + // We have something to send to remote side: + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(move_token_request), + ); + } } TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { - // Resend outgoing move token. - - // Resend with "request token back = true" if we have more things to send. - todo!(); + // Resend outgoing move token, + // possibly asking for the token if we have something to send + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(MoveTokenRequest { + move_token: move_token_out, + token_wanted: is_pending_move_token( + switch_db_client, + friend_public_key.clone(), + ) + .await?, + }), + ); } TcStatus::Inconsistent(..) => { // Resend reset terms @@ -205,9 +247,7 @@ pub async fn set_friend_online( } } - // TODO: Maybe change liveness to work directly, without the mutations concept? - // Maybe we don't need atomicity for the liveness struct? - switch_state.liveness.set_online(friend_public_key.clone()); + Ok(output) } pub async fn set_friend_offline( From 150bdb541eda860e5bd1116c8fd2a40ccad86aa8 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 13:16:13 +0200 Subject: [PATCH 260/478] funder: TcStatus::Inconsistent now contains full balances list --- .../funder/src/token_channel/tests/utils.rs | 11 +------- .../funder/src/token_channel/token_channel.rs | 28 +++++++++---------- components/funder/src/token_channel/types.rs | 3 +- 3 files changed, 16 insertions(+), 26 deletions(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index dca3a5e45..618fb7b97 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -140,16 +140,7 @@ impl TcDbClient for MockTokenChannel { } }, MockTcStatus::Inconsistent(local_reset_terms, opt_remote_reset_terms) => { - TcStatus::Inconsistent( - local_reset_terms.reset_token.clone(), - local_reset_terms.move_token_counter, - opt_remote_reset_terms.as_ref().map(|remote_reset_terms| { - ( - remote_reset_terms.reset_token.clone(), - remote_reset_terms.move_token_counter.clone(), - ) - }), - ) + TcStatus::Inconsistent(local_reset_terms.clone(), opt_remote_reset_terms.clone()) } }); Box::pin(future::ready(res)) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index f8185344b..77c64c18d 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -269,9 +269,9 @@ where ) .await } - TcStatus::Inconsistent(local_reset_token, local_reset_move_token_counter, _opt_remote) => { + TcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { // Might be a reset move token - if new_move_token.old_token == local_reset_token { + if new_move_token.old_token == local_reset_terms.reset_token { // This is a reset move token! // Simulate an outgoing move token with the correct `new_token`: @@ -282,7 +282,8 @@ where }, )) .await?, - move_token_counter: local_reset_move_token_counter + move_token_counter: local_reset_terms + .move_token_counter .checked_sub(1) .ok_or(TokenChannelError::MoveTokenCounterOverflow)?, }; @@ -292,7 +293,7 @@ where currencies_operations: Vec::new(), currencies_diff: Vec::new(), info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), - new_token: local_reset_token.clone(), + new_token: local_reset_terms.reset_token.clone(), }; // Atomically attempt to handle a reset move token: @@ -314,16 +315,16 @@ where let invalid_incoming = e?; // In this case the transaction was not committed: Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { - reset_token: local_reset_token, - move_token_counter: local_reset_move_token_counter, + reset_token: local_reset_terms.reset_token, + move_token_counter: local_reset_terms.move_token_counter, reset_balances: local_balances_for_reset(tc_client).await?, })) } } } else { Ok(ReceiveMoveTokenOutput::ChainInconsistent(ResetTerms { - reset_token: local_reset_token, - move_token_counter: local_reset_move_token_counter, + reset_token: local_reset_terms.reset_token, + move_token_counter: local_reset_terms.move_token_counter, reset_balances: local_balances_for_reset(tc_client).await?, })) } @@ -848,15 +849,14 @@ pub async fn accept_remote_reset( match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(..) | TcStatus::ConsistentOut(..) - | TcStatus::Inconsistent(_, _, None) => { + | TcStatus::Inconsistent(_, None) => { // We don't have the remote side's reset terms yet: return Err(TokenChannelError::InvalidTokenChannelStatus); } - TcStatus::Inconsistent( - _local_reset_token, - _local_reset_move_token_counter, - Some((remote_reset_token, remote_reset_move_token_counter)), - ) => (remote_reset_token, remote_reset_move_token_counter), + TcStatus::Inconsistent(_local_reset_terms, Some(remote_reset_terms)) => ( + remote_reset_terms.reset_token, + remote_reset_terms.move_token_counter, + ), }; // Simulate an incoming move token with the correct `new_token`: diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 06e92ce71..38c6bfc67 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -47,8 +47,7 @@ pub struct ResetTerms { pub enum TcStatus { ConsistentIn(MoveTokenHashed), // (move_token_in) ConsistentOut(MoveToken, Option), // (move_token_out, last_move_token_in) - Inconsistent(Signature, u128, Option<(Signature, u128)>), - // (local_reset_token, local_reset_move_token_counter, Option<(remote_reset_token, remote_reset_move_token_counter)>) + Inconsistent(ResetTerms, Option), // (local_reset_terms, Option Date: Wed, 23 Dec 2020 13:17:59 +0200 Subject: [PATCH 261/478] funder: TODO comment --- components/funder/src/token_channel/types.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 38c6bfc67..dbf603259 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -47,6 +47,9 @@ pub struct ResetTerms { pub enum TcStatus { ConsistentIn(MoveTokenHashed), // (move_token_in) ConsistentOut(MoveToken, Option), // (move_token_out, last_move_token_in) + // TODO: Is it too wasteful to save all the balances in memory? + // We took this decision because we assume that we might need to send all those balances in a + // message at some point anyways. Maybe could be improved in the future. Inconsistent(ResetTerms, Option), // (local_reset_terms, Option Date: Wed, 23 Dec 2020 13:36:49 +0200 Subject: [PATCH 262/478] funder: Some comments and thoughts --- components/funder/src/switch/switch.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 96db47dbe..ee3a225f3 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -241,8 +241,25 @@ pub async fn set_friend_online( }), ); } - TcStatus::Inconsistent(..) => { + TcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { + // Convert to proto's reset terms: + // TODO: This will probably not be required in the future, when we move to another + // serialization strategy? + + /* + let proto_local_reset_terms = proto::funder::messages::ResetTerms { + reset_token: local_reset_terms.reset_token, + move_token_counter: local_reset_terms.move_token_counter, + balance_for_reset: local_reset_terms.reset_balances.into_iter(|(currency, reset_balance) + + } + // Resend reset terms + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::InconsistencyError(local_reset_terms), + ); + */ todo!(); } } From 9909a98208ae6a3a4b5608fe0bbfdbd496327cfc Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 19:07:40 +0200 Subject: [PATCH 263/478] proto: Remove usage of capnp --- Cargo.lock | 3 - components/proto/Cargo.toml | 7 -- components/proto/build.rs | 22 ------ components/proto/src/app_server/messages.rs | 19 +----- components/proto/src/crypto/mod.rs | 30 ++------ components/proto/src/funder/messages.rs | 68 +++---------------- components/proto/src/index_client/messages.rs | 5 -- components/proto/src/index_server/messages.rs | 23 ------- components/proto/src/keepalive/messages.rs | 3 - components/proto/src/lib.rs | 12 ++-- components/proto/src/net/messages.rs | 3 - components/proto/src/relay/messages.rs | 5 -- components/proto/src/report/messages.rs | 33 --------- .../proto/src/secure_channel/messages.rs | 9 --- 14 files changed, 26 insertions(+), 216 deletions(-) delete mode 100644 components/proto/build.rs diff --git a/Cargo.lock b/Cargo.lock index 559c024bd..981c53038 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1307,13 +1307,10 @@ dependencies = [ "base64 0.10.1", "byteorder", "bytes", - "capnp", - "capnpc", "derive_more 0.14.1", "im", "num-bigint", "num-traits", - "offset-capnp-conv", "offset-common", "offset-mutual-from", "paste 0.1.16", diff --git a/components/proto/Cargo.toml b/components/proto/Cargo.toml index 7bb482c06..1055a9524 100644 --- a/components/proto/Cargo.toml +++ b/components/proto/Cargo.toml @@ -3,16 +3,12 @@ name = "offset-proto" version = "0.1.0" authors = ["real "] license = "MIT OR Apache-2.0" -build = "build.rs" edition = "2018" [dependencies] common = { path = "../common", version = "0.1.0", package = "offset-common" } offset-mutual-from = { path = "../mutual_from", version = "0.1.0"} -capnp_conv = { path = "../capnp_conv", version = "0.1.0", package = "offset-capnp-conv" } - -capnp = "0.10.0" byteorder = "1.1" @@ -39,6 +35,3 @@ rand = {version = "0.7.2"} [dev-dependencies] tempfile = "3.1.0" - -[build-dependencies] -capnpc = "0.10.0" diff --git a/components/proto/build.rs b/components/proto/build.rs deleted file mode 100644 index 451f45356..000000000 --- a/components/proto/build.rs +++ /dev/null @@ -1,22 +0,0 @@ -macro_rules! build_schema { - ($($path: expr),*) => { - capnpc::CompilerCommand::new() - .src_prefix("src/") - $(.file($path))* - .run() - .unwrap(); - }; -} - -fn main() { - build_schema! { - "src/schema/common.capnp", - "src/schema/funder.capnp", - "src/schema/dh.capnp", - "src/schema/relay.capnp", - "src/schema/keepalive.capnp", - "src/schema/app_server.capnp", - "src/schema/report.capnp", - "src/schema/index.capnp" - } -} diff --git a/components/proto/src/app_server/messages.rs b/components/proto/src/app_server/messages.rs index f28951bbc..37c9c5706 100644 --- a/components/proto/src/app_server/messages.rs +++ b/components/proto/src/app_server/messages.rs @@ -1,14 +1,12 @@ use serde::{Deserialize, Serialize}; -use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; - use common::ser_utils::ser_b64; use crate::crypto::{InvoiceId, NodePort, PaymentId, PublicKey, Uid}; // use crate::wrapper::Wrapper; use crate::funder::messages::{ - AckClosePayment, AddFriend, AddInvoice, Commit, CreatePayment, CreateTransaction, Currency, + AckClosePayment, AddFriend, AddInvoice, CreatePayment, CreateTransaction, Currency, RemoveFriendCurrency, ResetFriendChannel, ResponseClosePayment, SetFriendCurrencyMaxDebt, SetFriendCurrencyRate, SetFriendName, SetFriendRelays, TransactionResult, }; @@ -19,7 +17,6 @@ use crate::net::messages::NetAddress; // TODO: Move NamedRelayAddress and RelayAddress to another place in offset-proto? -#[capnp_conv(crate::common_capnp::named_relay_address)] #[derive(Arbitrary, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct NamedRelayAddress { @@ -29,14 +26,12 @@ pub struct NamedRelayAddress { pub name: String, } -#[capnp_conv(crate::common_capnp::relay_address)] #[derive(Arbitrary, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RelayAddress { #[serde(with = "ser_b64")] pub public_key: PublicKey, pub address: B, - // #[capnp_conv(with = Wrapper)] #[serde(with = "ser_b64")] pub port: NodePort, } @@ -53,14 +48,12 @@ impl From> for RelayAddress { */ /* -#[capnp_conv(crate::report_capnp::node_report)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct NodeReport { pub funder_report: FunderReport, pub index_client_report: IndexClientReport, } -#[capnp_conv(crate::report_capnp::node_report_mutation)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum NodeReportMutation { Funder(FunderReportMutation), @@ -93,17 +86,14 @@ impl From for Option { } /* -#[capnp_conv(crate::app_server_capnp::report_mutations)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ReportMutations { - #[capnp_conv(with = OptAppRequestId)] pub opt_app_request_id: Option, pub mutations: Vec>, } */ #[allow(clippy::large_enum_variant)] -#[capnp_conv(crate::app_server_capnp::app_server_to_app)] #[derive(Debug, PartialEq, Eq)] pub enum AppServerToApp { /// Funds: @@ -121,14 +111,12 @@ pub enum NamedRelaysMutation { RemoveRelay(PublicKey), } -#[capnp_conv(crate::app_server_capnp::open_friend_currency)] #[derive(Debug, PartialEq, Eq, Clone)] pub struct OpenFriendCurrency { pub friend_public_key: PublicKey, pub currency: Currency, } -#[capnp_conv(crate::app_server_capnp::close_friend_currency)] #[derive(Debug, PartialEq, Eq, Clone)] pub struct CloseFriendCurrency { pub friend_public_key: PublicKey, @@ -136,7 +124,6 @@ pub struct CloseFriendCurrency { } #[allow(clippy::large_enum_variant)] -#[capnp_conv(crate::app_server_capnp::app_request)] #[derive(Debug, PartialEq, Eq, Clone)] pub enum AppRequest { /// Manage locally used relays: @@ -163,14 +150,13 @@ pub enum AppRequest { /// Seller: AddInvoice(AddInvoice), CancelInvoice(InvoiceId), - CommitInvoice(Commit), + //CommitInvoice(Commit), /// Request routes from one node to another: RequestRoutes(RequestRoutes), /// Manage index servers: AddIndexServer(NamedIndexServerAddress), RemoveIndexServer(PublicKey), } -#[capnp_conv(crate::app_server_capnp::app_to_app_server)] #[derive(Debug, PartialEq, Eq, Clone)] pub struct AppToAppServer { pub app_request_id: Uid, @@ -226,7 +212,6 @@ where } */ -#[capnp_conv(crate::app_server_capnp::app_permissions)] #[derive(Arbitrary, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct AppPermissions { diff --git a/components/proto/src/crypto/mod.rs b/components/proto/src/crypto/mod.rs index 4820f6ada..e91a1e304 100644 --- a/components/proto/src/crypto/mod.rs +++ b/components/proto/src/crypto/mod.rs @@ -1,68 +1,50 @@ -use std::convert::TryFrom; +// use std::convert::TryFrom; -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +// use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::{Deserialize, Serialize}; -use capnp_conv::{CapnpConvError, ReadCapnp, WriteCapnp}; +// use capnp_conv::{CapnpConvError, ReadCapnp, WriteCapnp}; use common::big_array::BigArray; use common::define_fixed_bytes; -use crate::common_capnp; +// use crate::common_capnp; -#[macro_use] -mod serialize; +// #[macro_use] +// mod serialize; // use self::serialize::{type_capnp_serde128, type_capnp_serde256, type_capnp_serde512}; // define_fixed_bytes!(HmacResult, 32); -type_capnp_serde!(HmacResult, common_capnp::hmac_result, (x0, x1, x2, x3)); define_fixed_bytes!(HmacKey, 32); -type_capnp_serde!(HmacKey, common_capnp::hmac_key, (x0, x1, x2, x3)); define_fixed_bytes!(HashResult, 32); -type_capnp_serde!(HashResult, common_capnp::hash_result, (x0, x1, x2, x3)); define_fixed_bytes!(Salt, 32); -type_capnp_serde!(Salt, common_capnp::salt, (x0, x1, x2, x3)); define_fixed_bytes!(DhPublicKey, 32); -type_capnp_serde!(DhPublicKey, common_capnp::dh_public_key, (x0, x1, x2, x3)); define_fixed_bytes!(PlainLock, 32); -type_capnp_serde!(PlainLock, common_capnp::plain_lock, (x0, x1, x2, x3)); define_fixed_bytes!(HashedLock, 32); -type_capnp_serde!(HashedLock, common_capnp::hashed_lock, (x0, x1, x2, x3)); define_fixed_bytes!(PublicKey, 32); -type_capnp_serde!(PublicKey, common_capnp::public_key, (x0, x1, x2, x3)); // PKCS8 key pair define_fixed_bytes!(PrivateKey, 32); define_fixed_bytes!(Signature, 64); -type_capnp_serde!( - Signature, - common_capnp::signature, - (x0, x1, x2, x3, x4, x5, x6, x7) -); // An invoice identifier define_fixed_bytes!(InvoiceId, 32); -type_capnp_serde!(InvoiceId, common_capnp::invoice_id, (x0, x1, x2, x3)); define_fixed_bytes!(PaymentId, 16); -type_capnp_serde!(PaymentId, common_capnp::payment_id, (x0, x1)); define_fixed_bytes!(NodePort, 16); -type_capnp_serde!(NodePort, common_capnp::node_port, (x0, x1)); define_fixed_bytes!(RandValue, 16); -type_capnp_serde!(RandValue, common_capnp::rand_value, (x0, x1)); // An Universally Unique Identifier (UUID). define_fixed_bytes!(Uid, 16); -type_capnp_serde!(Uid, common_capnp::uid, (x0, x1)); diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index f34ea44b8..f1d07e440 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -13,8 +13,6 @@ use derive_more::Display; use num_bigint::BigUint; use num_traits::cast::ToPrimitive; -use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; - use crate::crypto::{ HashResult, HashedLock, HmacResult, InvoiceId, PaymentId, PlainLock, PublicKey, Signature, Uid, }; @@ -26,7 +24,7 @@ use crate::net::messages::NetAddress; use common::ser_utils::{ser_b64, ser_string, ser_vec_b64}; use common::u256::U256; -use crate::wrapper::Wrapper; +// use crate::wrapper::Wrapper; #[derive(Debug, Clone)] pub struct ChannelerUpdateFriend { @@ -68,14 +66,12 @@ pub const InvoiceId::len(): usize = 32; define_fixed_bytes!(InvoiceId, InvoiceId::len()); */ -#[capnp_conv(crate::funder_capnp::friends_route)] #[derive(Arbitrary, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct FriendsRoute { #[serde(with = "ser_vec_b64")] pub public_keys: Vec, } -#[capnp_conv(crate::funder_capnp::request_send_funds_op)] #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct RequestSendFundsOp { #[serde(with = "ser_b64")] @@ -83,28 +79,23 @@ pub struct RequestSendFundsOp { #[serde(with = "ser_b64")] pub src_hashed_lock: HashedLock, pub route: FriendsRoute, - #[capnp_conv(with = Wrapper)] pub dest_payment: u128, - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub total_dest_payment: u128, #[serde(with = "ser_b64")] pub invoice_hash: HashResult, #[serde(with = "ser_b64")] pub hmac: HmacResult, - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub left_fees: u128, } -#[capnp_conv(crate::funder_capnp::response_send_funds_op)] #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct ResponseSendFundsOp { #[serde(with = "ser_b64")] pub request_id: Uid, #[serde(with = "ser_b64")] pub src_plain_lock: PlainLock, - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub serial_num: u128, #[serde(with = "ser_b64")] @@ -121,15 +112,14 @@ pub struct UnsignedResponseSendFundsOp { pub serial_num: u128, } -#[capnp_conv(crate::funder_capnp::cancel_send_funds_op)] #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct CancelSendFundsOp { #[serde(with = "ser_b64")] pub request_id: Uid, } +/* #[allow(clippy::large_enum_variant)] -#[capnp_conv(crate::common_capnp::commit)] #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct Commit { #[serde(with = "ser_b64")] @@ -138,10 +128,8 @@ pub struct Commit { pub src_plain_lock: PlainLock, #[serde(with = "ser_b64")] pub dest_hashed_lock: HashedLock, - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub dest_payment: u128, - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub total_dest_payment: u128, #[serde(with = "ser_b64")] @@ -151,9 +139,9 @@ pub struct Commit { #[serde(with = "ser_b64")] pub signature: Signature, } +*/ // TODO: Possibly shorten names inside enum? -#[capnp_conv(crate::funder_capnp::friend_tc_op)] #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub enum FriendTcOp { RequestSendFunds(RequestSendFundsOp), @@ -162,7 +150,6 @@ pub enum FriendTcOp { } /* -#[capnp_conv(crate::funder_capnp::move_token::opt_local_relays)] #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub enum OptLocalRelays { Empty, @@ -236,7 +223,6 @@ pub struct TokenInfo { pub move_token_counter: u128, } -#[capnp_conv(crate::funder_capnp::currency_operations)] #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct CurrencyOperations { #[serde(with = "ser_string")] @@ -244,7 +230,6 @@ pub struct CurrencyOperations { pub operations: Vec, } -#[capnp_conv(crate::funder_capnp::move_token)] #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct MoveToken { #[serde(with = "ser_b64")] @@ -284,7 +269,6 @@ impl Into> for MoveToken { } */ -#[capnp_conv(crate::common_capnp::currency)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] #[display(fmt = "{}", currency)] pub struct Currency { @@ -350,26 +334,22 @@ impl quickcheck::Arbitrary for Currency { } } -#[capnp_conv(crate::funder_capnp::currency_balance)] #[derive(Arbitrary, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct CurrencyBalance { pub currency: Currency, - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub balance: i128, } -#[capnp_conv(crate::funder_capnp::reset_terms)] #[derive(Arbitrary, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ResetTerms { #[serde(with = "ser_b64")] pub reset_token: Signature, - #[capnp_conv(with = Wrapper)] + #[serde(with = "ser_string")] pub move_token_counter: u128, pub balance_for_reset: Vec, } -#[capnp_conv(crate::funder_capnp::move_token_request)] #[derive(Arbitrary, PartialEq, Eq, Clone, Serialize, Debug)] pub struct MoveTokenRequest { pub move_token: MoveToken, @@ -377,15 +357,12 @@ pub struct MoveTokenRequest { pub token_wanted: bool, } -#[capnp_conv(crate::funder_capnp::relays_update)] #[derive(Arbitrary, PartialEq, Eq, Clone, Serialize, Debug)] pub struct RelaysUpdate { - #[capnp_conv(with = Wrapper)] pub generation: u128, pub relays: Vec>, } -#[capnp_conv(crate::funder_capnp::friend_message)] #[allow(clippy::large_enum_variant)] #[derive(PartialEq, Eq, Debug, Clone)] pub enum FriendMessage { @@ -395,9 +372,9 @@ pub enum FriendMessage { RelaysAck(Uid), } +/* /// A `Receipt` is received if a `RequestSendFunds` is successful. /// It can be used a proof of payment for a specific `invoice_id`. -#[capnp_conv(crate::common_capnp::receipt)] #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct Receipt { @@ -412,10 +389,8 @@ pub struct Receipt { #[serde(with = "ser_b64")] pub dest_plain_lock: PlainLock, pub is_complete: bool, - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub dest_payment: u128, - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub total_dest_payment: u128, #[serde(with = "ser_b64")] @@ -434,6 +409,7 @@ pub struct Receipt { # ) */ } +*/ #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct PendingTransaction { @@ -579,7 +555,6 @@ impl RequestsStatus { /// Rates for forwarding a transaction /// For a transaction of `x` credits, the amount of fees will be: /// `(x * mul) / 2^32 + add` -#[capnp_conv(crate::common_capnp::rate)] #[derive(Arbitrary, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct Rate { @@ -626,7 +601,6 @@ impl Rate { } } -#[capnp_conv(crate::app_server_capnp::add_friend)] #[derive(Arbitrary, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct AddFriend { #[serde(with = "ser_b64")] @@ -653,37 +627,32 @@ pub struct SetFriendStatus { pub status: FriendStatus, } -#[capnp_conv(crate::app_server_capnp::set_friend_currency_max_debt)] -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct SetFriendCurrencyMaxDebt { pub friend_public_key: PublicKey, pub currency: Currency, - #[capnp_conv(with = Wrapper)] + #[serde(with = "ser_string")] pub remote_max_debt: u128, } -#[capnp_conv(crate::app_server_capnp::set_friend_name)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct SetFriendName { pub friend_public_key: PublicKey, pub name: String, } -#[capnp_conv(crate::app_server_capnp::set_friend_relays)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct SetFriendRelays { pub friend_public_key: PublicKey, pub relays: Vec>, } -#[capnp_conv(crate::app_server_capnp::reset_friend_channel)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ResetFriendChannel { pub friend_public_key: PublicKey, pub reset_token: Signature, } -#[capnp_conv(crate::app_server_capnp::set_friend_currency_rate)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct SetFriendCurrencyRate { pub friend_public_key: PublicKey, @@ -691,7 +660,6 @@ pub struct SetFriendCurrencyRate { pub rate: Rate, } -#[capnp_conv(crate::app_server_capnp::remove_friend_currency)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct RemoveFriendCurrency { pub friend_public_key: PublicKey, @@ -705,7 +673,6 @@ struct FriendsRouteCapacity { capacity: u128, } -#[capnp_conv(crate::app_server_capnp::receipt_ack)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ReceiptAck { pub request_id: Uid, @@ -713,7 +680,6 @@ pub struct ReceiptAck { } /// Start a payment, possibly by paying through multiple routes. -#[capnp_conv(crate::app_server_capnp::create_payment)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct CreatePayment { /// payment_id is a randomly generated value (by the user), allowing the user to refer to a @@ -721,13 +687,11 @@ pub struct CreatePayment { pub payment_id: PaymentId, pub invoice_id: InvoiceId, pub currency: Currency, - #[capnp_conv(with = Wrapper)] pub total_dest_payment: u128, pub dest_public_key: PublicKey, } /// Start a payment, possibly by paying through multiple routes. -#[capnp_conv(crate::app_server_capnp::create_transaction)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct CreateTransaction { /// A payment id of an existing payment. @@ -736,14 +700,11 @@ pub struct CreateTransaction { /// allows the user to refer to this request later. pub request_id: Uid, pub route: FriendsRoute, - #[capnp_conv(with = Wrapper)] pub dest_payment: u128, - #[capnp_conv(with = Wrapper)] pub fees: u128, } /// Start an invoice (A request for payment). -#[capnp_conv(crate::app_server_capnp::add_invoice)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct AddInvoice { /// Randomly generated invoice_id, allows to refer to this invoice. @@ -751,12 +712,10 @@ pub struct AddInvoice { /// Currency in use pub currency: Currency, /// Total amount of credits to be paid. - #[capnp_conv(with = Wrapper)] pub total_dest_payment: u128, } /// Start an invoice (A request for payment). -#[capnp_conv(crate::app_server_capnp::ack_close_payment)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct AckClosePayment { pub payment_id: PaymentId, @@ -786,7 +745,7 @@ pub enum FunderControl { // Seller API: AddInvoice(AddInvoice), CancelInvoice(InvoiceId), - CommitInvoice(Commit), + // CommitInvoice(Commit), } #[derive(Debug, Clone, PartialEq, Eq)] @@ -805,31 +764,27 @@ impl FunderIncomingControl { } #[allow(clippy::large_enum_variant)] -#[capnp_conv(crate::app_server_capnp::request_result)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum RequestResult { - Complete(Commit), + // Complete(Commit), Success, // TODO: Should we add more information to the failure here? Failure, } -#[capnp_conv(crate::app_server_capnp::transaction_result)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct TransactionResult { pub request_id: Uid, pub result: RequestResult, } -#[capnp_conv(crate::app_server_capnp::payment_status_success)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct PaymentStatusSuccess { - pub receipt: Receipt, + // pub receipt: Receipt, pub ack_uid: Uid, } #[allow(clippy::large_enum_variant)] -#[capnp_conv(crate::app_server_capnp::payment_status)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum PaymentStatus { PaymentNotFound, @@ -837,7 +792,6 @@ pub enum PaymentStatus { Canceled(Uid), // ack_id } -#[capnp_conv(crate::app_server_capnp::response_close_payment)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ResponseClosePayment { pub payment_id: PaymentId, diff --git a/components/proto/src/index_client/messages.rs b/components/proto/src/index_client/messages.rs index 027cc6371..4c59dbfb1 100644 --- a/components/proto/src/index_client/messages.rs +++ b/components/proto/src/index_client/messages.rs @@ -1,7 +1,5 @@ use std::collections::HashMap; -use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; - use crate::crypto::{PublicKey, Uid}; use crate::funder::messages::{Currency, Rate}; pub use crate::index_server::messages::{ @@ -59,7 +57,6 @@ pub struct IndexClientReport { /// A list of trusted index servers. pub index_servers: Vec>, /// The server we are currently connected to (None if not connected). - #[capnp_conv(with = OptConnectedServer)] pub opt_connected_server: Option, } */ @@ -103,14 +100,12 @@ pub enum IndexClientReportMutation { SetConnectedServer(Option), } -#[capnp_conv(crate::app_server_capnp::response_routes_result)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum ResponseRoutesResult { Success(Vec), Failure, } -#[capnp_conv(crate::app_server_capnp::client_response_routes)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ClientResponseRoutes { pub request_id: Uid, diff --git a/components/proto/src/index_server/messages.rs b/components/proto/src/index_server/messages.rs index 86ef34159..786fd0f12 100644 --- a/components/proto/src/index_server/messages.rs +++ b/components/proto/src/index_server/messages.rs @@ -1,22 +1,17 @@ use serde::{Deserialize, Serialize}; -use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; - use common::ser_utils::{ser_b64, ser_string}; use crate::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; use crate::funder::messages::{Currency, FriendsRoute, Rate}; use crate::net::messages::NetAddress; -use crate::wrapper::Wrapper; -#[capnp_conv(crate::index_capnp::edge)] #[derive(Debug, PartialEq, Eq, Clone)] pub struct Edge { pub from_public_key: PublicKey, pub to_public_key: PublicKey, } -#[capnp_conv(crate::index_capnp::request_routes::opt_exclude)] #[derive(Debug, PartialEq, Eq, Clone)] pub enum OptExclude { Empty, @@ -43,29 +38,24 @@ impl From for Option { } /// IndexClient -> IndexServer -#[capnp_conv(crate::index_capnp::request_routes)] #[derive(Debug, PartialEq, Eq, Clone)] pub struct RequestRoutes { pub request_id: Uid, pub currency: Currency, /// Wanted capacity for the route. /// 0 means we want to optimize for capacity?? - #[capnp_conv(with = Wrapper)] pub capacity: u128, pub source: PublicKey, pub destination: PublicKey, /// This directed edge must not show up any any route inside the multi-route. /// Useful for finding non trivial directed loops. - #[capnp_conv(with = OptExclude)] pub opt_exclude: Option, } -#[capnp_conv(crate::index_capnp::route_capacity_rate)] #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct RouteCapacityRate { pub route: FriendsRoute, /// How many credits we can push along this route? - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub capacity: u128, /// Combined rate of pushing credits along this route. @@ -74,14 +64,12 @@ pub struct RouteCapacityRate { /// Multiple routes that together allow to pass a certain amount of credits to a destination. /// All routes must have the same beginning and the same end. -#[capnp_conv(crate::index_capnp::multi_route)] #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct MultiRoute { pub routes: Vec, } /// IndexServer -> IndexClient -#[capnp_conv(crate::index_capnp::response_routes)] #[derive(Debug, Clone)] pub struct ResponseRoutes { pub request_id: Uid, @@ -91,7 +79,6 @@ pub struct ResponseRoutes { } // TODO: Possibly think of a better name for this structure? -#[capnp_conv(crate::index_capnp::update_friend_currency)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct UpdateFriendCurrency { /// Friend's public key @@ -99,7 +86,6 @@ pub struct UpdateFriendCurrency { /// Currency being updated pub currency: Currency, /// To denote local requests closed, assign 0 to recvCapacity - #[capnp_conv(with = Wrapper)] pub recv_capacity: u128, /// The rate we charge for forwarding messages to another friend from this friend. /// For example, in the following diagram we are X and A is the friend we are updating: @@ -112,7 +98,6 @@ pub struct UpdateFriendCurrency { } // TODO: Possibly think of a better name for this structure? -#[capnp_conv(crate::index_capnp::remove_friend_currency)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct RemoveFriendCurrency { /// Friend's public key @@ -122,14 +107,12 @@ pub struct RemoveFriendCurrency { } /// IndexClient -> IndexServer -#[capnp_conv(crate::index_capnp::index_mutation)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum IndexMutation { UpdateFriendCurrency(UpdateFriendCurrency), RemoveFriendCurrency(RemoveFriendCurrency), } -#[capnp_conv(crate::index_capnp::mutations_update)] #[derive(Debug, Clone)] pub struct MutationsUpdate { /// Public key of the node sending the mutations. @@ -156,7 +139,6 @@ pub struct MutationsUpdate { pub signature: Signature, } -#[capnp_conv(crate::index_capnp::time_proof_link)] #[derive(Debug, Clone)] pub struct TimeProofLink { /// List of hashes that produce a certain hash @@ -164,7 +146,6 @@ pub struct TimeProofLink { pub hashes: Vec, } -#[capnp_conv(crate::index_capnp::forward_mutations_update)] #[derive(Debug, Clone)] pub struct ForwardMutationsUpdate { pub mutations_update: MutationsUpdate, @@ -176,21 +157,18 @@ pub struct ForwardMutationsUpdate { pub time_proof_chain: Vec, } -#[capnp_conv(crate::index_capnp::index_server_to_client)] #[derive(Debug)] pub enum IndexServerToClient { TimeHash(HashResult), ResponseRoutes(ResponseRoutes), } -#[capnp_conv(crate::index_capnp::index_client_to_server)] #[derive(Debug)] pub enum IndexClientToServer { MutationsUpdate(MutationsUpdate), RequestRoutes(RequestRoutes), } -#[capnp_conv(crate::index_capnp::index_server_to_server)] #[derive(Debug)] pub enum IndexServerToServer { TimeHash(HashResult), @@ -200,7 +178,6 @@ pub enum IndexServerToServer { // ---------------------------------------------- // ---------------------------------------------- -#[capnp_conv(crate::common_capnp::named_index_server_address)] #[derive(Arbitrary, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct NamedIndexServerAddress { diff --git a/components/proto/src/keepalive/messages.rs b/components/proto/src/keepalive/messages.rs index e7191bf68..63838a195 100644 --- a/components/proto/src/keepalive/messages.rs +++ b/components/proto/src/keepalive/messages.rs @@ -1,6 +1,3 @@ -use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; - -#[capnp_conv(crate::keepalive_capnp::ka_message)] #[derive(Debug, PartialEq, Eq, Clone)] pub enum KaMessage { KeepAlive, diff --git a/components/proto/src/lib.rs b/components/proto/src/lib.rs index fa54f7af0..76bc3cdc8 100644 --- a/components/proto/src/lib.rs +++ b/components/proto/src/lib.rs @@ -13,8 +13,8 @@ extern crate quickcheck_derive; // Workaround for issue: https://github.com/rust-lang/rust/issues/64450 extern crate offset_mutual_from as mutual_from; -#[macro_use] -pub mod macros; +// #[macro_use] +// pub mod macros; pub mod app_server; pub mod consts; pub mod crypto; @@ -24,18 +24,20 @@ pub mod index_client; pub mod index_server; pub mod keepalive; pub mod net; -pub mod proto_ser; +// pub mod proto_ser; pub mod relay; // pub mod report; pub mod secure_channel; pub mod ser_string; -pub mod wrapper; +// pub mod wrapper; +/* // include_schema!(report_capnp, "report_capnp"); include_schema!(app_server_capnp, "app_server_capnp"); include_schema!(common_capnp, "common_capnp"); include_schema!(dh_capnp, "dh_capnp"); include_schema!(relay_capnp, "relay_capnp"); -include_schema!(funder_capnp, "funder_capnp"); +// include_schema!(funder_capnp, "funder_capnp"); include_schema!(keepalive_capnp, "keepalive_capnp"); include_schema!(index_capnp, "index_capnp"); +*/ diff --git a/components/proto/src/net/messages.rs b/components/proto/src/net/messages.rs index b334b69cf..3901be4b5 100644 --- a/components/proto/src/net/messages.rs +++ b/components/proto/src/net/messages.rs @@ -7,11 +7,8 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use derive_more::Display; -use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; - use crate::consts::MAX_NET_ADDRESS_LENGTH; -#[capnp_conv(crate::common_capnp::net_address)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] #[display(fmt = "{}", address)] pub struct NetAddress { diff --git a/components/proto/src/relay/messages.rs b/components/proto/src/relay/messages.rs index f81b10bc0..5b94693a9 100644 --- a/components/proto/src/relay/messages.rs +++ b/components/proto/src/relay/messages.rs @@ -1,8 +1,5 @@ -use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; - use crate::crypto::PublicKey; -#[capnp_conv(crate::relay_capnp::init_connection)] #[derive(Debug, PartialEq, Eq)] pub enum InitConnection { Listen, @@ -12,13 +9,11 @@ pub enum InitConnection { Connect(PublicKey), } -#[capnp_conv(crate::relay_capnp::reject_connection)] #[derive(Debug, PartialEq, Eq, Clone)] pub struct RejectConnection { pub public_key: PublicKey, } -#[capnp_conv(crate::relay_capnp::incoming_connection)] #[derive(Debug, PartialEq, Eq, Clone)] pub struct IncomingConnection { pub public_key: PublicKey, diff --git a/components/proto/src/report/messages.rs b/components/proto/src/report/messages.rs index 4b0a27812..67afbb750 100644 --- a/components/proto/src/report/messages.rs +++ b/components/proto/src/report/messages.rs @@ -8,8 +8,6 @@ use common::mutable_state::MutableState; use common::never::Never; use common::ser_utils::ser_string; -use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; - use crate::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; use crate::app_server::messages::{NamedRelayAddress, RelayAddress}; @@ -19,7 +17,6 @@ use crate::funder::messages::{ use crate::net::messages::NetAddress; use crate::wrapper::Wrapper; -#[capnp_conv(crate::report_capnp::move_token_hashed_report)] #[derive(Clone, Debug, PartialEq, Eq)] pub struct MoveTokenHashedReport { pub prefix_hash: HashResult, @@ -28,39 +25,32 @@ pub struct MoveTokenHashedReport { pub new_token: Signature, } -#[capnp_conv(crate::report_capnp::friend_status_report)] #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, Eq, PartialEq)] pub enum FriendStatusReport { Enabled, Disabled, } -#[capnp_conv(crate::report_capnp::requests_status_report)] #[derive(Arbitrary, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] pub enum RequestsStatusReport { Open, Closed, } -#[capnp_conv(crate::report_capnp::mc_balance_report)] #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct McBalanceReport { /// Amount of credits this side has against the remote side. /// The other side keeps the negation of this value. - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub balance: i128, /// Frozen credits by our side - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub local_pending_debt: u128, /// Frozen credits by the remote side - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub remote_pending_debt: u128, } -#[capnp_conv(crate::report_capnp::friend_liveness_report)] #[derive(Clone, Debug, Eq, PartialEq)] pub enum FriendLivenessReport { Online, @@ -77,21 +67,18 @@ impl FriendLivenessReport { } } -#[capnp_conv(crate::report_capnp::currency_report)] #[derive(Clone, Debug, PartialEq, Eq)] pub struct CurrencyReport { pub currency: Currency, pub balance: McBalanceReport, } -#[capnp_conv(crate::report_capnp::reset_terms_report)] #[derive(Clone, Debug, PartialEq, Eq)] pub struct ResetTermsReport { pub reset_token: Signature, pub balance_for_reset: Vec, } -#[capnp_conv(crate::report_capnp::channel_inconsistent_report::opt_remote_reset_terms)] #[derive(Clone, Debug, PartialEq, Eq)] pub enum OptRemoteResetTerms { RemoteResetTerms(ResetTermsReport), @@ -117,21 +104,17 @@ impl From for Option { } } -#[capnp_conv(crate::report_capnp::channel_inconsistent_report)] #[derive(Clone, Debug, PartialEq, Eq)] pub struct ChannelInconsistentReport { pub local_reset_terms: Vec, - #[capnp_conv(with = OptRemoteResetTerms)] pub opt_remote_reset_terms: Option, } -#[capnp_conv(crate::report_capnp::channel_consistent_report)] #[derive(Clone, Debug, PartialEq, Eq)] pub struct ChannelConsistentReport { pub currency_reports: Vec, } -#[capnp_conv(crate::report_capnp::channel_status_report)] #[derive(Clone, Debug, PartialEq, Eq)] pub enum ChannelStatusReport { Inconsistent(ChannelInconsistentReport), @@ -139,7 +122,6 @@ pub enum ChannelStatusReport { } #[allow(clippy::large_enum_variant)] -#[capnp_conv(crate::report_capnp::opt_last_incoming_move_token)] #[derive(Clone, Debug, PartialEq, Eq)] pub enum OptLastIncomingMoveToken { MoveTokenHashed(MoveTokenHashedReport), @@ -169,7 +151,6 @@ impl From for Option { } } -#[capnp_conv(crate::report_capnp::currency_config_report)] #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct CurrencyConfigReport { pub currency: Currency, @@ -177,14 +158,12 @@ pub struct CurrencyConfigReport { /// for a certain currency. pub rate: Rate, /// Credit frame for the remote side (Set by the user of this node) - #[capnp_conv(with = Wrapper)] #[serde(with = "ser_string")] pub remote_max_debt: u128, /// Can requests be sent through this mutual credit? pub is_open: bool, } -#[capnp_conv(crate::report_capnp::friend_report)] #[derive(Clone, Debug, PartialEq, Eq)] pub struct FriendReport { pub name: String, @@ -192,7 +171,6 @@ pub struct FriendReport { pub currency_configs: Vec, // Last message signed by the remote side. // Can be used as a proof for the last known balance. - #[capnp_conv(with = OptLastIncomingMoveToken)] pub opt_last_incoming_move_token: Option, // TODO: The state of liveness = true with status = disabled should never happen. // Can we somehow express this in the type system? @@ -201,14 +179,12 @@ pub struct FriendReport { pub status: FriendStatusReport, } -#[capnp_conv(crate::report_capnp::pk_friend_report)] #[derive(Clone, Debug, PartialEq, Eq)] pub struct PkFriendReport { pub friend_public_key: PublicKey, pub friend_report: FriendReport, } -#[capnp_conv(crate::report_capnp::pk_friend_report_list)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct PkFriendReportList { list: Vec>, @@ -245,18 +221,15 @@ impl From>> for PkFriendReportList { /// A FunderReport is a summary of a FunderState. /// It contains the information the Funder exposes to the user apps of the Offset node. -#[capnp_conv(crate::report_capnp::funder_report)] #[derive(Debug, Clone, PartialEq, Eq)] // TODO: Removed A: Clone here and ImHashMap. Should this struct be cloneable for some reason? pub struct FunderReport { pub local_public_key: PublicKey, pub relays: Vec>, - #[capnp_conv(with = PkFriendReportList)] pub friends: HashMap>, } #[allow(clippy::large_enum_variant)] -#[capnp_conv(crate::report_capnp::friend_report_mutation)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum FriendReportMutation { SetRemoteRelays(Vec>), @@ -265,23 +238,19 @@ pub enum FriendReportMutation { RemoveCurrencyConfig(Currency), SetChannelStatus(ChannelStatusReport), SetStatus(FriendStatusReport), - #[capnp_conv(with = OptLastIncomingMoveToken)] SetOptLastIncomingMoveToken(Option), SetLiveness(FriendLivenessReport), } -#[capnp_conv(crate::report_capnp::add_friend_report)] #[derive(Clone, Debug, PartialEq, Eq)] pub struct AddFriendReport { pub friend_public_key: PublicKey, pub name: String, pub relays: Vec>, - #[capnp_conv(with = OptLastIncomingMoveToken)] pub opt_last_incoming_move_token: Option, pub channel_status: ChannelStatusReport, } -#[capnp_conv(crate::report_capnp::pk_friend_report_mutation)] #[derive(Clone, Debug, PartialEq, Eq)] pub struct PkFriendReportMutation { friend_public_key: PublicKey, @@ -306,14 +275,12 @@ impl From<(PublicKey, FriendReportMutation)> for PkFriendReportMutation { } #[allow(clippy::large_enum_variant)] -#[capnp_conv(crate::report_capnp::funder_report_mutation)] #[derive(Debug, Clone, PartialEq, Eq)] pub enum FunderReportMutation { AddRelay(NamedRelayAddress), RemoveRelay(PublicKey), AddFriend(AddFriendReport), RemoveFriend(PublicKey), - #[capnp_conv(with = PkFriendReportMutation)] PkFriendReportMutation((PublicKey, FriendReportMutation)), } diff --git a/components/proto/src/secure_channel/messages.rs b/components/proto/src/secure_channel/messages.rs index 0f11de1de..d2ee8e5ac 100644 --- a/components/proto/src/secure_channel/messages.rs +++ b/components/proto/src/secure_channel/messages.rs @@ -1,8 +1,5 @@ -use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; - use crate::crypto::{DhPublicKey, PublicKey, RandValue, Salt, Signature}; -#[capnp_conv(crate::dh_capnp::exchange_rand_nonce::opt_dest_public_key)] #[derive(Debug, PartialEq, Eq)] enum OptDestPublicKey { Empty, @@ -28,17 +25,14 @@ impl From for Option { } /// First Diffie-Hellman message: -#[capnp_conv(crate::dh_capnp::exchange_rand_nonce)] #[derive(Debug, PartialEq, Eq)] pub struct ExchangeRandNonce { pub rand_nonce: RandValue, pub src_public_key: PublicKey, - #[capnp_conv(with = OptDestPublicKey)] pub opt_dest_public_key: Option, } /// Second Diffie-Hellman message: -#[capnp_conv(crate::dh_capnp::exchange_dh)] #[derive(Debug, PartialEq, Eq)] pub struct ExchangeDh { pub dh_public_key: DhPublicKey, @@ -57,21 +51,18 @@ impl ExchangeDh { } } -#[capnp_conv(crate::dh_capnp::rekey)] #[derive(Debug, PartialEq, Eq, Clone)] pub struct Rekey { pub dh_public_key: DhPublicKey, pub key_salt: Salt, } -#[capnp_conv(crate::dh_capnp::channel_content)] #[derive(Debug, PartialEq, Eq, Clone)] pub enum ChannelContent { Rekey(Rekey), User(Vec), } -#[capnp_conv(crate::dh_capnp::channel_message)] #[derive(Debug, PartialEq, Eq)] pub struct ChannelMessage { pub rand_padding: Vec, From decf4aec8abb04882e445fa4edf8f6575962f6cf Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 19:12:35 +0200 Subject: [PATCH 264/478] funder now compiles --- Cargo.lock | 38 -- Cargo.toml | 2 - components/capnp_conv/Cargo.toml | 24 -- components/capnp_conv/LICENSE-APACHE | 201 ----------- components/capnp_conv/LICENSE-MIT | 25 -- components/capnp_conv/build.rs | 7 - .../capnp_conv/capnp_conv_derive/Cargo.toml | 17 - .../capnp_conv_derive/LICENSE-APACHE | 201 ----------- .../capnp_conv/capnp_conv_derive/LICENSE-MIT | 25 -- .../capnp_conv_derive/src/derive_enum.rs | 277 --------------- .../capnp_conv_derive/src/derive_struct.rs | 205 ----------- .../capnp_conv/capnp_conv_derive/src/lib.rs | 110 ------ .../capnp_conv/capnp_conv_derive/src/util.rs | 333 ------------------ components/capnp_conv/src/lib.rs | 89 ----- components/capnp_conv/tests/capnp/test.capnp | 109 ------ components/capnp_conv/tests/derive.rs | 221 ------------ components/capnp_conv/tests/with.rs | 103 ------ components/proto/src/crypto/mod.rs | 2 - components/proto/src/macros.rs | 13 - components/proto/src/wrapper.rs | 105 ------ components/signature/src/canonical.rs | 4 +- components/signature/src/verify.rs | 17 +- 22 files changed, 14 insertions(+), 2114 deletions(-) delete mode 100644 components/capnp_conv/Cargo.toml delete mode 100644 components/capnp_conv/LICENSE-APACHE delete mode 100644 components/capnp_conv/LICENSE-MIT delete mode 100644 components/capnp_conv/build.rs delete mode 100644 components/capnp_conv/capnp_conv_derive/Cargo.toml delete mode 100644 components/capnp_conv/capnp_conv_derive/LICENSE-APACHE delete mode 100644 components/capnp_conv/capnp_conv_derive/LICENSE-MIT delete mode 100644 components/capnp_conv/capnp_conv_derive/src/derive_enum.rs delete mode 100644 components/capnp_conv/capnp_conv_derive/src/derive_struct.rs delete mode 100644 components/capnp_conv/capnp_conv_derive/src/lib.rs delete mode 100644 components/capnp_conv/capnp_conv_derive/src/util.rs delete mode 100644 components/capnp_conv/src/lib.rs delete mode 100644 components/capnp_conv/tests/capnp/test.capnp delete mode 100644 components/capnp_conv/tests/derive.rs delete mode 100644 components/capnp_conv/tests/with.rs delete mode 100644 components/proto/src/macros.rs delete mode 100644 components/proto/src/wrapper.rs diff --git a/Cargo.lock b/Cargo.lock index 981c53038..87a377f7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -258,21 +258,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24508e28c677875c380c20f4d28124fab6f8ed4ef929a1397d7b1a31e92f1005" -[[package]] -name = "capnp" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b867c15d8ff93c4d81b69c89280840f877331ef2a1fccbaf947afecc68b51a9e" - -[[package]] -name = "capnpc" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2afedfc194b01c6804ad0a10c7139024b99ee3df6a39bb09bdf759067ababff" -dependencies = [ - "capnp", -] - [[package]] name = "cc" version = "1.0.54" @@ -1045,29 +1030,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "offset-capnp-conv" -version = "0.1.0" -dependencies = [ - "byteorder", - "capnp", - "capnpc", - "derive_more 0.15.0", - "log", - "offset-capnp-conv-derive", - "pretty_env_logger", -] - -[[package]] -name = "offset-capnp-conv-derive" -version = "0.1.0" -dependencies = [ - "heck", - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", -] - [[package]] name = "offset-channeler" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 779a191a9..4288a1c82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,8 +25,6 @@ members = [ "components/app", "components/test", "components/mutual_from", - "components/capnp_conv", - "components/capnp_conv/capnp_conv_derive", "components/signature", "components/route", "components/lockfile", diff --git a/components/capnp_conv/Cargo.toml b/components/capnp_conv/Cargo.toml deleted file mode 100644 index 1376b0341..000000000 --- a/components/capnp_conv/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "offset-capnp-conv" -version = "0.1.0" -authors = ["real "] -license = "MIT OR Apache-2.0" -edition = "2018" - -[dependencies] - -log = "0.4" -pretty_env_logger = "0.2" - -offset-capnp-conv-derive = { path = "capnp_conv_derive", version = "0.1.0" } - -capnp = "0.10.0" -derive_more = "0.15.0" - -[build-dependencies] -capnpc = "0.10.0" - -[dev-dependencies] - -byteorder = {version = "1.3.2", features = ["i128"]} - diff --git a/components/capnp_conv/LICENSE-APACHE b/components/capnp_conv/LICENSE-APACHE deleted file mode 100644 index c753170bc..000000000 --- a/components/capnp_conv/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright (c) 2019 real - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/components/capnp_conv/LICENSE-MIT b/components/capnp_conv/LICENSE-MIT deleted file mode 100644 index 683ce3d46..000000000 --- a/components/capnp_conv/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2019 real - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/components/capnp_conv/build.rs b/components/capnp_conv/build.rs deleted file mode 100644 index 1ef2c362e..000000000 --- a/components/capnp_conv/build.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - capnpc::CompilerCommand::new() - .src_prefix("tests/") - .file("tests/capnp/test.capnp") - .run() - .unwrap(); -} diff --git a/components/capnp_conv/capnp_conv_derive/Cargo.toml b/components/capnp_conv/capnp_conv_derive/Cargo.toml deleted file mode 100644 index 4716f688f..000000000 --- a/components/capnp_conv/capnp_conv_derive/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "offset-capnp-conv-derive" -version = "0.1.0" -authors = ["real "] -license = "MIT OR Apache-2.0" -edition = "2018" - -[lib] -proc-macro = true - -[dependencies] - -quote = "0.6.12" -syn = "0.15.38" -proc-macro2 = "0.4" -heck = "0.3.1" - diff --git a/components/capnp_conv/capnp_conv_derive/LICENSE-APACHE b/components/capnp_conv/capnp_conv_derive/LICENSE-APACHE deleted file mode 100644 index c753170bc..000000000 --- a/components/capnp_conv/capnp_conv_derive/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright (c) 2019 real - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/components/capnp_conv/capnp_conv_derive/LICENSE-MIT b/components/capnp_conv/capnp_conv_derive/LICENSE-MIT deleted file mode 100644 index 683ce3d46..000000000 --- a/components/capnp_conv/capnp_conv_derive/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2019 real - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/components/capnp_conv/capnp_conv_derive/src/derive_enum.rs b/components/capnp_conv/capnp_conv_derive/src/derive_enum.rs deleted file mode 100644 index bd4962054..000000000 --- a/components/capnp_conv/capnp_conv_derive/src/derive_enum.rs +++ /dev/null @@ -1,277 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::spanned::Spanned; -// use syn::{parse_macro_input, Data, DeriveInput, Fields, Ident, Index}; -use syn::{DataEnum, Fields, Ident, Path, Variant}; - -use heck::SnakeCase; - -use crate::util::{ - capnp_result_shim, gen_list_read_iter, gen_list_write_iter, get_vec, is_data, is_primitive, - usize_to_u32_shim, CapnpWithAttribute, -}; - -// TODO: Deal with the case of multiple with attributes (Should report error) -/// Get the path from a with style field attribute. -/// Example: -/// ```text -/// #[capnp_conv(with = Wrapper)] -/// ``` -/// Will return the path `Wrapper` -fn get_with_attribute(variant: &syn::Variant) -> Option { - for attr in &variant.attrs { - if attr.path.is_ident("capnp_conv") { - let tts: proc_macro::TokenStream = attr.tts.clone().into(); - let capnp_with_attr = syn::parse::(tts).unwrap(); - return Some(capnp_with_attr.path); - } - } - None -} - -fn gen_type_write(variant: &Variant, assign_defaults: impl Fn(&mut syn::Path)) -> TokenStream { - let opt_with_path = get_with_attribute(variant); - // let variant_ident = &variant.ident; - let variant_name = &variant.ident; - let variant_snake_name = variant_name.to_string().to_snake_case(); - - match &variant.fields { - Fields::Unnamed(fields_unnamed) => { - let unnamed = &fields_unnamed.unnamed; - if unnamed.len() != 1 { - unimplemented!("gen_type_write: Amount of unnamed fields is not 1!"); - } - - let pair = unnamed.last().unwrap(); - let last_ident = match pair { - syn::punctuated::Pair::End(last_ident) => last_ident, - _ => unreachable!(), - }; - - let path = match opt_with_path { - Some(with_path) => with_path, - None => match &last_ident.ty { - syn::Type::Path(type_path) => type_path.path.clone(), - _ => { - panic!("{:?}", opt_with_path); - } - }, - }; - /* - let path = opt_with_path.clone().unwrap_or(match &last_ident.ty { - syn::Type::Path(type_path) => type_path.path.clone(), - _ => { - panic!("{:?}", opt_with_path); - // unimplemented!("gen_type_write: last ident is not a path!"), - } - }); - */ - - let mut path = path; - assign_defaults(&mut path); - - if is_primitive(&path) { - let set_method = - syn::Ident::new(&format!("set_{}", &variant_snake_name), variant.span()); - return quote! { - #variant_name(x) => writer.#set_method(<#path>::from(x.clone())), - }; - } - - if is_data(&path) { - let set_method = - syn::Ident::new(&format!("set_{}", &variant_snake_name), variant.span()); - return quote! { - #variant_name(x) => writer.#set_method(&<#path>::from(x.clone())), - }; - } - - if path.is_ident("String") { - let set_method = - syn::Ident::new(&format!("set_{}", &variant_snake_name), variant.span()); - return quote! { - #variant_name(x) => writer.#set_method(x), - }; - } - - // The case of list: - if let Some(inner_path) = get_vec(&path) { - let init_method = - syn::Ident::new(&format!("init_{}", &variant_snake_name), variant.span()); - let list_write_iter = gen_list_write_iter(&inner_path); - - // In the cases of more complicated types, list_builder needs to be mutable. - let let_list_builder = - if is_primitive(&path) || path.is_ident("String") || is_data(&path) { - quote! { let list_builder } - } else { - quote! { let mut list_builder } - }; - - let usize_to_u32 = usize_to_u32_shim(); - return quote! { - #variant_name(vec) => { - #usize_to_u32 - #let_list_builder = writer - .reborrow() - .#init_method(usize_to_u32(vec.len()).unwrap()); - - for (index, item) in vec.iter().enumerate() { - #list_write_iter - } - }, - }; - } - - let init_method = - syn::Ident::new(&format!("init_{}", &variant_snake_name), variant.span()); - quote! { - #variant_name(x) => <#path>::from(x.clone()).write_capnp(&mut writer.reborrow().#init_method()), - } - } - - Fields::Unit => { - let set_method = - syn::Ident::new(&format!("set_{}", &variant_snake_name), variant.span()); - quote! { - #variant_name => writer.#set_method(()), - } - } - // Rust enum variants don't have named fields (?) - Fields::Named(_) => unreachable!(), - } -} - -pub fn gen_write_capnp_enum( - data_enum: &DataEnum, - rust_enum: &Ident, - capnp_struct: &Path, - assign_defaults: impl Fn(&mut syn::Path), -) -> TokenStream { - let recurse = data_enum.variants.iter().map(|variant| { - let type_write = gen_type_write(&variant, &assign_defaults); - quote! { - #rust_enum::#type_write - } - }); - - quote! { - impl<'a> WriteCapnp<'a> for #rust_enum { - type WriterType = #capnp_struct::Builder<'a>; - fn write_capnp(&self, writer: &mut Self::WriterType) { - match &self { - #(#recurse)* - }; - } - } - } -} - -fn gen_type_read( - variant: &Variant, - rust_enum: &Ident, - assign_defaults: impl Fn(&mut syn::Path), -) -> TokenStream { - let opt_with_path = get_with_attribute(variant); - let variant_name = &variant.ident; - // let variant_snake_name = variant_name.to_string().to_snake_case(); - - match &variant.fields { - Fields::Unnamed(fields_unnamed) => { - let unnamed = &fields_unnamed.unnamed; - if unnamed.len() != 1 { - unimplemented!("gen_type_read: Amount of unnamed fields is not 1!"); - } - - let pair = unnamed.last().unwrap(); - let last_ident = match pair { - syn::punctuated::Pair::End(last_ident) => last_ident, - _ => unreachable!(), - }; - - let mut path = match opt_with_path { - Some(with_path) => with_path, - None => match &last_ident.ty { - syn::Type::Path(type_path) => type_path.path.clone(), - _ => { - panic!("{:?}", opt_with_path); - } - }, - }; - - assign_defaults(&mut path); - - if is_primitive(&path) { - return quote! { - #variant_name(x) => #rust_enum::#variant_name(x.into()), - }; - } - - if is_data(&path) || path.is_ident("String") { - return quote! { - #variant_name(x) => #rust_enum::#variant_name(x?.into()), - }; - } - - if let Some(inner_path) = get_vec(&path) { - // The case of a list: - let list_read_iter = gen_list_read_iter(&inner_path); - return quote! { - #variant_name(list_reader) => { - let mut res_vec = Vec::new(); - for item_reader in list_reader? { - // res_vec.push_back(read_named_relay_address(&named_relay_address)?); - #list_read_iter - } - #rust_enum::#variant_name(res_vec) - } - }; - } - - let capnp_result = capnp_result_shim(); - - quote! { - #variant_name(variant_reader) => { - #capnp_result - - let variant_reader = CapnpResult::from(variant_reader).into_result()?; - #rust_enum::#variant_name(<#path>::read_capnp(&variant_reader)?.into()) - }, - } - } - - Fields::Unit => { - quote! { - #variant_name(()) => #rust_enum::#variant_name, - } - } - // Rust enum variants don't have named fields (?) - Fields::Named(_) => unreachable!(), - } -} - -pub fn gen_read_capnp_enum( - data_enum: &DataEnum, - rust_enum: &Ident, - capnp_struct: &Path, - assign_defaults: impl Fn(&mut syn::Path), -) -> TokenStream { - let recurse = data_enum.variants.iter().map(|variant| { - let type_read = gen_type_read(&variant, rust_enum, &assign_defaults); - quote! { - #capnp_struct::#type_read - } - }); - - quote! { - impl<'a> ReadCapnp<'a> for #rust_enum { - type ReaderType = #capnp_struct::Reader<'a>; - - fn read_capnp(reader: &Self::ReaderType) -> Result { - Ok(match reader.which()? { - #(#recurse)* - }) - } - } - } -} diff --git a/components/capnp_conv/capnp_conv_derive/src/derive_struct.rs b/components/capnp_conv/capnp_conv_derive/src/derive_struct.rs deleted file mode 100644 index bde1bc0c3..000000000 --- a/components/capnp_conv/capnp_conv_derive/src/derive_struct.rs +++ /dev/null @@ -1,205 +0,0 @@ -use proc_macro2::TokenStream; -use quote::{quote, quote_spanned}; - -use syn::spanned::Spanned; -use syn::{FieldsNamed, Ident, Path}; - -use crate::util::{ - capnp_result_shim, gen_list_read_iter, gen_list_write_iter, get_vec, is_data, is_primitive, - usize_to_u32_shim, CapnpWithAttribute, -}; - -// TODO: Deal with the case of multiple with attributes (Should report error) -/// Get the path from a with style field attribute. -/// Example: -/// ```text -/// #[capnp_conv(with = Wrapper)] -/// ``` -/// Will return the path `Wrapper` -fn get_with_attribute(field: &syn::Field) -> Option { - for attr in &field.attrs { - if attr.path.is_ident("capnp_conv") { - let tts: proc_macro::TokenStream = attr.tts.clone().into(); - let capnp_with_attr = syn::parse::(tts).unwrap(); - return Some(capnp_with_attr.path); - } - } - None -} - -fn gen_type_write(field: &syn::Field, assign_defaults: impl Fn(&mut syn::Path)) -> TokenStream { - let opt_with_path = get_with_attribute(field); - match &field.ty { - syn::Type::Path(type_path) => { - if type_path.qself.is_some() { - // Self qualifier? - unimplemented!("self qualifier"); - } - - let mut path = type_path.path.clone(); - assign_defaults(&mut path); - let path = opt_with_path.unwrap_or(path); - - let name = &field.ident.as_ref().unwrap(); - - if is_primitive(&path) { - let set_method = syn::Ident::new(&format!("set_{}", &name), name.span()); - return quote_spanned! {field.span() => - writer.reborrow().#set_method(<#path>::from(self.#name)); - }; - } - - if path.is_ident("String") || is_data(&path) { - let set_method = syn::Ident::new(&format!("set_{}", &name), name.span()); - return quote_spanned! {field.span() => - writer.reborrow().#set_method(&<#path>::from(self.#name.clone())); - }; - } - - if let Some(inner_path) = get_vec(&path) { - let init_method = syn::Ident::new(&format!("init_{}", &name), name.span()); - let list_write_iter = gen_list_write_iter(&inner_path); - - // In the cases of more complicated types, list_builder needs to be mutable. - let let_list_builder = - if is_primitive(&path) || path.is_ident("String") || is_data(&path) { - quote! { let list_builder } - } else { - quote! { let mut list_builder } - }; - - let usize_to_u32 = usize_to_u32_shim(); - - return quote_spanned! {field.span() => - { - #usize_to_u32 - - #let_list_builder = { - writer - .reborrow() - .#init_method(usize_to_u32(self.#name.len()).unwrap()) - }; - - for (index, item) in self.#name.iter().enumerate() { - #list_write_iter - } - } - }; - } - - // Generic type: - let init_method = syn::Ident::new(&format!("init_{}", &name), name.span()); - quote_spanned! {field.span() => - <#path>::from(self.#name.clone()).write_capnp(&mut writer.reborrow().#init_method()); - } - } - _ => unimplemented!(), - } -} - -fn gen_type_read(field: &syn::Field, assign_defaults: impl Fn(&mut syn::Path)) -> TokenStream { - let opt_with_path = get_with_attribute(field); - - match &field.ty { - syn::Type::Path(type_path) => { - if type_path.qself.is_some() { - // Self qualifier? - unimplemented!("self qualifier"); - } - - let mut path = type_path.path.clone(); - assign_defaults(&mut path); - - let path = opt_with_path.unwrap_or(path); - - let name = &field.ident.as_ref().unwrap(); - - if is_primitive(&path) { - let get_method = syn::Ident::new(&format!("get_{}", &name), name.span()); - return quote_spanned! {field.span() => - #name: reader.#get_method().into() - }; - } - - if path.is_ident("String") || is_data(&path) { - let get_method = syn::Ident::new(&format!("get_{}", &name), name.span()); - return quote_spanned! {field.span() => - #name: reader.#get_method()?.into() - }; - } - - if let Some(inner_path) = get_vec(&path) { - let get_method = syn::Ident::new(&format!("get_{}", &name), name.span()); - let list_read_iter = gen_list_read_iter(&inner_path); - return quote_spanned! {field.span() => - #name: { - let mut res_vec = Vec::new(); - for item_reader in reader.#get_method()? { - // res_vec.push_back(read_named_relay_address(&named_relay_address)?); - #list_read_iter - } - res_vec.into() - } - }; - } - - // Generic type: - let get_method = syn::Ident::new(&format!("get_{}", &name), name.span()); - let capnp_result = capnp_result_shim(); - quote_spanned! {field.span() => - #name: { - #capnp_result - let inner_reader = CapnpResult::from(reader.#get_method()).into_result()?; - <#path>::read_capnp(&inner_reader)?.into() - } - } - } - _ => unimplemented!(), - } -} - -pub fn gen_write_capnp_named_struct( - fields_named: &FieldsNamed, - rust_struct: &Ident, - capnp_struct: &Path, - assign_defaults: impl Fn(&mut syn::Path), -) -> TokenStream { - let recurse = fields_named - .named - .iter() - .map(|field| gen_type_write(&field, &assign_defaults)); - - quote! { - impl<'a> WriteCapnp<'a> for #rust_struct { - type WriterType = #capnp_struct::Builder<'a>; - - fn write_capnp(&self, writer: &mut Self::WriterType) { - #(#recurse)* - } - } - } -} - -pub fn gen_read_capnp_named_struct( - fields_named: &FieldsNamed, - rust_struct: &Ident, - capnp_struct: &Path, - assign_defaults: impl Fn(&mut syn::Path), -) -> TokenStream { - let recurse = fields_named - .named - .iter() - .map(|field| gen_type_read(field, &assign_defaults)); - - quote! { - impl<'a> ReadCapnp<'a> for #rust_struct { - type ReaderType = #capnp_struct::Reader<'a>; - - fn read_capnp(reader: &Self::ReaderType) -> Result { - Ok(#rust_struct { - #(#recurse,)* - }) - } - } - } -} diff --git a/components/capnp_conv/capnp_conv_derive/src/lib.rs b/components/capnp_conv/capnp_conv_derive/src/lib.rs deleted file mode 100644 index 947f1b19c..000000000 --- a/components/capnp_conv/capnp_conv_derive/src/lib.rs +++ /dev/null @@ -1,110 +0,0 @@ -#![crate_type = "lib"] -#![recursion_limit = "128"] -#![deny(trivial_numeric_casts, warnings)] -#![allow(broken_intra_doc_links)] -#![allow( - clippy::too_many_arguments, - clippy::implicit_hasher, - clippy::module_inception, - clippy::new_without_default -)] -#![allow(unreachable_code)] - -extern crate proc_macro; - -mod derive_enum; -mod derive_struct; -mod util; - -use quote::quote; -use syn::{parse_macro_input, Data, DeriveInput, Fields, Path}; - -use self::derive_enum::{gen_read_capnp_enum, gen_write_capnp_enum}; -use self::derive_struct::{gen_read_capnp_named_struct, gen_write_capnp_named_struct}; -use self::util::{assign_defaults_path, extract_defaults, remove_with_attributes}; - -/// Generate code for conversion between Rust and capnp structs. -#[proc_macro_attribute] -pub fn capnp_conv( - args: proc_macro::TokenStream, - input: proc_macro::TokenStream, -) -> proc_macro::TokenStream { - // See: https://github.com/dtolnay/syn/issues/86 - // for information about arguments. - - // Name of capnp struct: - let capnp_struct = parse_macro_input!(args as Path); - let input = parse_macro_input!(input as DeriveInput); - - let defaults = extract_defaults(&input.generics); - let assign_defaults = |path: &mut syn::Path| assign_defaults_path(path, &defaults); - - // Name of local struct: - let rust_struct = &input.ident; - - let conversion = match input.data { - Data::Struct(ref data) => match data.fields { - Fields::Named(ref fields_named) => { - // Example: - // struct Point { - // x: u32, - // y: u32, - // } - - let write_capnp = gen_write_capnp_named_struct( - fields_named, - rust_struct, - &capnp_struct, - &assign_defaults, - ); - let read_capnp = gen_read_capnp_named_struct( - fields_named, - rust_struct, - &capnp_struct, - &assign_defaults, - ); - - quote! { - #[allow(clippy::all)] - #write_capnp - #[allow(clippy::all)] - #read_capnp - } - } - Fields::Unnamed(_) | Fields::Unit => unimplemented!(), - }, - Data::Enum(ref data_enum) => { - // Example: - // enum MyEnum { - // Type1(u32), - // Type2, - // Type3(MyStruct), - // } - let write_capnp = - gen_write_capnp_enum(data_enum, rust_struct, &capnp_struct, &assign_defaults); - let read_capnp = - gen_read_capnp_enum(data_enum, rust_struct, &capnp_struct, &assign_defaults); - - quote! { - #[allow(clippy::all)] - #write_capnp - #[allow(clippy::all)] - #read_capnp - } - } - Data::Union(_) => unimplemented!(), - }; - - // Remove all of our `#[capnp_conv(with = ... )]` attributes from the input: - let mut input = input; - remove_with_attributes(&mut input); - - let expanded = quote! { - // Original structure - #input - // Generated mutual From conversion code: - #conversion - }; - - proc_macro::TokenStream::from(expanded) -} diff --git a/components/capnp_conv/capnp_conv_derive/src/util.rs b/components/capnp_conv/capnp_conv_derive/src/util.rs deleted file mode 100644 index 7f94cb7a7..000000000 --- a/components/capnp_conv/capnp_conv_derive/src/util.rs +++ /dev/null @@ -1,333 +0,0 @@ -use std::collections::HashMap; - -use proc_macro2::TokenStream; -use quote::quote; - -/// A shim for converting usize to u32 -pub fn usize_to_u32_shim() -> TokenStream { - quote! { - pub fn usize_to_u32(num: usize) -> Option { - if num > 0xffffffff as usize { - None - } else { - Some(num as u32) - } - } - } -} - -/// Is a primitive type? -pub fn is_primitive(path: &syn::Path) -> bool { - path.is_ident("u8") - || path.is_ident("u16") - || path.is_ident("u32") - || path.is_ident("u64") - || path.is_ident("i8") - || path.is_ident("i16") - || path.is_ident("i32") - || path.is_ident("i64") - || path.is_ident("f32") - || path.is_ident("f64") - || path.is_ident("bool") -} - -/// Check if the path represents a Vec -pub fn is_data(path: &syn::Path) -> bool { - let last_segment = match path.segments.last().unwrap() { - syn::punctuated::Pair::End(last_segment) => last_segment, - _ => unreachable!(), - }; - if &last_segment.ident.to_string() != "Vec" { - return false; - } - let angle = match &last_segment.arguments { - syn::PathArguments::AngleBracketed(angle) => { - if angle.args.len() > 1 { - unreachable!("Too many arguments for Vec!"); - } - angle - } - _ => unreachable!("Vec with arguments that are not angle bracketed!"), - }; - let last_arg = match angle.args.last().unwrap() { - syn::punctuated::Pair::End(last_arg) => last_arg, - _ => return false, - }; - - let arg_ty = match last_arg { - syn::GenericArgument::Type(arg_ty) => arg_ty, - _ => return false, - }; - - let arg_ty_path = match arg_ty { - syn::Type::Path(arg_ty_path) => arg_ty_path, - _ => return false, - }; - - if arg_ty_path.qself.is_some() { - return false; - } - - if !arg_ty_path.path.is_ident("u8") { - return false; - } - - true -} - -/// Check if the path represents a Vec, where SomeStruct != u8 -pub fn get_vec(path: &syn::Path) -> Option { - let last_segment = match path.segments.last().unwrap() { - syn::punctuated::Pair::End(last_segment) => last_segment, - _ => unreachable!(), - }; - if &last_segment.ident.to_string() != "Vec" { - return None; - } - let angle = match &last_segment.arguments { - syn::PathArguments::AngleBracketed(angle) => { - if angle.args.len() > 1 { - unreachable!("Too many arguments for Vec!"); - } - angle - } - _ => unreachable!("Vec with arguments that are not angle bracketed!"), - }; - let last_arg = match angle.args.last().unwrap() { - syn::punctuated::Pair::End(last_arg) => last_arg, - _ => return None, - }; - - let arg_ty = match last_arg { - syn::GenericArgument::Type(arg_ty) => arg_ty, - _ => return None, - }; - - let arg_ty_path = match arg_ty { - syn::Type::Path(arg_ty_path) => arg_ty_path, - _ => return None, - }; - - if arg_ty_path.qself.is_some() { - return None; - } - - // Make sure that we don't deal with Vec: - if arg_ty_path.path.is_ident("u8") { - return None; - } - - Some(arg_ty_path.path.clone()) -} - -pub fn gen_list_write_iter(path: &syn::Path) -> TokenStream { - if is_primitive(path) || path.is_ident("String") || is_data(path) { - // A primitive list: - quote! { - list_builder - .reborrow() - .set(usize_to_u32(index).unwrap(), item.clone().into()); - } - } else { - // Not a primitive list: - quote! { - let mut item_builder = list_builder - .reborrow() - .get(usize_to_u32(index).unwrap()); - - item.clone().write_capnp(&mut item_builder); - } - } - // TODO: It seems like we do not support List(List(...)) at the moment. - // How to support it? -} - -pub fn gen_list_read_iter(path: &syn::Path) -> TokenStream { - if is_primitive(path) || path.is_ident("String") || is_data(path) { - // A primitive list: - quote! { - res_vec.push(item_reader.into()); - } - } else { - // Not a primitive list: - quote! { - res_vec.push(<#path>::read_capnp(&item_reader)?); - } - } - // TODO: It seems like we do not support List(List(...)) at the moment. - // How to support it? -} - -/// A shim allowing to merge cases where either -/// Result> or a T is returned. -pub fn capnp_result_shim() -> TokenStream { - quote! { - pub enum CapnpResult { - Ok(T), - Err(CapnpConvError), - } - - impl CapnpResult { - pub fn into_result(self) -> Result { - match self { - CapnpResult::Ok(t) => Ok(t), - CapnpResult::Err(e) => Err(e), - } - } - } - - impl From for CapnpResult { - fn from(input: T) -> Self { - CapnpResult::Ok(input) - } - } - - impl From> for CapnpResult - where - E: Into, - { - fn from(input: Result) -> Self { - match input { - Ok(t) => CapnpResult::Ok(t), - Err(e) => CapnpResult::Err(e.into()), - } - } - } - } -} - -/// Obtain a map of default values from generics. -/// Example: -/// -/// ```text -/// struct MyStruct { ... } -/// ``` -/// -/// We expect to get a map, mapping A -> u32, B -> u64. -/// -pub fn extract_defaults(generics: &syn::Generics) -> HashMap { - let mut defaults = HashMap::new(); - for param in &generics.params { - let type_param = match *param { - syn::GenericParam::Type(ref type_param) => type_param, - _ => continue, - }; - - if type_param.eq_token.is_none() { - continue; - }; - - let default_type = match &type_param.default { - Some(default_type) => default_type, - None => continue, - }; - - let default_type_path = match default_type { - syn::Type::Path(default_type_path) => default_type_path, - _ => unimplemented!("Only paths default params are supported"), - }; - - if default_type_path.qself.is_some() { - unimplemented!("qself is not implemented!"); - } - - defaults.insert(type_param.ident.clone(), default_type_path.path.clone()); - } - defaults -} - -/// For every generic along a path, assign a default value if possible -pub fn assign_defaults_path(path: &mut syn::Path, defaults: &HashMap) { - // Deal with the case of a single Ident: `T` - - if path.segments.len() == 1 { - let last_segment = match path.segments.last_mut().unwrap() { - syn::punctuated::Pair::End(last_segment) => last_segment, - _ => unreachable!(), - }; - - if let syn::PathArguments::None = last_segment.arguments { - if let Some(default_path) = defaults.get(&last_segment.ident) { - let _ = std::mem::replace(path, default_path.clone()); - return; - } - } - } - - // Deal with the more general case of a Path with various arguments - // that should be assigned their default value - - for segment in path.segments.iter_mut() { - let args = match &mut segment.arguments { - syn::PathArguments::None => continue, - syn::PathArguments::AngleBracketed(angle_bracketed) => &mut angle_bracketed.args, - _ => unimplemented!("Only angle bracketed arguments are supported!"), - }; - - for generic_arg in args.iter_mut() { - let ty = match generic_arg { - syn::GenericArgument::Type(ty) => ty, - _ => unimplemented!(), - }; - - let type_path = match ty { - syn::Type::Path(type_path) => type_path, - _ => unimplemented!(), - }; - - if type_path.qself.is_some() { - unimplemented!(); - } - - // Recursively replace default arguments: - assign_defaults_path(&mut type_path.path, defaults); - } - } -} - -/// Remove all of our `#[capnp_conv(with = ...)]` attributes -pub fn remove_with_attributes(input: &mut syn::DeriveInput) { - match input.data { - syn::Data::Struct(ref mut data) => match data.fields { - syn::Fields::Named(ref mut fields_named) => { - for field in fields_named.named.iter_mut() { - // Remove all the attributes that look like: `capnp_conv(...)` - field.attrs.retain(|attr| !attr.path.is_ident("capnp_conv")); - } - } - syn::Fields::Unnamed(_) | syn::Fields::Unit => unimplemented!(), - }, - syn::Data::Enum(ref mut data_enum) => { - for variant in data_enum.variants.iter_mut() { - // Remove all the attributes that look like: `capnp_conv(...)` - variant - .attrs - .retain(|attr| !attr.path.is_ident("capnp_conv")); - } - } - - syn::Data::Union(_) => unimplemented!(), - }; -} - -#[derive(Debug)] -pub struct CapnpWithAttribute { - #[allow(dead_code)] - pub paren_token: syn::token::Paren, - pub with_ident: syn::Ident, - pub eq_token: syn::Token![=], - pub path: syn::Path, -} - -impl syn::parse::Parse for CapnpWithAttribute { - fn parse(input: syn::parse::ParseStream) -> syn::parse::Result { - let content; - let paren_token = syn::parenthesized!(content in input); - Ok(Self { - paren_token, - with_ident: content.parse()?, - eq_token: content.parse()?, - path: content.parse()?, - }) - } -} diff --git a/components/capnp_conv/src/lib.rs b/components/capnp_conv/src/lib.rs deleted file mode 100644 index 29097e839..000000000 --- a/components/capnp_conv/src/lib.rs +++ /dev/null @@ -1,89 +0,0 @@ -#![crate_type = "lib"] -#![deny(trivial_numeric_casts, warnings)] -#![allow(broken_intra_doc_links)] -#![allow( - clippy::too_many_arguments, - clippy::implicit_hasher, - clippy::module_inception, - clippy::new_without_default -)] - -// Workaround for issue: https://github.com/rust-lang/rust/issues/64450 -extern crate offset_capnp_conv_derive as capnp_conv_derive; - -use std::io; - -use derive_more::From; - -pub use capnp_conv_derive::capnp_conv; - -#[derive(Debug, From)] -pub enum CapnpConvError { - CapnpError(capnp::Error), - NotInSchema(capnp::NotInSchema), - IoError(io::Error), -} - -/// Convert Rust struct to Capnp. -pub trait WriteCapnp<'a> { - /// The corresponding Capnp writer type. - // type WriterType: capnp::traits::FromPointerBuilder<'a>; - type WriterType: capnp::traits::FromPointerBuilder<'a>; - - /// Converts a Rust struct to corresponding Capnp struct. This should not fail. - fn write_capnp(&self, writer: &mut Self::WriterType); -} - -/// Convert Capnp struct to Rust. -pub trait ReadCapnp<'a>: Sized { - /// The corresponding Capnp reader type. - type ReaderType: capnp::traits::FromPointerReader<'a>; - - /// Converts a Capnp struct to corresponding Rust struct. - fn read_capnp(reader: &Self::ReaderType) -> Result; -} - -pub trait ToCapnpBytes { - /// Serialize a Rust struct into bytes using Capnp - fn to_capnp_bytes(&self) -> Vec; -} - -pub trait FromCapnpBytes: Sized { - /// Deserialize a Rust struct from bytes using Capnp - fn from_capnp_bytes(bytes: &[u8]) -> Result; -} - -impl ToCapnpBytes for T -where - T: for<'a> WriteCapnp<'a>, -{ - fn to_capnp_bytes(&self) -> Vec { - let mut builder = capnp::message::Builder::new_default(); - - // A trick to avoid borrow checker issues: - { - let mut struct_builder = builder.init_root::(); - self.write_capnp(&mut struct_builder); - } - - let mut data = Vec::new(); - // Should never really fail: - capnp::serialize_packed::write_message(&mut data, &builder).unwrap(); - data - } -} - -impl FromCapnpBytes for T -where - T: for<'a> ReadCapnp<'a>, -{ - fn from_capnp_bytes(bytes: &[u8]) -> Result { - let mut cursor = io::Cursor::new(&bytes); - let reader = capnp::serialize_packed::read_message( - &mut cursor, - capnp::message::ReaderOptions::new(), - )?; - let struct_reader = reader.get_root::()?; - Ok(Self::read_capnp(&struct_reader)?) - } -} diff --git a/components/capnp_conv/tests/capnp/test.capnp b/components/capnp_conv/tests/capnp/test.capnp deleted file mode 100644 index 61ca67a6b..000000000 --- a/components/capnp_conv/tests/capnp/test.capnp +++ /dev/null @@ -1,109 +0,0 @@ -@0xc90daeac68e62b2a; - -struct TestStructInner { - innerU8 @0: UInt8; -} - -struct TestUnion { - union { - variantOne @0: UInt64; - variantTwo @1: TestStructInner; - variantThree @2: Void; - variantFour @3: Text; - } -} - -struct ListUnion { - union { - empty @0: Void; - withList @1: List(TestStructInner); - withData @2: Data; - testUnion @3: TestUnion; - inlineInnerUnion: union { - ab @4: UInt32; - cd @5: UInt64; - } - } -} - -struct TestStruct { - myBool @0: Bool; - myInt8 @1: Int8; - myInt16 @2: Int16; - myInt32 @3: Int32; - myInt64 @4: Int64; - myUint8 @5: UInt8; - myUint16 @6: UInt16; - myUint32 @7: UInt32; - myUint64 @8: UInt64; - # my_float32: f32, - # my_float64: f64, - myText @9: Text; - myData @10: Data; - structInner @11: TestStructInner; - myPrimitiveList @12: List(UInt16); - myList @13: List(TestStructInner); - inlineUnion: union { - firstVariant @14: UInt64; - secondVariant @15: TestStructInner; - thirdVariant @16: Void; - } - externalUnion @17: TestUnion; - listUnion @18: ListUnion; -} - -struct FloatStruct { - myFloat32 @0: Float32; - myFloat64 @1: Float64; -} - -struct GenericStruct { - a @0: UInt32; - b @1: UInt64; - c @2: UInt8; - d @3: Data; - e @4: List(TestStructInner); - f @5: TestStructInner; -} - -struct GenericEnum { - union { - varA @0: UInt32; - varB @1: TestStructInner; - varC @2: UInt64; - varD @3: Data; - } -} - -struct InnerGeneric { - a @0: UInt32; -} - -struct ListGeneric { - list @0: List(InnerGeneric); -} - -# A custom made 128 bit data structure. -struct Buffer128 { - x0 @0: UInt64; - x1 @1: UInt64; -} - -# Unsigned 128 bit integer -struct CustomUInt128 { - inner @0: Buffer128; -} - - -struct TestWithStruct { - a @0: CustomUInt128; - b @1: UInt64; -} - -struct TestWithEnum { - union { - varA @0: CustomUInt128; - varB @1: UInt64; - varC @2: Void; - } -} diff --git a/components/capnp_conv/tests/derive.rs b/components/capnp_conv/tests/derive.rs deleted file mode 100644 index e68a56e61..000000000 --- a/components/capnp_conv/tests/derive.rs +++ /dev/null @@ -1,221 +0,0 @@ -#![deny(warnings)] - -use offset_capnp_conv::{ - capnp_conv, CapnpConvError, FromCapnpBytes, ReadCapnp, ToCapnpBytes, WriteCapnp, -}; - -#[allow(unused)] -mod test_capnp { - include!(concat!(env!("OUT_DIR"), "/capnp/test_capnp.rs")); -} - -#[capnp_conv(test_capnp::test_struct_inner)] -#[derive(Debug, Clone, PartialEq)] -struct TestStructInner { - inner_u8: u8, -} - -#[capnp_conv(test_capnp::test_struct::inline_union)] -#[derive(Debug, Clone, PartialEq)] -enum InlineUnion { - FirstVariant(u64), - SecondVariant(TestStructInner), - ThirdVariant, -} - -#[capnp_conv(test_capnp::test_union)] -#[derive(Debug, Clone, PartialEq)] -enum TestUnion { - VariantOne(u64), - VariantTwo(TestStructInner), - VariantThree, - VariantFour(String), -} - -#[capnp_conv(test_capnp::list_union::inline_inner_union)] -#[derive(Debug, Clone, PartialEq)] -enum InlineInnerUnion { - Ab(u32), - Cd(u64), -} - -#[capnp_conv(test_capnp::list_union)] -#[derive(Debug, Clone, PartialEq)] -enum ListUnion { - Empty, - WithList(Vec), - WithData(Vec), - TestUnion(TestUnion), - InlineInnerUnion(InlineInnerUnion), -} - -#[capnp_conv(test_capnp::test_struct)] -#[derive(Debug, Clone, PartialEq)] -struct TestStruct { - my_bool: bool, - my_int8: i8, - my_int16: i16, - my_int32: i32, - my_int64: i64, - my_uint8: u8, - my_uint16: u16, - my_uint32: u32, - my_uint64: u64, - my_text: String, - my_data: Vec, - struct_inner: TestStructInner, - my_primitive_list: Vec, - my_list: Vec, - inline_union: InlineUnion, - external_union: TestUnion, - list_union: ListUnion, -} - -#[test] -fn capnp_serialize_basic_struct() { - let test_struct = TestStruct { - my_bool: true, - my_int8: -1i8, - my_int16: 1i16, - my_int32: -1i32, - my_int64: 1i64, - my_uint8: 1u8, - my_uint16: 2u16, - my_uint32: 3u32, - my_uint64: 4u64, - my_text: "my_text".to_owned(), - my_data: vec![1, 2, 3, 4, 5u8], - struct_inner: TestStructInner { inner_u8: 1u8 }, - my_primitive_list: vec![10, 11, 12, 13, 14u16], - my_list: vec![ - TestStructInner { inner_u8: 2u8 }, - TestStructInner { inner_u8: 3u8 }, - TestStructInner { inner_u8: 4u8 }, - ], - inline_union: InlineUnion::SecondVariant(TestStructInner { inner_u8: 5u8 }), - external_union: TestUnion::VariantOne(6u64), - list_union: ListUnion::WithList(vec![ - TestStructInner { inner_u8: 10u8 }, - TestStructInner { inner_u8: 11u8 }, - ]), - }; - - let data = test_struct.to_capnp_bytes(); - let test_struct2 = TestStruct::from_capnp_bytes(&data).unwrap(); - - assert_eq!(test_struct, test_struct2); -} - -#[capnp_conv(test_capnp::float_struct)] -#[derive(Debug, Clone)] -struct FloatStruct { - my_float32: f32, - my_float64: f64, -} - -/// We test floats separately, because in Rust floats to not implement PartialEq -#[test] -fn capnp_serialize_floats() { - let float_struct = FloatStruct { - my_float32: -0.5f32, - my_float64: 0.5f64, - }; - - let data = float_struct.to_capnp_bytes(); - let float_struct2 = FloatStruct::from_capnp_bytes(&data).unwrap(); - - // Sloppily check that the floats are close enough (We can't compare them directly, as they - // don't implement PartialEq) - assert_eq!( - (float_struct.my_float32 * 10000.0).trunc(), - (float_struct2.my_float32 * 10000.0).trunc() - ); - - assert_eq!( - (float_struct.my_float64 * 10000.0).trunc(), - (float_struct2.my_float64 * 10000.0).trunc() - ); -} - -#[capnp_conv(test_capnp::generic_struct)] -#[derive(Debug, Clone, PartialEq)] -struct GenericStruct { - a: A, - pub b: B, - c: u8, - pub d: Vec, - e: Vec, - f: E, -} - -#[test] -fn capnp_serialize_generic_struct() { - let generic_struct = GenericStruct { - a: 1u32, - b: 2u64, - c: 3u8, - d: vec![1, 2, 3, 4u8], - e: vec![ - TestStructInner { inner_u8: 2u8 }, - TestStructInner { inner_u8: 3u8 }, - TestStructInner { inner_u8: 4u8 }, - ], - f: TestStructInner { inner_u8: 5u8 }, - }; - - let data = generic_struct.to_capnp_bytes(); - let generic_struct2 = GenericStruct::from_capnp_bytes(&data).unwrap(); - - assert_eq!(generic_struct, generic_struct2); -} - -#[capnp_conv(test_capnp::generic_enum)] -#[derive(Debug, Clone, PartialEq)] -enum GenericEnum> { - VarA(A), - VarB(B), - VarC(u64), - VarD(V), -} - -#[test] -fn capnp_serialize_generic_enum() { - for generic_enum in &[ - GenericEnum::VarA(1u32), - GenericEnum::VarB(TestStructInner { inner_u8: 2u8 }), - GenericEnum::VarC(3u64), - GenericEnum::VarD(vec![1, 2, 3, 4u8]), - ] { - let data = generic_enum.to_capnp_bytes(); - let generic_enum2 = GenericEnum::from_capnp_bytes(&data).unwrap(); - assert_eq!(generic_enum.clone(), generic_enum2); - } -} - -#[capnp_conv(test_capnp::inner_generic)] -#[derive(Debug, Clone, PartialEq)] -struct InnerGeneric { - a: A, -} - -#[capnp_conv(test_capnp::list_generic)] -#[derive(Debug, Clone, PartialEq)] -struct ListGeneric { - list: Vec>, -} - -#[test] -fn capnp_serialize_generic_list() { - let list_generic = ListGeneric { - list: vec![ - InnerGeneric { a: 1u32 }, - InnerGeneric { a: 2u32 }, - InnerGeneric { a: 3u32 }, - ], - }; - - let data = list_generic.to_capnp_bytes(); - let list_generic2 = ListGeneric::from_capnp_bytes(&data).unwrap(); - - assert_eq!(list_generic, list_generic2); -} diff --git a/components/capnp_conv/tests/with.rs b/components/capnp_conv/tests/with.rs deleted file mode 100644 index 733711dfd..000000000 --- a/components/capnp_conv/tests/with.rs +++ /dev/null @@ -1,103 +0,0 @@ -#![deny(warnings)] - -use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt}; -#[allow(unused)] -use offset_capnp_conv::{ - capnp_conv, CapnpConvError, FromCapnpBytes, ReadCapnp, ToCapnpBytes, WriteCapnp, -}; - -#[allow(unused)] -mod test_capnp { - include!(concat!(env!("OUT_DIR"), "/capnp/test_capnp.rs")); -} - -#[derive(derive_more::Constructor, Debug, Clone, Copy, PartialEq, Eq)] -pub struct Wrapper(T); - -/* -impl std::ops::Deref for Wrapper { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -}*/ - -impl From for Wrapper { - fn from(t: T) -> Self { - Wrapper(t) - } -} - -impl Into for Wrapper { - fn into(self) -> u128 { - self.0 - } -} - -impl<'a> WriteCapnp<'a> for Wrapper { - type WriterType = crate::test_capnp::custom_u_int128::Builder<'a>; - - fn write_capnp(&self, writer: &mut Self::WriterType) { - let mut inner = writer.reborrow().get_inner().unwrap(); - - let mut data_bytes = Vec::new(); - - data_bytes - .write_u128::(self.clone().into()) - .unwrap(); - let mut cursor = std::io::Cursor::new(AsRef::<[u8]>::as_ref(&data_bytes)); - - inner.set_x0(cursor.read_u64::().unwrap()); - inner.set_x1(cursor.read_u64::().unwrap()); - } -} - -impl<'a> ReadCapnp<'a> for Wrapper { - type ReaderType = crate::test_capnp::custom_u_int128::Reader<'a>; - - fn read_capnp(reader: &Self::ReaderType) -> Result { - let inner = reader.get_inner()?; - let mut vec = Vec::new(); - vec.write_u64::(inner.get_x0())?; - vec.write_u64::(inner.get_x1())?; - Ok(Wrapper::new(BigEndian::read_u128(&vec[..]))) - } -} - -#[capnp_conv(test_capnp::test_with_struct)] -#[derive(Debug, Clone, PartialEq)] -struct TestWithStruct { - #[capnp_conv(with = Wrapper)] - a: u128, - b: u64, -} - -#[test] -fn capnp_serialize_with_struct() { - let test_with_struct = TestWithStruct { a: 1u128, b: 2u64 }; - - let data = test_with_struct.to_capnp_bytes(); - let test_with_struct2 = TestWithStruct::from_capnp_bytes(&data).unwrap(); - - assert_eq!(test_with_struct, test_with_struct2); -} - -#[capnp_conv(test_capnp::test_with_enum)] -#[derive(Debug, Clone, PartialEq)] -enum TestWithEnum { - #[capnp_conv(with = Wrapper)] - VarA(u128), - VarB(u64), - VarC, -} - -#[test] -fn capnp_serialize_with_enum() { - let test_with_enum = TestWithEnum::VarA(1u128); - - let data = test_with_enum.to_capnp_bytes(); - let test_with_enum2 = TestWithEnum::from_capnp_bytes(&data).unwrap(); - - assert_eq!(test_with_enum, test_with_enum2); -} diff --git a/components/proto/src/crypto/mod.rs b/components/proto/src/crypto/mod.rs index e91a1e304..af636c5b6 100644 --- a/components/proto/src/crypto/mod.rs +++ b/components/proto/src/crypto/mod.rs @@ -14,8 +14,6 @@ use common::define_fixed_bytes; // #[macro_use] // mod serialize; -// use self::serialize::{type_capnp_serde128, type_capnp_serde256, type_capnp_serde512}; -// define_fixed_bytes!(HmacResult, 32); define_fixed_bytes!(HmacKey, 32); diff --git a/components/proto/src/macros.rs b/components/proto/src/macros.rs deleted file mode 100644 index 9eb50e73e..000000000 --- a/components/proto/src/macros.rs +++ /dev/null @@ -1,13 +0,0 @@ -/// Include a capnp schema -macro_rules! include_schema { - ($( $name:ident, $path:expr );*) => { - $( - #[allow(unused, clippy::all)] - pub mod $name { - include!(concat!(env!("OUT_DIR"), "/schema/", $path, ".rs")); - } - - // use self::$name::*; - )* - }; -} diff --git a/components/proto/src/wrapper.rs b/components/proto/src/wrapper.rs deleted file mode 100644 index 3fea306cc..000000000 --- a/components/proto/src/wrapper.rs +++ /dev/null @@ -1,105 +0,0 @@ -use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt}; - -use serde::{Deserialize, Serialize}; - -use capnp_conv::{CapnpConvError, ReadCapnp, WriteCapnp}; - -#[derive( - derive_more::Constructor, - derive_more::From, - Serialize, - Deserialize, - Debug, - Clone, - Copy, - PartialEq, - Eq, -)] -pub struct Wrapper(T); - -impl std::ops::Deref for Wrapper { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Into for Wrapper { - fn into(self) -> u128 { - self.0 - } -} - -impl Into for Wrapper { - fn into(self) -> i128 { - self.0 - } -} - -impl<'a> WriteCapnp<'a> for Wrapper { - type WriterType = crate::common_capnp::custom_u_int128::Builder<'a>; - - fn write_capnp(&self, writer: &mut Self::WriterType) { - let mut inner = writer.reborrow().get_inner().unwrap(); - - let mut data_bytes = Vec::new(); - data_bytes.write_u128::(**self).unwrap(); - let mut cursor = std::io::Cursor::new(AsRef::<[u8]>::as_ref(&data_bytes)); - - inner.set_x0(cursor.read_u64::().unwrap()); - inner.set_x1(cursor.read_u64::().unwrap()); - } -} - -impl<'a> ReadCapnp<'a> for Wrapper { - type ReaderType = crate::common_capnp::custom_u_int128::Reader<'a>; - - fn read_capnp(reader: &Self::ReaderType) -> Result { - let inner = reader.get_inner()?; - let mut vec = Vec::new(); - vec.write_u64::(inner.get_x0())?; - vec.write_u64::(inner.get_x1())?; - Ok(Wrapper::new(BigEndian::read_u128(&vec[..]))) - } -} - -impl<'a> WriteCapnp<'a> for Wrapper { - type WriterType = crate::common_capnp::custom_int128::Builder<'a>; - - fn write_capnp(&self, writer: &mut Self::WriterType) { - let mut inner = writer.reborrow().get_inner().unwrap(); - - let mut data_bytes = Vec::new(); - data_bytes.write_i128::(**self).unwrap(); - let mut cursor = std::io::Cursor::new(AsRef::<[u8]>::as_ref(&data_bytes)); - - inner.set_x0(cursor.read_u64::().unwrap()); - inner.set_x1(cursor.read_u64::().unwrap()); - } -} - -impl<'a> ReadCapnp<'a> for Wrapper { - type ReaderType = crate::common_capnp::custom_int128::Reader<'a>; - - fn read_capnp(reader: &Self::ReaderType) -> Result { - let inner = reader.get_inner()?; - let mut vec = Vec::new(); - vec.write_u64::(inner.get_x0())?; - vec.write_u64::(inner.get_x1())?; - Ok(Wrapper::new(BigEndian::read_i128(&vec[..]))) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - fn test_convert_wrapper() { - let _wrapper: Wrapper = 1i128.into(); - let _signed: i128 = Wrapper(1i128).into(); - let _signed: i128 = *Wrapper(1i128); - } -} diff --git a/components/signature/src/canonical.rs b/components/signature/src/canonical.rs index 4d1a13172..774ffeb4f 100644 --- a/components/signature/src/canonical.rs +++ b/components/signature/src/canonical.rs @@ -3,7 +3,7 @@ use byteorder::{BigEndian, WriteBytesExt}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ - CancelSendFundsOp, Currency, CurrencyOperations, FriendTcOp, FriendsRoute, McBalance, Receipt, + CancelSendFundsOp, Currency, CurrencyOperations, FriendTcOp, FriendsRoute, McBalance, RequestSendFundsOp, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; @@ -224,6 +224,7 @@ impl CanonicalSerialize for FriendsRoute { } } +/* impl CanonicalSerialize for Receipt { fn canonical_serialize(&self) -> Vec { let mut res_bytes = Vec::new(); @@ -236,6 +237,7 @@ impl CanonicalSerialize for Receipt { res_bytes } } +*/ impl CanonicalSerialize for NetAddress { fn canonical_serialize(&self) -> Vec { diff --git a/components/signature/src/verify.rs b/components/signature/src/verify.rs index d9cddc3eb..03d18e70d 100644 --- a/components/signature/src/verify.rs +++ b/components/signature/src/verify.rs @@ -1,19 +1,21 @@ -use byteorder::{BigEndian, WriteBytesExt}; +// use byteorder::{BigEndian, WriteBytesExt}; -use crypto::hash; -use crypto::hash_lock::HashLock; +// use crypto::hash; +// use crypto::hash_lock::HashLock; use crypto::identity::verify_signature; use proto::crypto::PublicKey; -use proto::funder::messages::{Commit, MoveToken, Receipt}; +use proto::funder::messages::MoveToken; use proto::index_server::messages::MutationsUpdate; -use crate::canonical::CanonicalSerialize; +// use crate::canonical::CanonicalSerialize; use crate::signature_buff::{ - create_mutations_update_signature_buff, move_token_signature_buff, FUNDS_RESPONSE_PREFIX, + create_mutations_update_signature_buff, + move_token_signature_buff, /*, FUNDS_RESPONSE_PREFIX,*/ }; +/* // TODO: Add a local test that makes sure verify_receipt is in sync with verify_commit_signature /// Verify that a given receipt's signature is valid pub fn verify_receipt(receipt: &Receipt, public_key: &PublicKey) -> bool { @@ -31,7 +33,9 @@ pub fn verify_receipt(receipt: &Receipt, public_key: &PublicKey) -> bool { data.extend_from_slice(&receipt.currency.canonical_serialize()); verify_signature(&data, public_key, &receipt.signature) } +*/ +/* /// Verify that a given Commit signature is valid fn verify_commit_signature(commit: &Commit, local_public_key: &PublicKey) -> bool { let mut data = Vec::new(); @@ -60,6 +64,7 @@ pub fn verify_commit(commit: &Commit, local_public_key: &PublicKey) -> bool { // Verify signature: verify_commit_signature(commit, local_public_key) } +*/ /// Verify that new_token is a valid signature over the rest of the fields. pub fn verify_move_token(move_token: &MoveToken, public_key: &PublicKey) -> bool { From 9e222f4c92cc3a73d7547d41fbcdd0b6cdc2747c Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 19:18:25 +0200 Subject: [PATCH 265/478] proto: Removed unused proto_ser.rs file --- components/proto/src/proto_ser.rs | 36 ------------------------------- 1 file changed, 36 deletions(-) delete mode 100644 components/proto/src/proto_ser.rs diff --git a/components/proto/src/proto_ser.rs b/components/proto/src/proto_ser.rs deleted file mode 100644 index 045b99872..000000000 --- a/components/proto/src/proto_ser.rs +++ /dev/null @@ -1,36 +0,0 @@ -use derive_more::From; - -use capnp_conv::{CapnpConvError, FromCapnpBytes, ToCapnpBytes}; - -#[derive(Debug, From)] -pub enum ProtoSerializeError { - CapnpConvError(CapnpConvError), -} - -pub trait ProtoSerialize { - /// Serialize a Rust struct into bytes using Capnp - fn proto_serialize(&self) -> Vec; -} - -pub trait ProtoDeserialize: Sized { - /// Deserialize a Rust struct from bytes using Capnp - fn proto_deserialize(bytes: &[u8]) -> Result; -} - -impl ProtoSerialize for T -where - T: ToCapnpBytes, -{ - fn proto_serialize(&self) -> Vec { - self.to_capnp_bytes() - } -} - -impl ProtoDeserialize for T -where - T: FromCapnpBytes, -{ - fn proto_deserialize(bytes: &[u8]) -> Result { - Ok(Self::from_capnp_bytes(bytes)?) - } -} From e89bc267d5016c7857993b16055069ef459e3f28 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 19:23:22 +0200 Subject: [PATCH 266/478] proto: Removed old comments --- components/proto/src/lib.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/components/proto/src/lib.rs b/components/proto/src/lib.rs index 76bc3cdc8..eb281ae41 100644 --- a/components/proto/src/lib.rs +++ b/components/proto/src/lib.rs @@ -13,8 +13,6 @@ extern crate quickcheck_derive; // Workaround for issue: https://github.com/rust-lang/rust/issues/64450 extern crate offset_mutual_from as mutual_from; -// #[macro_use] -// pub mod macros; pub mod app_server; pub mod consts; pub mod crypto; @@ -24,20 +22,7 @@ pub mod index_client; pub mod index_server; pub mod keepalive; pub mod net; -// pub mod proto_ser; pub mod relay; // pub mod report; pub mod secure_channel; pub mod ser_string; -// pub mod wrapper; - -/* -// include_schema!(report_capnp, "report_capnp"); -include_schema!(app_server_capnp, "app_server_capnp"); -include_schema!(common_capnp, "common_capnp"); -include_schema!(dh_capnp, "dh_capnp"); -include_schema!(relay_capnp, "relay_capnp"); -// include_schema!(funder_capnp, "funder_capnp"); -include_schema!(keepalive_capnp, "keepalive_capnp"); -include_schema!(index_capnp, "index_capnp"); -*/ From 3560b7d8d83018048e85d8d5d5554619af770980 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 19:27:23 +0200 Subject: [PATCH 267/478] README.md: Removed capnp installation info --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index baaa69386..333d4c417 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,6 @@ the crate's `Cargo.toml`. ### Install dependencies - Install [Rust](https://www.rust-lang.org/tools/install). -- Install [capnproto](https://capnproto.org): - - On Ubuntu, run: `sudo apt install capnproto` - - On macOS, run: `brew install canpnp` ### Rust toolchain version From e30f8d13cac8b377378cd25dba0923b4fb4448e9 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 20:10:13 +0200 Subject: [PATCH 268/478] Removed capnp installation from ci --- .travis.yml | 5 ----- ci/android_install.sh | 3 --- ci/pre/capnp.sh | 25 ------------------------- 3 files changed, 33 deletions(-) delete mode 100755 ci/pre/capnp.sh diff --git a/.travis.yml b/.travis.yml index e7d5d389d..34693f96a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,8 +43,6 @@ jobs: # Add clippy and rustfmt: - rustup update - rustup component add clippy rustfmt - # Install capnp: - - ci/pre/capnp.sh # Check formatting: - cargo fmt --all -- --check # Run clippy check: @@ -69,8 +67,6 @@ jobs: os: osx osx_image: xcode11.3 # Solution due to https://travis-ci.community/t/homebrew-syntax-error/5623 : - before_script: - - HOMEBREW_NO_AUTO_UPDATE=1 brew install capnp script: - cargo test @@ -81,7 +77,6 @@ jobs: # See: https://travis-ci.community/t/windows-instances-hanging-before-install/250/25 filter_secrets: false before_script: - - choco install capnproto - rustup target add x86_64-pc-windows-msvc script: - cargo test diff --git a/ci/android_install.sh b/ci/android_install.sh index f3f20bb67..a2b7d0b1a 100755 --- a/ci/android_install.sh +++ b/ci/android_install.sh @@ -43,6 +43,3 @@ cd - # Make sure rust stable is installed rustup install stable - -# Install capnp: -ci/pre/capnp.sh diff --git a/ci/pre/capnp.sh b/ci/pre/capnp.sh deleted file mode 100755 index c0b085d54..000000000 --- a/ci/pre/capnp.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -# See: https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ -set -eux -o pipefail - -CAPNP_INSTALL_PREFIX="${HOME}/install/capnp" - -CAPNP_VERSION="0.7.0" - -export CC="gcc-6" -export CXX="g++-6" -export CPPFLAGS="-std=c++14" -export CXXFLAGS="-std=c++14" - -# Build only if we don't have a cached installation: -if [ ! -d "$CAPNP_INSTALL_PREFIX/lib" ]; then - curl -L https://capnproto.org/capnproto-c++-${CAPNP_VERSION}.tar.gz | tar -zxf - - pushd capnproto-c++-${CAPNP_VERSION} - ./configure --prefix=${CAPNP_INSTALL_PREFIX} - make check -j2 - sudo make install - popd -fi - -sudo ln -s ${CAPNP_INSTALL_PREFIX}/bin/capnp /usr/local/bin/capnp From df66257ffae43fc77a1157ea10e94e0c02cca8fe Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 20:17:00 +0200 Subject: [PATCH 269/478] funder: Moved structures to offset-proto --- components/funder/src/token_channel/mod.rs | 2 +- .../tests/inconsistency_resolve.rs | 7 +++--- .../funder/src/token_channel/tests/utils.rs | 6 +++-- .../funder/src/token_channel/token_channel.rs | 6 +++-- components/funder/src/token_channel/types.rs | 22 +------------------ components/proto/src/funder/messages.rs | 20 ++++++++++++----- 6 files changed, 29 insertions(+), 34 deletions(-) diff --git a/components/funder/src/token_channel/mod.rs b/components/funder/src/token_channel/mod.rs index 63b133143..d7509bd43 100644 --- a/components/funder/src/token_channel/mod.rs +++ b/components/funder/src/token_channel/mod.rs @@ -10,4 +10,4 @@ pub use self::token_channel::{ ReceiveMoveTokenOutput, TokenChannelError, }; -pub use types::{ResetBalance, TcDbClient, TcStatus}; +pub use types::{TcDbClient, TcStatus}; diff --git a/components/funder/src/token_channel/tests/inconsistency_resolve.rs b/components/funder/src/token_channel/tests/inconsistency_resolve.rs index 37c35cd7b..8cb7c6e68 100644 --- a/components/funder/src/token_channel/tests/inconsistency_resolve.rs +++ b/components/funder/src/token_channel/tests/inconsistency_resolve.rs @@ -16,7 +16,8 @@ use proto::crypto::{ HashResult, HashedLock, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid, }; use proto::funder::messages::{ - Currency, CurrencyOperations, FriendTcOp, FriendsRoute, RequestSendFundsOp, ResponseSendFundsOp, + Currency, CurrencyOperations, FriendTcOp, FriendsRoute, RequestSendFundsOp, ResetBalance, + ResponseSendFundsOp, }; use identity::{create_identity, IdentityClient}; @@ -25,8 +26,8 @@ use crate::mutual_credit::incoming::IncomingMessage; use crate::token_channel::tests::utils::MockTokenChannel; use crate::token_channel::{ accept_remote_reset, handle_in_move_token, handle_out_move_token, load_remote_reset_terms, - reset_balance_to_mc_balance, MoveTokenReceived, ReceiveMoveTokenOutput, ResetBalance, - TcDbClient, TcStatus, TokenChannelError, + reset_balance_to_mc_balance, MoveTokenReceived, ReceiveMoveTokenOutput, TcDbClient, TcStatus, + TokenChannelError, }; use crate::types::create_pending_transaction; diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 618fb7b97..c2e053f99 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -10,7 +10,9 @@ use common::safe_arithmetic::SafeSignedArithmetic; use common::u256::U256; use proto::crypto::{PublicKey, Signature}; -use proto::funder::messages::{Currency, McBalance, MoveToken, TokenInfo}; +use proto::funder::messages::{ + Currency, McBalance, MoveToken, ResetBalance, ResetTerms, TokenInfo, +}; use signature::canonical::CanonicalSerialize; @@ -21,7 +23,7 @@ use crypto::hash::hash_buffer; use crypto::identity::compare_public_key; use crate::mutual_credit::tests::MockMutualCredit; -use crate::token_channel::types::{ResetBalance, ResetTerms, TcStatus}; +use crate::token_channel::types::TcStatus; use crate::token_channel::{initial_move_token, reset_balance_to_mc_balance, TcDbClient}; use crate::types::{create_hashed, MoveTokenHashed}; diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 77c64c18d..4eb4b0eda 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -18,7 +18,9 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddress; use proto::crypto::{HashResult, PublicKey, RandValue, Signature}; -use proto::funder::messages::{Currency, CurrencyOperations, McBalance, MoveToken, TokenInfo}; +use proto::funder::messages::{ + Currency, CurrencyOperations, McBalance, MoveToken, ResetBalance, ResetTerms, TokenInfo, +}; use signature::canonical::CanonicalSerialize; use signature::signature_buff::{ @@ -34,7 +36,7 @@ use crate::mutual_credit::incoming::{ use crate::mutual_credit::outgoing::{queue_operation, QueueOperationError}; use crate::mutual_credit::types::McDbClient; -use crate::token_channel::types::{ResetBalance, ResetTerms, TcDbClient, TcStatus}; +use crate::token_channel::types::{TcDbClient, TcStatus}; use crate::types::{create_hashed, MoveTokenHashed}; /// Unrecoverable TokenChannel error diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index dbf603259..b34bb7ea3 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -6,7 +6,7 @@ use common::async_rpc::{AsyncOpResult, AsyncOpStream}; use common::u256::U256; use proto::crypto::Signature; -use proto::funder::messages::{Currency, McBalance, MoveToken}; +use proto::funder::messages::{Currency, McBalance, MoveToken, ResetBalance, ResetTerms}; use database::interface::funder::CurrencyConfig; @@ -22,26 +22,6 @@ pub enum TcOpError { pub type TcOpResult = Result; pub type TcOpSenderResult = oneshot::Sender>; -// TODO: Might move to proto in the future: -/// Balances for resetting a currency -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ResetBalance { - pub balance: i128, - pub in_fees: U256, - pub out_fees: U256, -} - -// TODO: Maybe shouldn't be cloneable (because reset balances could be large) -// TODO: Might move to proto in the future: -/// Reset terms for a token channel -#[derive(Debug, Clone)] -pub struct ResetTerms { - pub reset_token: Signature, - pub move_token_counter: u128, - // TODO: Rename: - pub reset_balances: HashMap, -} - /// Status of a TokenChannel. Could be either outgoing, incoming or inconsistent. #[derive(Debug)] pub enum TcStatus { diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index f1d07e440..d66a40509 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -1,5 +1,5 @@ use std::cmp::Eq; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::convert::TryFrom; use std::fmt; use std::hash::Hash; @@ -341,13 +341,23 @@ pub struct CurrencyBalance { pub balance: i128, } -#[derive(Arbitrary, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +/// Balances for resetting a currency +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ResetBalance { + pub balance: i128, + pub in_fees: U256, + pub out_fees: U256, +} + +// TODO: Maybe shouldn't be cloneable (because reset balances could be large) +// TODO: Might move to proto in the future: +/// Reset terms for a token channel +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ResetTerms { - #[serde(with = "ser_b64")] pub reset_token: Signature, - #[serde(with = "ser_string")] pub move_token_counter: u128, - pub balance_for_reset: Vec, + // TODO: Rename: + pub reset_balances: HashMap, } #[derive(Arbitrary, PartialEq, Eq, Clone, Serialize, Debug)] From a922b850038904dcf10a76f7faddba9cb203770f Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 20:39:42 +0200 Subject: [PATCH 270/478] funder: Added to set_friend_online() impl --- components/funder/src/switch/switch.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index ee3a225f3..215a71b92 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -242,25 +242,11 @@ pub async fn set_friend_online( ); } TcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { - // Convert to proto's reset terms: - // TODO: This will probably not be required in the future, when we move to another - // serialization strategy? - - /* - let proto_local_reset_terms = proto::funder::messages::ResetTerms { - reset_token: local_reset_terms.reset_token, - move_token_counter: local_reset_terms.move_token_counter, - balance_for_reset: local_reset_terms.reset_balances.into_iter(|(currency, reset_balance) - - } - // Resend reset terms output.add_friend_message( friend_public_key.clone(), FriendMessage::InconsistencyError(local_reset_terms), ); - */ - todo!(); } } From c1609bef0e1f2cacf646a1a88e548b23e1feaea7 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 20:42:26 +0200 Subject: [PATCH 271/478] funder: Initial stub for set_friend_offline() --- components/funder/src/switch/switch.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 215a71b92..7808fa95d 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -18,6 +18,7 @@ use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenCha #[derive(Debug, From)] pub enum SwitchError { FriendAlreadyOnline, + FriendAlreadyOffline, GenerationOverflow, TokenChannelError(TokenChannelError), OpError(OpError), @@ -254,10 +255,22 @@ pub async fn set_friend_online( } pub async fn set_friend_offline( - _switch_db_client: &mut impl SwitchDbClient, - _switch_state: &mut SwitchState, - _friend_public_key: PublicKey, + switch_db_client: &mut impl SwitchDbClient, + switch_state: &mut SwitchState, + friend_public_key: PublicKey, ) -> Result { + if !switch_state.liveness.is_online(&friend_public_key) { + // The friend is already marked as offline! + return Err(SwitchError::FriendAlreadyOffline); + } + switch_state.liveness.set_offline(&friend_public_key); + + // TODO: + // - Cancel all pending requests + // - Possibly send outgoing cancels to relevant friends? (Through SwitchOutput) + // - Cancel all user pending requests + // - Possibly send outgoing cancels? (Through SwitchOutput) + todo!(); } From 632e14e218c4ee62677b87a28acec1c0164a245d Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 20:45:55 +0200 Subject: [PATCH 272/478] funder: Removed old comment --- components/funder/src/token_channel/token_channel.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 4eb4b0eda..3a9c87038 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -650,9 +650,6 @@ async fn handle_incoming_token_match( } } - // TODO: How do we pass the new relay's information? Do we need to update anything related to - // the new relays? - // Attempt to apply operations for every currency: for currency_operations in &new_move_token.currencies_operations { let remote_max_debt = tc_client From f7929e4b8127d221934746d693c64f31285ad5b5 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 21:13:29 +0200 Subject: [PATCH 273/478] funder: CurrenciesOperations updated to be a HashMap --- components/funder/src/switch/switch.rs | 22 ++++-------- .../tests/inconsistency_resolve.rs | 7 ++-- .../token_channel/tests/move_token_basic.rs | 29 +++++++++------ .../funder/src/token_channel/token_channel.rs | 35 +++++++++---------- components/proto/src/funder/messages.rs | 5 ++- 5 files changed, 50 insertions(+), 48 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 7808fa95d..0a73af929 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -8,8 +8,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddress; use proto::crypto::PublicKey; use proto::funder::messages::{ - CancelSendFundsOp, Currency, CurrencyOperations, FriendMessage, FriendTcOp, MoveToken, - MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, + CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, + FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, }; use crate::switch::types::{BackwardsOp, SwitchDbClient, SwitchOutput, SwitchState}; @@ -26,22 +26,12 @@ pub enum SwitchError { fn operations_vec_to_currencies_operations( operations_vec: Vec<(Currency, FriendTcOp)>, -) -> Vec { - let mut operations_map = HashMap::>::new(); +) -> CurrenciesOperations { + let mut currencies_operations = HashMap::>::new(); for (currency, tc_op) in operations_vec { - let entry = operations_map.entry(currency).or_insert(Vec::new()); + let entry = currencies_operations.entry(currency).or_insert(Vec::new()); (*entry).push(tc_op); } - - // Sort by currency, for deterministic results: - let mut currencies_operations: Vec = operations_map - .into_iter() - .map(|(currency, operations)| CurrencyOperations { - currency, - operations, - }) - .collect(); - currencies_operations.sort_by(|co_a, co_b| co_a.currency.cmp(&co_b.currency)); currencies_operations } @@ -49,7 +39,7 @@ async fn collect_currencies_operations( switch_db_client: &mut impl SwitchDbClient, friend_public_key: PublicKey, max_operations_in_batch: usize, -) -> Result, SwitchError> { +) -> Result { let mut operations_vec = Vec::<(Currency, FriendTcOp)>::new(); // Collect any pending responses and cancels: diff --git a/components/funder/src/token_channel/tests/inconsistency_resolve.rs b/components/funder/src/token_channel/tests/inconsistency_resolve.rs index 8cb7c6e68..2ce366483 100644 --- a/components/funder/src/token_channel/tests/inconsistency_resolve.rs +++ b/components/funder/src/token_channel/tests/inconsistency_resolve.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::convert::TryFrom; use futures::task::SpawnExt; @@ -72,7 +73,7 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { // Send a MoveToken message from b to a, adding a currency: // -------------------------------------------------------- - let currencies_operations = Vec::new(); + let currencies_operations = HashMap::new(); let currencies_diff = vec![currency1.clone()]; let move_token = handle_out_move_token( &mut tc_b_a, @@ -106,7 +107,7 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { // Send a MoveToken message from a to b, adding two currencies, // and set incorrect token info hash. // ------------------------------------------------------------ - let currencies_operations = Vec::new(); + let currencies_operations = HashMap::new(); let currencies_diff = vec![currency1.clone(), currency2.clone()]; let move_token = handle_out_move_token( &mut tc_a_b, @@ -191,7 +192,7 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { // b accepts a's reset terms: // -------------------------- - let currencies_operations = Vec::new(); + let currencies_operations = HashMap::new(); let currencies_diff = Vec::new(); let move_token = accept_remote_reset( &mut tc_b_a, diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index e9f457900..b995a2e21 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::convert::TryFrom; use futures::task::SpawnExt; @@ -70,7 +71,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { // Send a MoveToken message from b to a, adding a currency: // -------------------------------------------------------- - let currencies_operations = Vec::new(); + let currencies_operations = HashMap::new(); let currencies_diff = vec![currency1.clone()]; let move_token = handle_out_move_token( &mut tc_b_a, @@ -99,7 +100,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { // Send a MoveToken message from a to b, adding two currencies: // ------------------------------------------------------------ - let currencies_operations = Vec::new(); + let currencies_operations = HashMap::new(); let currencies_diff = vec![currency1.clone(), currency2.clone()]; let move_token = handle_out_move_token( &mut tc_a_b, @@ -142,10 +143,14 @@ async fn task_move_token_basic(test_executor: TestExecutor) { left_fees: 5u128, }; let pending_transaction = create_pending_transaction(&request_send_funds_op); - let currencies_operations = vec![CurrencyOperations { - currency: currency1.clone(), - operations: vec![FriendTcOp::RequestSendFunds(request_send_funds_op.clone())], - }]; + let currencies_operations: HashMap<_, _> = [( + currency1.clone(), + vec![FriendTcOp::RequestSendFunds(request_send_funds_op.clone())], + )] + .iter() + .cloned() + .collect(); + let currencies_diff = vec![]; let move_token = handle_out_move_token( &mut tc_b_a, @@ -233,12 +238,16 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .await .unwrap(); - let currencies_operations = vec![CurrencyOperations { - currency: currency1.clone(), - operations: vec![FriendTcOp::ResponseSendFunds( + let currencies_operations: HashMap<_, _> = [( + currency1.clone(), + vec![FriendTcOp::ResponseSendFunds( response_send_funds_op.clone(), )], - }]; + )] + .iter() + .cloned() + .collect(); + let currencies_diff = vec![]; let move_token = handle_out_move_token( &mut tc_a_b, diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 3a9c87038..addd667e1 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -19,7 +19,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddress; use proto::crypto::{HashResult, PublicKey, RandValue, Signature}; use proto::funder::messages::{ - Currency, CurrencyOperations, McBalance, MoveToken, ResetBalance, ResetTerms, TokenInfo, + Currency, CurrencyOperations, FriendTcOp, McBalance, MoveToken, ResetBalance, ResetTerms, + TokenInfo, }; use signature::canonical::CanonicalSerialize; @@ -103,7 +104,7 @@ pub fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKe // doesn't have the private key). Therefore we use a dummy new_token instead. let move_token_out = MoveToken { old_token: token_from_public_key(&low_public_key), - currencies_operations: Vec::new(), + currencies_operations: HashMap::new(), currencies_diff: Vec::new(), info_hash: hash_token_info(&low_public_key, &high_public_key, &token_info), new_token: token_from_public_key(&high_public_key), @@ -292,7 +293,7 @@ where let move_token_out = MoveToken { old_token: Signature::from(&[0; Signature::len()]), - currencies_operations: Vec::new(), + currencies_operations: HashMap::new(), currencies_diff: Vec::new(), info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), new_token: local_reset_terms.reset_token.clone(), @@ -651,15 +652,13 @@ async fn handle_incoming_token_match( } // Attempt to apply operations for every currency: - for currency_operations in &new_move_token.currencies_operations { - let remote_max_debt = tc_client - .get_remote_max_debt(currency_operations.currency.clone()) - .await?; + for (currency, friend_tc_ops) in &new_move_token.currencies_operations { + let remote_max_debt = tc_client.get_remote_max_debt(currency.clone()).await?; let res = process_operations_list( - tc_client.mc_db_client(currency_operations.currency.clone()), - currency_operations.operations.clone(), - ¤cy_operations.currency, + tc_client.mc_db_client(currency.clone()), + friend_tc_ops.clone(), + ¤cy, remote_public_key, remote_max_debt, ) @@ -677,7 +676,7 @@ async fn handle_incoming_token_match( // We apply mutations on this token channel, to verify stated balance values // let mut check_mutual_credit = mutual_credit.clone(); let move_token_received_currency = MoveTokenReceivedCurrency { - currency: currency_operations.currency.clone(), + currency: currency.clone(), incoming_messages, }; @@ -725,7 +724,7 @@ async fn handle_incoming_token_match( pub async fn handle_out_move_token( tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, - currencies_operations: Vec, + currencies_operations: HashMap>, currencies_diff: Vec, local_public_key: &PublicKey, remote_public_key: &PublicKey, @@ -782,12 +781,12 @@ pub async fn handle_out_move_token( } // Update mutual credits: - for currency_operations in ¤cies_operations { - for operation in currency_operations.operations.iter().cloned() { + for (currency, friend_tc_ops) in ¤cies_operations { + for operation in friend_tc_ops.iter().cloned() { queue_operation( - tc_client.mc_db_client(currency_operations.currency.clone()), + tc_client.mc_db_client(currency.clone()), operation, - ¤cy_operations.currency, + ¤cy, local_public_key, ) .await?; @@ -837,7 +836,7 @@ pub async fn handle_out_move_token( pub async fn accept_remote_reset( tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, - currencies_operations: Vec, + currencies_operations: HashMap>, currencies_diff: Vec, local_public_key: &PublicKey, remote_public_key: &PublicKey, @@ -871,7 +870,7 @@ pub async fn accept_remote_reset( let move_token_in = MoveToken { old_token: Signature::from(&[0; Signature::len()]), - currencies_operations: Vec::new(), + currencies_operations: HashMap::new(), currencies_diff: Vec::new(), info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), new_token: remote_reset_token.clone(), diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index d66a40509..5dca246f3 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -230,11 +230,14 @@ pub struct CurrencyOperations { pub operations: Vec, } +pub type CurrenciesOperations = HashMap>; + #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct MoveToken { #[serde(with = "ser_b64")] pub old_token: Signature, - pub currencies_operations: Vec, + // pub currencies_operations: Vec, + pub currencies_operations: CurrenciesOperations, pub currencies_diff: Vec, #[serde(with = "ser_b64")] pub info_hash: HashResult, From 1252fa24989fa57554e6be87356b1da3e8055120 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 23 Dec 2020 21:15:56 +0200 Subject: [PATCH 274/478] funder: Added TODO --- components/funder/src/switch/switch.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 0a73af929..03f112872 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -241,6 +241,9 @@ pub async fn set_friend_online( } } + // TODO: How to calculate index mutations? + todo!(); + Ok(output) } From 333387fe84f07b52b9c1981d4215bebe70d6b171 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 25 Dec 2020 17:38:00 +0200 Subject: [PATCH 275/478] funder: set_friend_online(): Reporting index mutations --- components/funder/src/switch/switch.rs | 60 ++++++++++++++++++++++++-- components/funder/src/switch/types.rs | 40 +++++++++++++++-- 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 03f112872..bde5d71dd 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -1,7 +1,11 @@ -use derive_more::From; use std::collections::{HashMap, HashSet}; +use futures::StreamExt; + +use derive_more::From; + use common::async_rpc::OpError; +use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; use identity::IdentityClient; @@ -11,8 +15,9 @@ use proto::funder::messages::{ CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, }; +use proto::index_server::messages::{IndexMutation, UpdateFriendCurrency}; -use crate::switch::types::{BackwardsOp, SwitchDbClient, SwitchOutput, SwitchState}; +use crate::switch::types::{BackwardsOp, CurrencyInfo, SwitchDbClient, SwitchOutput, SwitchState}; use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; #[derive(Debug, From)] @@ -20,6 +25,7 @@ pub enum SwitchError { FriendAlreadyOnline, FriendAlreadyOffline, GenerationOverflow, + BalanceOverflow, TokenChannelError(TokenChannelError), OpError(OpError), } @@ -165,6 +171,45 @@ async fn is_pending_move_token( ) } +/// Calculate receive capacity for a certain currency +fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result { + if !currency_info.is_open { + return Ok(0); + } + + let info_local = if let Some(info_local) = ¤cy_info.opt_local { + info_local + } else { + return Ok(0); + }; + + let mc_balance = if let Some(mc_balance) = &info_local.opt_remote { + mc_balance + } else { + return Ok(0); + }; + + Ok(currency_info.remote_max_debt.saturating_sub_signed( + mc_balance + .balance + .checked_add_unsigned(mc_balance.remote_pending_debt) + .ok_or(SwitchError::BalanceOverflow)?, + )) +} + +fn create_update_index_mutation( + friend_public_key: PublicKey, + currency_info: CurrencyInfo, +) -> Result { + let recv_capacity = calc_recv_capacity(¤cy_info)?; + Ok(IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { + public_key: friend_public_key, + currency: currency_info.currency, + recv_capacity, + rate: currency_info.rate, + })) +} + pub async fn set_friend_online( switch_db_client: &mut impl SwitchDbClient, switch_state: &mut SwitchState, @@ -241,8 +286,15 @@ pub async fn set_friend_online( } } - // TODO: How to calculate index mutations? - todo!(); + // Add an index mutation for all open currencies: + let mut open_currencies = switch_db_client.list_open_currencies(friend_public_key.clone()); + while let Some(res) = open_currencies.next().await { + let open_currency = res?; + output.add_index_mutation(create_update_index_mutation( + friend_public_key.clone(), + open_currency, + )?); + } Ok(output) } diff --git a/components/funder/src/switch/types.rs b/components/funder/src/switch/types.rs index 5f4e11137..37737a0cc 100644 --- a/components/funder/src/switch/types.rs +++ b/components/funder/src/switch/types.rs @@ -1,4 +1,4 @@ -use common::async_rpc::AsyncOpResult; +use common::async_rpc::{AsyncOpResult, AsyncOpStream}; use std::collections::HashMap; // use common::ser_utils::ser_string; // use common::u256::U256; @@ -9,11 +9,10 @@ use crate::token_channel::TcDbClient; use proto::app_server::messages::{NamedRelayAddress, RelayAddress}; use proto::crypto::PublicKey; use proto::funder::messages::{ - CancelSendFundsOp, Currency, FriendMessage, RequestSendFundsOp, ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendMessage, McBalance, Rate, RequestSendFundsOp, + ResponseSendFundsOp, }; use proto::index_server::messages::IndexMutation; -// use proto::funder::messages::{McBalance, PendingTransaction}; -// /// Switch's ephemeral state (Not saved inside the database) #[derive(Debug)] @@ -27,6 +26,30 @@ pub enum BackwardsOp { Cancel(CancelSendFundsOp), } +#[derive(Debug)] +pub struct CurrencyInfoLocal { + /// Is locally marked for removal? + pub is_remove: bool, + /// Was set by remote side too? + pub opt_remote: Option, +} + +#[derive(Debug)] +pub struct CurrencyInfo { + /// Currency name + pub currency: Currency, + /// Currency rate: This is how much it costs to the remote friend to send credits through us. + pub rate: Rate, + /// Maximum amount of debt we allow to the remote side. This is the maximum rich we can get + /// from this currency relationship. + pub remote_max_debt: u128, + /// Do we allow requests to go through this currency? + /// TODO: Find out exactly what this means. + pub is_open: bool, + /// Was the remote side told about this currency? + pub opt_local: Option, +} + pub trait SwitchDbClient { type TcDbClient: TcDbClient; fn tc_db_client(&mut self, friend_public_key: PublicKey) -> &mut Self::TcDbClient; @@ -114,6 +137,15 @@ pub trait SwitchDbClient { fn pending_requests_is_empty(&mut self, friend_public_key: PublicKey) -> AsyncOpResult; + fn list_open_currencies(&mut self, friend_public_key: PublicKey) + -> AsyncOpStream; + + fn get_currency_info( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + ) -> AsyncOpResult>; + /* /// Get a list of configured currencies that were not yet added as local currencies fn currencies_to_add(&mut self, friend_public_key: PublicKey) -> AsyncOpResult>; From 3b014e5952ede04dbcdb0b6fed363d3f09d6e305 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 25 Dec 2020 21:09:40 +0200 Subject: [PATCH 276/478] funder: Added missing send_response + send_cancel --- components/funder/src/switch/switch.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index bde5d71dd..708eb76aa 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -332,6 +332,20 @@ pub async fn send_request( todo!(); } +pub async fn send_response( + _switch_db_client: &mut impl SwitchDbClient, + _response: ResponseSendFundsOp, +) -> Result { + todo!(); +} + +pub async fn send_cancel( + _switch_db_client: &mut impl SwitchDbClient, + _cancel: CancelSendFundsOp, +) -> Result { + todo!(); +} + pub async fn add_currency( _switch_db_client: &mut impl SwitchDbClient, _friend_public_key: PublicKey, From 18b9fa71c4040b8e98f386c22d4276bd196ab0eb Mon Sep 17 00:00:00 2001 From: real Date: Fri, 25 Dec 2020 21:11:00 +0200 Subject: [PATCH 277/478] funder: TODO comments --- components/funder/src/switch/switch.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 708eb76aa..20933b11b 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -315,6 +315,8 @@ pub async fn set_friend_offline( // - Possibly send outgoing cancels to relevant friends? (Through SwitchOutput) // - Cancel all user pending requests // - Possibly send outgoing cancels? (Through SwitchOutput) + // - Add index mutations: + // - Remove mutations for all currencies that are considered open with this friend. todo!(); } From 161c90b73f6f115f2bcc4bc2eed0cfcf7422721a Mon Sep 17 00:00:00 2001 From: real Date: Fri, 25 Dec 2020 21:38:37 +0200 Subject: [PATCH 278/478] funder: impl set_friend_offline() --- components/funder/src/switch/switch.rs | 61 +++++++++++++++++++++----- components/funder/src/switch/types.rs | 7 ++- 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 20933b11b..fe1ac3e50 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -12,10 +12,11 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddress; use proto::crypto::PublicKey; use proto::funder::messages::{ - CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, - FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, + CancelSendFundsOp, CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, + FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, + ResponseSendFundsOp, }; -use proto::index_server::messages::{IndexMutation, UpdateFriendCurrency}; +use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use crate::switch::types::{BackwardsOp, CurrencyInfo, SwitchDbClient, SwitchOutput, SwitchState}; use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; @@ -310,15 +311,53 @@ pub async fn set_friend_offline( } switch_state.liveness.set_offline(&friend_public_key); - // TODO: - // - Cancel all pending requests - // - Possibly send outgoing cancels to relevant friends? (Through SwitchOutput) - // - Cancel all user pending requests - // - Possibly send outgoing cancels? (Through SwitchOutput) - // - Add index mutations: - // - Remove mutations for all currencies that are considered open with this friend. + let mut output = SwitchOutput::new(); - todo!(); + // Cancel all pending user requests + while let Some((_currency, pending_user_request)) = switch_db_client + .pending_user_requests_pop_front(friend_public_key.clone()) + .await? + { + // Send outgoing cancel to user: + output.add_incoming_cancel(CancelSendFundsOp { + request_id: pending_user_request.request_id, + }); + } + + // Cancel all pending requests + while let Some((currency, pending_request)) = switch_db_client + .pending_requests_pop_front(friend_public_key.clone()) + .await? + { + // Find from which friend this pending request has originated from: + let origin_public_key = switch_db_client + .get_remote_pending_request_friend_public_key(pending_request.request_id.clone()) + .await?; + + // Cancel request by queue-ing a cancel into the relevant friend's queue: + switch_db_client + .pending_backwards_push_back( + origin_public_key, + currency, + BackwardsOp::Cancel(CancelSendFundsOp { + request_id: pending_request.request_id, + }), + ) + .await?; + } + + // Add index mutations + // We send index mutations to remove all currencies that are considered open + let mut open_currencies = switch_db_client.list_open_currencies(friend_public_key.clone()); + while let Some(res) = open_currencies.next().await { + let open_currency = res?; + output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { + public_key: friend_public_key.clone(), + currency: open_currency.currency, + })); + } + + Ok(output) } pub async fn send_request( diff --git a/components/funder/src/switch/types.rs b/components/funder/src/switch/types.rs index 37737a0cc..7108f3d3b 100644 --- a/components/funder/src/switch/types.rs +++ b/components/funder/src/switch/types.rs @@ -7,7 +7,7 @@ use crate::liveness::Liveness; use crate::token_channel::TcDbClient; use proto::app_server::messages::{NamedRelayAddress, RelayAddress}; -use proto::crypto::PublicKey; +use proto::crypto::{PublicKey, Uid}; use proto::funder::messages::{ CancelSendFundsOp, Currency, FriendMessage, McBalance, Rate, RequestSendFundsOp, ResponseSendFundsOp, @@ -146,6 +146,11 @@ pub trait SwitchDbClient { currency: Currency, ) -> AsyncOpResult>; + fn get_remote_pending_request_friend_public_key( + &mut self, + request_id: Uid, + ) -> AsyncOpResult; + /* /// Get a list of configured currencies that were not yet added as local currencies fn currencies_to_add(&mut self, friend_public_key: PublicKey) -> AsyncOpResult>; From 6d5b322b9bced6f74f45bdd6d3d406fb2e2dcbbf Mon Sep 17 00:00:00 2001 From: real Date: Sat, 26 Dec 2020 10:31:15 +0200 Subject: [PATCH 279/478] proto: TODO comment --- components/proto/src/funder/messages.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 5dca246f3..8a1d8cb0f 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -445,6 +445,8 @@ pub struct PendingTransaction { // ================================================================== // ================================================================== +// TODO: Possibly impl FriendsRoute as a trait for Vec? + impl FriendsRoute { pub fn len(&self) -> usize { self.public_keys.len() From ec466cc1a11d24d3bcfad81f0c2707ed8807c62e Mon Sep 17 00:00:00 2001 From: real Date: Sat, 26 Dec 2020 10:32:33 +0200 Subject: [PATCH 280/478] funder: comments --- components/funder/src/switch/switch.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index fe1ac3e50..534b21451 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -12,9 +12,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddress; use proto::crypto::PublicKey; use proto::funder::messages::{ - CancelSendFundsOp, CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, - FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, - ResponseSendFundsOp, + CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, + FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; @@ -362,8 +361,19 @@ pub async fn set_friend_offline( pub async fn send_request( _switch_db_client: &mut impl SwitchDbClient, + _currency: Currency, _request: RequestSendFundsOp, ) -> Result { + // TODO: Check if request route is valid? (As part)? + // + /* + // TODO: Deduce next public key from route + let friend_public_key = request.route.get( + switch_db_client + .pending_user_requests_push_back(friend_public_key, currency, request) + .await?; + */ + // TODO: // - Add request to relevant user pending requests queue (According to friend on route) // - For the relevant friend: If token is present: From 33f662329adbd02096285d658d9eaab0dae06c8f Mon Sep 17 00:00:00 2001 From: real Date: Sat, 26 Dec 2020 11:33:41 +0200 Subject: [PATCH 281/478] Refactored FriendsRoute code into a trait --- components/funder/src/lib.rs | 1 + .../funder/src/mutual_credit/incoming.rs | 5 +- .../funder/src/mutual_credit/outgoing.rs | 5 +- .../tests/request_cancel_send_funds.rs | 16 +-- .../tests/request_response_send_funds.rs | 16 +-- components/funder/src/route.rs | 113 ++++++++++++++++++ .../tests/inconsistency_resolve.rs | 3 +- .../token_channel/tests/move_token_basic.rs | 6 +- components/proto/src/funder/messages.rs | 19 ++- components/proto/src/index_server/messages.rs | 4 +- components/signature/src/canonical.rs | 17 ++- 11 files changed, 165 insertions(+), 40 deletions(-) create mode 100644 components/funder/src/route.rs diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 5fbea1549..e0639c531 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -26,6 +26,7 @@ extern crate quickcheck_derive; #[allow(unused)] mod liveness; mod mutual_credit; +mod route; // pub mod report; // mod state; #[allow(unused)] diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 12a1fa444..9af1569ab 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -14,6 +14,7 @@ use proto::funder::messages::{ use signature::signature_buff::create_response_signature_buffer; +use crate::route::Route; use crate::types::create_pending_transaction; use super::types::McDbClient; @@ -196,10 +197,10 @@ async fn process_response_send_funds( return Err(ProcessOperationError::InvalidSrcPlainLock); } - let dest_public_key = if pending_transaction.route.public_keys.is_empty() { + let dest_public_key = if pending_transaction.route.is_empty() { remote_public_key } else { - pending_transaction.route.public_keys.last().unwrap() + pending_transaction.route.last().unwrap() }; let response_signature_buffer = create_response_signature_buffer( diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 0f3a8f77c..77eb99138 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -13,6 +13,7 @@ use proto::funder::messages::{ use signature::signature_buff::create_response_signature_buffer; use crate::mutual_credit::types::McDbClient; +use crate::route::Route; use crate::types::create_pending_transaction; #[derive(Debug, From)] @@ -130,10 +131,10 @@ async fn queue_response_send_funds( &pending_transaction, ); // The response was signed by the destination node: - let dest_public_key = if pending_transaction.route.public_keys.is_empty() { + let dest_public_key = if pending_transaction.route.is_empty() { local_public_key } else { - pending_transaction.route.public_keys.last().unwrap() + pending_transaction.route.last().unwrap() }; // Verify response funds signature: diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index 1e87d4b8d..625a56213 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -8,9 +8,7 @@ use crypto::rand::RandGen; use crypto::test_utils::DummyRandom; use proto::crypto::{HashResult, HmacResult, PlainLock, PrivateKey, PublicKey, Uid}; -use proto::funder::messages::{ - CancelSendFundsOp, Currency, FriendTcOp, FriendsRoute, RequestSendFundsOp, -}; +use proto::funder::messages::{CancelSendFundsOp, Currency, FriendTcOp, RequestSendFundsOp}; use crate::mutual_credit::tests::utils::MockMutualCredit; use crate::mutual_credit::types::McDbClient; @@ -36,13 +34,11 @@ async fn task_request_cancel_send_funds() { // -----[RequestSendFunds]-------- // ----------------------------- let request_id = Uid::from(&[3; Uid::len()]); - let route = FriendsRoute { - public_keys: vec![ - PublicKey::from(&[0xaa; PublicKey::len()]), - public_key_b.clone(), - PublicKey::from(&[0xcc; PublicKey::len()]), - ], - }; + let route = vec![ + PublicKey::from(&[0xaa; PublicKey::len()]), + public_key_b.clone(), + PublicKey::from(&[0xcc; PublicKey::len()]), + ]; let invoice_hash = HashResult::from(&[0; HashResult::len()]); let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); let hmac = HmacResult::from(&[2; HmacResult::len()]); diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index d497adbff..8aba778e0 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -8,9 +8,7 @@ use crypto::rand::RandGen; use crypto::test_utils::DummyRandom; use proto::crypto::{HashResult, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid}; -use proto::funder::messages::{ - Currency, FriendTcOp, FriendsRoute, RequestSendFundsOp, ResponseSendFundsOp, -}; +use proto::funder::messages::{Currency, FriendTcOp, RequestSendFundsOp, ResponseSendFundsOp}; use signature::signature_buff::create_response_signature_buffer; use crate::mutual_credit::tests::utils::MockMutualCredit; @@ -38,13 +36,11 @@ async fn task_request_response_send_funds() { let public_key_c = identity.get_public_key(); let request_id = Uid::from(&[3; Uid::len()]); - let route = FriendsRoute { - public_keys: vec![ - PublicKey::from(&[0xaa; PublicKey::len()]), - PublicKey::from(&[0xbb; PublicKey::len()]), - public_key_c.clone(), - ], - }; + let route = vec![ + PublicKey::from(&[0xaa; PublicKey::len()]), + PublicKey::from(&[0xbb; PublicKey::len()]), + public_key_c.clone(), + ]; let invoice_hash = HashResult::from(&[0; HashResult::len()]); let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); let hmac = HmacResult::from(&[2; HmacResult::len()]); diff --git a/components/funder/src/route.rs b/components/funder/src/route.rs new file mode 100644 index 000000000..a9f5ce174 --- /dev/null +++ b/components/funder/src/route.rs @@ -0,0 +1,113 @@ +use std::collections::HashSet; +use std::hash::Hash; + +use proto::consts::MAX_ROUTE_LEN; + +pub trait Route { + /// Check if the route (e.g. `FriendsRoute`) is valid. + /// A valid route must have at least 2 unique nodes, and is in one of the following forms: + /// A -- B -- C -- D -- E -- F -- A (Single cycle, first == last) + /// A -- B -- C -- D -- E -- F (A route with no repetitions) + fn is_valid(&self) -> bool; + + /// Checks if the remaining part of the route (e.g. `FriendsRoute`) is valid. + /// Compared to regular version, this one does not check for minimal unique + /// nodes amount. It returns `true` if the part is empty. + /// It does not accept routes parts with a cycle, though. + fn is_part_valid(&self) -> bool; +} + +/// Check if no element repeats twice in the slice +fn no_duplicates(array: &[T]) -> bool { + let mut seen = HashSet::new(); + for item in array { + if !seen.insert(item) { + return false; + } + } + true +} + +fn is_route_valid(route: &[T]) -> bool +where + T: Hash + Eq, +{ + if route.len() < 2 { + return false; + } + if route.len() > MAX_ROUTE_LEN { + return false; + } + + // route.len() >= 2 + let last_key = route.last().unwrap(); + if last_key == &route[0] { + // We have a first == last cycle. + if route.len() > 2 { + // We have a cycle that is long enough (no A -- A). + // We just check if it's a single cycle. + no_duplicates(&route[1..]) + } else { + // A -- A + false + } + } else { + // No first == last cycle. + // But we have to check if there is any other cycle. + no_duplicates(&route) + } +} + +fn is_route_part_valid(route: &[T]) -> bool +where + T: Hash + Eq, +{ + // Route part should not be full route. + // TODO: ensure it never is. + if route.len() >= MAX_ROUTE_LEN { + return false; + } + + no_duplicates(route) +} + +impl Route for R +where + T: Hash + Eq, + R: AsRef<[T]>, +{ + fn is_valid(&self) -> bool { + is_route_valid(self.as_ref()) + } + + fn is_part_valid(&self) -> bool { + is_route_part_valid(self.as_ref()) + } +} + +#[cfg(test)] +mod tests { + use super::Route; + + #[test] + fn test_friends_is_route_valid() { + assert_eq!([1].is_valid(), false); // too short + assert_eq!([1].is_part_valid(), true); // long enough + assert_eq!(Vec::::new().is_valid(), false); // empty route is invalid + assert_eq!(Vec::::new().is_part_valid(), true); // partial routes may be empty + + // Test cases taken from https://github.com/freedomlayer/offset/pull/215#discussion_r292327613 + assert_eq!([1, 2, 3, 4].is_valid(), true); // usual route + assert_eq!([1, 2, 3, 4, 1].is_valid(), true); // cyclic route that is at least 3 nodes long, having first item equal the last item + assert_eq!([1, 1].is_valid(), false); // cyclic route that is too short (only 2 nodes long) + assert_eq!([1, 2, 3, 2, 4].is_valid(), false); // Should have no repetitions that are not the first and last nodes. + + assert_eq!([1, 2, 3, 4].is_part_valid(), true); // usual route + assert_eq!([1, 2, 3, 4, 1].is_part_valid(), false); // should have no cycles in a partial route + assert_eq!([1, 1].is_part_valid(), false); // should have no repetitions ins a partial route + assert_eq!([1, 2, 3, 2, 4].is_part_valid(), false); // should have no repetitions in a partial route + + assert_eq!(vec![1, 2, 3, 2, 4].is_part_valid(), false); // should have no repetitions in a partial route + assert_eq!((&[1, 2, 3, 2, 4]).is_part_valid(), false); // should have no repetitions in a partial route + } +} diff --git a/components/funder/src/token_channel/tests/inconsistency_resolve.rs b/components/funder/src/token_channel/tests/inconsistency_resolve.rs index 2ce366483..1f8cbfb27 100644 --- a/components/funder/src/token_channel/tests/inconsistency_resolve.rs +++ b/components/funder/src/token_channel/tests/inconsistency_resolve.rs @@ -17,8 +17,7 @@ use proto::crypto::{ HashResult, HashedLock, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid, }; use proto::funder::messages::{ - Currency, CurrencyOperations, FriendTcOp, FriendsRoute, RequestSendFundsOp, ResetBalance, - ResponseSendFundsOp, + Currency, CurrencyOperations, FriendTcOp, RequestSendFundsOp, ResetBalance, ResponseSendFundsOp, }; use identity::{create_identity, IdentityClient}; diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index b995a2e21..624b94e9b 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -17,7 +17,7 @@ use proto::crypto::{ HashResult, HashedLock, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid, }; use proto::funder::messages::{ - Currency, CurrencyOperations, FriendTcOp, FriendsRoute, RequestSendFundsOp, ResponseSendFundsOp, + Currency, CurrencyOperations, FriendTcOp, RequestSendFundsOp, ResponseSendFundsOp, }; use identity::{create_identity, IdentityClient}; @@ -133,9 +133,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { let request_send_funds_op = RequestSendFundsOp { request_id: Uid::from(&[0; Uid::len()]), src_hashed_lock: src_plain_lock.hash_lock(), - route: FriendsRoute { - public_keys: vec![pk_a.clone()], - }, + route: vec![pk_a.clone()], dest_payment: 20u128, total_dest_payment: 30u128, invoice_hash: HashResult::from(&[0; HashResult::len()]), diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 8a1d8cb0f..b7eef42d6 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -1,5 +1,5 @@ use std::cmp::Eq; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::convert::TryFrom; use std::fmt; use std::hash::Hash; @@ -18,7 +18,7 @@ use crate::crypto::{ }; use crate::app_server::messages::{NamedRelayAddress, RelayAddress}; -use crate::consts::{MAX_CURRENCY_LEN, MAX_ROUTE_LEN}; +use crate::consts::MAX_CURRENCY_LEN; use crate::net::messages::NetAddress; use common::ser_utils::{ser_b64, ser_string, ser_vec_b64}; @@ -66,11 +66,13 @@ pub const InvoiceId::len(): usize = 32; define_fixed_bytes!(InvoiceId, InvoiceId::len()); */ +/* #[derive(Arbitrary, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct FriendsRoute { #[serde(with = "ser_vec_b64")] pub public_keys: Vec, } +*/ #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct RequestSendFundsOp { @@ -78,7 +80,8 @@ pub struct RequestSendFundsOp { pub request_id: Uid, #[serde(with = "ser_b64")] pub src_hashed_lock: HashedLock, - pub route: FriendsRoute, + #[serde(with = "ser_vec_b64")] + pub route: Vec, pub dest_payment: u128, #[serde(with = "ser_string")] pub total_dest_payment: u128, @@ -430,7 +433,9 @@ pub struct PendingTransaction { pub request_id: Uid, #[serde(with = "ser_b64")] pub src_hashed_lock: HashedLock, - pub route: FriendsRoute, + // pub route: FriendsRoute, + #[serde(with = "ser_vec_b64")] + pub route: Vec, pub dest_payment: u128, #[serde(with = "ser_string")] pub total_dest_payment: u128, @@ -447,6 +452,7 @@ pub struct PendingTransaction { // TODO: Possibly impl FriendsRoute as a trait for Vec? +/* impl FriendsRoute { pub fn len(&self) -> usize { self.public_keys.len() @@ -541,6 +547,7 @@ fn is_route_part_valid(route: &[T]) -> bool { no_duplicates(route) } +*/ // AppServer <-> Funder communication: // =================================== @@ -684,7 +691,7 @@ pub struct RemoveFriendCurrency { /// A friend's route with known capacity #[derive(Debug, Clone, PartialEq, Eq)] struct FriendsRouteCapacity { - route: FriendsRoute, + route: Vec, capacity: u128, } @@ -714,7 +721,7 @@ pub struct CreateTransaction { /// Randomly generated request_id (by the user), /// allows the user to refer to this request later. pub request_id: Uid, - pub route: FriendsRoute, + pub route: Vec, pub dest_payment: u128, pub fees: u128, } diff --git a/components/proto/src/index_server/messages.rs b/components/proto/src/index_server/messages.rs index 786fd0f12..a1594a9ec 100644 --- a/components/proto/src/index_server/messages.rs +++ b/components/proto/src/index_server/messages.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use common::ser_utils::{ser_b64, ser_string}; use crate::crypto::{HashResult, PublicKey, RandValue, Signature, Uid}; -use crate::funder::messages::{Currency, FriendsRoute, Rate}; +use crate::funder::messages::{Currency, Rate}; use crate::net::messages::NetAddress; #[derive(Debug, PartialEq, Eq, Clone)] @@ -54,7 +54,7 @@ pub struct RequestRoutes { #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct RouteCapacityRate { - pub route: FriendsRoute, + pub route: Vec, /// How many credits we can push along this route? #[serde(with = "ser_string")] pub capacity: u128, diff --git a/components/signature/src/canonical.rs b/components/signature/src/canonical.rs index 774ffeb4f..ab46ce1a5 100644 --- a/components/signature/src/canonical.rs +++ b/components/signature/src/canonical.rs @@ -2,9 +2,10 @@ use byteorder::{BigEndian, WriteBytesExt}; // use std::collections::HashMap; use proto::app_server::messages::RelayAddress; +use proto::crypto::PublicKey; use proto::funder::messages::{ - CancelSendFundsOp, Currency, CurrencyOperations, FriendTcOp, FriendsRoute, McBalance, - RequestSendFundsOp, ResponseSendFundsOp, + CancelSendFundsOp, Currency, CurrencyOperations, FriendTcOp, McBalance, RequestSendFundsOp, + ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -55,6 +56,16 @@ where } } +// TODO: Possibly be more generic here? We might be able to impl CanonicalSerialize for all fixed +// sized bytes types we have, if required. Not sure that we want to do this, though. +impl CanonicalSerialize for PublicKey { + fn canonical_serialize(&self) -> Vec { + let mut res_bytes = Vec::new(); + res_bytes.extend_from_slice(self); + res_bytes + } +} + impl CanonicalSerialize for String { fn canonical_serialize(&self) -> Vec { self.as_bytes().to_vec() @@ -211,6 +222,7 @@ impl CanonicalSerialize for FriendTcOp { } } +/* impl CanonicalSerialize for FriendsRoute { fn canonical_serialize(&self) -> Vec { let mut res_bytes = Vec::new(); @@ -223,6 +235,7 @@ impl CanonicalSerialize for FriendsRoute { res_bytes } } +*/ /* impl CanonicalSerialize for Receipt { From bbe677259248615d175f7a56cb8daf2fbdb2083e Mon Sep 17 00:00:00 2001 From: real Date: Sat, 26 Dec 2020 12:05:29 +0200 Subject: [PATCH 282/478] funder: is_online() now takes a shared ref --- components/funder/src/liveness.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/funder/src/liveness.rs b/components/funder/src/liveness.rs index 13c2401d8..6486640ff 100644 --- a/components/funder/src/liveness.rs +++ b/components/funder/src/liveness.rs @@ -22,7 +22,7 @@ impl Liveness { self.friends.remove(&public_key).is_some() } - pub fn is_online(&mut self, public_key: &PublicKey) -> bool { + pub fn is_online(&self, public_key: &PublicKey) -> bool { self.friends.contains(public_key) } } From 293640ed83a109865c9b20bb1af92870e98e20f1 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 26 Dec 2020 12:05:50 +0200 Subject: [PATCH 283/478] funder: impl send_request() --- components/funder/src/switch/switch.rs | 112 ++++++++++++++++++++----- 1 file changed, 93 insertions(+), 19 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 534b21451..6bb8f8046 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -17,6 +17,7 @@ use proto::funder::messages::{ }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; +use crate::route::Route; use crate::switch::types::{BackwardsOp, CurrencyInfo, SwitchDbClient, SwitchOutput, SwitchState}; use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; @@ -26,6 +27,7 @@ pub enum SwitchError { FriendAlreadyOffline, GenerationOverflow, BalanceOverflow, + InvalidRoute, TokenChannelError(TokenChannelError), OpError(OpError), } @@ -360,27 +362,99 @@ pub async fn set_friend_offline( } pub async fn send_request( - _switch_db_client: &mut impl SwitchDbClient, - _currency: Currency, - _request: RequestSendFundsOp, + switch_db_client: &mut impl SwitchDbClient, + switch_state: &SwitchState, + currency: Currency, + request: RequestSendFundsOp, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, ) -> Result { - // TODO: Check if request route is valid? (As part)? - // - /* - // TODO: Deduce next public key from route - let friend_public_key = request.route.get( - switch_db_client - .pending_user_requests_push_back(friend_public_key, currency, request) + // Make sure that the provided route is valid: + if !request.route.is_valid() { + return Err(SwitchError::InvalidRoute); + } + + let mut output = SwitchOutput::new(); + + // First public key is ours, next public key is the next friend. + // TODO: Could be a mistake, verify later + let friend_public_key = request + .route + .get(1) + .ok_or(SwitchError::InvalidRoute)? + .clone(); + + // Gather information about friend's channel and liveness: + let tc_status = switch_db_client + .tc_db_client(friend_public_key.clone()) + .get_tc_status() .await?; - */ - - // TODO: - // - Add request to relevant user pending requests queue (According to friend on route) - // - For the relevant friend: If token is present: - // - Compose a friend move token message - // - If the token is not present: - // - Compose a request token message. - todo!(); + let is_online = switch_state.liveness.is_online(&friend_public_key); + + // If friend is ready (online + consistent): + // - push the request + // - If token is incoming: + // - Send an outoging token + // - Else (token is outgoing): + // - Request token + // Else (Friend is not ready): + // - Send a cancel + match (tc_status, is_online) { + (TcStatus::ConsistentIn(_), true) => { + // Push request: + switch_db_client + .pending_user_requests_push_back(friend_public_key.clone(), currency, request) + .await?; + + // Create an outgoing move token if we have something to send. + let opt_move_token_request = collect_outgoing_move_token( + switch_db_client, + identity_client, + local_public_key, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + if let Some(move_token_request) = opt_move_token_request { + // We have something to send to remote side: + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(move_token_request), + ); + } + } + (TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in), true) => { + // Push request: + switch_db_client + .pending_user_requests_push_back(friend_public_key.clone(), currency, request) + .await?; + + // Resend outgoing move token, + // possibly asking for the token if we have something to send + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(MoveTokenRequest { + move_token: move_token_out, + token_wanted: is_pending_move_token( + switch_db_client, + friend_public_key.clone(), + ) + .await?, + }), + ); + } + _ => { + // Friend is not ready to accept a request. + // We cancel the request: + output.add_incoming_cancel(CancelSendFundsOp { + request_id: request.request_id, + }); + } + } + + Ok(output) } pub async fn send_response( From a6dfb52437a67a3f2d7b22a9f5413de17f168ead Mon Sep 17 00:00:00 2001 From: real Date: Sat, 26 Dec 2020 12:11:43 +0200 Subject: [PATCH 284/478] funder: send_request(): Cut first two public keys from route --- components/funder/src/switch/switch.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 6bb8f8046..014128d17 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -365,7 +365,7 @@ pub async fn send_request( switch_db_client: &mut impl SwitchDbClient, switch_state: &SwitchState, currency: Currency, - request: RequestSendFundsOp, + mut request: RequestSendFundsOp, identity_client: &mut IdentityClient, local_public_key: &PublicKey, max_operations_in_batch: usize, @@ -377,13 +377,14 @@ pub async fn send_request( let mut output = SwitchOutput::new(); - // First public key is ours, next public key is the next friend. - // TODO: Could be a mistake, verify later - let friend_public_key = request - .route - .get(1) - .ok_or(SwitchError::InvalidRoute)? - .clone(); + // We cut the first two public keys from the route: + // Pop first route public key: + let route_local_public_key = request.route.remove(0); + if &route_local_public_key != local_public_key { + return Err(SwitchError::InvalidRoute); + } + // Pop second route public key: + let friend_public_key = request.route.remove(0); // Gather information about friend's channel and liveness: let tc_status = switch_db_client From 15b8c02d9c19db2fb4a9ce9327ce281f739c05cc Mon Sep 17 00:00:00 2001 From: real Date: Sat, 26 Dec 2020 13:33:19 +0200 Subject: [PATCH 285/478] funder: Added TODO comment --- components/funder/src/switch/switch.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 014128d17..21df39286 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -455,6 +455,12 @@ pub async fn send_request( } } + // TODO: Add index mutations. How to do this? + // - Look at produced MoveToken at relevant places + // + // + todo!(); + Ok(output) } From deeeab82500e77005c65a83429bcaf8f3bf61308 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 26 Dec 2020 13:45:38 +0200 Subject: [PATCH 286/478] funder: Initial work on create_index_mutations_from_move_token --- components/funder/src/switch/switch.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 21df39286..f2e617ead 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -212,6 +212,22 @@ fn create_update_index_mutation( })) } +fn create_index_mutations_from_move_token( + switch_db_client: &mut impl SwitchDbClient, + move_token: MoveToken, +) -> Result, SwitchError> { + // let mut _index_mutations = Vec::new(); + + // TODO: + // - Collect currencies to be mutated: + // - All currencies from currencies operations + // - Currencies that were added from currencies diff. + // - Iterate over all currencies. + // If a currency is present, create a mutation. If not, create a removal mutation. + + todo!(); +} + pub async fn set_friend_online( switch_db_client: &mut impl SwitchDbClient, switch_state: &mut SwitchState, From 46e7017a8154eefc63fd27b20f48a25569c367c3 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 26 Dec 2020 15:30:21 +0200 Subject: [PATCH 287/478] funder: create_index_mutations_from_move_token() impl --- components/funder/src/switch/switch.rs | 50 ++++++++++++++++++++------ 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index f2e617ead..1f5e30f13 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -174,6 +174,7 @@ async fn is_pending_move_token( } /// Calculate receive capacity for a certain currency +/// This is the number we are going to report to an index server fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result { if !currency_info.is_open { return Ok(0); @@ -199,6 +200,7 @@ fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result )) } +/// Create one update index mutation, based on a given currency info. fn create_update_index_mutation( friend_public_key: PublicKey, currency_info: CurrencyInfo, @@ -212,20 +214,48 @@ fn create_update_index_mutation( })) } -fn create_index_mutations_from_move_token( +/// Create a list of index mutations based on a MoveToken message. +async fn create_index_mutations_from_move_token( switch_db_client: &mut impl SwitchDbClient, - move_token: MoveToken, + friend_public_key: PublicKey, + move_token: &MoveToken, ) -> Result, SwitchError> { - // let mut _index_mutations = Vec::new(); + // Collect all mentioned currencies: + let currencies = { + let mut currencies = HashSet::new(); + for currency in &move_token.currencies_diff { + currencies.insert(currency.clone()); + } - // TODO: - // - Collect currencies to be mutated: - // - All currencies from currencies operations - // - Currencies that were added from currencies diff. - // - Iterate over all currencies. - // If a currency is present, create a mutation. If not, create a removal mutation. + for currency in move_token.currencies_operations.keys() { + currencies.insert(currency.clone()); + } + currencies + }; - todo!(); + let mut index_mutations = Vec::new(); + + // Create all index mutations: + for currency in currencies.into_iter() { + let opt_currency_info = switch_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await?; + if let Some(currency_info) = opt_currency_info { + // Currency exists + index_mutations.push(create_update_index_mutation( + friend_public_key.clone(), + currency_info, + )?); + } else { + // Currency does not exist anymore + index_mutations.push(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { + public_key: friend_public_key.clone(), + currency, + })); + } + } + + Ok(index_mutations) } pub async fn set_friend_online( From 3dedf445c9423e66641f0d29f8e5f66fd35a9cd8 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 26 Dec 2020 15:38:36 +0200 Subject: [PATCH 288/478] funder: send_request(): Create index mutations --- components/funder/src/switch/switch.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 1f5e30f13..0e885315e 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -465,7 +465,19 @@ pub async fn send_request( .await?; if let Some(move_token_request) = opt_move_token_request { - // We have something to send to remote side: + // We have something to send to remote side + // Deduce index mutations according to move token: + let index_mutations = create_index_mutations_from_move_token( + switch_db_client, + friend_public_key.clone(), + &move_token_request.move_token, + ) + .await?; + for index_mutation in index_mutations { + output.add_index_mutation(index_mutation); + } + + // Send move token request to remote side: output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(move_token_request), @@ -501,12 +513,6 @@ pub async fn send_request( } } - // TODO: Add index mutations. How to do this? - // - Look at produced MoveToken at relevant places - // - // - todo!(); - Ok(output) } From 04437ca2d996ab1ae652ac22249fd6a964ca91ce Mon Sep 17 00:00:00 2001 From: real Date: Sat, 26 Dec 2020 19:45:03 +0200 Subject: [PATCH 289/478] funder: TODO comments --- components/funder/src/switch/switch.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 0e885315e..179ba351d 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -520,6 +520,10 @@ pub async fn send_response( _switch_db_client: &mut impl SwitchDbClient, _response: ResponseSendFundsOp, ) -> Result { + // TODO: + // - Find relevant request (And so, find relevant friend_public_key) + // - Queue response + // - Attempt to collect a MoveToken for the relevant friend. todo!(); } From b37f8c7d4c0010018fa685c71a3001bae77259b2 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 26 Dec 2020 21:56:51 +0200 Subject: [PATCH 290/478] funder: remote pending request might not always exist --- components/funder/src/switch/switch.rs | 27 ++++++++++++++------------ components/funder/src/switch/types.rs | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/switch/switch.rs index 179ba351d..60a1474fe 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/switch/switch.rs @@ -376,21 +376,24 @@ pub async fn set_friend_offline( .pending_requests_pop_front(friend_public_key.clone()) .await? { - // Find from which friend this pending request has originated from: - let origin_public_key = switch_db_client + // Find from which friend this pending request has originated from. + // Due to inconsistencies, it is possible that this pending request has no origin. + let opt_origin_public_key = switch_db_client .get_remote_pending_request_friend_public_key(pending_request.request_id.clone()) .await?; - // Cancel request by queue-ing a cancel into the relevant friend's queue: - switch_db_client - .pending_backwards_push_back( - origin_public_key, - currency, - BackwardsOp::Cancel(CancelSendFundsOp { - request_id: pending_request.request_id, - }), - ) - .await?; + if let Some(origin_public_key) = opt_origin_public_key { + // Cancel request by queue-ing a cancel into the relevant friend's queue: + switch_db_client + .pending_backwards_push_back( + origin_public_key, + currency, + BackwardsOp::Cancel(CancelSendFundsOp { + request_id: pending_request.request_id, + }), + ) + .await?; + } } // Add index mutations diff --git a/components/funder/src/switch/types.rs b/components/funder/src/switch/types.rs index 7108f3d3b..80d15026b 100644 --- a/components/funder/src/switch/types.rs +++ b/components/funder/src/switch/types.rs @@ -149,7 +149,7 @@ pub trait SwitchDbClient { fn get_remote_pending_request_friend_public_key( &mut self, request_id: Uid, - ) -> AsyncOpResult; + ) -> AsyncOpResult>; /* /// Get a list of configured currencies that were not yet added as local currencies From 1c6c412c495faa59c54db61c125f61acbd9bf926 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 28 Dec 2020 21:46:23 +0200 Subject: [PATCH 291/478] database: Fixed column name --- components/database/src/create.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 1fb417ee3..3eeb8f80b 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -541,7 +541,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { backwards_type TEXT NOT NULL CHECK (backwards_type == 'R') DEFAULT 'R', - src_hashed_lock BLOB NOT NULL, + src_plain_lock BLOB NOT NULL, serial_num BLOB NOT NULL, signature BLOB NOT NULL, FOREIGN KEY(request_id, backwards_type) From 245a2198172502fc98a685cdad90757bc548f9ab Mon Sep 17 00:00:00 2001 From: real Date: Mon, 28 Dec 2020 21:47:02 +0200 Subject: [PATCH 292/478] database: Maintaining requests origin, and uniqueness invariants --- components/database/src/create.rs | 105 ++++++++++++++++++------------ 1 file changed, 64 insertions(+), 41 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 3eeb8f80b..13dea3ec0 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -397,20 +397,42 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // A list of all requests currently being processed tx.execute( - "CREATE TABLE local_open_transactions( - friend_public_key BLOB NOT NULL, - currency TEXT NOT NULL, + "CREATE TABLE requests( request_id BLOB NOT NULL PRIMARY KEY, + currency TEXT NOT NULL, + origin_type TEXT CHECK (origin_type IN ('F', 'L')) NOT NULL, + -- Originated from a (F)riend or (L)ocally src_hashed_lock BLOB NOT NULL, - route BLOB NOT NULL, dest_payment BLOB NOT NULL, total_dest_payment BLOB NOT NULL, invoice_hash BLOB NOT NULL, hmac BLOB NOT NULL, + FOREIGN KEY(currency) + REFERENCES mutual_credits(currency) + ON DELETE CASCADE + );", + params![], + )?; + + tx.execute( + "CREATE UNIQUE INDEX idx_orig_requests ON requests(request_id);", + params![], + )?; + + // Requests that were sent through our node to a remote friend. + tx.execute( + "CREATE TABLE local_open_transactions( + request_id BLOB NOT NULL PRIMARY KEY, + friend_public_key BLOB NOT NULL, + route BLOB NOT NULL, left_fees BLOB NOT NULL, - FOREIGN KEY(friend_public_key, currency) - REFERENCES mutual_credits(friend_public_key, currency) + FOREIGN KEY(friend_public_key) + REFERENCES mutual_credits(friend_public_key) + ON DELETE CASCADE + FOREIGN KEY(request_id) + REFERENCES requests(request_id) ON DELETE CASCADE );", params![], @@ -421,20 +443,21 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; + // Requests that were sent through a friend along our node. tx.execute( "CREATE TABLE remote_open_transactions( - friend_public_key BLOB NOT NULL, - currency TEXT NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, - src_hashed_lock BLOB NOT NULL, + origin_type TEXT NOT NULL + CHECK (origin_type == 'F') + DEFAULT 'F', + friend_public_key BLOB NOT NULL, route BLOB NOT NULL, - dest_payment BLOB NOT NULL, - total_dest_payment BLOB NOT NULL, - invoice_hash BLOB NOT NULL, - hmac BLOB NOT NULL, left_fees BLOB NOT NULL, - FOREIGN KEY(friend_public_key, currency) - REFERENCES mutual_credits(friend_public_key, currency) + FOREIGN KEY(friend_public_key) + REFERENCES mutual_credits(friend_public_key) + ON DELETE CASCADE + FOREIGN KEY(request_id, origin_type) + REFERENCES requests(request_id, origin_type) ON DELETE CASCADE );", params![], @@ -447,19 +470,20 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE pending_user_requests( - friend_public_key BLOB NOT NULL, - currency TEXT NOT NULL, - request_id BLOB NOT NULL PRIMARY KEY, queue_index BLOB NOT NULL UNIQUE, - src_hashed_lock BLOB NOT NULL, + request_id BLOB NOT NULL PRIMARY KEY, + origin_type TEXT NOT NULL + CHECK (origin_type == 'L') + DEFAULT 'L', + friend_public_key BLOB NOT NULL, route BLOB NOT NULL, - dest_payment BLOB NOT NULL, - total_dest_payment BLOB NOT NULL, - invoice_hash BLOB NOT NULL, - hmac BLOB NOT NULL, left_fees BLOB NOT NULL, - FOREIGN KEY(friend_public_key, currency) - REFERENCES mutual_credits(friend_public_key, currency) + UNIQUE (friend_public_key, queue_index), + FOREIGN KEY(friend_public_key) + REFERENCES mutual_credits(friend_public_key) + ON DELETE CASCADE + FOREIGN KEY(request_id, origin_type) + REFERENCES requests(request_id, origin_type) ON DELETE CASCADE );", params![], @@ -477,20 +501,20 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE pending_requests( - friend_public_key BLOB NOT NULL, - currency TEXT NOT NULL, - request_id BLOB NOT NULL PRIMARY KEY, queue_index BLOB NOT NULL, - src_hashed_lock BLOB NOT NULL, + request_id BLOB NOT NULL PRIMARY KEY, + origin_type TEXT NOT NULL + CHECK (origin_type == 'F') + DEFAULT 'F', + friend_public_key BLOB NOT NULL, route BLOB NOT NULL, - dest_payment BLOB NOT NULL, - total_dest_payment BLOB NOT NULL, - invoice_hash BLOB NOT NULL, - hmac BLOB NOT NULL, left_fees BLOB NOT NULL, UNIQUE (friend_public_key, queue_index), - FOREIGN KEY(friend_public_key, currency) - REFERENCES mutual_credits(friend_public_key, currency) + FOREIGN KEY(friend_public_key) + REFERENCES mutual_credits(friend_public_key) + ON DELETE CASCADE + FOREIGN KEY(request_id, origin_type) + REFERENCES requests(request_id, origin_type) ON DELETE CASCADE );", params![], @@ -508,18 +532,17 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { tx.execute( "CREATE TABLE pending_backwards( - friend_public_key BLOB NOT NULL, - currency TEXT NOT NULL, - request_id BLOB NOT NULL PRIMARY KEY, queue_index BLOB NOT NULL UNIQUE, + request_id BLOB NOT NULL PRIMARY KEY, + friend_public_key BLOB NOT NULL, backwards_type TEXT CHECK (backwards_type IN ('R', 'C')) NOT NULL, -- R: Response, C: Cancel UNIQUE (friend_public_key, queue_index), - FOREIGN KEY(friend_public_key, currency) - REFERENCES mutual_credits(friend_public_key, currency) + FOREIGN KEY(friend_public_key) + REFERENCES mutual_credits(friend_public_key) ON DELETE CASCADE, FOREIGN KEY(request_id) - REFERENCES pending_requests(request_id) + REFERENCES requests(request_id) ON DELETE CASCADE );", params![], From 01819694f31a42ece8d6fd52e80facd500cc2155 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 29 Dec 2020 10:38:24 +0200 Subject: [PATCH 293/478] funder: Renamed switch -> router --- components/funder/src/lib.rs | 2 +- components/funder/src/router/mod.rs | 2 + .../{switch/switch.rs => router/router.rs} | 170 +++++++++--------- .../funder/src/{switch => router}/types.rs | 12 +- components/funder/src/switch/mod.rs | 2 - 5 files changed, 94 insertions(+), 94 deletions(-) create mode 100644 components/funder/src/router/mod.rs rename components/funder/src/{switch/switch.rs => router/router.rs} (81%) rename components/funder/src/{switch => router}/types.rs (97%) delete mode 100644 components/funder/src/switch/mod.rs diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index e0639c531..58ce224b0 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -33,7 +33,7 @@ mod route; mod token_channel; #[allow(unused)] -mod switch; +mod router; // // For testing: diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs new file mode 100644 index 000000000..c2a3e5600 --- /dev/null +++ b/components/funder/src/router/mod.rs @@ -0,0 +1,2 @@ +mod router; +mod types; diff --git a/components/funder/src/switch/switch.rs b/components/funder/src/router/router.rs similarity index 81% rename from components/funder/src/switch/switch.rs rename to components/funder/src/router/router.rs index 60a1474fe..a8fee4818 100644 --- a/components/funder/src/switch/switch.rs +++ b/components/funder/src/router/router.rs @@ -18,11 +18,11 @@ use proto::funder::messages::{ use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use crate::route::Route; -use crate::switch::types::{BackwardsOp, CurrencyInfo, SwitchDbClient, SwitchOutput, SwitchState}; +use crate::router::types::{BackwardsOp, CurrencyInfo, RouterDbClient, RouterOutput, RouterState}; use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; #[derive(Debug, From)] -pub enum SwitchError { +pub enum RouterError { FriendAlreadyOnline, FriendAlreadyOffline, GenerationOverflow, @@ -44,14 +44,14 @@ fn operations_vec_to_currencies_operations( } async fn collect_currencies_operations( - switch_db_client: &mut impl SwitchDbClient, + router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, max_operations_in_batch: usize, -) -> Result { +) -> Result { let mut operations_vec = Vec::<(Currency, FriendTcOp)>::new(); // Collect any pending responses and cancels: - while let Some((currency, backwards_op)) = switch_db_client + while let Some((currency, backwards_op)) = router_db_client .pending_backwards_pop_front(friend_public_key.clone()) .await? { @@ -68,7 +68,7 @@ async fn collect_currencies_operations( } // Collect any pending user requests: - while let Some((currency, request_op)) = switch_db_client + while let Some((currency, request_op)) = router_db_client .pending_user_requests_pop_front(friend_public_key.clone()) .await? { @@ -82,7 +82,7 @@ async fn collect_currencies_operations( } // Collect any pending requests: - while let Some((currency, request_op)) = switch_db_client + while let Some((currency, request_op)) = router_db_client .pending_requests_pop_front(friend_public_key.clone()) .await? { @@ -100,16 +100,16 @@ async fn collect_currencies_operations( /// Do we have more pending currencies operations? async fn is_pending_currencies_operations( - switch_db_client: &mut impl SwitchDbClient, + router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, -) -> Result { - Ok(!switch_db_client +) -> Result { + Ok(!router_db_client .pending_backwards_is_empty(friend_public_key.clone()) .await? - || !switch_db_client + || !router_db_client .pending_user_requests_is_empty(friend_public_key.clone()) .await? - || !switch_db_client + || !router_db_client .pending_requests_is_empty(friend_public_key.clone()) .await?) } @@ -117,20 +117,20 @@ async fn is_pending_currencies_operations( /// Attempt to create an outgoing move token /// Return Ok(None) if we have nothing to send async fn collect_outgoing_move_token( - switch_db_client: &mut impl SwitchDbClient, + router_db_client: &mut impl RouterDbClient, identity_client: &mut IdentityClient, local_public_key: &PublicKey, friend_public_key: PublicKey, max_operations_in_batch: usize, -) -> Result, SwitchError> { +) -> Result, RouterError> { let currencies_operations = collect_currencies_operations( - switch_db_client, + router_db_client, friend_public_key.clone(), max_operations_in_batch, ) .await?; - let mut currencies_diff = switch_db_client + let mut currencies_diff = router_db_client .currencies_diff(friend_public_key.clone()) .await?; @@ -141,7 +141,7 @@ async fn collect_outgoing_move_token( } else { // We have something to send to remote side let move_token = handle_out_move_token( - switch_db_client.tc_db_client(friend_public_key.clone()), + router_db_client.tc_db_client(friend_public_key.clone()), identity_client, currencies_operations, currencies_diff, @@ -151,7 +151,7 @@ async fn collect_outgoing_move_token( .await?; Some(MoveTokenRequest { move_token, - token_wanted: is_pending_currencies_operations(switch_db_client, friend_public_key) + token_wanted: is_pending_currencies_operations(router_db_client, friend_public_key) .await?, }) }, @@ -161,12 +161,12 @@ async fn collect_outgoing_move_token( /// Check if we have anything to send to a remove friend on a move token message, /// without performing any data mutations async fn is_pending_move_token( - switch_db_client: &mut impl SwitchDbClient, + router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, -) -> Result { +) -> Result { Ok( - is_pending_currencies_operations(switch_db_client, friend_public_key.clone()).await? - || !switch_db_client + is_pending_currencies_operations(router_db_client, friend_public_key.clone()).await? + || !router_db_client .currencies_diff(friend_public_key.clone()) .await? .is_empty(), @@ -175,7 +175,7 @@ async fn is_pending_move_token( /// Calculate receive capacity for a certain currency /// This is the number we are going to report to an index server -fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result { +fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result { if !currency_info.is_open { return Ok(0); } @@ -196,7 +196,7 @@ fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result mc_balance .balance .checked_add_unsigned(mc_balance.remote_pending_debt) - .ok_or(SwitchError::BalanceOverflow)?, + .ok_or(RouterError::BalanceOverflow)?, )) } @@ -204,7 +204,7 @@ fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result fn create_update_index_mutation( friend_public_key: PublicKey, currency_info: CurrencyInfo, -) -> Result { +) -> Result { let recv_capacity = calc_recv_capacity(¤cy_info)?; Ok(IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { public_key: friend_public_key, @@ -216,10 +216,10 @@ fn create_update_index_mutation( /// Create a list of index mutations based on a MoveToken message. async fn create_index_mutations_from_move_token( - switch_db_client: &mut impl SwitchDbClient, + router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, move_token: &MoveToken, -) -> Result, SwitchError> { +) -> Result, RouterError> { // Collect all mentioned currencies: let currencies = { let mut currencies = HashSet::new(); @@ -237,7 +237,7 @@ async fn create_index_mutations_from_move_token( // Create all index mutations: for currency in currencies.into_iter() { - let opt_currency_info = switch_db_client + let opt_currency_info = router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) .await?; if let Some(currency_info) = opt_currency_info { @@ -259,23 +259,23 @@ async fn create_index_mutations_from_move_token( } pub async fn set_friend_online( - switch_db_client: &mut impl SwitchDbClient, - switch_state: &mut SwitchState, + router_db_client: &mut impl RouterDbClient, + router_state: &mut RouterState, identity_client: &mut IdentityClient, local_public_key: &PublicKey, friend_public_key: PublicKey, max_operations_in_batch: usize, -) -> Result { - if switch_state.liveness.is_online(&friend_public_key) { +) -> Result { + if router_state.liveness.is_online(&friend_public_key) { // The friend is already marked as online! - return Err(SwitchError::FriendAlreadyOnline); + return Err(RouterError::FriendAlreadyOnline); } - switch_state.liveness.set_online(friend_public_key.clone()); + router_state.liveness.set_online(friend_public_key.clone()); - let mut output = SwitchOutput::new(); + let mut output = RouterOutput::new(); // Check if we have any relays information to send to the remote side: - if let (Some(generation), relays) = switch_db_client + if let (Some(generation), relays) = router_db_client .get_sent_relays(friend_public_key.clone()) .await? { @@ -286,7 +286,7 @@ pub async fn set_friend_online( ); } - match switch_db_client + match router_db_client .tc_db_client(friend_public_key.clone()) .get_tc_status() .await? @@ -294,7 +294,7 @@ pub async fn set_friend_online( TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. let opt_move_token_request = collect_outgoing_move_token( - switch_db_client, + router_db_client, identity_client, local_public_key, friend_public_key.clone(), @@ -318,7 +318,7 @@ pub async fn set_friend_online( FriendMessage::MoveTokenRequest(MoveTokenRequest { move_token: move_token_out, token_wanted: is_pending_move_token( - switch_db_client, + router_db_client, friend_public_key.clone(), ) .await?, @@ -335,7 +335,7 @@ pub async fn set_friend_online( } // Add an index mutation for all open currencies: - let mut open_currencies = switch_db_client.list_open_currencies(friend_public_key.clone()); + let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); while let Some(res) = open_currencies.next().await { let open_currency = res?; output.add_index_mutation(create_update_index_mutation( @@ -348,20 +348,20 @@ pub async fn set_friend_online( } pub async fn set_friend_offline( - switch_db_client: &mut impl SwitchDbClient, - switch_state: &mut SwitchState, + router_db_client: &mut impl RouterDbClient, + router_state: &mut RouterState, friend_public_key: PublicKey, -) -> Result { - if !switch_state.liveness.is_online(&friend_public_key) { +) -> Result { + if !router_state.liveness.is_online(&friend_public_key) { // The friend is already marked as offline! - return Err(SwitchError::FriendAlreadyOffline); + return Err(RouterError::FriendAlreadyOffline); } - switch_state.liveness.set_offline(&friend_public_key); + router_state.liveness.set_offline(&friend_public_key); - let mut output = SwitchOutput::new(); + let mut output = RouterOutput::new(); // Cancel all pending user requests - while let Some((_currency, pending_user_request)) = switch_db_client + while let Some((_currency, pending_user_request)) = router_db_client .pending_user_requests_pop_front(friend_public_key.clone()) .await? { @@ -372,19 +372,19 @@ pub async fn set_friend_offline( } // Cancel all pending requests - while let Some((currency, pending_request)) = switch_db_client + while let Some((currency, pending_request)) = router_db_client .pending_requests_pop_front(friend_public_key.clone()) .await? { // Find from which friend this pending request has originated from. // Due to inconsistencies, it is possible that this pending request has no origin. - let opt_origin_public_key = switch_db_client + let opt_origin_public_key = router_db_client .get_remote_pending_request_friend_public_key(pending_request.request_id.clone()) .await?; if let Some(origin_public_key) = opt_origin_public_key { // Cancel request by queue-ing a cancel into the relevant friend's queue: - switch_db_client + router_db_client .pending_backwards_push_back( origin_public_key, currency, @@ -398,7 +398,7 @@ pub async fn set_friend_offline( // Add index mutations // We send index mutations to remove all currencies that are considered open - let mut open_currencies = switch_db_client.list_open_currencies(friend_public_key.clone()); + let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); while let Some(res) = open_currencies.next().await { let open_currency = res?; output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { @@ -411,36 +411,36 @@ pub async fn set_friend_offline( } pub async fn send_request( - switch_db_client: &mut impl SwitchDbClient, - switch_state: &SwitchState, + router_db_client: &mut impl RouterDbClient, + router_state: &RouterState, currency: Currency, mut request: RequestSendFundsOp, identity_client: &mut IdentityClient, local_public_key: &PublicKey, max_operations_in_batch: usize, -) -> Result { +) -> Result { // Make sure that the provided route is valid: if !request.route.is_valid() { - return Err(SwitchError::InvalidRoute); + return Err(RouterError::InvalidRoute); } - let mut output = SwitchOutput::new(); + let mut output = RouterOutput::new(); // We cut the first two public keys from the route: // Pop first route public key: let route_local_public_key = request.route.remove(0); if &route_local_public_key != local_public_key { - return Err(SwitchError::InvalidRoute); + return Err(RouterError::InvalidRoute); } // Pop second route public key: let friend_public_key = request.route.remove(0); // Gather information about friend's channel and liveness: - let tc_status = switch_db_client + let tc_status = router_db_client .tc_db_client(friend_public_key.clone()) .get_tc_status() .await?; - let is_online = switch_state.liveness.is_online(&friend_public_key); + let is_online = router_state.liveness.is_online(&friend_public_key); // If friend is ready (online + consistent): // - push the request @@ -453,13 +453,13 @@ pub async fn send_request( match (tc_status, is_online) { (TcStatus::ConsistentIn(_), true) => { // Push request: - switch_db_client + router_db_client .pending_user_requests_push_back(friend_public_key.clone(), currency, request) .await?; // Create an outgoing move token if we have something to send. let opt_move_token_request = collect_outgoing_move_token( - switch_db_client, + router_db_client, identity_client, local_public_key, friend_public_key.clone(), @@ -471,7 +471,7 @@ pub async fn send_request( // We have something to send to remote side // Deduce index mutations according to move token: let index_mutations = create_index_mutations_from_move_token( - switch_db_client, + router_db_client, friend_public_key.clone(), &move_token_request.move_token, ) @@ -489,7 +489,7 @@ pub async fn send_request( } (TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in), true) => { // Push request: - switch_db_client + router_db_client .pending_user_requests_push_back(friend_public_key.clone(), currency, request) .await?; @@ -500,7 +500,7 @@ pub async fn send_request( FriendMessage::MoveTokenRequest(MoveTokenRequest { move_token: move_token_out, token_wanted: is_pending_move_token( - switch_db_client, + router_db_client, friend_public_key.clone(), ) .await?, @@ -520,9 +520,9 @@ pub async fn send_request( } pub async fn send_response( - _switch_db_client: &mut impl SwitchDbClient, + _router_db_client: &mut impl RouterDbClient, _response: ResponseSendFundsOp, -) -> Result { +) -> Result { // TODO: // - Find relevant request (And so, find relevant friend_public_key) // - Queue response @@ -531,83 +531,83 @@ pub async fn send_response( } pub async fn send_cancel( - _switch_db_client: &mut impl SwitchDbClient, + _router_db_client: &mut impl RouterDbClient, _cancel: CancelSendFundsOp, -) -> Result { +) -> Result { todo!(); } pub async fn add_currency( - _switch_db_client: &mut impl SwitchDbClient, + _router_db_client: &mut impl RouterDbClient, _friend_public_key: PublicKey, _currency: Currency, -) -> Result { +) -> Result { // TODO todo!(); } pub async fn set_remove_currency( - _switch_db_client: &mut impl SwitchDbClient, + _router_db_client: &mut impl RouterDbClient, _friend_public_key: PublicKey, _currency: Currency, -) -> Result { +) -> Result { // TODO todo!(); } pub async fn unset_remove_currency( - _switch_db_client: &mut impl SwitchDbClient, + _router_db_client: &mut impl RouterDbClient, _friend_public_key: PublicKey, _currency: Currency, -) -> Result { +) -> Result { // TODO todo!(); } // TODO: Do we need to send an update to index client somehow? pub async fn set_remote_max_debt( - _switch_db_client: &mut impl SwitchDbClient, + _router_db_client: &mut impl RouterDbClient, _friend_public_key: PublicKey, _currency: Currency, _remote_max_debt: u128, -) -> Result { +) -> Result { // TODO todo!(); } // TODO: Do we need to send an update to index client somehow? pub async fn open_currency( - _switch_db_client: &mut impl SwitchDbClient, + _router_db_client: &mut impl RouterDbClient, _friend_public_key: PublicKey, _currency: Currency, -) -> Result { +) -> Result { // TODO todo!(); } // TODO: Do we need to send an update to index client somehow? pub async fn close_currency( - _switch_db_client: &mut impl SwitchDbClient, + _router_db_client: &mut impl RouterDbClient, _friend_public_key: PublicKey, _currency: Currency, -) -> Result { +) -> Result { // TODO todo!(); } pub async fn update_local_relays( - _switch_db_client: &mut impl SwitchDbClient, + _router_db_client: &mut impl RouterDbClient, _local_relays: HashMap, -) -> Result { +) -> Result { // TODO todo!(); } pub async fn incoming_friend_message( - _switch_db_client: &mut impl SwitchDbClient, + _router_db_client: &mut impl RouterDbClient, _friend_public_key: PublicKey, _friend_message: FriendMessage, -) -> Result { +) -> Result { // TODO todo!(); } diff --git a/components/funder/src/switch/types.rs b/components/funder/src/router/types.rs similarity index 97% rename from components/funder/src/switch/types.rs rename to components/funder/src/router/types.rs index 80d15026b..ff853efcb 100644 --- a/components/funder/src/switch/types.rs +++ b/components/funder/src/router/types.rs @@ -14,9 +14,9 @@ use proto::funder::messages::{ }; use proto::index_server::messages::IndexMutation; -/// Switch's ephemeral state (Not saved inside the database) +/// Router's ephemeral state (Not saved inside the database) #[derive(Debug)] -pub struct SwitchState { +pub struct RouterState { pub liveness: Liveness, } @@ -50,7 +50,7 @@ pub struct CurrencyInfo { pub opt_local: Option, } -pub trait SwitchDbClient { +pub trait RouterDbClient { type TcDbClient: TcDbClient; fn tc_db_client(&mut self, friend_public_key: PublicKey) -> &mut Self::TcDbClient; @@ -177,7 +177,7 @@ pub trait SwitchDbClient { } #[derive(Debug)] -pub struct SwitchOutput { +pub struct RouterOutput { pub friends_messages: HashMap>, pub index_mutations: Vec, pub updated_remote_relays: Vec, @@ -186,9 +186,9 @@ pub struct SwitchOutput { pub incoming_cancels: Vec, } -impl SwitchOutput { +impl RouterOutput { pub fn new() -> Self { - SwitchOutput { + RouterOutput { friends_messages: HashMap::new(), index_mutations: Vec::new(), updated_remote_relays: Vec::new(), diff --git a/components/funder/src/switch/mod.rs b/components/funder/src/switch/mod.rs deleted file mode 100644 index 8fee2a555..000000000 --- a/components/funder/src/switch/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod switch; -mod types; From 0fe60f952a86246e96ea87dc092a43378bd34a4b Mon Sep 17 00:00:00 2001 From: real Date: Tue, 29 Dec 2020 12:52:17 +0200 Subject: [PATCH 294/478] database: 'local_requests' strategy to remember locally created requests --- components/database/src/create.rs | 95 ++++++++++++++----------------- 1 file changed, 43 insertions(+), 52 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 13dea3ec0..fd1052978 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -397,74 +397,67 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - // A list of all requests currently being processed + // Requests that were sent through our node to a friend. tx.execute( - "CREATE TABLE requests( + "CREATE TABLE local_open_transactions( request_id BLOB NOT NULL PRIMARY KEY, currency TEXT NOT NULL, - origin_type TEXT CHECK (origin_type IN ('F', 'L')) NOT NULL, - -- Originated from a (F)riend or (L)ocally + friend_public_key BLOB NOT NULL, + route BLOB NOT NULL, src_hashed_lock BLOB NOT NULL, dest_payment BLOB NOT NULL, total_dest_payment BLOB NOT NULL, invoice_hash BLOB NOT NULL, hmac BLOB NOT NULL, - FOREIGN KEY(currency) - REFERENCES mutual_credits(currency) + left_fees BLOB NOT NULL, + FOREIGN KEY(friend_public_key, currency) + REFERENCES mutual_credits(friend_public_key, currency) ON DELETE CASCADE );", params![], )?; tx.execute( - "CREATE UNIQUE INDEX idx_orig_requests ON requests(request_id);", + "CREATE UNIQUE INDEX idx_local_open_transactions ON local_open_transactions(request_id);", params![], )?; - // Requests that were sent through our node to a remote friend. + // Requests that were sent through a friend along our node. tx.execute( - "CREATE TABLE local_open_transactions( + "CREATE TABLE remote_open_transactions( request_id BLOB NOT NULL PRIMARY KEY, + currency TEXT NOT NULL, friend_public_key BLOB NOT NULL, route BLOB NOT NULL, + src_hashed_lock BLOB NOT NULL, + dest_payment BLOB NOT NULL, + total_dest_payment BLOB NOT NULL, + invoice_hash BLOB NOT NULL, + hmac BLOB NOT NULL, left_fees BLOB NOT NULL, - FOREIGN KEY(friend_public_key) - REFERENCES mutual_credits(friend_public_key) - ON DELETE CASCADE - FOREIGN KEY(request_id) - REFERENCES requests(request_id) + FOREIGN KEY(friend_public_key, currency) + REFERENCES mutual_credits(friend_public_key, currency) ON DELETE CASCADE );", params![], )?; tx.execute( - "CREATE UNIQUE INDEX idx_local_open_transactions ON local_open_transactions(request_id);", + "CREATE UNIQUE INDEX idx_remote_open_transactions ON remote_open_transactions(request_id);", params![], )?; - // Requests that were sent through a friend along our node. + // Requests that were created locally + // (As opposed to requests that were received for the first time from a friend) tx.execute( - "CREATE TABLE remote_open_transactions( + "CREATE TABLE local_requests( request_id BLOB NOT NULL PRIMARY KEY, - origin_type TEXT NOT NULL - CHECK (origin_type == 'F') - DEFAULT 'F', - friend_public_key BLOB NOT NULL, - route BLOB NOT NULL, - left_fees BLOB NOT NULL, - FOREIGN KEY(friend_public_key) - REFERENCES mutual_credits(friend_public_key) - ON DELETE CASCADE - FOREIGN KEY(request_id, origin_type) - REFERENCES requests(request_id, origin_type) - ON DELETE CASCADE - );", + );", params![], )?; tx.execute( - "CREATE UNIQUE INDEX idx_remote_open_transactions ON remote_open_transactions(request_id);", + "CREATE UNIQUE INDEX idx_local_requests ON local_requests(request_id);", params![], )?; @@ -472,18 +465,18 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE pending_user_requests( queue_index BLOB NOT NULL UNIQUE, request_id BLOB NOT NULL PRIMARY KEY, - origin_type TEXT NOT NULL - CHECK (origin_type == 'L') - DEFAULT 'L', + currency TEXT NOT NULL, friend_public_key BLOB NOT NULL, route BLOB NOT NULL, + src_hashed_lock BLOB NOT NULL, + dest_payment BLOB NOT NULL, + total_dest_payment BLOB NOT NULL, + invoice_hash BLOB NOT NULL, + hmac BLOB NOT NULL, left_fees BLOB NOT NULL, UNIQUE (friend_public_key, queue_index), - FOREIGN KEY(friend_public_key) - REFERENCES mutual_credits(friend_public_key) - ON DELETE CASCADE - FOREIGN KEY(request_id, origin_type) - REFERENCES requests(request_id, origin_type) + FOREIGN KEY(friend_public_key, currency) + REFERENCES mutual_credits(friend_public_key, currency) ON DELETE CASCADE );", params![], @@ -503,18 +496,18 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE pending_requests( queue_index BLOB NOT NULL, request_id BLOB NOT NULL PRIMARY KEY, - origin_type TEXT NOT NULL - CHECK (origin_type == 'F') - DEFAULT 'F', + currency TEXT NOT NULL, friend_public_key BLOB NOT NULL, route BLOB NOT NULL, + src_hashed_lock BLOB NOT NULL, + dest_payment BLOB NOT NULL, + total_dest_payment BLOB NOT NULL, + invoice_hash BLOB NOT NULL, + hmac BLOB NOT NULL, left_fees BLOB NOT NULL, UNIQUE (friend_public_key, queue_index), - FOREIGN KEY(friend_public_key) - REFERENCES mutual_credits(friend_public_key) - ON DELETE CASCADE - FOREIGN KEY(request_id, origin_type) - REFERENCES requests(request_id, origin_type) + FOREIGN KEY(friend_public_key, currency) + REFERENCES mutual_credits(friend_public_key, currency) ON DELETE CASCADE );", params![], @@ -534,15 +527,13 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE pending_backwards( queue_index BLOB NOT NULL UNIQUE, request_id BLOB NOT NULL PRIMARY KEY, + currency BLOB NOT NULL, friend_public_key BLOB NOT NULL, backwards_type TEXT CHECK (backwards_type IN ('R', 'C')) NOT NULL, -- R: Response, C: Cancel UNIQUE (friend_public_key, queue_index), - FOREIGN KEY(friend_public_key) - REFERENCES mutual_credits(friend_public_key) - ON DELETE CASCADE, - FOREIGN KEY(request_id) - REFERENCES requests(request_id) + FOREIGN KEY(friend_public_key, currency) + REFERENCES mutual_credits(friend_public_key, currency) ON DELETE CASCADE );", params![], From 31f936d78d3bac5cd96d49b6db66d1aae70b8eff Mon Sep 17 00:00:00 2001 From: real Date: Tue, 29 Dec 2020 14:16:09 +0200 Subject: [PATCH 295/478] funder: impl send_response() --- components/funder/src/router/router.rs | 97 ++++++++++++++++++++++---- components/funder/src/router/types.rs | 10 ++- 2 files changed, 93 insertions(+), 14 deletions(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index a8fee4818..6f3930db9 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -378,16 +378,16 @@ pub async fn set_friend_offline( { // Find from which friend this pending request has originated from. // Due to inconsistencies, it is possible that this pending request has no origin. - let opt_origin_public_key = router_db_client - .get_remote_pending_request_friend_public_key(pending_request.request_id.clone()) + let opt_request_origin = router_db_client + .get_remote_pending_request_origin(pending_request.request_id.clone()) .await?; - if let Some(origin_public_key) = opt_origin_public_key { + if let Some(request_origin) = opt_request_origin { // Cancel request by queue-ing a cancel into the relevant friend's queue: router_db_client .pending_backwards_push_back( - origin_public_key, - currency, + request_origin.friend_public_key, + request_origin.currency, BackwardsOp::Cancel(CancelSendFundsOp { request_id: pending_request.request_id, }), @@ -520,14 +520,87 @@ pub async fn send_request( } pub async fn send_response( - _router_db_client: &mut impl RouterDbClient, - _response: ResponseSendFundsOp, + router_db_client: &mut impl RouterDbClient, + response: ResponseSendFundsOp, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, ) -> Result { - // TODO: - // - Find relevant request (And so, find relevant friend_public_key) - // - Queue response - // - Attempt to collect a MoveToken for the relevant friend. - todo!(); + let mut output = RouterOutput::new(); + + let opt_request_origin = router_db_client + .get_remote_pending_request_origin(response.request_id.clone()) + .await?; + + // Attempt to find which node originally sent us this request, + // so that we can forward him the response. + // If we can not find the request's origin, we discard the response. + if let Some(request_origin) = opt_request_origin { + router_db_client + .pending_backwards_push_back( + request_origin.friend_public_key.clone(), + request_origin.currency, + BackwardsOp::Response(response), + ) + .await?; + + match router_db_client + .tc_db_client(request_origin.friend_public_key.clone()) + .get_tc_status() + .await? + { + TcStatus::ConsistentIn(_) => { + // Create an outgoing move token if we have something to send. + let opt_move_token_request = collect_outgoing_move_token( + router_db_client, + identity_client, + local_public_key, + request_origin.friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + if let Some(move_token_request) = opt_move_token_request { + // We have something to send to remote side: + + // Update index mutations: + let index_mutations = create_index_mutations_from_move_token( + router_db_client, + request_origin.friend_public_key.clone(), + &move_token_request.move_token, + ) + .await?; + for index_mutation in index_mutations { + output.add_index_mutation(index_mutation); + } + output.add_friend_message( + request_origin.friend_public_key.clone(), + FriendMessage::MoveTokenRequest(move_token_request), + ); + } + } + TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { + // Resend outgoing move token, + // possibly asking for the token if we have something to send + output.add_friend_message( + request_origin.friend_public_key.clone(), + FriendMessage::MoveTokenRequest(MoveTokenRequest { + move_token: move_token_out, + token_wanted: is_pending_move_token( + router_db_client, + request_origin.friend_public_key.clone(), + ) + .await?, + }), + ); + } + // This state is not possible, because we did manage to locate our request with this + // friend: + TcStatus::Inconsistent(..) => unreachable!(), + } + } + + Ok(output) } pub async fn send_cancel( diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index ff853efcb..129ae9640 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -50,6 +50,12 @@ pub struct CurrencyInfo { pub opt_local: Option, } +#[derive(Debug)] +pub struct RequestOrigin { + pub friend_public_key: PublicKey, + pub currency: Currency, +} + pub trait RouterDbClient { type TcDbClient: TcDbClient; fn tc_db_client(&mut self, friend_public_key: PublicKey) -> &mut Self::TcDbClient; @@ -146,10 +152,10 @@ pub trait RouterDbClient { currency: Currency, ) -> AsyncOpResult>; - fn get_remote_pending_request_friend_public_key( + fn get_remote_pending_request_origin( &mut self, request_id: Uid, - ) -> AsyncOpResult>; + ) -> AsyncOpResult>; /* /// Get a list of configured currencies that were not yet added as local currencies From 90b255763e1012681babf2881f5a3b74d359e3c0 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 29 Dec 2020 17:17:45 +0200 Subject: [PATCH 296/478] funder: Refactored send_response() + Added send_cancel() --- components/funder/src/router/router.rs | 170 ++++++++++++++++--------- 1 file changed, 113 insertions(+), 57 deletions(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 6f3930db9..37b756671 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -28,6 +28,7 @@ pub enum RouterError { GenerationOverflow, BalanceOverflow, InvalidRoute, + UnexpectedTcStatus, TokenChannelError(TokenChannelError), OpError(OpError), } @@ -519,6 +520,74 @@ pub async fn send_request( Ok(output) } +/// Attempt to send as much as possible through a token channel to remote side +/// Assumes that the token channel is in consistent state (Incoming / Outgoing). +async fn flush_friend( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, + router_output: &mut RouterOutput, +) -> Result<(), RouterError> { + match router_db_client + .tc_db_client(friend_public_key.clone()) + .get_tc_status() + .await? + { + TcStatus::ConsistentIn(_) => { + // Create an outgoing move token if we have something to send. + let opt_move_token_request = collect_outgoing_move_token( + router_db_client, + identity_client, + local_public_key, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + if let Some(move_token_request) = opt_move_token_request { + // We have something to send to remote side: + + // Update index mutations: + let index_mutations = create_index_mutations_from_move_token( + router_db_client, + friend_public_key.clone(), + &move_token_request.move_token, + ) + .await?; + for index_mutation in index_mutations { + router_output.add_index_mutation(index_mutation); + } + router_output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(move_token_request), + ); + } + } + TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { + // Resend outgoing move token, + // possibly asking for the token if we have something to send + router_output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(MoveTokenRequest { + move_token: move_token_out, + token_wanted: is_pending_move_token( + router_db_client, + friend_public_key.clone(), + ) + .await?, + }), + ); + } + // This state is not possible, because we did manage to locate our request with this + // friend: + TcStatus::Inconsistent(..) => return Err(RouterError::UnexpectedTcStatus), + } + + Ok(()) +} + pub async fn send_response( router_db_client: &mut impl RouterDbClient, response: ResponseSendFundsOp, @@ -544,70 +613,57 @@ pub async fn send_response( ) .await?; - match router_db_client - .tc_db_client(request_origin.friend_public_key.clone()) - .get_tc_status() - .await? - { - TcStatus::ConsistentIn(_) => { - // Create an outgoing move token if we have something to send. - let opt_move_token_request = collect_outgoing_move_token( - router_db_client, - identity_client, - local_public_key, - request_origin.friend_public_key.clone(), - max_operations_in_batch, - ) - .await?; - - if let Some(move_token_request) = opt_move_token_request { - // We have something to send to remote side: - - // Update index mutations: - let index_mutations = create_index_mutations_from_move_token( - router_db_client, - request_origin.friend_public_key.clone(), - &move_token_request.move_token, - ) - .await?; - for index_mutation in index_mutations { - output.add_index_mutation(index_mutation); - } - output.add_friend_message( - request_origin.friend_public_key.clone(), - FriendMessage::MoveTokenRequest(move_token_request), - ); - } - } - TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { - // Resend outgoing move token, - // possibly asking for the token if we have something to send - output.add_friend_message( - request_origin.friend_public_key.clone(), - FriendMessage::MoveTokenRequest(MoveTokenRequest { - move_token: move_token_out, - token_wanted: is_pending_move_token( - router_db_client, - request_origin.friend_public_key.clone(), - ) - .await?, - }), - ); - } - // This state is not possible, because we did manage to locate our request with this - // friend: - TcStatus::Inconsistent(..) => unreachable!(), - } + flush_friend( + router_db_client, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + &mut output, + ) + .await?; } Ok(output) } pub async fn send_cancel( - _router_db_client: &mut impl RouterDbClient, - _cancel: CancelSendFundsOp, + router_db_client: &mut impl RouterDbClient, + cancel: CancelSendFundsOp, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, ) -> Result { - todo!(); + let mut output = RouterOutput::new(); + + let opt_request_origin = router_db_client + .get_remote_pending_request_origin(cancel.request_id.clone()) + .await?; + + // Attempt to find which node originally sent us this request, + // so that we can forward him the response. + // If we can not find the request's origin, we discard the response. + if let Some(request_origin) = opt_request_origin { + router_db_client + .pending_backwards_push_back( + request_origin.friend_public_key.clone(), + request_origin.currency, + BackwardsOp::Cancel(cancel), + ) + .await?; + + flush_friend( + router_db_client, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + &mut output, + ) + .await?; + } + + Ok(output) } pub async fn add_currency( From 4b9436b84f529f3fbd15783a1d50a619cd5b2554 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 29 Dec 2020 17:39:06 +0200 Subject: [PATCH 297/478] funder: add_currency, {set,unset}_remove_currency --- components/funder/src/router/router.rs | 77 ++++++++++++++++++++------ components/funder/src/router/types.rs | 20 +++++++ 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 37b756671..81a8cb092 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -654,7 +654,7 @@ pub async fn send_cancel( flush_friend( router_db_client, - friend_public_key, + request_origin.friend_public_key, identity_client, local_public_key, max_operations_in_batch, @@ -667,30 +667,75 @@ pub async fn send_cancel( } pub async fn add_currency( - _router_db_client: &mut impl RouterDbClient, - _friend_public_key: PublicKey, - _currency: Currency, + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, ) -> Result { - // TODO - todo!(); + let mut output = RouterOutput::new(); + router_db_client + .add_currency_config(friend_public_key.clone(), currency) + .await?; + + flush_friend( + router_db_client, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + &mut output, + ) + .await?; + Ok(output) } pub async fn set_remove_currency( - _router_db_client: &mut impl RouterDbClient, - _friend_public_key: PublicKey, - _currency: Currency, + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, ) -> Result { - // TODO - todo!(); + let mut output = RouterOutput::new(); + router_db_client + .set_currency_remove(friend_public_key.clone(), currency) + .await?; + + flush_friend( + router_db_client, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + &mut output, + ) + .await?; + Ok(output) } pub async fn unset_remove_currency( - _router_db_client: &mut impl RouterDbClient, - _friend_public_key: PublicKey, - _currency: Currency, + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, ) -> Result { - // TODO - todo!(); + let mut output = RouterOutput::new(); + router_db_client + .unset_currency_remove(friend_public_key.clone(), currency) + .await?; + + flush_friend( + router_db_client, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + &mut output, + ) + .await?; + Ok(output) } // TODO: Do we need to send an update to index client somehow? diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 129ae9640..511c65076 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -157,6 +157,26 @@ pub trait RouterDbClient { request_id: Uid, ) -> AsyncOpResult>; + fn add_currency_config( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + ) -> AsyncOpResult<()>; + + /// Set currency to be removed when possible + fn set_currency_remove( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + ) -> AsyncOpResult<()>; + + /// Unset currency removal + fn unset_currency_remove( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + ) -> AsyncOpResult<()>; + /* /// Get a list of configured currencies that were not yet added as local currencies fn currencies_to_add(&mut self, friend_public_key: PublicKey) -> AsyncOpResult>; From 3783d46868e4ba4f3dd056741ac7f0cf21adb04d Mon Sep 17 00:00:00 2001 From: real Date: Tue, 29 Dec 2020 17:44:39 +0200 Subject: [PATCH 298/478] funder: Fixed compilation error --- components/funder/src/router/router.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 81a8cb092..edccff23a 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -615,7 +615,7 @@ pub async fn send_response( flush_friend( router_db_client, - friend_public_key, + request_origin.friend_public_key, identity_client, local_public_key, max_operations_in_batch, From 58cb0a2e4d30dbd2f02bbe6529a77c1ef13a932c Mon Sep 17 00:00:00 2001 From: real Date: Tue, 29 Dec 2020 17:44:57 +0200 Subject: [PATCH 299/478] funder: Added missing function arguments --- components/funder/src/router/router.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index edccff23a..907880a5e 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -720,6 +720,9 @@ pub async fn unset_remove_currency( router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, currency: Currency, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, ) -> Result { let mut output = RouterOutput::new(); router_db_client From 88963f2e896f455b15d1492197b3dc4ca6cfbd8b Mon Sep 17 00:00:00 2001 From: real Date: Tue, 29 Dec 2020 17:45:14 +0200 Subject: [PATCH 300/478] funder: TODO comments --- components/funder/src/router/router.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 907880a5e..6991b153b 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -749,6 +749,7 @@ pub async fn set_remote_max_debt( _remote_max_debt: u128, ) -> Result { // TODO + // - Note: Should effect index mutations todo!(); } @@ -759,6 +760,7 @@ pub async fn open_currency( _currency: Currency, ) -> Result { // TODO + // - Note: Should effect index mutations todo!(); } @@ -769,6 +771,7 @@ pub async fn close_currency( _currency: Currency, ) -> Result { // TODO + // - Note: Should effect index mutations todo!(); } From 1c3603ceb093a345a08878e09777647e3f81671b Mon Sep 17 00:00:00 2001 From: real Date: Tue, 29 Dec 2020 18:11:15 +0200 Subject: [PATCH 301/478] funder: set_remote_max_debt() impl --- components/funder/src/router/router.rs | 35 ++++++++++++++++++++------ components/funder/src/router/types.rs | 7 ++++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 6991b153b..10eb878af 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -743,14 +743,35 @@ pub async fn unset_remove_currency( // TODO: Do we need to send an update to index client somehow? pub async fn set_remote_max_debt( - _router_db_client: &mut impl RouterDbClient, - _friend_public_key: PublicKey, - _currency: Currency, - _remote_max_debt: u128, + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, + remote_max_debt: u128, ) -> Result { - // TODO - // - Note: Should effect index mutations - todo!(); + // TODO: What to do if currency does not exist? + // Do we need to somehow report back? + + let mut output = RouterOutput::new(); + router_db_client + .set_remote_max_debt(friend_public_key.clone(), currency.clone(), remote_max_debt) + .await?; + + // TODO: Create an index mutation + let opt_currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await?; + if let Some(currency_info) = opt_currency_info { + // Currency exists + if currency_info.is_open { + // Currency is open: + output.add_index_mutation(create_update_index_mutation( + friend_public_key.clone(), + currency_info, + )?); + } + } + + Ok(output) } // TODO: Do we need to send an update to index client somehow? diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 511c65076..20adc7df1 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -177,6 +177,13 @@ pub trait RouterDbClient { currency: Currency, ) -> AsyncOpResult<()>; + fn set_remote_max_debt( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + remote_max_debt: u128, + ) -> AsyncOpResult<()>; + /* /// Get a list of configured currencies that were not yet added as local currencies fn currencies_to_add(&mut self, friend_public_key: PublicKey) -> AsyncOpResult>; From abf869b48253f393feb307922a3f43637052915c Mon Sep 17 00:00:00 2001 From: real Date: Wed, 30 Dec 2020 09:31:54 +0200 Subject: [PATCH 302/478] funder: impl open_currency() --- components/funder/src/router/router.rs | 48 +++++++++++++++++++------- components/funder/src/router/types.rs | 12 +++++++ 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 10eb878af..1c28e9bfe 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -741,7 +741,6 @@ pub async fn unset_remove_currency( Ok(output) } -// TODO: Do we need to send an update to index client somehow? pub async fn set_remote_max_debt( router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, @@ -752,16 +751,18 @@ pub async fn set_remote_max_debt( // Do we need to somehow report back? let mut output = RouterOutput::new(); - router_db_client - .set_remote_max_debt(friend_public_key.clone(), currency.clone(), remote_max_debt) - .await?; - // TODO: Create an index mutation let opt_currency_info = router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) .await?; if let Some(currency_info) = opt_currency_info { - // Currency exists + // Currency exists (We don't do anything otherwise) + // Set remote max debt: + router_db_client + .set_remote_max_debt(friend_public_key.clone(), currency.clone(), remote_max_debt) + .await?; + + // Create an index mutation if needed: if currency_info.is_open { // Currency is open: output.add_index_mutation(create_update_index_mutation( @@ -774,15 +775,36 @@ pub async fn set_remote_max_debt( Ok(output) } -// TODO: Do we need to send an update to index client somehow? pub async fn open_currency( - _router_db_client: &mut impl RouterDbClient, - _friend_public_key: PublicKey, - _currency: Currency, + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, ) -> Result { - // TODO - // - Note: Should effect index mutations - todo!(); + let mut output = RouterOutput::new(); + + let opt_currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await?; + + if let Some(currency_info) = opt_currency_info { + // Currency exists: + if !currency_info.is_open { + // currency is closed: + + // Open currency: + router_db_client + .open_currency(friend_public_key.clone(), currency) + .await?; + + // Add index mutation: + output.add_index_mutation(create_update_index_mutation( + friend_public_key, + currency_info, + )?); + } + } + + Ok(output) } // TODO: Do we need to send an update to index client somehow? diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 20adc7df1..c353dba09 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -184,6 +184,18 @@ pub trait RouterDbClient { remote_max_debt: u128, ) -> AsyncOpResult<()>; + fn open_currency( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + ) -> AsyncOpResult<()>; + + fn close_currency( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + ) -> AsyncOpResult<()>; + /* /// Get a list of configured currencies that were not yet added as local currencies fn currencies_to_add(&mut self, friend_public_key: PublicKey) -> AsyncOpResult>; From 03d5b2a119129ddde7d829c4193c1f78ccc5ab11 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 30 Dec 2020 09:35:50 +0200 Subject: [PATCH 303/478] funder: impl close_currency() --- components/funder/src/router/router.rs | 35 ++++++++++++++++++++------ 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 1c28e9bfe..20ebcfb7b 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -807,15 +807,36 @@ pub async fn open_currency( Ok(output) } -// TODO: Do we need to send an update to index client somehow? pub async fn close_currency( - _router_db_client: &mut impl RouterDbClient, - _friend_public_key: PublicKey, - _currency: Currency, + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, ) -> Result { - // TODO - // - Note: Should effect index mutations - todo!(); + let mut output = RouterOutput::new(); + + let opt_currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await?; + + if let Some(currency_info) = opt_currency_info { + // Currency exists: + if currency_info.is_open { + // currency is open: + + // Close currency: + router_db_client + .close_currency(friend_public_key.clone(), currency.clone()) + .await?; + + // Add index mutation: + output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { + public_key: friend_public_key, + currency, + })); + } + } + + Ok(output) } pub async fn update_local_relays( From 6f58935919e78cbf2a02da6d4d6de0c9fc08a373 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 30 Dec 2020 09:36:09 +0200 Subject: [PATCH 304/478] funder: TODO comment --- components/funder/src/router/types.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index c353dba09..4cd16d038 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -36,6 +36,7 @@ pub struct CurrencyInfoLocal { #[derive(Debug)] pub struct CurrencyInfo { + // TODO: Maybe remove this field? /// Currency name pub currency: Currency, /// Currency rate: This is how much it costs to the remote friend to send credits through us. From d47604c417071672e919e5e76b726794e0bb3152 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 30 Dec 2020 10:17:00 +0200 Subject: [PATCH 305/478] funder: TODO comments --- components/funder/src/router/router.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 20ebcfb7b..ba9cc6d71 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -844,6 +844,9 @@ pub async fn update_local_relays( _local_relays: HashMap, ) -> Result { // TODO + // - Pick an internal u128 port for every friend for every relay. + // - This info is saved in the db + // - What should we report outside? todo!(); } From c25e110e12c099b424e825f7e51a10a4bb75ab9f Mon Sep 17 00:00:00 2001 From: real Date: Wed, 30 Dec 2020 10:23:52 +0200 Subject: [PATCH 306/478] funder: update_local_relays() comments --- components/funder/src/router/router.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index ba9cc6d71..991c522d0 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -846,7 +846,8 @@ pub async fn update_local_relays( // TODO // - Pick an internal u128 port for every friend for every relay. // - This info is saved in the db - // - What should we report outside? + // - Send relays update messages to all relevant friends. + // - How to deal with acks? (Maybe in incoming_friend_message handler?) todo!(); } From 0c5e410578b2807b9d751f82f3f75c9f972fccac Mon Sep 17 00:00:00 2001 From: real Date: Fri, 1 Jan 2021 16:09:57 +0200 Subject: [PATCH 307/478] proto: TODO comment --- components/proto/src/app_server/messages.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/proto/src/app_server/messages.rs b/components/proto/src/app_server/messages.rs index 37c9c5706..0c82d305f 100644 --- a/components/proto/src/app_server/messages.rs +++ b/components/proto/src/app_server/messages.rs @@ -26,6 +26,7 @@ pub struct NamedRelayAddress { pub name: String, } +// TODO: Remove port from RelayAddress? Create another struct? #[derive(Arbitrary, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RelayAddress { From 817d5d6f225a68522d8f779e2e4feebd90990566 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 1 Jan 2021 16:10:22 +0200 Subject: [PATCH 308/478] funder: router: Work on update_local_relays() --- components/funder/src/router/router.rs | 134 +++++++++++++++++++++++-- components/funder/src/router/types.rs | 45 +++++++-- 2 files changed, 160 insertions(+), 19 deletions(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 991c522d0..686a811a9 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -10,15 +10,20 @@ use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; use identity::IdentityClient; use proto::app_server::messages::RelayAddress; -use proto::crypto::PublicKey; +use proto::crypto::{NodePort, PublicKey}; use proto::funder::messages::{ CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; +use proto::net::messages::NetAddress; + +use crypto::rand::{CryptoRandom, RandGen}; use crate::route::Route; -use crate::router::types::{BackwardsOp, CurrencyInfo, RouterDbClient, RouterOutput, RouterState}; +use crate::router::types::{ + BackwardsOp, CurrencyInfo, RouterDbClient, RouterOutput, RouterState, SentRelay, +}; use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; #[derive(Debug, From)] @@ -277,7 +282,7 @@ pub async fn set_friend_online( // Check if we have any relays information to send to the remote side: if let (Some(generation), relays) = router_db_client - .get_sent_relays(friend_public_key.clone()) + .get_last_sent_relays(friend_public_key.clone()) .await? { // Add a message for sending relays: @@ -339,6 +344,7 @@ pub async fn set_friend_online( let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); while let Some(res) = open_currencies.next().await { let open_currency = res?; + output.add_index_mutation(create_update_index_mutation( friend_public_key.clone(), open_currency, @@ -839,16 +845,122 @@ pub async fn close_currency( Ok(output) } +/// Calculate max generation +/// Returns None if no generation was found: This would mean that the remote friend is fully +/// synced. +fn max_generation(sent_relays: &[SentRelay]) -> Option { + let mut opt_max_generation = None; + for sent_relay in sent_relays { + if let Some(sent_relay_generation) = &sent_relay.opt_generation { + if let Some(max_generation) = &mut opt_max_generation { + if sent_relay_generation > max_generation { + *max_generation = *sent_relay_generation; + } + } else { + opt_max_generation = Some(*sent_relay_generation); + } + } + } + opt_max_generation +} + +/// Returns whether friend's relays were updated +async fn update_friend_local_relays( + router_db_client: &mut impl RouterDbClient, + local_relays: HashMap, + friend_public_key: PublicKey, + rng: &mut impl CryptoRandom, +) -> Result { + let sent_relays = router_db_client + .get_sent_relays(friend_public_key.clone()) + .await?; + + let opt_max_generation = max_generation(&sent_relays); + let new_generation = match opt_max_generation { + Some(g) => g.checked_add(1).ok_or(RouterError::GenerationOverflow)?, + None => 0, + }; + + // Update local relays: + let mut new_sent_relays = Vec::new(); + let mut sent_relays_updated: bool = false; + let mut c_local_relays = local_relays.clone(); + for mut sent_relay in sent_relays.into_iter() { + if let Some(relay_address) = c_local_relays.remove(&sent_relay.relay_address.public_key) { + // We should update this relay: + let new_sent_relay = SentRelay { + relay_address: sent_relay.relay_address.clone(), + is_remove: false, + opt_generation: sent_relay.opt_generation, // ?? + }; + sent_relays_updated |= sent_relay != new_sent_relay; + sent_relay.is_remove = false; + } else { + // We should remove this relay from sent_relays: + if !sent_relay.is_remove { + sent_relay.is_remove = true; + sent_relay.opt_generation = Some(new_generation); + sent_relays_updated = true; + } + new_sent_relays.push(sent_relay); + } + } + + // Add remaining local relays: + for (relay_public_key, address) in c_local_relays.into_iter() { + let relay_address = RelayAddress { + public_key: relay_public_key, + address, + // Randomly generate a new port: + port: NodePort::rand_gen(rng), + }; + new_sent_relays.push(SentRelay { + relay_address, + is_remove: false, + opt_generation: Some(new_generation), + }); + sent_relays_updated = true; + } + + Ok(if sent_relays_updated { + // Update sent relays: + router_db_client + .set_sent_relays(friend_public_key.clone(), new_sent_relays) + .await?; + true + } else { + false + }) +} + pub async fn update_local_relays( - _router_db_client: &mut impl RouterDbClient, - _local_relays: HashMap, + router_db_client: &mut impl RouterDbClient, + local_relays: HashMap, + rng: &mut impl CryptoRandom, ) -> Result { - // TODO - // - Pick an internal u128 port for every friend for every relay. - // - This info is saved in the db - // - Send relays update messages to all relevant friends. - // - How to deal with acks? (Maybe in incoming_friend_message handler?) - todo!(); + let mut output = RouterOutput::new(); + + let mut opt_friend_public_key = None; + while let Some(friend_public_key) = router_db_client + .get_next_friend(opt_friend_public_key) + .await? + { + opt_friend_public_key = Some(friend_public_key.clone()); + + let sent_relays_updated = update_friend_local_relays( + router_db_client, + local_relays.clone(), + friend_public_key, + rng, + ) + .await?; + + // TODO: If sent_relays was updated and the friend is ready, we need to send relays to + // remote friend: + todo!(); + } + + Ok(output) } pub async fn incoming_friend_message( diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 4cd16d038..9eb726499 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -51,35 +51,63 @@ pub struct CurrencyInfo { pub opt_local: Option, } +/* +#[derive(Debug)] +pub struct FriendInfo { + pub public_key: PublicKey, + pub name: PublicKey, + pub is_enabled: bool, +} +*/ + #[derive(Debug)] pub struct RequestOrigin { pub friend_public_key: PublicKey, pub currency: Currency, } +#[derive(Debug, PartialEq, Eq)] +pub struct SentRelay { + pub relay_address: RelayAddress, + pub is_remove: bool, + pub opt_generation: Option, +} + pub trait RouterDbClient { type TcDbClient: TcDbClient; fn tc_db_client(&mut self, friend_public_key: PublicKey) -> &mut Self::TcDbClient; + /* /// Get the current list of local relays fn get_local_relays(&mut self) -> AsyncOpResult>; + */ - /* - /// Get the maximum value of sent relay generation. - /// Returns None if all relays were acked by the remote side. - fn get_max_sent_relays_generation( + /// A util to iterate over friends and mutating them. + /// A None input will return the first friend. + /// A None output means that there are no more friends. + fn get_next_friend( &mut self, - friend_public_key: PublicKey, - ) -> AsyncOpResult>; - */ + prev_friend_public_key: Option, + ) -> AsyncOpResult>; /// Get the last set of sent relays, together with their generation /// Generation == None means that the sent relays were already acked - fn get_sent_relays( + fn get_last_sent_relays( &mut self, friend_public_key: PublicKey, ) -> AsyncOpResult<(Option, Vec)>; + /// Get detailed list of sent relays, including generation information + fn get_sent_relays(&mut self, friend_public_key: PublicKey) -> AsyncOpResult<(Vec)>; + + /// Set list of sent relays + fn set_sent_relays( + &mut self, + friend_public_key: PublicKey, + sent_relays: Vec, + ) -> AsyncOpResult<()>; + + /* /// Update sent relays for friend `friend_public_key` with the list of current local relays. fn update_sent_relays( &mut self, @@ -87,6 +115,7 @@ pub trait RouterDbClient { generation: u128, sent_relays: Vec, ) -> AsyncOpResult<()>; + */ /* fn get_balance(&mut self) -> AsyncOpResult; From aae847f9c021eec8e721f0d98b02d3bdb79a21ee Mon Sep 17 00:00:00 2001 From: real Date: Fri, 1 Jan 2021 16:23:54 +0200 Subject: [PATCH 309/478] funder: update_local_relays(): Initial impl --- components/funder/src/router/router.rs | 28 ++++++++++++++++++-------- components/funder/src/router/types.rs | 2 +- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 686a811a9..62e81c161 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -870,7 +870,7 @@ async fn update_friend_local_relays( local_relays: HashMap, friend_public_key: PublicKey, rng: &mut impl CryptoRandom, -) -> Result { +) -> Result)>, RouterError> { let sent_relays = router_db_client .get_sent_relays(friend_public_key.clone()) .await?; @@ -925,11 +925,17 @@ async fn update_friend_local_relays( Ok(if sent_relays_updated { // Update sent relays: router_db_client - .set_sent_relays(friend_public_key.clone(), new_sent_relays) + .set_sent_relays(friend_public_key.clone(), new_sent_relays.clone()) .await?; - true + Some(( + new_generation, + new_sent_relays + .into_iter() + .map(|sent_relay| sent_relay.relay_address) + .collect(), + )) } else { - false + None }) } @@ -947,17 +953,23 @@ pub async fn update_local_relays( { opt_friend_public_key = Some(friend_public_key.clone()); - let sent_relays_updated = update_friend_local_relays( + let opt_res = update_friend_local_relays( router_db_client, local_relays.clone(), - friend_public_key, + friend_public_key.clone(), rng, ) .await?; - // TODO: If sent_relays was updated and the friend is ready, we need to send relays to + // If sent_relays was updated and the friend is ready, we need to send relays to // remote friend: - todo!(); + if let Some((generation, relays)) = opt_res { + // Add a message for sending relays: + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), + ); + } } Ok(output) diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 9eb726499..f92e35ed6 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -66,7 +66,7 @@ pub struct RequestOrigin { pub currency: Currency, } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct SentRelay { pub relay_address: RelayAddress, pub is_remove: bool, From 486d0811c729158e364960074e6078003d2a1c7c Mon Sep 17 00:00:00 2001 From: real Date: Fri, 1 Jan 2021 16:57:15 +0200 Subject: [PATCH 310/478] proto: Added RelayAddressPort --- components/funder/src/router/router.rs | 6 +++--- components/funder/src/router/types.rs | 6 +++--- components/funder/src/types.rs | 8 ++++---- components/proto/src/app_server/messages.rs | 9 +++++++++ components/proto/src/file.rs | 4 +--- components/proto/src/funder/messages.rs | 10 +++++----- 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 62e81c161..3c70d4f83 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -9,7 +9,7 @@ use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; use identity::IdentityClient; -use proto::app_server::messages::RelayAddress; +use proto::app_server::messages::RelayAddressPort; use proto::crypto::{NodePort, PublicKey}; use proto::funder::messages::{ CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, @@ -870,7 +870,7 @@ async fn update_friend_local_relays( local_relays: HashMap, friend_public_key: PublicKey, rng: &mut impl CryptoRandom, -) -> Result)>, RouterError> { +) -> Result)>, RouterError> { let sent_relays = router_db_client .get_sent_relays(friend_public_key.clone()) .await?; @@ -908,7 +908,7 @@ async fn update_friend_local_relays( // Add remaining local relays: for (relay_public_key, address) in c_local_relays.into_iter() { - let relay_address = RelayAddress { + let relay_address = RelayAddressPort { public_key: relay_public_key, address, // Randomly generate a new port: diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index f92e35ed6..946cd3b34 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -6,7 +6,7 @@ use std::collections::HashMap; use crate::liveness::Liveness; use crate::token_channel::TcDbClient; -use proto::app_server::messages::{NamedRelayAddress, RelayAddress}; +use proto::app_server::messages::{NamedRelayAddress, RelayAddressPort}; use proto::crypto::{PublicKey, Uid}; use proto::funder::messages::{ CancelSendFundsOp, Currency, FriendMessage, McBalance, Rate, RequestSendFundsOp, @@ -68,7 +68,7 @@ pub struct RequestOrigin { #[derive(Debug, Clone, PartialEq, Eq)] pub struct SentRelay { - pub relay_address: RelayAddress, + pub relay_address: RelayAddressPort, pub is_remove: bool, pub opt_generation: Option, } @@ -95,7 +95,7 @@ pub trait RouterDbClient { fn get_last_sent_relays( &mut self, friend_public_key: PublicKey, - ) -> AsyncOpResult<(Option, Vec)>; + ) -> AsyncOpResult<(Option, Vec)>; /// Get detailed list of sent relays, including generation information fn get_sent_relays(&mut self, friend_public_key: PublicKey) -> AsyncOpResult<(Vec)>; diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 09cad180d..65794a6b9 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -192,9 +192,9 @@ pub enum ChannelerConfig { #[derive(Debug, Clone)] #[allow(clippy::large_enum_variant)] -pub enum FunderIncomingComm { +pub enum FunderIncomingComm { Liveness(IncomingLivenessMessage), - Friend((PublicKey, FriendMessage)), + Friend((PublicKey, FriendMessage)), } /// An incoming message to the Funder: @@ -203,7 +203,7 @@ pub enum FunderIncomingComm { pub enum FunderIncoming { Init, Control(FunderIncomingControl), - Comm(FunderIncomingComm), + Comm(FunderIncomingComm), } #[allow(clippy::large_enum_variant)] @@ -219,6 +219,6 @@ where #[allow(clippy::large_enum_variant)] #[derive(Debug)] pub enum FunderOutgoingComm { - FriendMessage((PublicKey, FriendMessage)), + FriendMessage((PublicKey, FriendMessage)), ChannelerConfig(ChannelerConfig>), } diff --git a/components/proto/src/app_server/messages.rs b/components/proto/src/app_server/messages.rs index 0c82d305f..4f2aaad42 100644 --- a/components/proto/src/app_server/messages.rs +++ b/components/proto/src/app_server/messages.rs @@ -33,6 +33,15 @@ pub struct RelayAddress { #[serde(with = "ser_b64")] pub public_key: PublicKey, pub address: B, +} + +// TODO: Remove port from RelayAddress? Create another struct? +#[derive(Arbitrary, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RelayAddressPort { + #[serde(with = "ser_b64")] + pub public_key: PublicKey, + pub address: NetAddress, #[serde(with = "ser_b64")] pub port: NodePort, } diff --git a/components/proto/src/file.rs b/components/proto/src/file.rs index 3ec8dc76f..020214b73 100644 --- a/components/proto/src/file.rs +++ b/components/proto/src/file.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use crate::crypto::{NodePort, PrivateKey, PublicKey}; +use crate::crypto::{PrivateKey, PublicKey}; use mutual_from::mutual_from; @@ -35,8 +35,6 @@ pub struct RelayAddressFile { pub public_key: PublicKey, #[serde(with = "ser_string")] pub address: NetAddress, - #[serde(with = "ser_b64")] - pub port: NodePort, } /// A helper structure for serialize and deserializing FriendAddress. diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index b7eef42d6..d6fd29463 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -17,7 +17,7 @@ use crate::crypto::{ HashResult, HashedLock, HmacResult, InvoiceId, PaymentId, PlainLock, PublicKey, Signature, Uid, }; -use crate::app_server::messages::{NamedRelayAddress, RelayAddress}; +use crate::app_server::messages::{NamedRelayAddress, RelayAddress, RelayAddressPort}; use crate::consts::MAX_CURRENCY_LEN; use crate::net::messages::NetAddress; @@ -374,17 +374,17 @@ pub struct MoveTokenRequest { } #[derive(Arbitrary, PartialEq, Eq, Clone, Serialize, Debug)] -pub struct RelaysUpdate { +pub struct RelaysUpdate { pub generation: u128, - pub relays: Vec>, + pub relays: Vec, } #[allow(clippy::large_enum_variant)] #[derive(PartialEq, Eq, Debug, Clone)] -pub enum FriendMessage { +pub enum FriendMessage { MoveTokenRequest(MoveTokenRequest), InconsistencyError(ResetTerms), - RelaysUpdate(RelaysUpdate), + RelaysUpdate(RelaysUpdate), RelaysAck(Uid), } From 1c19f1fcd7351fd1c45cdcae5a23ac30ec4f925c Mon Sep 17 00:00:00 2001 From: real Date: Fri, 1 Jan 2021 17:13:58 +0200 Subject: [PATCH 311/478] funder: router: Refactored util functions to separate files --- .../funder/src/router/index_mutation.rs | 113 ++++++++ components/funder/src/router/mod.rs | 3 + components/funder/src/router/move_token.rs | 168 +++++++++++ components/funder/src/router/router.rs | 270 ++---------------- components/funder/src/router/types.rs | 21 +- components/proto/src/funder/messages.rs | 2 +- 6 files changed, 326 insertions(+), 251 deletions(-) create mode 100644 components/funder/src/router/index_mutation.rs create mode 100644 components/funder/src/router/move_token.rs diff --git a/components/funder/src/router/index_mutation.rs b/components/funder/src/router/index_mutation.rs new file mode 100644 index 000000000..cacd41f4b --- /dev/null +++ b/components/funder/src/router/index_mutation.rs @@ -0,0 +1,113 @@ +use std::collections::{HashMap, HashSet}; + +use futures::StreamExt; + +use derive_more::From; + +use common::async_rpc::OpError; +use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; + +use identity::IdentityClient; + +use proto::app_server::messages::RelayAddressPort; +use proto::crypto::{NodePort, PublicKey}; +use proto::funder::messages::{ + CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, + FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, +}; +use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; +use proto::net::messages::NetAddress; + +use crypto::rand::{CryptoRandom, RandGen}; + +use crate::route::Route; +use crate::router::move_token::{collect_outgoing_move_token, is_pending_move_token}; +use crate::router::types::{ + BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, +}; +use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; + +/// Calculate receive capacity for a certain currency +/// This is the number we are going to report to an index server +fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result { + if !currency_info.is_open { + return Ok(0); + } + + let info_local = if let Some(info_local) = ¤cy_info.opt_local { + info_local + } else { + return Ok(0); + }; + + let mc_balance = if let Some(mc_balance) = &info_local.opt_remote { + mc_balance + } else { + return Ok(0); + }; + + Ok(currency_info.remote_max_debt.saturating_sub_signed( + mc_balance + .balance + .checked_add_unsigned(mc_balance.remote_pending_debt) + .ok_or(RouterError::BalanceOverflow)?, + )) +} + +/// Create one update index mutation, based on a given currency info. +pub fn create_update_index_mutation( + friend_public_key: PublicKey, + currency_info: CurrencyInfo, +) -> Result { + let recv_capacity = calc_recv_capacity(¤cy_info)?; + Ok(IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { + public_key: friend_public_key, + currency: currency_info.currency, + recv_capacity, + rate: currency_info.rate, + })) +} + +/// Create a list of index mutations based on a MoveToken message. +pub async fn create_index_mutations_from_move_token( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + move_token: &MoveToken, +) -> Result, RouterError> { + // Collect all mentioned currencies: + let currencies = { + let mut currencies = HashSet::new(); + for currency in &move_token.currencies_diff { + currencies.insert(currency.clone()); + } + + for currency in move_token.currencies_operations.keys() { + currencies.insert(currency.clone()); + } + currencies + }; + + let mut index_mutations = Vec::new(); + + // Create all index mutations: + for currency in currencies.into_iter() { + let opt_currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await?; + if let Some(currency_info) = opt_currency_info { + // Currency exists + index_mutations.push(create_update_index_mutation( + friend_public_key.clone(), + currency_info, + )?); + } else { + // Currency does not exist anymore + index_mutations.push(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { + public_key: friend_public_key.clone(), + currency, + })); + } + } + + Ok(index_mutations) +} diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index c2a3e5600..3899d2d23 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -1,2 +1,5 @@ +mod index_mutation; +mod move_token; + mod router; mod types; diff --git a/components/funder/src/router/move_token.rs b/components/funder/src/router/move_token.rs new file mode 100644 index 000000000..46df97c2c --- /dev/null +++ b/components/funder/src/router/move_token.rs @@ -0,0 +1,168 @@ +use std::collections::{HashMap, HashSet}; + +use futures::StreamExt; + +use derive_more::From; + +use common::async_rpc::OpError; +use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; + +use identity::IdentityClient; + +use proto::app_server::messages::RelayAddressPort; +use proto::crypto::{NodePort, PublicKey}; +use proto::funder::messages::{ + CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, + FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, +}; +use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; +use proto::net::messages::NetAddress; + +use crypto::rand::{CryptoRandom, RandGen}; + +use crate::route::Route; +use crate::router::types::{ + BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, +}; +use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; + +fn operations_vec_to_currencies_operations( + operations_vec: Vec<(Currency, FriendTcOp)>, +) -> CurrenciesOperations { + let mut currencies_operations = HashMap::>::new(); + for (currency, tc_op) in operations_vec { + let entry = currencies_operations.entry(currency).or_insert(Vec::new()); + (*entry).push(tc_op); + } + currencies_operations +} + +async fn collect_currencies_operations( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + max_operations_in_batch: usize, +) -> Result { + let mut operations_vec = Vec::<(Currency, FriendTcOp)>::new(); + + // Collect any pending responses and cancels: + while let Some((currency, backwards_op)) = router_db_client + .pending_backwards_pop_front(friend_public_key.clone()) + .await? + { + let friend_tc_op = match backwards_op { + BackwardsOp::Response(response_op) => FriendTcOp::ResponseSendFunds(response_op), + BackwardsOp::Cancel(cancel_op) => FriendTcOp::CancelSendFunds(cancel_op), + }; + operations_vec.push((currency, friend_tc_op)); + + // Make sure we do not exceed maximum amount of operations: + if operations_vec.len() >= max_operations_in_batch { + return Ok(operations_vec_to_currencies_operations(operations_vec)); + } + } + + // Collect any pending user requests: + while let Some((currency, request_op)) = router_db_client + .pending_user_requests_pop_front(friend_public_key.clone()) + .await? + { + let friend_tc_op = FriendTcOp::RequestSendFunds(request_op); + operations_vec.push((currency, friend_tc_op)); + + // Make sure we do not exceed maximum amount of operations: + if operations_vec.len() >= max_operations_in_batch { + return Ok(operations_vec_to_currencies_operations(operations_vec)); + } + } + + // Collect any pending requests: + while let Some((currency, request_op)) = router_db_client + .pending_requests_pop_front(friend_public_key.clone()) + .await? + { + let friend_tc_op = FriendTcOp::RequestSendFunds(request_op); + operations_vec.push((currency, friend_tc_op)); + + // Make sure we do not exceed maximum amount of operations: + if operations_vec.len() >= max_operations_in_batch { + return Ok(operations_vec_to_currencies_operations(operations_vec)); + } + } + + Ok(operations_vec_to_currencies_operations(operations_vec)) +} + +/// Do we have more pending currencies operations? +async fn is_pending_currencies_operations( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, +) -> Result { + Ok(!router_db_client + .pending_backwards_is_empty(friend_public_key.clone()) + .await? + || !router_db_client + .pending_user_requests_is_empty(friend_public_key.clone()) + .await? + || !router_db_client + .pending_requests_is_empty(friend_public_key.clone()) + .await?) +} + +/// Attempt to create an outgoing move token +/// Return Ok(None) if we have nothing to send +pub async fn collect_outgoing_move_token( + router_db_client: &mut impl RouterDbClient, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + friend_public_key: PublicKey, + max_operations_in_batch: usize, +) -> Result, RouterError> { + let currencies_operations = collect_currencies_operations( + router_db_client, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + let mut currencies_diff = router_db_client + .currencies_diff(friend_public_key.clone()) + .await?; + + Ok( + if currencies_operations.is_empty() && currencies_diff.is_empty() { + // There is nothing interesting to send to remote side + None + } else { + // We have something to send to remote side + let move_token = handle_out_move_token( + router_db_client.tc_db_client(friend_public_key.clone()), + identity_client, + currencies_operations, + currencies_diff, + local_public_key, + &friend_public_key, + ) + .await?; + Some(MoveTokenRequest { + move_token, + token_wanted: is_pending_currencies_operations(router_db_client, friend_public_key) + .await?, + }) + }, + ) +} + +/// Check if we have anything to send to a remove friend on a move token message, +/// without performing any data mutations +pub async fn is_pending_move_token( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, +) -> Result { + Ok( + is_pending_currencies_operations(router_db_client, friend_public_key.clone()).await? + || !router_db_client + .currencies_diff(friend_public_key.clone()) + .await? + .is_empty(), + ) +} diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 3c70d4f83..69fc9af90 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -21,249 +21,15 @@ use proto::net::messages::NetAddress; use crypto::rand::{CryptoRandom, RandGen}; use crate::route::Route; +use crate::router::index_mutation::{ + create_index_mutations_from_move_token, create_update_index_mutation, +}; +use crate::router::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::router::types::{ - BackwardsOp, CurrencyInfo, RouterDbClient, RouterOutput, RouterState, SentRelay, + BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; -#[derive(Debug, From)] -pub enum RouterError { - FriendAlreadyOnline, - FriendAlreadyOffline, - GenerationOverflow, - BalanceOverflow, - InvalidRoute, - UnexpectedTcStatus, - TokenChannelError(TokenChannelError), - OpError(OpError), -} - -fn operations_vec_to_currencies_operations( - operations_vec: Vec<(Currency, FriendTcOp)>, -) -> CurrenciesOperations { - let mut currencies_operations = HashMap::>::new(); - for (currency, tc_op) in operations_vec { - let entry = currencies_operations.entry(currency).or_insert(Vec::new()); - (*entry).push(tc_op); - } - currencies_operations -} - -async fn collect_currencies_operations( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - max_operations_in_batch: usize, -) -> Result { - let mut operations_vec = Vec::<(Currency, FriendTcOp)>::new(); - - // Collect any pending responses and cancels: - while let Some((currency, backwards_op)) = router_db_client - .pending_backwards_pop_front(friend_public_key.clone()) - .await? - { - let friend_tc_op = match backwards_op { - BackwardsOp::Response(response_op) => FriendTcOp::ResponseSendFunds(response_op), - BackwardsOp::Cancel(cancel_op) => FriendTcOp::CancelSendFunds(cancel_op), - }; - operations_vec.push((currency, friend_tc_op)); - - // Make sure we do not exceed maximum amount of operations: - if operations_vec.len() >= max_operations_in_batch { - return Ok(operations_vec_to_currencies_operations(operations_vec)); - } - } - - // Collect any pending user requests: - while let Some((currency, request_op)) = router_db_client - .pending_user_requests_pop_front(friend_public_key.clone()) - .await? - { - let friend_tc_op = FriendTcOp::RequestSendFunds(request_op); - operations_vec.push((currency, friend_tc_op)); - - // Make sure we do not exceed maximum amount of operations: - if operations_vec.len() >= max_operations_in_batch { - return Ok(operations_vec_to_currencies_operations(operations_vec)); - } - } - - // Collect any pending requests: - while let Some((currency, request_op)) = router_db_client - .pending_requests_pop_front(friend_public_key.clone()) - .await? - { - let friend_tc_op = FriendTcOp::RequestSendFunds(request_op); - operations_vec.push((currency, friend_tc_op)); - - // Make sure we do not exceed maximum amount of operations: - if operations_vec.len() >= max_operations_in_batch { - return Ok(operations_vec_to_currencies_operations(operations_vec)); - } - } - - Ok(operations_vec_to_currencies_operations(operations_vec)) -} - -/// Do we have more pending currencies operations? -async fn is_pending_currencies_operations( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, -) -> Result { - Ok(!router_db_client - .pending_backwards_is_empty(friend_public_key.clone()) - .await? - || !router_db_client - .pending_user_requests_is_empty(friend_public_key.clone()) - .await? - || !router_db_client - .pending_requests_is_empty(friend_public_key.clone()) - .await?) -} - -/// Attempt to create an outgoing move token -/// Return Ok(None) if we have nothing to send -async fn collect_outgoing_move_token( - router_db_client: &mut impl RouterDbClient, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - friend_public_key: PublicKey, - max_operations_in_batch: usize, -) -> Result, RouterError> { - let currencies_operations = collect_currencies_operations( - router_db_client, - friend_public_key.clone(), - max_operations_in_batch, - ) - .await?; - - let mut currencies_diff = router_db_client - .currencies_diff(friend_public_key.clone()) - .await?; - - Ok( - if currencies_operations.is_empty() && currencies_diff.is_empty() { - // There is nothing interesting to send to remote side - None - } else { - // We have something to send to remote side - let move_token = handle_out_move_token( - router_db_client.tc_db_client(friend_public_key.clone()), - identity_client, - currencies_operations, - currencies_diff, - local_public_key, - &friend_public_key, - ) - .await?; - Some(MoveTokenRequest { - move_token, - token_wanted: is_pending_currencies_operations(router_db_client, friend_public_key) - .await?, - }) - }, - ) -} - -/// Check if we have anything to send to a remove friend on a move token message, -/// without performing any data mutations -async fn is_pending_move_token( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, -) -> Result { - Ok( - is_pending_currencies_operations(router_db_client, friend_public_key.clone()).await? - || !router_db_client - .currencies_diff(friend_public_key.clone()) - .await? - .is_empty(), - ) -} - -/// Calculate receive capacity for a certain currency -/// This is the number we are going to report to an index server -fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result { - if !currency_info.is_open { - return Ok(0); - } - - let info_local = if let Some(info_local) = ¤cy_info.opt_local { - info_local - } else { - return Ok(0); - }; - - let mc_balance = if let Some(mc_balance) = &info_local.opt_remote { - mc_balance - } else { - return Ok(0); - }; - - Ok(currency_info.remote_max_debt.saturating_sub_signed( - mc_balance - .balance - .checked_add_unsigned(mc_balance.remote_pending_debt) - .ok_or(RouterError::BalanceOverflow)?, - )) -} - -/// Create one update index mutation, based on a given currency info. -fn create_update_index_mutation( - friend_public_key: PublicKey, - currency_info: CurrencyInfo, -) -> Result { - let recv_capacity = calc_recv_capacity(¤cy_info)?; - Ok(IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { - public_key: friend_public_key, - currency: currency_info.currency, - recv_capacity, - rate: currency_info.rate, - })) -} - -/// Create a list of index mutations based on a MoveToken message. -async fn create_index_mutations_from_move_token( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - move_token: &MoveToken, -) -> Result, RouterError> { - // Collect all mentioned currencies: - let currencies = { - let mut currencies = HashSet::new(); - for currency in &move_token.currencies_diff { - currencies.insert(currency.clone()); - } - - for currency in move_token.currencies_operations.keys() { - currencies.insert(currency.clone()); - } - currencies - }; - - let mut index_mutations = Vec::new(); - - // Create all index mutations: - for currency in currencies.into_iter() { - let opt_currency_info = router_db_client - .get_currency_info(friend_public_key.clone(), currency.clone()) - .await?; - if let Some(currency_info) = opt_currency_info { - // Currency exists - index_mutations.push(create_update_index_mutation( - friend_public_key.clone(), - currency_info, - )?); - } else { - // Currency does not exist anymore - index_mutations.push(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { - public_key: friend_public_key.clone(), - currency, - })); - } - } - - Ok(index_mutations) -} - pub async fn set_friend_online( router_db_client: &mut impl RouterDbClient, router_state: &mut RouterState, @@ -941,6 +707,7 @@ async fn update_friend_local_relays( pub async fn update_local_relays( router_db_client: &mut impl RouterDbClient, + router_state: &RouterState, local_relays: HashMap, rng: &mut impl CryptoRandom, ) -> Result { @@ -964,11 +731,14 @@ pub async fn update_local_relays( // If sent_relays was updated and the friend is ready, we need to send relays to // remote friend: if let Some((generation, relays)) = opt_res { - // Add a message for sending relays: - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), - ); + // Make sure that remote friend is online: + if router_state.liveness.is_online(&friend_public_key) { + // Add a message for sending relays: + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), + ); + } } } @@ -976,10 +746,16 @@ pub async fn update_local_relays( } pub async fn incoming_friend_message( - _router_db_client: &mut impl RouterDbClient, - _friend_public_key: PublicKey, - _friend_message: FriendMessage, + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + friend_message: FriendMessage, ) -> Result { + match friend_message { + FriendMessage::MoveTokenRequest(_move_token_request) => todo!(), + FriendMessage::InconsistencyError(_reset_terms) => todo!(), + FriendMessage::RelaysUpdate(_relays_update) => todo!(), + FriendMessage::RelaysAck(_generation) => todo!(), + } // TODO todo!(); } diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 946cd3b34..c6c104ca4 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -1,7 +1,8 @@ -use common::async_rpc::{AsyncOpResult, AsyncOpStream}; use std::collections::HashMap; -// use common::ser_utils::ser_string; -// use common::u256::U256; + +use derive_more::From; + +use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; use crate::liveness::Liveness; use crate::token_channel::TcDbClient; @@ -14,6 +15,20 @@ use proto::funder::messages::{ }; use proto::index_server::messages::IndexMutation; +use crate::token_channel::TokenChannelError; + +#[derive(Debug, From)] +pub enum RouterError { + FriendAlreadyOnline, + FriendAlreadyOffline, + GenerationOverflow, + BalanceOverflow, + InvalidRoute, + UnexpectedTcStatus, + TokenChannelError(TokenChannelError), + OpError(OpError), +} + /// Router's ephemeral state (Not saved inside the database) #[derive(Debug)] pub struct RouterState { diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index d6fd29463..c740275d0 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -385,7 +385,7 @@ pub enum FriendMessage { MoveTokenRequest(MoveTokenRequest), InconsistencyError(ResetTerms), RelaysUpdate(RelaysUpdate), - RelaysAck(Uid), + RelaysAck(u128), // generation } /* From 84aaee768f6c99619c034f0d9c25576c80ea90a4 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 1 Jan 2021 17:24:43 +0200 Subject: [PATCH 312/478] funder: initial incoming_friend_message() skeleton --- components/funder/src/router/router.rs | 54 ++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 69fc9af90..0f7228336 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -13,7 +13,8 @@ use proto::app_server::messages::RelayAddressPort; use proto::crypto::{NodePort, PublicKey}; use proto::funder::messages::{ CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, - FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, + FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, + ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -745,17 +746,56 @@ pub async fn update_local_relays( Ok(output) } +async fn incoming_move_token_request( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + move_token_request: MoveTokenRequest, +) -> Result { + todo!(); +} + +async fn incoming_inconsistency_error( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + reset_terms: ResetTerms, +) -> Result { + todo!(); +} + +async fn incoming_relays_update( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + relays_update: RelaysUpdate, +) -> Result { + todo!(); +} + +async fn incoming_relays_ack( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + generation: u128, +) -> Result { + todo!(); +} + pub async fn incoming_friend_message( router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, friend_message: FriendMessage, ) -> Result { match friend_message { - FriendMessage::MoveTokenRequest(_move_token_request) => todo!(), - FriendMessage::InconsistencyError(_reset_terms) => todo!(), - FriendMessage::RelaysUpdate(_relays_update) => todo!(), - FriendMessage::RelaysAck(_generation) => todo!(), + FriendMessage::MoveTokenRequest(move_token_request) => { + incoming_move_token_request(router_db_client, friend_public_key, move_token_request) + .await + } + FriendMessage::InconsistencyError(reset_terms) => { + incoming_inconsistency_error(router_db_client, friend_public_key, reset_terms).await + } + FriendMessage::RelaysUpdate(relays_update) => { + incoming_relays_update(router_db_client, friend_public_key, relays_update).await + } + FriendMessage::RelaysAck(generation) => { + incoming_relays_ack(router_db_client, friend_public_key, generation).await + } } - // TODO - todo!(); } From 79e263d101c3cbb02b97e7b46801f4a7dc879829 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 1 Jan 2021 17:27:47 +0200 Subject: [PATCH 313/478] funder: router: Refactored code into utils submodule --- components/funder/src/router/mod.rs | 3 +-- components/funder/src/router/router.rs | 8 ++++---- .../funder/src/router/{ => utils}/index_mutation.rs | 1 - components/funder/src/router/utils/mod.rs | 2 ++ components/funder/src/router/{ => utils}/move_token.rs | 0 5 files changed, 7 insertions(+), 7 deletions(-) rename components/funder/src/router/{ => utils}/index_mutation.rs (97%) create mode 100644 components/funder/src/router/utils/mod.rs rename components/funder/src/router/{ => utils}/move_token.rs (100%) diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 3899d2d23..0a9b8cf14 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -1,5 +1,4 @@ -mod index_mutation; -mod move_token; +mod utils; mod router; mod types; diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 0f7228336..b162671bf 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -22,13 +22,13 @@ use proto::net::messages::NetAddress; use crypto::rand::{CryptoRandom, RandGen}; use crate::route::Route; -use crate::router::index_mutation::{ - create_index_mutations_from_move_token, create_update_index_mutation, -}; -use crate::router::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; +use crate::router::utils::index_mutation::{ + create_index_mutations_from_move_token, create_update_index_mutation, +}; +use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; pub async fn set_friend_online( diff --git a/components/funder/src/router/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs similarity index 97% rename from components/funder/src/router/index_mutation.rs rename to components/funder/src/router/utils/index_mutation.rs index cacd41f4b..79ae2b0c0 100644 --- a/components/funder/src/router/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -21,7 +21,6 @@ use proto::net::messages::NetAddress; use crypto::rand::{CryptoRandom, RandGen}; use crate::route::Route; -use crate::router::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; diff --git a/components/funder/src/router/utils/mod.rs b/components/funder/src/router/utils/mod.rs new file mode 100644 index 000000000..1d584c6b4 --- /dev/null +++ b/components/funder/src/router/utils/mod.rs @@ -0,0 +1,2 @@ +pub mod index_mutation; +pub mod move_token; diff --git a/components/funder/src/router/move_token.rs b/components/funder/src/router/utils/move_token.rs similarity index 100% rename from components/funder/src/router/move_token.rs rename to components/funder/src/router/utils/move_token.rs From 77716a75dee14622450e684334944676f72444a2 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 1 Jan 2021 18:14:18 +0200 Subject: [PATCH 314/478] funder: TODO comments --- components/funder/src/router/types.rs | 1 + components/funder/src/token_channel/types.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index c6c104ca4..7a3b5dcb8 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -90,6 +90,7 @@ pub struct SentRelay { pub trait RouterDbClient { type TcDbClient: TcDbClient; + // TODO: Maybe should return an Option instead? What if friend doesn't exist? fn tc_db_client(&mut self, friend_public_key: PublicKey) -> &mut Self::TcDbClient; /* diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index b34bb7ea3..13f6b4d12 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -35,6 +35,7 @@ pub enum TcStatus { pub trait TcDbClient { type McDbClient: McDbClient; + // TODO: Maybe should return an Option instead? What if currency doesn't exist? fn mc_db_client(&mut self, currency: Currency) -> &mut Self::McDbClient; fn get_tc_status(&mut self) -> AsyncOpResult; From 7bce2eaaee497b49c15ccff61fd801da9286a68b Mon Sep 17 00:00:00 2001 From: real Date: Fri, 1 Jan 2021 18:15:13 +0200 Subject: [PATCH 315/478] funder: Work on incoming_move_token_request() --- components/funder/src/router/router.rs | 66 ++++++++++++++++--- .../funder/src/token_channel/token_channel.rs | 2 +- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index b162671bf..216649abe 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -7,6 +7,8 @@ use derive_more::From; use common::async_rpc::OpError; use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; +use database::transaction::Transaction; + use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; @@ -29,7 +31,9 @@ use crate::router::utils::index_mutation::{ create_index_mutations_from_move_token, create_update_index_mutation, }; use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; -use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; +use crate::token_channel::{ + handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, +}; pub async fn set_friend_online( router_db_client: &mut impl RouterDbClient, @@ -746,12 +750,39 @@ pub async fn update_local_relays( Ok(output) } -async fn incoming_move_token_request( - router_db_client: &mut impl RouterDbClient, +async fn incoming_move_token_request( + mut router_db_client: &mut RC, friend_public_key: PublicKey, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, move_token_request: MoveTokenRequest, -) -> Result { - todo!(); +) -> Result +where + RC: RouterDbClient, + RC::TcDbClient: Transaction + Send, + ::McDbClient: Send, +{ + let receive_move_token_output = handle_in_move_token( + router_db_client.tc_db_client(friend_public_key.clone()), + identity_client, + move_token_request.move_token, + local_public_key, + &friend_public_key, + ) + .await?; + + match receive_move_token_output { + ReceiveMoveTokenOutput::Duplicate => { + // TODO: Possibly send token to remote side (According to token_wanted) + // We should have nothing else to send at this point, otherwise we would have already + // sent it. + todo!(); + } + ReceiveMoveTokenOutput::RetransmitOutgoing(move_token) => todo!(), + ReceiveMoveTokenOutput::Received(move_token_received) => todo!(), + ReceiveMoveTokenOutput::ChainInconsistent(reset_terms) => todo!(), // (local_reset_token, local_reset_move_token_counter) + } } async fn incoming_inconsistency_error( @@ -778,15 +809,30 @@ async fn incoming_relays_ack( todo!(); } -pub async fn incoming_friend_message( - router_db_client: &mut impl RouterDbClient, +pub async fn incoming_friend_message( + router_db_client: &mut RC, friend_public_key: PublicKey, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, friend_message: FriendMessage, -) -> Result { +) -> Result +where + RC: RouterDbClient, + RC::TcDbClient: Transaction + Send, + ::McDbClient: Send, +{ match friend_message { FriendMessage::MoveTokenRequest(move_token_request) => { - incoming_move_token_request(router_db_client, friend_public_key, move_token_request) - .await + incoming_move_token_request( + router_db_client, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + move_token_request, + ) + .await } FriendMessage::InconsistencyError(reset_terms) => { incoming_inconsistency_error(router_db_client, friend_public_key, reset_terms).await diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index addd667e1..e90e1a8cd 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -70,7 +70,7 @@ pub enum ReceiveMoveTokenOutput { Duplicate, RetransmitOutgoing(MoveToken), Received(MoveTokenReceived), - ChainInconsistent(ResetTerms), // (local_reset_token, local_reset_move_token_counter) + ChainInconsistent(ResetTerms), } /// Create a token from a public key From d0319ae60ecbca8c118af09390a82b31738bbf06 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 1 Jan 2021 18:31:58 +0200 Subject: [PATCH 316/478] funder: router: Work on incoming_move_token_request() impl --- components/funder/src/router/router.rs | 36 ++++++++++++++++-- .../funder/src/router/utils/move_token.rs | 37 +++++++++++++++++++ 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 216649abe..01ce84f3b 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -30,7 +30,9 @@ use crate::router::types::{ use crate::router::utils::index_mutation::{ create_index_mutations_from_move_token, create_update_index_mutation, }; -use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; +use crate::router::utils::move_token::{ + collect_outgoing_move_token, collect_outgoing_move_token_allow_empty, is_pending_move_token, +}; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; @@ -752,6 +754,7 @@ pub async fn update_local_relays( async fn incoming_move_token_request( mut router_db_client: &mut RC, + router_state: &mut RouterState, friend_public_key: PublicKey, identity_client: &mut IdentityClient, local_public_key: &PublicKey, @@ -763,6 +766,7 @@ where RC::TcDbClient: Transaction + Send, ::McDbClient: Send, { + let mut output = RouterOutput::new(); let receive_move_token_output = handle_in_move_token( router_db_client.tc_db_client(friend_public_key.clone()), identity_client, @@ -774,15 +778,39 @@ where match receive_move_token_output { ReceiveMoveTokenOutput::Duplicate => { - // TODO: Possibly send token to remote side (According to token_wanted) // We should have nothing else to send at this point, otherwise we would have already // sent it. - todo!(); + assert!(!is_pending_move_token(router_db_client, friend_public_key.clone()).await?); + + // Possibly send token to remote side (According to token_wanted) + if move_token_request.token_wanted { + let out_move_token_request = collect_outgoing_move_token_allow_empty( + router_db_client, + identity_client, + local_public_key, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + // TODO: Should we really check for liveness here? We just got a message from this + // friend. Think about liveness design here. What if we ever forget to check for + // liveness before adding a friend message? Maybe this should be checked in + // different way, or a different layer? + if router_state.liveness.is_online(&friend_public_key) { + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(out_move_token_request), + ); + } + } } ReceiveMoveTokenOutput::RetransmitOutgoing(move_token) => todo!(), ReceiveMoveTokenOutput::Received(move_token_received) => todo!(), ReceiveMoveTokenOutput::ChainInconsistent(reset_terms) => todo!(), // (local_reset_token, local_reset_move_token_counter) } + + Ok(output) } async fn incoming_inconsistency_error( @@ -811,6 +839,7 @@ async fn incoming_relays_ack( pub async fn incoming_friend_message( router_db_client: &mut RC, + router_state: &mut RouterState, friend_public_key: PublicKey, identity_client: &mut IdentityClient, local_public_key: &PublicKey, @@ -826,6 +855,7 @@ where FriendMessage::MoveTokenRequest(move_token_request) => { incoming_move_token_request( router_db_client, + router_state, friend_public_key, identity_client, local_public_key, diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 46df97c2c..e09324846 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -108,6 +108,43 @@ async fn is_pending_currencies_operations( .await?) } +/// Attempt to create an outgoing move token +/// May create an empty move token. +pub async fn collect_outgoing_move_token_allow_empty( + router_db_client: &mut impl RouterDbClient, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + friend_public_key: PublicKey, + max_operations_in_batch: usize, +) -> Result { + let currencies_operations = collect_currencies_operations( + router_db_client, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + let mut currencies_diff = router_db_client + .currencies_diff(friend_public_key.clone()) + .await?; + + // Create move token and update internal state: + let move_token = handle_out_move_token( + router_db_client.tc_db_client(friend_public_key.clone()), + identity_client, + currencies_operations, + currencies_diff, + local_public_key, + &friend_public_key, + ) + .await?; + + Ok(MoveTokenRequest { + move_token, + token_wanted: is_pending_currencies_operations(router_db_client, friend_public_key).await?, + }) +} + /// Attempt to create an outgoing move token /// Return Ok(None) if we have nothing to send pub async fn collect_outgoing_move_token( From f817c4b25b70bde3e5949e58297b808cab0ce538 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 1 Jan 2021 18:37:47 +0200 Subject: [PATCH 317/478] funder: incoming_move_token_request: impl RetransmitOutgoing case --- components/funder/src/router/router.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 01ce84f3b..ec540aae6 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -805,7 +805,21 @@ where } } } - ReceiveMoveTokenOutput::RetransmitOutgoing(move_token) => todo!(), + ReceiveMoveTokenOutput::RetransmitOutgoing(move_token) => { + // Retransmit outgoing move token message to friend: + let move_token_request = MoveTokenRequest { + move_token, + token_wanted: is_pending_move_token(router_db_client, friend_public_key.clone()) + .await?, + }; + + if router_state.liveness.is_online(&friend_public_key) { + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(move_token_request), + ); + } + } ReceiveMoveTokenOutput::Received(move_token_received) => todo!(), ReceiveMoveTokenOutput::ChainInconsistent(reset_terms) => todo!(), // (local_reset_token, local_reset_move_token_counter) } From dc875a20b5574cd15633e727c37f0b6e34491057 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 1 Jan 2021 18:39:07 +0200 Subject: [PATCH 318/478] funder: TODO comment --- components/funder/src/token_channel/token_channel.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index e90e1a8cd..8fc85de24 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -61,6 +61,7 @@ pub struct MoveTokenReceivedCurrency { #[derive(Debug)] pub struct MoveTokenReceived { + // TODO: Why isn't this a hash map? Does the order matter here? pub currencies: Vec, } From 21064e22ca0de823e5708c88d23805b765477bdd Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 14:27:24 +0200 Subject: [PATCH 319/478] funder: CurrenciesOperations is now an ordered vector of tuples --- .../funder/src/mutual_credit/incoming.rs | 37 ---------- .../tests/request_cancel_send_funds.rs | 2 +- .../tests/request_response_send_funds.rs | 7 +- .../funder/src/mutual_credit/tests/utils.rs | 42 +++++++++++- .../funder/src/router/utils/index_mutation.rs | 2 +- .../funder/src/router/utils/move_token.rs | 10 +-- .../tests/inconsistency_resolve.rs | 6 +- .../token_channel/tests/move_token_basic.rs | 42 +++++------- .../funder/src/token_channel/token_channel.rs | 67 ++++++++----------- components/proto/src/funder/messages.rs | 3 +- 10 files changed, 100 insertions(+), 118 deletions(-) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 9af1569ab..382af2c67 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -52,43 +52,6 @@ pub enum ProcessOperationError { OpError(OpError), } -#[derive(Debug)] -pub struct ProcessTransListError { - index: usize, - process_trans_error: ProcessOperationError, -} - -pub async fn process_operations_list( - mc_client: &mut impl McDbClient, - operations: Vec, - currency: &Currency, - remote_public_key: &PublicKey, - remote_max_debt: u128, -) -> Result, ProcessTransListError> { - let mut outputs = Vec::new(); - - for (index, friend_tc_op) in operations.into_iter().enumerate() { - match process_operation( - mc_client, - friend_tc_op, - currency, - remote_public_key, - remote_max_debt, - ) - .await - { - Err(e) => { - return Err(ProcessTransListError { - index, - process_trans_error: e, - }) - } - Ok(incoming_message) => outputs.push(incoming_message), - } - } - Ok(outputs) -} - pub async fn process_operation( mc_client: &mut impl McDbClient, friend_tc_op: FriendTcOp, diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index 625a56213..7e5d1beec 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -13,8 +13,8 @@ use proto::funder::messages::{CancelSendFundsOp, Currency, FriendTcOp, RequestSe use crate::mutual_credit::tests::utils::MockMutualCredit; use crate::mutual_credit::types::McDbClient; -use crate::mutual_credit::incoming::process_operations_list; use crate::mutual_credit::outgoing::queue_operation; +use crate::mutual_credit::tests::utils::process_operations_list; async fn task_request_cancel_send_funds() { let currency = Currency::try_from("FST".to_owned()).unwrap(); diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index 8aba778e0..ce47c74f6 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -11,12 +11,11 @@ use proto::crypto::{HashResult, HmacResult, PlainLock, PrivateKey, PublicKey, Si use proto::funder::messages::{Currency, FriendTcOp, RequestSendFundsOp, ResponseSendFundsOp}; use signature::signature_buff::create_response_signature_buffer; -use crate::mutual_credit::tests::utils::MockMutualCredit; +use crate::mutual_credit::outgoing::queue_operation; +use crate::mutual_credit::tests::utils::{process_operations_list, MockMutualCredit}; use crate::mutual_credit::types::McDbClient; -use crate::types::create_pending_transaction; -use crate::mutual_credit::incoming::process_operations_list; -use crate::mutual_credit::outgoing::queue_operation; +use crate::types::create_pending_transaction; async fn task_request_response_send_funds() { let currency = Currency::try_from("FST".to_owned()).unwrap(); diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index 20d219913..6ba63dc9b 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -4,9 +4,10 @@ use common::async_rpc::OpError; use common::conn::BoxFuture; use common::u256::U256; -use proto::crypto::Uid; -use proto::funder::messages::{Currency, McBalance, PendingTransaction}; +use proto::crypto::{PublicKey, Uid}; +use proto::funder::messages::{Currency, FriendTcOp, McBalance, PendingTransaction}; +use crate::mutual_credit::incoming::{process_operation, IncomingMessage, ProcessOperationError}; use crate::mutual_credit::types::McDbClient; #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] @@ -137,3 +138,40 @@ impl McDbClient for MockMutualCredit { Box::pin(async move { Ok(()) }) } } + +#[derive(Debug)] +pub struct ProcessTransListError { + index: usize, + process_trans_error: ProcessOperationError, +} + +pub async fn process_operations_list( + mc_client: &mut impl McDbClient, + operations: Vec, + currency: &Currency, + remote_public_key: &PublicKey, + remote_max_debt: u128, +) -> Result, ProcessTransListError> { + let mut outputs = Vec::new(); + + for (index, friend_tc_op) in operations.into_iter().enumerate() { + match process_operation( + mc_client, + friend_tc_op, + currency, + remote_public_key, + remote_max_debt, + ) + .await + { + Err(e) => { + return Err(ProcessTransListError { + index, + process_trans_error: e, + }) + } + Ok(incoming_message) => outputs.push(incoming_message), + } + } + Ok(outputs) +} diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index 79ae2b0c0..23b9533d9 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -80,7 +80,7 @@ pub async fn create_index_mutations_from_move_token( currencies.insert(currency.clone()); } - for currency in move_token.currencies_operations.keys() { + for (currency, _operation) in &move_token.currencies_operations { currencies.insert(currency.clone()); } currencies diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index e09324846..215f7df7b 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -26,6 +26,7 @@ use crate::router::types::{ }; use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; +/* fn operations_vec_to_currencies_operations( operations_vec: Vec<(Currency, FriendTcOp)>, ) -> CurrenciesOperations { @@ -36,6 +37,7 @@ fn operations_vec_to_currencies_operations( } currencies_operations } +*/ async fn collect_currencies_operations( router_db_client: &mut impl RouterDbClient, @@ -57,7 +59,7 @@ async fn collect_currencies_operations( // Make sure we do not exceed maximum amount of operations: if operations_vec.len() >= max_operations_in_batch { - return Ok(operations_vec_to_currencies_operations(operations_vec)); + return Ok(operations_vec); } } @@ -71,7 +73,7 @@ async fn collect_currencies_operations( // Make sure we do not exceed maximum amount of operations: if operations_vec.len() >= max_operations_in_batch { - return Ok(operations_vec_to_currencies_operations(operations_vec)); + return Ok(operations_vec); } } @@ -85,11 +87,11 @@ async fn collect_currencies_operations( // Make sure we do not exceed maximum amount of operations: if operations_vec.len() >= max_operations_in_batch { - return Ok(operations_vec_to_currencies_operations(operations_vec)); + return Ok(operations_vec); } } - Ok(operations_vec_to_currencies_operations(operations_vec)) + Ok(operations_vec) } /// Do we have more pending currencies operations? diff --git a/components/funder/src/token_channel/tests/inconsistency_resolve.rs b/components/funder/src/token_channel/tests/inconsistency_resolve.rs index 1f8cbfb27..f58149374 100644 --- a/components/funder/src/token_channel/tests/inconsistency_resolve.rs +++ b/components/funder/src/token_channel/tests/inconsistency_resolve.rs @@ -72,7 +72,7 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { // Send a MoveToken message from b to a, adding a currency: // -------------------------------------------------------- - let currencies_operations = HashMap::new(); + let currencies_operations = Vec::new(); let currencies_diff = vec![currency1.clone()]; let move_token = handle_out_move_token( &mut tc_b_a, @@ -106,7 +106,7 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { // Send a MoveToken message from a to b, adding two currencies, // and set incorrect token info hash. // ------------------------------------------------------------ - let currencies_operations = HashMap::new(); + let currencies_operations = Vec::new(); let currencies_diff = vec![currency1.clone(), currency2.clone()]; let move_token = handle_out_move_token( &mut tc_a_b, @@ -191,7 +191,7 @@ async fn task_inconsistency_resolve(test_executor: TestExecutor) { // b accepts a's reset terms: // -------------------------- - let currencies_operations = HashMap::new(); + let currencies_operations = Vec::new(); let currencies_diff = Vec::new(); let move_token = accept_remote_reset( &mut tc_b_a, diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index 624b94e9b..a3996098a 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -71,7 +71,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { // Send a MoveToken message from b to a, adding a currency: // -------------------------------------------------------- - let currencies_operations = HashMap::new(); + let currencies_operations = Vec::new(); let currencies_diff = vec![currency1.clone()]; let move_token = handle_out_move_token( &mut tc_b_a, @@ -100,7 +100,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { // Send a MoveToken message from a to b, adding two currencies: // ------------------------------------------------------------ - let currencies_operations = HashMap::new(); + let currencies_operations = Vec::new(); let currencies_diff = vec![currency1.clone(), currency2.clone()]; let move_token = handle_out_move_token( &mut tc_a_b, @@ -141,13 +141,10 @@ async fn task_move_token_basic(test_executor: TestExecutor) { left_fees: 5u128, }; let pending_transaction = create_pending_transaction(&request_send_funds_op); - let currencies_operations: HashMap<_, _> = [( + let currencies_operations = vec![( currency1.clone(), - vec![FriendTcOp::RequestSendFunds(request_send_funds_op.clone())], - )] - .iter() - .cloned() - .collect(); + FriendTcOp::RequestSendFunds(request_send_funds_op.clone()), + )]; let currencies_diff = vec![]; let move_token = handle_out_move_token( @@ -195,19 +192,16 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .unwrap(); // Make sure the the result is as expected: - let mut currencies = match res { - ReceiveMoveTokenOutput::Received(MoveTokenReceived { currencies }) => currencies, + let mut incoming_messages = match res { + ReceiveMoveTokenOutput::Received(MoveTokenReceived { incoming_messages }) => { + incoming_messages + } _ => unreachable!(), }; - assert_eq!(currencies.len(), 1); - let mut move_token_received_currency = currencies.pop().unwrap(); - assert_eq!(move_token_received_currency.currency, currency1); - assert_eq!(move_token_received_currency.incoming_messages.len(), 1); - let incoming_message = move_token_received_currency - .incoming_messages - .pop() - .unwrap(); + assert_eq!(incoming_messages.len(), 1); + let (currency, incoming_message) = incoming_messages.pop().unwrap(); + assert_eq!(currency, currency1); let received_request_send_funds_op = match incoming_message { IncomingMessage::Request(request_send_funds_op) => request_send_funds_op, _ => unreachable!(), @@ -236,16 +230,10 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .await .unwrap(); - let currencies_operations: HashMap<_, _> = [( + let currencies_operations = vec![( currency1.clone(), - vec![FriendTcOp::ResponseSendFunds( - response_send_funds_op.clone(), - )], - )] - .iter() - .cloned() - .collect(); - + FriendTcOp::ResponseSendFunds(response_send_funds_op.clone()), + )]; let currencies_diff = vec![]; let move_token = handle_out_move_token( &mut tc_a_b, diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 8fc85de24..84c128e0b 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -19,8 +19,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddress; use proto::crypto::{HashResult, PublicKey, RandValue, Signature}; use proto::funder::messages::{ - Currency, CurrencyOperations, FriendTcOp, McBalance, MoveToken, ResetBalance, ResetTerms, - TokenInfo, + CurrenciesOperations, Currency, CurrencyOperations, FriendTcOp, McBalance, MoveToken, + ResetBalance, ResetTerms, TokenInfo, }; use signature::canonical::CanonicalSerialize; @@ -31,9 +31,7 @@ use signature::verify::verify_move_token; use database::transaction::{TransFunc, Transaction}; -use crate::mutual_credit::incoming::{ - process_operations_list, IncomingMessage, ProcessTransListError, -}; +use crate::mutual_credit::incoming::{process_operation, IncomingMessage, ProcessOperationError}; use crate::mutual_credit::outgoing::{queue_operation, QueueOperationError}; use crate::mutual_credit::types::McDbClient; @@ -43,7 +41,7 @@ use crate::types::{create_hashed, MoveTokenHashed}; /// Unrecoverable TokenChannel error #[derive(Debug, From)] pub enum TokenChannelError { - InvalidTransaction(ProcessTransListError), + InvalidTransaction(ProcessOperationError), MoveTokenCounterOverflow, CanNotRemoveCurrencyInUse, InvalidTokenChannelStatus, @@ -53,16 +51,9 @@ pub enum TokenChannelError { QueueOperationError(QueueOperationError), } -#[derive(Debug)] -pub struct MoveTokenReceivedCurrency { - pub currency: Currency, - pub incoming_messages: Vec, -} - #[derive(Debug)] pub struct MoveTokenReceived { - // TODO: Why isn't this a hash map? Does the order matter here? - pub currencies: Vec, + pub incoming_messages: Vec<(Currency, IncomingMessage)>, } #[allow(clippy::large_enum_variant)] @@ -105,7 +96,7 @@ pub fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKe // doesn't have the private key). Therefore we use a dummy new_token instead. let move_token_out = MoveToken { old_token: token_from_public_key(&low_public_key), - currencies_operations: HashMap::new(), + currencies_operations: Vec::new(), currencies_diff: Vec::new(), info_hash: hash_token_info(&low_public_key, &high_public_key, &token_info), new_token: token_from_public_key(&high_public_key), @@ -294,7 +285,7 @@ where let move_token_out = MoveToken { old_token: Signature::from(&[0; Signature::len()]), - currencies_operations: HashMap::new(), + currencies_operations: Vec::new(), currencies_diff: Vec::new(), info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), new_token: local_reset_terms.reset_token.clone(), @@ -593,9 +584,9 @@ async fn handle_incoming_token_match( )); } - // Aggregate results for every currency: + // Aggregate incoming messages: let mut move_token_received = MoveTokenReceived { - currencies: Vec::new(), + incoming_messages: Vec::new(), }; // Handle active currencies: @@ -653,20 +644,20 @@ async fn handle_incoming_token_match( } // Attempt to apply operations for every currency: - for (currency, friend_tc_ops) in &new_move_token.currencies_operations { + for (currency, friend_tc_op) in &new_move_token.currencies_operations { let remote_max_debt = tc_client.get_remote_max_debt(currency.clone()).await?; - let res = process_operations_list( + let res = process_operation( tc_client.mc_db_client(currency.clone()), - friend_tc_ops.clone(), + friend_tc_op.clone(), ¤cy, remote_public_key, remote_max_debt, ) .await; - let incoming_messages = match res { - Ok(incoming_messages) => incoming_messages, + let incoming_message = match res { + Ok(incoming_message) => incoming_message, Err(_) => { return Ok(IncomingTokenMatchOutput::InvalidIncoming( InvalidIncoming::InvalidOperation, @@ -674,16 +665,18 @@ async fn handle_incoming_token_match( } }; + /* // We apply mutations on this token channel, to verify stated balance values // let mut check_mutual_credit = mutual_credit.clone(); let move_token_received_currency = MoveTokenReceivedCurrency { currency: currency.clone(), incoming_messages, }; + */ move_token_received - .currencies - .push(move_token_received_currency); + .incoming_messages + .push((currency.clone(), incoming_message)); } let move_token_counter = tc_client.get_move_token_counter().await?; @@ -725,7 +718,7 @@ async fn handle_incoming_token_match( pub async fn handle_out_move_token( tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, - currencies_operations: HashMap>, + currencies_operations: CurrenciesOperations, currencies_diff: Vec, local_public_key: &PublicKey, remote_public_key: &PublicKey, @@ -782,16 +775,14 @@ pub async fn handle_out_move_token( } // Update mutual credits: - for (currency, friend_tc_ops) in ¤cies_operations { - for operation in friend_tc_ops.iter().cloned() { - queue_operation( - tc_client.mc_db_client(currency.clone()), - operation, - ¤cy, - local_public_key, - ) - .await?; - } + for (currency, friend_tc_op) in ¤cies_operations { + queue_operation( + tc_client.mc_db_client(currency.clone()), + friend_tc_op.clone(), + ¤cy, + local_public_key, + ) + .await?; } let new_move_token_counter = tc_client @@ -837,7 +828,7 @@ pub async fn handle_out_move_token( pub async fn accept_remote_reset( tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, - currencies_operations: HashMap>, + currencies_operations: CurrenciesOperations, currencies_diff: Vec, local_public_key: &PublicKey, remote_public_key: &PublicKey, @@ -871,7 +862,7 @@ pub async fn accept_remote_reset( let move_token_in = MoveToken { old_token: Signature::from(&[0; Signature::len()]), - currencies_operations: HashMap::new(), + currencies_operations: Vec::new(), currencies_diff: Vec::new(), info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), new_token: remote_reset_token.clone(), diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index c740275d0..46279759e 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -233,7 +233,8 @@ pub struct CurrencyOperations { pub operations: Vec, } -pub type CurrenciesOperations = HashMap>; +// pub type CurrenciesOperations = HashMap>; +pub type CurrenciesOperations = Vec<(Currency, FriendTcOp)>; #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct MoveToken { From a0bb1e1e1a16ec3206538d7014235501fe1d2b9e Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 14:53:36 +0200 Subject: [PATCH 320/478] funder: Refactored router handlers into separate files --- components/funder/src/router/handle_config.rs | 365 +++++++++++ .../funder/src/router/handle_move_token.rs | 188 ++++++ components/funder/src/router/handle_relays.rs | 174 +++++ components/funder/src/router/mod.rs | 5 + components/funder/src/router/router.rs | 598 ------------------ components/funder/src/router/utils/flush.rs | 98 +++ components/funder/src/router/utils/mod.rs | 1 + 7 files changed, 831 insertions(+), 598 deletions(-) create mode 100644 components/funder/src/router/handle_config.rs create mode 100644 components/funder/src/router/handle_move_token.rs create mode 100644 components/funder/src/router/handle_relays.rs create mode 100644 components/funder/src/router/utils/flush.rs diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs new file mode 100644 index 000000000..6dfa4c129 --- /dev/null +++ b/components/funder/src/router/handle_config.rs @@ -0,0 +1,365 @@ +use std::collections::{HashMap, HashSet}; + +use futures::StreamExt; + +use derive_more::From; + +use common::async_rpc::OpError; +use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; + +use database::transaction::Transaction; + +use identity::IdentityClient; + +use proto::app_server::messages::RelayAddressPort; +use proto::crypto::{NodePort, PublicKey}; +use proto::funder::messages::{ + CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, + FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, + ResponseSendFundsOp, +}; +use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; +use proto::net::messages::NetAddress; + +use crypto::rand::{CryptoRandom, RandGen}; + +use crate::route::Route; +use crate::router::types::{ + BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, +}; +use crate::router::utils::flush::flush_friend; +use crate::router::utils::index_mutation::{ + create_index_mutations_from_move_token, create_update_index_mutation, +}; +use crate::router::utils::move_token::{ + collect_outgoing_move_token, collect_outgoing_move_token_allow_empty, is_pending_move_token, +}; +use crate::token_channel::{ + handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, +}; + +pub async fn set_friend_online( + router_db_client: &mut impl RouterDbClient, + router_state: &mut RouterState, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + friend_public_key: PublicKey, + max_operations_in_batch: usize, +) -> Result { + if router_state.liveness.is_online(&friend_public_key) { + // The friend is already marked as online! + return Err(RouterError::FriendAlreadyOnline); + } + router_state.liveness.set_online(friend_public_key.clone()); + + let mut output = RouterOutput::new(); + + // Check if we have any relays information to send to the remote side: + if let (Some(generation), relays) = router_db_client + .get_last_sent_relays(friend_public_key.clone()) + .await? + { + // Add a message for sending relays: + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), + ); + } + + match router_db_client + .tc_db_client(friend_public_key.clone()) + .get_tc_status() + .await? + { + TcStatus::ConsistentIn(_) => { + // Create an outgoing move token if we have something to send. + let opt_move_token_request = collect_outgoing_move_token( + router_db_client, + identity_client, + local_public_key, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + if let Some(move_token_request) = opt_move_token_request { + // We have something to send to remote side: + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(move_token_request), + ); + } + } + TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { + // Resend outgoing move token, + // possibly asking for the token if we have something to send + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(MoveTokenRequest { + move_token: move_token_out, + token_wanted: is_pending_move_token( + router_db_client, + friend_public_key.clone(), + ) + .await?, + }), + ); + } + TcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { + // Resend reset terms + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::InconsistencyError(local_reset_terms), + ); + } + } + + // Add an index mutation for all open currencies: + let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); + while let Some(res) = open_currencies.next().await { + let open_currency = res?; + + output.add_index_mutation(create_update_index_mutation( + friend_public_key.clone(), + open_currency, + )?); + } + + Ok(output) +} + +pub async fn set_friend_offline( + router_db_client: &mut impl RouterDbClient, + router_state: &mut RouterState, + friend_public_key: PublicKey, +) -> Result { + if !router_state.liveness.is_online(&friend_public_key) { + // The friend is already marked as offline! + return Err(RouterError::FriendAlreadyOffline); + } + router_state.liveness.set_offline(&friend_public_key); + + let mut output = RouterOutput::new(); + + // Cancel all pending user requests + while let Some((_currency, pending_user_request)) = router_db_client + .pending_user_requests_pop_front(friend_public_key.clone()) + .await? + { + // Send outgoing cancel to user: + output.add_incoming_cancel(CancelSendFundsOp { + request_id: pending_user_request.request_id, + }); + } + + // Cancel all pending requests + while let Some((currency, pending_request)) = router_db_client + .pending_requests_pop_front(friend_public_key.clone()) + .await? + { + // Find from which friend this pending request has originated from. + // Due to inconsistencies, it is possible that this pending request has no origin. + let opt_request_origin = router_db_client + .get_remote_pending_request_origin(pending_request.request_id.clone()) + .await?; + + if let Some(request_origin) = opt_request_origin { + // Cancel request by queue-ing a cancel into the relevant friend's queue: + router_db_client + .pending_backwards_push_back( + request_origin.friend_public_key, + request_origin.currency, + BackwardsOp::Cancel(CancelSendFundsOp { + request_id: pending_request.request_id, + }), + ) + .await?; + } + } + + // Add index mutations + // We send index mutations to remove all currencies that are considered open + let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); + while let Some(res) = open_currencies.next().await { + let open_currency = res?; + output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { + public_key: friend_public_key.clone(), + currency: open_currency.currency, + })); + } + + Ok(output) +} + +pub async fn add_currency( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, +) -> Result { + let mut output = RouterOutput::new(); + router_db_client + .add_currency_config(friend_public_key.clone(), currency) + .await?; + + flush_friend( + router_db_client, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + &mut output, + ) + .await?; + Ok(output) +} + +pub async fn set_remove_currency( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, +) -> Result { + let mut output = RouterOutput::new(); + router_db_client + .set_currency_remove(friend_public_key.clone(), currency) + .await?; + + flush_friend( + router_db_client, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + &mut output, + ) + .await?; + Ok(output) +} + +pub async fn unset_remove_currency( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, +) -> Result { + let mut output = RouterOutput::new(); + router_db_client + .unset_currency_remove(friend_public_key.clone(), currency) + .await?; + + flush_friend( + router_db_client, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + &mut output, + ) + .await?; + Ok(output) +} + +pub async fn set_remote_max_debt( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, + remote_max_debt: u128, +) -> Result { + // TODO: What to do if currency does not exist? + // Do we need to somehow report back? + + let mut output = RouterOutput::new(); + + let opt_currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await?; + if let Some(currency_info) = opt_currency_info { + // Currency exists (We don't do anything otherwise) + // Set remote max debt: + router_db_client + .set_remote_max_debt(friend_public_key.clone(), currency.clone(), remote_max_debt) + .await?; + + // Create an index mutation if needed: + if currency_info.is_open { + // Currency is open: + output.add_index_mutation(create_update_index_mutation( + friend_public_key.clone(), + currency_info, + )?); + } + } + + Ok(output) +} + +pub async fn open_currency( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, +) -> Result { + let mut output = RouterOutput::new(); + + let opt_currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await?; + + if let Some(currency_info) = opt_currency_info { + // Currency exists: + if !currency_info.is_open { + // currency is closed: + + // Open currency: + router_db_client + .open_currency(friend_public_key.clone(), currency) + .await?; + + // Add index mutation: + output.add_index_mutation(create_update_index_mutation( + friend_public_key, + currency_info, + )?); + } + } + + Ok(output) +} + +pub async fn close_currency( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, +) -> Result { + let mut output = RouterOutput::new(); + + let opt_currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await?; + + if let Some(currency_info) = opt_currency_info { + // Currency exists: + if currency_info.is_open { + // currency is open: + + // Close currency: + router_db_client + .close_currency(friend_public_key.clone(), currency.clone()) + .await?; + + // Add index mutation: + output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { + public_key: friend_public_key, + currency, + })); + } + } + + Ok(output) +} diff --git a/components/funder/src/router/handle_move_token.rs b/components/funder/src/router/handle_move_token.rs new file mode 100644 index 000000000..915c368e5 --- /dev/null +++ b/components/funder/src/router/handle_move_token.rs @@ -0,0 +1,188 @@ +use std::collections::{HashMap, HashSet}; + +use futures::StreamExt; + +use derive_more::From; + +use common::async_rpc::OpError; +use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; + +use database::transaction::Transaction; + +use identity::IdentityClient; + +use proto::app_server::messages::RelayAddressPort; +use proto::crypto::{NodePort, PublicKey}; +use proto::funder::messages::{ + CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, + FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, + ResponseSendFundsOp, +}; +use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; +use proto::net::messages::NetAddress; + +use crypto::rand::{CryptoRandom, RandGen}; + +use crate::route::Route; +use crate::router::types::{ + BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, +}; + +use crate::mutual_credit::incoming::IncomingMessage; +use crate::router::utils::index_mutation::{ + create_index_mutations_from_move_token, create_update_index_mutation, +}; +use crate::router::utils::move_token::{ + collect_outgoing_move_token, collect_outgoing_move_token_allow_empty, is_pending_move_token, +}; +use crate::token_channel::{ + handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, +}; + +async fn incoming_move_token_request( + mut router_db_client: &mut RC, + router_state: &mut RouterState, + friend_public_key: PublicKey, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, + move_token_request: MoveTokenRequest, +) -> Result +where + RC: RouterDbClient, + RC::TcDbClient: Transaction + Send, + ::McDbClient: Send, +{ + let mut output = RouterOutput::new(); + let receive_move_token_output = handle_in_move_token( + router_db_client.tc_db_client(friend_public_key.clone()), + identity_client, + move_token_request.move_token, + local_public_key, + &friend_public_key, + ) + .await?; + + match receive_move_token_output { + ReceiveMoveTokenOutput::Duplicate => { + // We should have nothing else to send at this point, otherwise we would have already + // sent it. + assert!(!is_pending_move_token(router_db_client, friend_public_key.clone()).await?); + + // Possibly send token to remote side (According to token_wanted) + if move_token_request.token_wanted { + let out_move_token_request = collect_outgoing_move_token_allow_empty( + router_db_client, + identity_client, + local_public_key, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + // TODO: Should we really check for liveness here? We just got a message from this + // friend. Think about liveness design here. What if we ever forget to check for + // liveness before adding a friend message? Maybe this should be checked in + // different way, or a different layer? + if router_state.liveness.is_online(&friend_public_key) { + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(out_move_token_request), + ); + } + } + } + ReceiveMoveTokenOutput::RetransmitOutgoing(move_token) => { + // Retransmit outgoing move token message to friend: + let move_token_request = MoveTokenRequest { + move_token, + token_wanted: is_pending_move_token(router_db_client, friend_public_key.clone()) + .await?, + }; + + if router_state.liveness.is_online(&friend_public_key) { + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(move_token_request), + ); + } + } + ReceiveMoveTokenOutput::Received(move_token_received) => { + for (currency, incoming_message) in move_token_received.incoming_messages { + match incoming_message { + IncomingMessage::Request(request_send_funds) => todo!(), + IncomingMessage::RequestCancel(request_send_funds) => todo!(), + IncomingMessage::Response(response_send_funds) => todo!(), + IncomingMessage::Cancel(cancel_send_funds) => todo!(), + } + } + todo!(); + } + ReceiveMoveTokenOutput::ChainInconsistent(reset_terms) => todo!(), // (local_reset_token, local_reset_move_token_counter) + } + + Ok(output) +} + +async fn incoming_inconsistency_error( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + reset_terms: ResetTerms, +) -> Result { + todo!(); +} + +async fn incoming_relays_update( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + relays_update: RelaysUpdate, +) -> Result { + todo!(); +} + +async fn incoming_relays_ack( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + generation: u128, +) -> Result { + todo!(); +} + +pub async fn incoming_friend_message( + router_db_client: &mut RC, + router_state: &mut RouterState, + friend_public_key: PublicKey, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, + friend_message: FriendMessage, +) -> Result +where + RC: RouterDbClient, + RC::TcDbClient: Transaction + Send, + ::McDbClient: Send, +{ + match friend_message { + FriendMessage::MoveTokenRequest(move_token_request) => { + incoming_move_token_request( + router_db_client, + router_state, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + move_token_request, + ) + .await + } + FriendMessage::InconsistencyError(reset_terms) => { + incoming_inconsistency_error(router_db_client, friend_public_key, reset_terms).await + } + FriendMessage::RelaysUpdate(relays_update) => { + incoming_relays_update(router_db_client, friend_public_key, relays_update).await + } + FriendMessage::RelaysAck(generation) => { + incoming_relays_ack(router_db_client, friend_public_key, generation).await + } + } +} diff --git a/components/funder/src/router/handle_relays.rs b/components/funder/src/router/handle_relays.rs new file mode 100644 index 000000000..7c10b50a8 --- /dev/null +++ b/components/funder/src/router/handle_relays.rs @@ -0,0 +1,174 @@ +use std::collections::{HashMap, HashSet}; + +use futures::StreamExt; + +use derive_more::From; + +use common::async_rpc::OpError; +use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; + +use database::transaction::Transaction; + +use identity::IdentityClient; + +use proto::app_server::messages::RelayAddressPort; +use proto::crypto::{NodePort, PublicKey}; +use proto::funder::messages::{ + CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, + FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, + ResponseSendFundsOp, +}; +use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; +use proto::net::messages::NetAddress; + +use crypto::rand::{CryptoRandom, RandGen}; + +use crate::route::Route; +use crate::router::types::{ + BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, +}; + +use crate::mutual_credit::incoming::IncomingMessage; +use crate::router::utils::index_mutation::{ + create_index_mutations_from_move_token, create_update_index_mutation, +}; +use crate::router::utils::move_token::{ + collect_outgoing_move_token, collect_outgoing_move_token_allow_empty, is_pending_move_token, +}; +use crate::token_channel::{ + handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, +}; + +/// Calculate max generation +/// Returns None if no generation was found: This would mean that the remote friend is fully +/// synced. +fn max_generation(sent_relays: &[SentRelay]) -> Option { + let mut opt_max_generation = None; + for sent_relay in sent_relays { + if let Some(sent_relay_generation) = &sent_relay.opt_generation { + if let Some(max_generation) = &mut opt_max_generation { + if sent_relay_generation > max_generation { + *max_generation = *sent_relay_generation; + } + } else { + opt_max_generation = Some(*sent_relay_generation); + } + } + } + opt_max_generation +} + +/// Returns whether friend's relays were updated +async fn update_friend_local_relays( + router_db_client: &mut impl RouterDbClient, + local_relays: HashMap, + friend_public_key: PublicKey, + rng: &mut impl CryptoRandom, +) -> Result)>, RouterError> { + let sent_relays = router_db_client + .get_sent_relays(friend_public_key.clone()) + .await?; + + let opt_max_generation = max_generation(&sent_relays); + let new_generation = match opt_max_generation { + Some(g) => g.checked_add(1).ok_or(RouterError::GenerationOverflow)?, + None => 0, + }; + + // Update local relays: + let mut new_sent_relays = Vec::new(); + let mut sent_relays_updated: bool = false; + let mut c_local_relays = local_relays.clone(); + for mut sent_relay in sent_relays.into_iter() { + if let Some(relay_address) = c_local_relays.remove(&sent_relay.relay_address.public_key) { + // We should update this relay: + let new_sent_relay = SentRelay { + relay_address: sent_relay.relay_address.clone(), + is_remove: false, + opt_generation: sent_relay.opt_generation, // ?? + }; + sent_relays_updated |= sent_relay != new_sent_relay; + sent_relay.is_remove = false; + } else { + // We should remove this relay from sent_relays: + if !sent_relay.is_remove { + sent_relay.is_remove = true; + sent_relay.opt_generation = Some(new_generation); + sent_relays_updated = true; + } + new_sent_relays.push(sent_relay); + } + } + + // Add remaining local relays: + for (relay_public_key, address) in c_local_relays.into_iter() { + let relay_address = RelayAddressPort { + public_key: relay_public_key, + address, + // Randomly generate a new port: + port: NodePort::rand_gen(rng), + }; + new_sent_relays.push(SentRelay { + relay_address, + is_remove: false, + opt_generation: Some(new_generation), + }); + sent_relays_updated = true; + } + + Ok(if sent_relays_updated { + // Update sent relays: + router_db_client + .set_sent_relays(friend_public_key.clone(), new_sent_relays.clone()) + .await?; + Some(( + new_generation, + new_sent_relays + .into_iter() + .map(|sent_relay| sent_relay.relay_address) + .collect(), + )) + } else { + None + }) +} + +pub async fn update_local_relays( + router_db_client: &mut impl RouterDbClient, + router_state: &RouterState, + local_relays: HashMap, + rng: &mut impl CryptoRandom, +) -> Result { + let mut output = RouterOutput::new(); + + let mut opt_friend_public_key = None; + while let Some(friend_public_key) = router_db_client + .get_next_friend(opt_friend_public_key) + .await? + { + opt_friend_public_key = Some(friend_public_key.clone()); + + let opt_res = update_friend_local_relays( + router_db_client, + local_relays.clone(), + friend_public_key.clone(), + rng, + ) + .await?; + + // If sent_relays was updated and the friend is ready, we need to send relays to + // remote friend: + if let Some((generation, relays)) = opt_res { + // Make sure that remote friend is online: + if router_state.liveness.is_online(&friend_public_key) { + // Add a message for sending relays: + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), + ); + } + } + } + + Ok(output) +} diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 0a9b8cf14..2acdf31f9 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -1,4 +1,9 @@ mod utils; +mod handle_config; +mod handle_move_token; +mod handle_relays; + mod router; + mod types; diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index ec540aae6..0e9a3a4e9 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -37,159 +37,6 @@ use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; -pub async fn set_friend_online( - router_db_client: &mut impl RouterDbClient, - router_state: &mut RouterState, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - friend_public_key: PublicKey, - max_operations_in_batch: usize, -) -> Result { - if router_state.liveness.is_online(&friend_public_key) { - // The friend is already marked as online! - return Err(RouterError::FriendAlreadyOnline); - } - router_state.liveness.set_online(friend_public_key.clone()); - - let mut output = RouterOutput::new(); - - // Check if we have any relays information to send to the remote side: - if let (Some(generation), relays) = router_db_client - .get_last_sent_relays(friend_public_key.clone()) - .await? - { - // Add a message for sending relays: - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), - ); - } - - match router_db_client - .tc_db_client(friend_public_key.clone()) - .get_tc_status() - .await? - { - TcStatus::ConsistentIn(_) => { - // Create an outgoing move token if we have something to send. - let opt_move_token_request = collect_outgoing_move_token( - router_db_client, - identity_client, - local_public_key, - friend_public_key.clone(), - max_operations_in_batch, - ) - .await?; - - if let Some(move_token_request) = opt_move_token_request { - // We have something to send to remote side: - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(move_token_request), - ); - } - } - TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { - // Resend outgoing move token, - // possibly asking for the token if we have something to send - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(MoveTokenRequest { - move_token: move_token_out, - token_wanted: is_pending_move_token( - router_db_client, - friend_public_key.clone(), - ) - .await?, - }), - ); - } - TcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { - // Resend reset terms - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::InconsistencyError(local_reset_terms), - ); - } - } - - // Add an index mutation for all open currencies: - let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); - while let Some(res) = open_currencies.next().await { - let open_currency = res?; - - output.add_index_mutation(create_update_index_mutation( - friend_public_key.clone(), - open_currency, - )?); - } - - Ok(output) -} - -pub async fn set_friend_offline( - router_db_client: &mut impl RouterDbClient, - router_state: &mut RouterState, - friend_public_key: PublicKey, -) -> Result { - if !router_state.liveness.is_online(&friend_public_key) { - // The friend is already marked as offline! - return Err(RouterError::FriendAlreadyOffline); - } - router_state.liveness.set_offline(&friend_public_key); - - let mut output = RouterOutput::new(); - - // Cancel all pending user requests - while let Some((_currency, pending_user_request)) = router_db_client - .pending_user_requests_pop_front(friend_public_key.clone()) - .await? - { - // Send outgoing cancel to user: - output.add_incoming_cancel(CancelSendFundsOp { - request_id: pending_user_request.request_id, - }); - } - - // Cancel all pending requests - while let Some((currency, pending_request)) = router_db_client - .pending_requests_pop_front(friend_public_key.clone()) - .await? - { - // Find from which friend this pending request has originated from. - // Due to inconsistencies, it is possible that this pending request has no origin. - let opt_request_origin = router_db_client - .get_remote_pending_request_origin(pending_request.request_id.clone()) - .await?; - - if let Some(request_origin) = opt_request_origin { - // Cancel request by queue-ing a cancel into the relevant friend's queue: - router_db_client - .pending_backwards_push_back( - request_origin.friend_public_key, - request_origin.currency, - BackwardsOp::Cancel(CancelSendFundsOp { - request_id: pending_request.request_id, - }), - ) - .await?; - } - } - - // Add index mutations - // We send index mutations to remove all currencies that are considered open - let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); - while let Some(res) = open_currencies.next().await { - let open_currency = res?; - output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { - public_key: friend_public_key.clone(), - currency: open_currency.currency, - })); - } - - Ok(output) -} - pub async fn send_request( router_db_client: &mut impl RouterDbClient, router_state: &RouterState, @@ -444,448 +291,3 @@ pub async fn send_cancel( Ok(output) } - -pub async fn add_currency( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - currency: Currency, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, -) -> Result { - let mut output = RouterOutput::new(); - router_db_client - .add_currency_config(friend_public_key.clone(), currency) - .await?; - - flush_friend( - router_db_client, - friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, - ) - .await?; - Ok(output) -} - -pub async fn set_remove_currency( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - currency: Currency, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, -) -> Result { - let mut output = RouterOutput::new(); - router_db_client - .set_currency_remove(friend_public_key.clone(), currency) - .await?; - - flush_friend( - router_db_client, - friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, - ) - .await?; - Ok(output) -} - -pub async fn unset_remove_currency( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - currency: Currency, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, -) -> Result { - let mut output = RouterOutput::new(); - router_db_client - .unset_currency_remove(friend_public_key.clone(), currency) - .await?; - - flush_friend( - router_db_client, - friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, - ) - .await?; - Ok(output) -} - -pub async fn set_remote_max_debt( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - currency: Currency, - remote_max_debt: u128, -) -> Result { - // TODO: What to do if currency does not exist? - // Do we need to somehow report back? - - let mut output = RouterOutput::new(); - - let opt_currency_info = router_db_client - .get_currency_info(friend_public_key.clone(), currency.clone()) - .await?; - if let Some(currency_info) = opt_currency_info { - // Currency exists (We don't do anything otherwise) - // Set remote max debt: - router_db_client - .set_remote_max_debt(friend_public_key.clone(), currency.clone(), remote_max_debt) - .await?; - - // Create an index mutation if needed: - if currency_info.is_open { - // Currency is open: - output.add_index_mutation(create_update_index_mutation( - friend_public_key.clone(), - currency_info, - )?); - } - } - - Ok(output) -} - -pub async fn open_currency( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - currency: Currency, -) -> Result { - let mut output = RouterOutput::new(); - - let opt_currency_info = router_db_client - .get_currency_info(friend_public_key.clone(), currency.clone()) - .await?; - - if let Some(currency_info) = opt_currency_info { - // Currency exists: - if !currency_info.is_open { - // currency is closed: - - // Open currency: - router_db_client - .open_currency(friend_public_key.clone(), currency) - .await?; - - // Add index mutation: - output.add_index_mutation(create_update_index_mutation( - friend_public_key, - currency_info, - )?); - } - } - - Ok(output) -} - -pub async fn close_currency( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - currency: Currency, -) -> Result { - let mut output = RouterOutput::new(); - - let opt_currency_info = router_db_client - .get_currency_info(friend_public_key.clone(), currency.clone()) - .await?; - - if let Some(currency_info) = opt_currency_info { - // Currency exists: - if currency_info.is_open { - // currency is open: - - // Close currency: - router_db_client - .close_currency(friend_public_key.clone(), currency.clone()) - .await?; - - // Add index mutation: - output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { - public_key: friend_public_key, - currency, - })); - } - } - - Ok(output) -} - -/// Calculate max generation -/// Returns None if no generation was found: This would mean that the remote friend is fully -/// synced. -fn max_generation(sent_relays: &[SentRelay]) -> Option { - let mut opt_max_generation = None; - for sent_relay in sent_relays { - if let Some(sent_relay_generation) = &sent_relay.opt_generation { - if let Some(max_generation) = &mut opt_max_generation { - if sent_relay_generation > max_generation { - *max_generation = *sent_relay_generation; - } - } else { - opt_max_generation = Some(*sent_relay_generation); - } - } - } - opt_max_generation -} - -/// Returns whether friend's relays were updated -async fn update_friend_local_relays( - router_db_client: &mut impl RouterDbClient, - local_relays: HashMap, - friend_public_key: PublicKey, - rng: &mut impl CryptoRandom, -) -> Result)>, RouterError> { - let sent_relays = router_db_client - .get_sent_relays(friend_public_key.clone()) - .await?; - - let opt_max_generation = max_generation(&sent_relays); - let new_generation = match opt_max_generation { - Some(g) => g.checked_add(1).ok_or(RouterError::GenerationOverflow)?, - None => 0, - }; - - // Update local relays: - let mut new_sent_relays = Vec::new(); - let mut sent_relays_updated: bool = false; - let mut c_local_relays = local_relays.clone(); - for mut sent_relay in sent_relays.into_iter() { - if let Some(relay_address) = c_local_relays.remove(&sent_relay.relay_address.public_key) { - // We should update this relay: - let new_sent_relay = SentRelay { - relay_address: sent_relay.relay_address.clone(), - is_remove: false, - opt_generation: sent_relay.opt_generation, // ?? - }; - sent_relays_updated |= sent_relay != new_sent_relay; - sent_relay.is_remove = false; - } else { - // We should remove this relay from sent_relays: - if !sent_relay.is_remove { - sent_relay.is_remove = true; - sent_relay.opt_generation = Some(new_generation); - sent_relays_updated = true; - } - new_sent_relays.push(sent_relay); - } - } - - // Add remaining local relays: - for (relay_public_key, address) in c_local_relays.into_iter() { - let relay_address = RelayAddressPort { - public_key: relay_public_key, - address, - // Randomly generate a new port: - port: NodePort::rand_gen(rng), - }; - new_sent_relays.push(SentRelay { - relay_address, - is_remove: false, - opt_generation: Some(new_generation), - }); - sent_relays_updated = true; - } - - Ok(if sent_relays_updated { - // Update sent relays: - router_db_client - .set_sent_relays(friend_public_key.clone(), new_sent_relays.clone()) - .await?; - Some(( - new_generation, - new_sent_relays - .into_iter() - .map(|sent_relay| sent_relay.relay_address) - .collect(), - )) - } else { - None - }) -} - -pub async fn update_local_relays( - router_db_client: &mut impl RouterDbClient, - router_state: &RouterState, - local_relays: HashMap, - rng: &mut impl CryptoRandom, -) -> Result { - let mut output = RouterOutput::new(); - - let mut opt_friend_public_key = None; - while let Some(friend_public_key) = router_db_client - .get_next_friend(opt_friend_public_key) - .await? - { - opt_friend_public_key = Some(friend_public_key.clone()); - - let opt_res = update_friend_local_relays( - router_db_client, - local_relays.clone(), - friend_public_key.clone(), - rng, - ) - .await?; - - // If sent_relays was updated and the friend is ready, we need to send relays to - // remote friend: - if let Some((generation, relays)) = opt_res { - // Make sure that remote friend is online: - if router_state.liveness.is_online(&friend_public_key) { - // Add a message for sending relays: - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), - ); - } - } - } - - Ok(output) -} - -async fn incoming_move_token_request( - mut router_db_client: &mut RC, - router_state: &mut RouterState, - friend_public_key: PublicKey, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, - move_token_request: MoveTokenRequest, -) -> Result -where - RC: RouterDbClient, - RC::TcDbClient: Transaction + Send, - ::McDbClient: Send, -{ - let mut output = RouterOutput::new(); - let receive_move_token_output = handle_in_move_token( - router_db_client.tc_db_client(friend_public_key.clone()), - identity_client, - move_token_request.move_token, - local_public_key, - &friend_public_key, - ) - .await?; - - match receive_move_token_output { - ReceiveMoveTokenOutput::Duplicate => { - // We should have nothing else to send at this point, otherwise we would have already - // sent it. - assert!(!is_pending_move_token(router_db_client, friend_public_key.clone()).await?); - - // Possibly send token to remote side (According to token_wanted) - if move_token_request.token_wanted { - let out_move_token_request = collect_outgoing_move_token_allow_empty( - router_db_client, - identity_client, - local_public_key, - friend_public_key.clone(), - max_operations_in_batch, - ) - .await?; - - // TODO: Should we really check for liveness here? We just got a message from this - // friend. Think about liveness design here. What if we ever forget to check for - // liveness before adding a friend message? Maybe this should be checked in - // different way, or a different layer? - if router_state.liveness.is_online(&friend_public_key) { - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(out_move_token_request), - ); - } - } - } - ReceiveMoveTokenOutput::RetransmitOutgoing(move_token) => { - // Retransmit outgoing move token message to friend: - let move_token_request = MoveTokenRequest { - move_token, - token_wanted: is_pending_move_token(router_db_client, friend_public_key.clone()) - .await?, - }; - - if router_state.liveness.is_online(&friend_public_key) { - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(move_token_request), - ); - } - } - ReceiveMoveTokenOutput::Received(move_token_received) => todo!(), - ReceiveMoveTokenOutput::ChainInconsistent(reset_terms) => todo!(), // (local_reset_token, local_reset_move_token_counter) - } - - Ok(output) -} - -async fn incoming_inconsistency_error( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - reset_terms: ResetTerms, -) -> Result { - todo!(); -} - -async fn incoming_relays_update( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - relays_update: RelaysUpdate, -) -> Result { - todo!(); -} - -async fn incoming_relays_ack( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - generation: u128, -) -> Result { - todo!(); -} - -pub async fn incoming_friend_message( - router_db_client: &mut RC, - router_state: &mut RouterState, - friend_public_key: PublicKey, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, - friend_message: FriendMessage, -) -> Result -where - RC: RouterDbClient, - RC::TcDbClient: Transaction + Send, - ::McDbClient: Send, -{ - match friend_message { - FriendMessage::MoveTokenRequest(move_token_request) => { - incoming_move_token_request( - router_db_client, - router_state, - friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - move_token_request, - ) - .await - } - FriendMessage::InconsistencyError(reset_terms) => { - incoming_inconsistency_error(router_db_client, friend_public_key, reset_terms).await - } - FriendMessage::RelaysUpdate(relays_update) => { - incoming_relays_update(router_db_client, friend_public_key, relays_update).await - } - FriendMessage::RelaysAck(generation) => { - incoming_relays_ack(router_db_client, friend_public_key, generation).await - } - } -} diff --git a/components/funder/src/router/utils/flush.rs b/components/funder/src/router/utils/flush.rs new file mode 100644 index 000000000..86ad4c81b --- /dev/null +++ b/components/funder/src/router/utils/flush.rs @@ -0,0 +1,98 @@ +use std::collections::{HashMap, HashSet}; + +use futures::StreamExt; + +use derive_more::From; + +use common::async_rpc::OpError; +use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; + +use identity::IdentityClient; + +use proto::app_server::messages::RelayAddressPort; +use proto::crypto::{NodePort, PublicKey}; +use proto::funder::messages::{ + CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, + FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, +}; +use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; +use proto::net::messages::NetAddress; + +use crypto::rand::{CryptoRandom, RandGen}; + +use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; + +use crate::route::Route; +use crate::router::types::{ + BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, +}; +use crate::router::utils::index_mutation::create_index_mutations_from_move_token; +use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; + +/// Attempt to send as much as possible through a token channel to remote side +/// Assumes that the token channel is in consistent state (Incoming / Outgoing). +pub async fn flush_friend( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, + router_output: &mut RouterOutput, +) -> Result<(), RouterError> { + match router_db_client + .tc_db_client(friend_public_key.clone()) + .get_tc_status() + .await? + { + TcStatus::ConsistentIn(_) => { + // Create an outgoing move token if we have something to send. + let opt_move_token_request = collect_outgoing_move_token( + router_db_client, + identity_client, + local_public_key, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + if let Some(move_token_request) = opt_move_token_request { + // We have something to send to remote side: + + // Update index mutations: + let index_mutations = create_index_mutations_from_move_token( + router_db_client, + friend_public_key.clone(), + &move_token_request.move_token, + ) + .await?; + for index_mutation in index_mutations { + router_output.add_index_mutation(index_mutation); + } + router_output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(move_token_request), + ); + } + } + TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { + // Resend outgoing move token, + // possibly asking for the token if we have something to send + router_output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(MoveTokenRequest { + move_token: move_token_out, + token_wanted: is_pending_move_token( + router_db_client, + friend_public_key.clone(), + ) + .await?, + }), + ); + } + // This state is not possible, because we did manage to locate our request with this + // friend: + TcStatus::Inconsistent(..) => return Err(RouterError::UnexpectedTcStatus), + } + + Ok(()) +} diff --git a/components/funder/src/router/utils/mod.rs b/components/funder/src/router/utils/mod.rs index 1d584c6b4..5bb7b7705 100644 --- a/components/funder/src/router/utils/mod.rs +++ b/components/funder/src/router/utils/mod.rs @@ -1,2 +1,3 @@ +pub mod flush; pub mod index_mutation; pub mod move_token; From 551702605de2f1bd024bea51c7f1e33df2c2a7ac Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 14:54:58 +0200 Subject: [PATCH 321/478] funder: Renamed file --- components/funder/src/router/handle_route.rs | 293 +++++++++++++++++++ components/funder/src/router/mod.rs | 3 +- components/funder/src/router/router.rs | 67 ----- 3 files changed, 294 insertions(+), 69 deletions(-) create mode 100644 components/funder/src/router/handle_route.rs diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs new file mode 100644 index 000000000..0e9a3a4e9 --- /dev/null +++ b/components/funder/src/router/handle_route.rs @@ -0,0 +1,293 @@ +use std::collections::{HashMap, HashSet}; + +use futures::StreamExt; + +use derive_more::From; + +use common::async_rpc::OpError; +use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; + +use database::transaction::Transaction; + +use identity::IdentityClient; + +use proto::app_server::messages::RelayAddressPort; +use proto::crypto::{NodePort, PublicKey}; +use proto::funder::messages::{ + CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, + FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, + ResponseSendFundsOp, +}; +use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; +use proto::net::messages::NetAddress; + +use crypto::rand::{CryptoRandom, RandGen}; + +use crate::route::Route; +use crate::router::types::{ + BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, +}; +use crate::router::utils::index_mutation::{ + create_index_mutations_from_move_token, create_update_index_mutation, +}; +use crate::router::utils::move_token::{ + collect_outgoing_move_token, collect_outgoing_move_token_allow_empty, is_pending_move_token, +}; +use crate::token_channel::{ + handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, +}; + +pub async fn send_request( + router_db_client: &mut impl RouterDbClient, + router_state: &RouterState, + currency: Currency, + mut request: RequestSendFundsOp, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, +) -> Result { + // Make sure that the provided route is valid: + if !request.route.is_valid() { + return Err(RouterError::InvalidRoute); + } + + let mut output = RouterOutput::new(); + + // We cut the first two public keys from the route: + // Pop first route public key: + let route_local_public_key = request.route.remove(0); + if &route_local_public_key != local_public_key { + return Err(RouterError::InvalidRoute); + } + // Pop second route public key: + let friend_public_key = request.route.remove(0); + + // Gather information about friend's channel and liveness: + let tc_status = router_db_client + .tc_db_client(friend_public_key.clone()) + .get_tc_status() + .await?; + let is_online = router_state.liveness.is_online(&friend_public_key); + + // If friend is ready (online + consistent): + // - push the request + // - If token is incoming: + // - Send an outoging token + // - Else (token is outgoing): + // - Request token + // Else (Friend is not ready): + // - Send a cancel + match (tc_status, is_online) { + (TcStatus::ConsistentIn(_), true) => { + // Push request: + router_db_client + .pending_user_requests_push_back(friend_public_key.clone(), currency, request) + .await?; + + // Create an outgoing move token if we have something to send. + let opt_move_token_request = collect_outgoing_move_token( + router_db_client, + identity_client, + local_public_key, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + if let Some(move_token_request) = opt_move_token_request { + // We have something to send to remote side + // Deduce index mutations according to move token: + let index_mutations = create_index_mutations_from_move_token( + router_db_client, + friend_public_key.clone(), + &move_token_request.move_token, + ) + .await?; + for index_mutation in index_mutations { + output.add_index_mutation(index_mutation); + } + + // Send move token request to remote side: + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(move_token_request), + ); + } + } + (TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in), true) => { + // Push request: + router_db_client + .pending_user_requests_push_back(friend_public_key.clone(), currency, request) + .await?; + + // Resend outgoing move token, + // possibly asking for the token if we have something to send + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(MoveTokenRequest { + move_token: move_token_out, + token_wanted: is_pending_move_token( + router_db_client, + friend_public_key.clone(), + ) + .await?, + }), + ); + } + _ => { + // Friend is not ready to accept a request. + // We cancel the request: + output.add_incoming_cancel(CancelSendFundsOp { + request_id: request.request_id, + }); + } + } + + Ok(output) +} + +/// Attempt to send as much as possible through a token channel to remote side +/// Assumes that the token channel is in consistent state (Incoming / Outgoing). +async fn flush_friend( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, + router_output: &mut RouterOutput, +) -> Result<(), RouterError> { + match router_db_client + .tc_db_client(friend_public_key.clone()) + .get_tc_status() + .await? + { + TcStatus::ConsistentIn(_) => { + // Create an outgoing move token if we have something to send. + let opt_move_token_request = collect_outgoing_move_token( + router_db_client, + identity_client, + local_public_key, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + if let Some(move_token_request) = opt_move_token_request { + // We have something to send to remote side: + + // Update index mutations: + let index_mutations = create_index_mutations_from_move_token( + router_db_client, + friend_public_key.clone(), + &move_token_request.move_token, + ) + .await?; + for index_mutation in index_mutations { + router_output.add_index_mutation(index_mutation); + } + router_output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(move_token_request), + ); + } + } + TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { + // Resend outgoing move token, + // possibly asking for the token if we have something to send + router_output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(MoveTokenRequest { + move_token: move_token_out, + token_wanted: is_pending_move_token( + router_db_client, + friend_public_key.clone(), + ) + .await?, + }), + ); + } + // This state is not possible, because we did manage to locate our request with this + // friend: + TcStatus::Inconsistent(..) => return Err(RouterError::UnexpectedTcStatus), + } + + Ok(()) +} + +pub async fn send_response( + router_db_client: &mut impl RouterDbClient, + response: ResponseSendFundsOp, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, +) -> Result { + let mut output = RouterOutput::new(); + + let opt_request_origin = router_db_client + .get_remote_pending_request_origin(response.request_id.clone()) + .await?; + + // Attempt to find which node originally sent us this request, + // so that we can forward him the response. + // If we can not find the request's origin, we discard the response. + if let Some(request_origin) = opt_request_origin { + router_db_client + .pending_backwards_push_back( + request_origin.friend_public_key.clone(), + request_origin.currency, + BackwardsOp::Response(response), + ) + .await?; + + flush_friend( + router_db_client, + request_origin.friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + &mut output, + ) + .await?; + } + + Ok(output) +} + +pub async fn send_cancel( + router_db_client: &mut impl RouterDbClient, + cancel: CancelSendFundsOp, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, +) -> Result { + let mut output = RouterOutput::new(); + + let opt_request_origin = router_db_client + .get_remote_pending_request_origin(cancel.request_id.clone()) + .await?; + + // Attempt to find which node originally sent us this request, + // so that we can forward him the response. + // If we can not find the request's origin, we discard the response. + if let Some(request_origin) = opt_request_origin { + router_db_client + .pending_backwards_push_back( + request_origin.friend_public_key.clone(), + request_origin.currency, + BackwardsOp::Cancel(cancel), + ) + .await?; + + flush_friend( + router_db_client, + request_origin.friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + &mut output, + ) + .await?; + } + + Ok(output) +} diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 2acdf31f9..ca65e503f 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -3,7 +3,6 @@ mod utils; mod handle_config; mod handle_move_token; mod handle_relays; - -mod router; +mod handle_route; mod types; diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs index 0e9a3a4e9..83182830c 100644 --- a/components/funder/src/router/router.rs +++ b/components/funder/src/router/router.rs @@ -146,73 +146,6 @@ pub async fn send_request( Ok(output) } -/// Attempt to send as much as possible through a token channel to remote side -/// Assumes that the token channel is in consistent state (Incoming / Outgoing). -async fn flush_friend( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, - router_output: &mut RouterOutput, -) -> Result<(), RouterError> { - match router_db_client - .tc_db_client(friend_public_key.clone()) - .get_tc_status() - .await? - { - TcStatus::ConsistentIn(_) => { - // Create an outgoing move token if we have something to send. - let opt_move_token_request = collect_outgoing_move_token( - router_db_client, - identity_client, - local_public_key, - friend_public_key.clone(), - max_operations_in_batch, - ) - .await?; - - if let Some(move_token_request) = opt_move_token_request { - // We have something to send to remote side: - - // Update index mutations: - let index_mutations = create_index_mutations_from_move_token( - router_db_client, - friend_public_key.clone(), - &move_token_request.move_token, - ) - .await?; - for index_mutation in index_mutations { - router_output.add_index_mutation(index_mutation); - } - router_output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(move_token_request), - ); - } - } - TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { - // Resend outgoing move token, - // possibly asking for the token if we have something to send - router_output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(MoveTokenRequest { - move_token: move_token_out, - token_wanted: is_pending_move_token( - router_db_client, - friend_public_key.clone(), - ) - .await?, - }), - ); - } - // This state is not possible, because we did manage to locate our request with this - // friend: - TcStatus::Inconsistent(..) => return Err(RouterError::UnexpectedTcStatus), - } - - Ok(()) -} pub async fn send_response( router_db_client: &mut impl RouterDbClient, From 875c7bd36dac98836cc2fa24c6752ab1a39518e4 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 14:56:21 +0200 Subject: [PATCH 322/478] funder: Renamed file --- .../src/router/{handle_move_token.rs => handle_friend.rs} | 0 components/funder/src/router/mod.rs | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename components/funder/src/router/{handle_move_token.rs => handle_friend.rs} (100%) diff --git a/components/funder/src/router/handle_move_token.rs b/components/funder/src/router/handle_friend.rs similarity index 100% rename from components/funder/src/router/handle_move_token.rs rename to components/funder/src/router/handle_friend.rs diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index ca65e503f..0e72a80e0 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -1,7 +1,7 @@ mod utils; mod handle_config; -mod handle_move_token; +mod handle_friend; mod handle_relays; mod handle_route; From 2b238dc9c5bbff7a8a902d83dfeb52ba25c18f02 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 15:11:57 +0200 Subject: [PATCH 323/478] funder: TODO comment --- components/funder/src/mutual_credit/incoming.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 382af2c67..bfe07de07 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -28,6 +28,8 @@ pub struct IncomingResponseSendFundsOp { #[derive(Debug)] pub struct IncomingCancelSendFundsOp { pub pending_transaction: PendingTransaction, + // TODO: incoming_cancel looks redundant, because we can already deduce request_id from + // `pending_transaction`. Maybe remove it? pub incoming_cancel: CancelSendFundsOp, } From feef07e8849f12b186cf60ca2bcb4b97736c7787 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 15:12:26 +0200 Subject: [PATCH 324/478] funder: Work on incoming_move_token_request() --- components/funder/src/router/handle_friend.rs | 96 ++++++++++++++++++- 1 file changed, 91 insertions(+), 5 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 915c368e5..8352d9225 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -28,7 +28,9 @@ use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; -use crate::mutual_credit::incoming::IncomingMessage; +use crate::mutual_credit::incoming::{ + IncomingCancelSendFundsOp, IncomingMessage, IncomingResponseSendFundsOp, +}; use crate::router::utils::index_mutation::{ create_index_mutations_from_move_token, create_update_index_mutation, }; @@ -39,6 +41,50 @@ use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; +async fn incoming_message_request( + mut router_db_client: &mut RC, + router_state: &mut RouterState, + friend_public_key: PublicKey, + identity_client: &mut IdentityClient, + router_output: &mut RouterOutput, + request_send_funds: RequestSendFundsOp, +) { + todo!(); +} + +async fn incoming_message_request_cancel( + mut router_db_client: &mut RC, + router_state: &mut RouterState, + friend_public_key: PublicKey, + identity_client: &mut IdentityClient, + router_output: &mut RouterOutput, + request_send_funds: RequestSendFundsOp, +) { + todo!(); +} + +async fn incoming_message_response( + mut router_db_client: &mut RC, + router_state: &mut RouterState, + friend_public_key: PublicKey, + identity_client: &mut IdentityClient, + router_output: &mut RouterOutput, + incoming_response: IncomingResponseSendFundsOp, +) { + todo!(); +} + +async fn incoming_message_cancel( + mut router_db_client: &mut RC, + router_state: &mut RouterState, + friend_public_key: PublicKey, + identity_client: &mut IdentityClient, + router_output: &mut RouterOutput, + cancel_send_funds: IncomingCancelSendFundsOp, +) { + todo!(); +} + async fn incoming_move_token_request( mut router_db_client: &mut RC, router_state: &mut RouterState, @@ -110,10 +156,50 @@ where ReceiveMoveTokenOutput::Received(move_token_received) => { for (currency, incoming_message) in move_token_received.incoming_messages { match incoming_message { - IncomingMessage::Request(request_send_funds) => todo!(), - IncomingMessage::RequestCancel(request_send_funds) => todo!(), - IncomingMessage::Response(response_send_funds) => todo!(), - IncomingMessage::Cancel(cancel_send_funds) => todo!(), + IncomingMessage::Request(request_send_funds) => { + incoming_message_request( + router_db_client, + router_state, + friend_public_key.clone(), + identity_client, + &mut output, + request_send_funds, + ) + .await + } + IncomingMessage::RequestCancel(request_send_funds) => { + incoming_message_request_cancel( + router_db_client, + router_state, + friend_public_key.clone(), + identity_client, + &mut output, + request_send_funds, + ) + .await + } + IncomingMessage::Response(incoming_response) => { + incoming_message_response( + router_db_client, + router_state, + friend_public_key.clone(), + identity_client, + &mut output, + incoming_response, + ) + .await + } + IncomingMessage::Cancel(incoming_cancel) => { + incoming_message_cancel( + router_db_client, + router_state, + friend_public_key.clone(), + identity_client, + &mut output, + incoming_cancel, + ) + .await + } } } todo!(); From 9570e120b04a42f7183860231127f32f5ea1a578 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 17:00:10 +0200 Subject: [PATCH 325/478] funder: Removed redundant file --- components/funder/src/router/router.rs | 226 ------------------------- 1 file changed, 226 deletions(-) delete mode 100644 components/funder/src/router/router.rs diff --git a/components/funder/src/router/router.rs b/components/funder/src/router/router.rs deleted file mode 100644 index 83182830c..000000000 --- a/components/funder/src/router/router.rs +++ /dev/null @@ -1,226 +0,0 @@ -use std::collections::{HashMap, HashSet}; - -use futures::StreamExt; - -use derive_more::From; - -use common::async_rpc::OpError; -use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; - -use database::transaction::Transaction; - -use identity::IdentityClient; - -use proto::app_server::messages::RelayAddressPort; -use proto::crypto::{NodePort, PublicKey}; -use proto::funder::messages::{ - CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, - FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, - ResponseSendFundsOp, -}; -use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; -use proto::net::messages::NetAddress; - -use crypto::rand::{CryptoRandom, RandGen}; - -use crate::route::Route; -use crate::router::types::{ - BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, -}; -use crate::router::utils::index_mutation::{ - create_index_mutations_from_move_token, create_update_index_mutation, -}; -use crate::router::utils::move_token::{ - collect_outgoing_move_token, collect_outgoing_move_token_allow_empty, is_pending_move_token, -}; -use crate::token_channel::{ - handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, -}; - -pub async fn send_request( - router_db_client: &mut impl RouterDbClient, - router_state: &RouterState, - currency: Currency, - mut request: RequestSendFundsOp, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, -) -> Result { - // Make sure that the provided route is valid: - if !request.route.is_valid() { - return Err(RouterError::InvalidRoute); - } - - let mut output = RouterOutput::new(); - - // We cut the first two public keys from the route: - // Pop first route public key: - let route_local_public_key = request.route.remove(0); - if &route_local_public_key != local_public_key { - return Err(RouterError::InvalidRoute); - } - // Pop second route public key: - let friend_public_key = request.route.remove(0); - - // Gather information about friend's channel and liveness: - let tc_status = router_db_client - .tc_db_client(friend_public_key.clone()) - .get_tc_status() - .await?; - let is_online = router_state.liveness.is_online(&friend_public_key); - - // If friend is ready (online + consistent): - // - push the request - // - If token is incoming: - // - Send an outoging token - // - Else (token is outgoing): - // - Request token - // Else (Friend is not ready): - // - Send a cancel - match (tc_status, is_online) { - (TcStatus::ConsistentIn(_), true) => { - // Push request: - router_db_client - .pending_user_requests_push_back(friend_public_key.clone(), currency, request) - .await?; - - // Create an outgoing move token if we have something to send. - let opt_move_token_request = collect_outgoing_move_token( - router_db_client, - identity_client, - local_public_key, - friend_public_key.clone(), - max_operations_in_batch, - ) - .await?; - - if let Some(move_token_request) = opt_move_token_request { - // We have something to send to remote side - // Deduce index mutations according to move token: - let index_mutations = create_index_mutations_from_move_token( - router_db_client, - friend_public_key.clone(), - &move_token_request.move_token, - ) - .await?; - for index_mutation in index_mutations { - output.add_index_mutation(index_mutation); - } - - // Send move token request to remote side: - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(move_token_request), - ); - } - } - (TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in), true) => { - // Push request: - router_db_client - .pending_user_requests_push_back(friend_public_key.clone(), currency, request) - .await?; - - // Resend outgoing move token, - // possibly asking for the token if we have something to send - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(MoveTokenRequest { - move_token: move_token_out, - token_wanted: is_pending_move_token( - router_db_client, - friend_public_key.clone(), - ) - .await?, - }), - ); - } - _ => { - // Friend is not ready to accept a request. - // We cancel the request: - output.add_incoming_cancel(CancelSendFundsOp { - request_id: request.request_id, - }); - } - } - - Ok(output) -} - - -pub async fn send_response( - router_db_client: &mut impl RouterDbClient, - response: ResponseSendFundsOp, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, -) -> Result { - let mut output = RouterOutput::new(); - - let opt_request_origin = router_db_client - .get_remote_pending_request_origin(response.request_id.clone()) - .await?; - - // Attempt to find which node originally sent us this request, - // so that we can forward him the response. - // If we can not find the request's origin, we discard the response. - if let Some(request_origin) = opt_request_origin { - router_db_client - .pending_backwards_push_back( - request_origin.friend_public_key.clone(), - request_origin.currency, - BackwardsOp::Response(response), - ) - .await?; - - flush_friend( - router_db_client, - request_origin.friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, - ) - .await?; - } - - Ok(output) -} - -pub async fn send_cancel( - router_db_client: &mut impl RouterDbClient, - cancel: CancelSendFundsOp, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, -) -> Result { - let mut output = RouterOutput::new(); - - let opt_request_origin = router_db_client - .get_remote_pending_request_origin(cancel.request_id.clone()) - .await?; - - // Attempt to find which node originally sent us this request, - // so that we can forward him the response. - // If we can not find the request's origin, we discard the response. - if let Some(request_origin) = opt_request_origin { - router_db_client - .pending_backwards_push_back( - request_origin.friend_public_key.clone(), - request_origin.currency, - BackwardsOp::Cancel(cancel), - ) - .await?; - - flush_friend( - router_db_client, - request_origin.friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, - ) - .await?; - } - - Ok(output) -} From ce6799c7d402d5ccc8653f8f50163a260930c54c Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 17:10:57 +0200 Subject: [PATCH 326/478] funder: Initial work on incoming_message_request() --- components/funder/src/router/handle_friend.rs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 8352d9225..eae408660 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -47,8 +47,28 @@ async fn incoming_message_request( friend_public_key: PublicKey, identity_client: &mut IdentityClient, router_output: &mut RouterOutput, - request_send_funds: RequestSendFundsOp, + mut request_send_funds: RequestSendFundsOp, ) { + // TODO: + // - Check if the message is directed to us, or to a next hop. + // - If directed to us, punt + // - If directed to another friend, + // - If friend exists and ready, forward to next hop + // - otherwise, queue cancel + + if request_send_funds.route.is_empty() { + // Directed to us. Punt: + router_output.add_incoming_request(request_send_funds); + } else { + // Route is not empty. We need to forward the request to a friend + let next_public_key = request_send_funds.route.remove(0); + + // Check if next public key corresponds to a friend that is ready + + // Directed to another friend + todo!(); + } + todo!(); } From 3696f1701ccb50e40b349628c5a6670f42864edc Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 17:12:01 +0200 Subject: [PATCH 327/478] funder: Added missing trait bounds --- components/funder/src/router/handle_friend.rs | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index eae408660..febc75767 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -48,7 +48,11 @@ async fn incoming_message_request( identity_client: &mut IdentityClient, router_output: &mut RouterOutput, mut request_send_funds: RequestSendFundsOp, -) { +) where + RC: RouterDbClient, + RC::TcDbClient: Transaction + Send, + ::McDbClient: Send, +{ // TODO: // - Check if the message is directed to us, or to a next hop. // - If directed to us, punt @@ -79,7 +83,11 @@ async fn incoming_message_request_cancel( identity_client: &mut IdentityClient, router_output: &mut RouterOutput, request_send_funds: RequestSendFundsOp, -) { +) where + RC: RouterDbClient, + RC::TcDbClient: Transaction + Send, + ::McDbClient: Send, +{ todo!(); } @@ -90,7 +98,11 @@ async fn incoming_message_response( identity_client: &mut IdentityClient, router_output: &mut RouterOutput, incoming_response: IncomingResponseSendFundsOp, -) { +) where + RC: RouterDbClient, + RC::TcDbClient: Transaction + Send, + ::McDbClient: Send, +{ todo!(); } @@ -101,7 +113,11 @@ async fn incoming_message_cancel( identity_client: &mut IdentityClient, router_output: &mut RouterOutput, cancel_send_funds: IncomingCancelSendFundsOp, -) { +) where + RC: RouterDbClient, + RC::TcDbClient: Transaction + Send, + ::McDbClient: Send, +{ todo!(); } From 20002aae7aa2f483f0ca65c53f9557f832974c4b Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 17:12:30 +0200 Subject: [PATCH 328/478] funder: comments --- components/funder/src/router/handle_friend.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index febc75767..3fc074df9 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -50,6 +50,7 @@ async fn incoming_message_request( mut request_send_funds: RequestSendFundsOp, ) where RC: RouterDbClient, + // TODO: Maybe not necessary: RC::TcDbClient: Transaction + Send, ::McDbClient: Send, { @@ -85,6 +86,7 @@ async fn incoming_message_request_cancel( request_send_funds: RequestSendFundsOp, ) where RC: RouterDbClient, + // TODO: Maybe not necessary: RC::TcDbClient: Transaction + Send, ::McDbClient: Send, { @@ -115,6 +117,7 @@ async fn incoming_message_cancel( cancel_send_funds: IncomingCancelSendFundsOp, ) where RC: RouterDbClient, + // TODO: Maybe not necessary: RC::TcDbClient: Transaction + Send, ::McDbClient: Send, { @@ -132,6 +135,7 @@ async fn incoming_move_token_request( ) -> Result where RC: RouterDbClient, + // TODO: Maybe not necessary: RC::TcDbClient: Transaction + Send, ::McDbClient: Send, { From 2203fd9798a2cd8bf7a1578f7d8fe8635ef1c5b7 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 17:23:29 +0200 Subject: [PATCH 329/478] funder: TcDbClient: Take failure into account in mc_db_client() --- components/funder/src/token_channel/tests/utils.rs | 9 +++++---- .../funder/src/token_channel/token_channel.rs | 14 ++++++++++++-- components/funder/src/token_channel/types.rs | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index c2e053f99..2f5726a22 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -124,11 +124,12 @@ fn calc_reset_balance(mock_token_channel: &MockMutualCredit) -> ResetBalance { impl TcDbClient for MockTokenChannel { type McDbClient = MockMutualCredit; - fn mc_db_client(&mut self, currency: Currency) -> &mut Self::McDbClient { + // TODO: Maybe take into account other return values, like None, instead of unwrapping? + fn mc_db_client(&mut self, currency: Currency) -> AsyncOpResult> { match &mut self.status { - MockTcStatus::Consistent(tc_consistent) => { - tc_consistent.mutual_credits.get_mut(¤cy).unwrap() - } + MockTcStatus::Consistent(tc_consistent) => Box::pin(future::ready(Ok(Some( + tc_consistent.mutual_credits.get_mut(¤cy).unwrap(), + )))), _ => unreachable!(), } } diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 84c128e0b..69c63f044 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -615,6 +615,8 @@ async fn handle_incoming_token_match( if is_local_currency { let mc_balance = tc_client .mc_db_client(diff_currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidDbState)? .get_balance() .await?; if mc_balance.balance == 0 @@ -648,7 +650,10 @@ async fn handle_incoming_token_match( let remote_max_debt = tc_client.get_remote_max_debt(currency.clone()).await?; let res = process_operation( - tc_client.mc_db_client(currency.clone()), + tc_client + .mc_db_client(currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidDbState)?, friend_tc_op.clone(), ¤cy, remote_public_key, @@ -747,6 +752,8 @@ pub async fn handle_out_move_token( if is_remote_currency { let mc_balance = tc_client .mc_db_client(diff_currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidDbState)? .get_balance() .await?; if mc_balance.balance == 0 @@ -777,7 +784,10 @@ pub async fn handle_out_move_token( // Update mutual credits: for (currency, friend_tc_op) in ¤cies_operations { queue_operation( - tc_client.mc_db_client(currency.clone()), + tc_client + .mc_db_client(currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidDbState)?, friend_tc_op.clone(), ¤cy, local_public_key, diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 13f6b4d12..1b3e09bcb 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -36,7 +36,7 @@ pub enum TcStatus { pub trait TcDbClient { type McDbClient: McDbClient; // TODO: Maybe should return an Option instead? What if currency doesn't exist? - fn mc_db_client(&mut self, currency: Currency) -> &mut Self::McDbClient; + fn mc_db_client(&mut self, currency: Currency) -> AsyncOpResult>; fn get_tc_status(&mut self) -> AsyncOpResult; fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; From 8577045f4fa34870763ae398f07497b7cc826154 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 17:24:14 +0200 Subject: [PATCH 330/478] funder: Removed TODO comment --- components/funder/src/token_channel/types.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 1b3e09bcb..35b4442b8 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -35,7 +35,6 @@ pub enum TcStatus { pub trait TcDbClient { type McDbClient: McDbClient; - // TODO: Maybe should return an Option instead? What if currency doesn't exist? fn mc_db_client(&mut self, currency: Currency) -> AsyncOpResult>; fn get_tc_status(&mut self) -> AsyncOpResult; From 6f17d90dda0879a867bb3d7089ba5775ec148643 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 17:51:38 +0200 Subject: [PATCH 331/478] funder: RouterDbClient: tc_db_client() can now fail --- components/funder/src/router/handle_config.rs | 82 ++++++++++++++--- components/funder/src/router/handle_friend.rs | 5 +- components/funder/src/router/handle_relays.rs | 6 ++ components/funder/src/router/handle_route.rs | 87 ++++--------------- components/funder/src/router/types.rs | 7 +- components/funder/src/router/utils/flush.rs | 2 + .../funder/src/router/utils/move_token.rs | 10 ++- 7 files changed, 111 insertions(+), 88 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 6dfa4c129..93a4f0ea2 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -46,14 +46,23 @@ pub async fn set_friend_online( friend_public_key: PublicKey, max_operations_in_batch: usize, ) -> Result { + // First we make sure that the friend exists: + let mut output = RouterOutput::new(); + let tc_status = if let Some(tc_db_client) = router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + { + tc_db_client.get_tc_status().await? + } else { + return Ok(output); + }; + if router_state.liveness.is_online(&friend_public_key) { // The friend is already marked as online! return Err(RouterError::FriendAlreadyOnline); } router_state.liveness.set_online(friend_public_key.clone()); - let mut output = RouterOutput::new(); - // Check if we have any relays information to send to the remote side: if let (Some(generation), relays) = router_db_client .get_last_sent_relays(friend_public_key.clone()) @@ -66,11 +75,7 @@ pub async fn set_friend_online( ); } - match router_db_client - .tc_db_client(friend_public_key.clone()) - .get_tc_status() - .await? - { + match tc_status { TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. let opt_move_token_request = collect_outgoing_move_token( @@ -133,14 +138,22 @@ pub async fn set_friend_offline( router_state: &mut RouterState, friend_public_key: PublicKey, ) -> Result { + // First we make sure that the friend exists: + let mut output = RouterOutput::new(); + if router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .is_none() + { + return Ok(output); + } + if !router_state.liveness.is_online(&friend_public_key) { // The friend is already marked as offline! return Err(RouterError::FriendAlreadyOffline); } router_state.liveness.set_offline(&friend_public_key); - let mut output = RouterOutput::new(); - // Cancel all pending user requests while let Some((_currency, pending_user_request)) = router_db_client .pending_user_requests_pop_front(friend_public_key.clone()) @@ -199,7 +212,15 @@ pub async fn add_currency( local_public_key: &PublicKey, max_operations_in_batch: usize, ) -> Result { + // First we make sure that the friend exists: let mut output = RouterOutput::new(); + if router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .is_none() + { + return Ok(output); + } router_db_client .add_currency_config(friend_public_key.clone(), currency) .await?; @@ -224,7 +245,15 @@ pub async fn set_remove_currency( local_public_key: &PublicKey, max_operations_in_batch: usize, ) -> Result { + // First we make sure that the friend exists: let mut output = RouterOutput::new(); + if router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .is_none() + { + return Ok(output); + } router_db_client .set_currency_remove(friend_public_key.clone(), currency) .await?; @@ -249,7 +278,15 @@ pub async fn unset_remove_currency( local_public_key: &PublicKey, max_operations_in_batch: usize, ) -> Result { + // First we make sure that the friend exists: let mut output = RouterOutput::new(); + if router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .is_none() + { + return Ok(output); + } router_db_client .unset_currency_remove(friend_public_key.clone(), currency) .await?; @@ -272,10 +309,15 @@ pub async fn set_remote_max_debt( currency: Currency, remote_max_debt: u128, ) -> Result { - // TODO: What to do if currency does not exist? - // Do we need to somehow report back? - + // First we make sure that the friend exists: let mut output = RouterOutput::new(); + if router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .is_none() + { + return Ok(output); + } let opt_currency_info = router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) @@ -305,7 +347,15 @@ pub async fn open_currency( friend_public_key: PublicKey, currency: Currency, ) -> Result { + // First we make sure that the friend exists: let mut output = RouterOutput::new(); + if router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .is_none() + { + return Ok(output); + } let opt_currency_info = router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) @@ -337,7 +387,15 @@ pub async fn close_currency( friend_public_key: PublicKey, currency: Currency, ) -> Result { + // First we make sure that the friend exists: let mut output = RouterOutput::new(); + if router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .is_none() + { + return Ok(output); + } let opt_currency_info = router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 3fc074df9..5f47e788f 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -141,7 +141,10 @@ where { let mut output = RouterOutput::new(); let receive_move_token_output = handle_in_move_token( - router_db_client.tc_db_client(friend_public_key.clone()), + router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .ok_or(RouterError::InvalidDbState)?, identity_client, move_token_request.move_token, local_public_key, diff --git a/components/funder/src/router/handle_relays.rs b/components/funder/src/router/handle_relays.rs index 7c10b50a8..29a8e7f95 100644 --- a/components/funder/src/router/handle_relays.rs +++ b/components/funder/src/router/handle_relays.rs @@ -65,6 +65,12 @@ async fn update_friend_local_relays( friend_public_key: PublicKey, rng: &mut impl CryptoRandom, ) -> Result)>, RouterError> { + // First we make sure that the friend exists: + let _ = router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .ok_or(RouterError::InvalidDbState)?; + let sent_relays = router_db_client .get_sent_relays(friend_public_key.clone()) .await?; diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index 0e9a3a4e9..4aadcb1cb 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -27,6 +27,7 @@ use crate::route::Route; use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; +use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::{ create_index_mutations_from_move_token, create_update_index_mutation, }; @@ -62,11 +63,23 @@ pub async fn send_request( // Pop second route public key: let friend_public_key = request.route.remove(0); - // Gather information about friend's channel and liveness: - let tc_status = router_db_client + let opt_tc_db_client = router_db_client .tc_db_client(friend_public_key.clone()) - .get_tc_status() .await?; + + let tc_db_client = if let Some(tc_db_client) = opt_tc_db_client { + tc_db_client + } else { + // Friend is not ready to accept a request. + // We cancel the request: + output.add_incoming_cancel(CancelSendFundsOp { + request_id: request.request_id, + }); + return Ok(output); + }; + + // Gather information about friend's channel and liveness: + let tc_status = tc_db_client.get_tc_status().await?; let is_online = router_state.liveness.is_online(&friend_public_key); // If friend is ready (online + consistent): @@ -146,74 +159,6 @@ pub async fn send_request( Ok(output) } -/// Attempt to send as much as possible through a token channel to remote side -/// Assumes that the token channel is in consistent state (Incoming / Outgoing). -async fn flush_friend( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, - router_output: &mut RouterOutput, -) -> Result<(), RouterError> { - match router_db_client - .tc_db_client(friend_public_key.clone()) - .get_tc_status() - .await? - { - TcStatus::ConsistentIn(_) => { - // Create an outgoing move token if we have something to send. - let opt_move_token_request = collect_outgoing_move_token( - router_db_client, - identity_client, - local_public_key, - friend_public_key.clone(), - max_operations_in_batch, - ) - .await?; - - if let Some(move_token_request) = opt_move_token_request { - // We have something to send to remote side: - - // Update index mutations: - let index_mutations = create_index_mutations_from_move_token( - router_db_client, - friend_public_key.clone(), - &move_token_request.move_token, - ) - .await?; - for index_mutation in index_mutations { - router_output.add_index_mutation(index_mutation); - } - router_output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(move_token_request), - ); - } - } - TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { - // Resend outgoing move token, - // possibly asking for the token if we have something to send - router_output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(MoveTokenRequest { - move_token: move_token_out, - token_wanted: is_pending_move_token( - router_db_client, - friend_public_key.clone(), - ) - .await?, - }), - ); - } - // This state is not possible, because we did manage to locate our request with this - // friend: - TcStatus::Inconsistent(..) => return Err(RouterError::UnexpectedTcStatus), - } - - Ok(()) -} - pub async fn send_response( router_db_client: &mut impl RouterDbClient, response: ResponseSendFundsOp, diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 7a3b5dcb8..205d4e166 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -24,6 +24,7 @@ pub enum RouterError { GenerationOverflow, BalanceOverflow, InvalidRoute, + InvalidDbState, UnexpectedTcStatus, TokenChannelError(TokenChannelError), OpError(OpError), @@ -90,8 +91,10 @@ pub struct SentRelay { pub trait RouterDbClient { type TcDbClient: TcDbClient; - // TODO: Maybe should return an Option instead? What if friend doesn't exist? - fn tc_db_client(&mut self, friend_public_key: PublicKey) -> &mut Self::TcDbClient; + fn tc_db_client( + &mut self, + friend_public_key: PublicKey, + ) -> AsyncOpResult>; /* /// Get the current list of local relays diff --git a/components/funder/src/router/utils/flush.rs b/components/funder/src/router/utils/flush.rs index 86ad4c81b..04456494a 100644 --- a/components/funder/src/router/utils/flush.rs +++ b/components/funder/src/router/utils/flush.rs @@ -41,6 +41,8 @@ pub async fn flush_friend( ) -> Result<(), RouterError> { match router_db_client .tc_db_client(friend_public_key.clone()) + .await? + .ok_or(RouterError::InvalidDbState)? .get_tc_status() .await? { diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 215f7df7b..de6c3088a 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -132,7 +132,10 @@ pub async fn collect_outgoing_move_token_allow_empty( // Create move token and update internal state: let move_token = handle_out_move_token( - router_db_client.tc_db_client(friend_public_key.clone()), + router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .ok_or(RouterError::InvalidDbState)?, identity_client, currencies_operations, currencies_diff, @@ -174,7 +177,10 @@ pub async fn collect_outgoing_move_token( } else { // We have something to send to remote side let move_token = handle_out_move_token( - router_db_client.tc_db_client(friend_public_key.clone()), + router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .ok_or(RouterError::InvalidDbState)?, identity_client, currencies_operations, currencies_diff, From 5c36acff58fd2f86a200d8c979684546f009c9ee Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 18:17:26 +0200 Subject: [PATCH 332/478] funder: impl incoming_message_request() --- components/funder/src/router/handle_friend.rs | 84 +++++++++++++++---- 1 file changed, 67 insertions(+), 17 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 5f47e788f..45c3473e6 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -31,6 +31,7 @@ use crate::router::types::{ use crate::mutual_credit::incoming::{ IncomingCancelSendFundsOp, IncomingMessage, IncomingResponseSendFundsOp, }; +use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::{ create_index_mutations_from_move_token, create_update_index_mutation, }; @@ -46,21 +47,19 @@ async fn incoming_message_request( router_state: &mut RouterState, friend_public_key: PublicKey, identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, router_output: &mut RouterOutput, + currency: Currency, mut request_send_funds: RequestSendFundsOp, -) where +) -> Result<(), RouterError> +where RC: RouterDbClient, - // TODO: Maybe not necessary: - RC::TcDbClient: Transaction + Send, - ::McDbClient: Send, { - // TODO: - // - Check if the message is directed to us, or to a next hop. // - If directed to us, punt - // - If directed to another friend, + // - If directed to another friend: // - If friend exists and ready, forward to next hop - // - otherwise, queue cancel - + // - Otherwise, queue cancel if request_send_funds.route.is_empty() { // Directed to us. Punt: router_output.add_incoming_request(request_send_funds); @@ -69,12 +68,57 @@ async fn incoming_message_request( let next_public_key = request_send_funds.route.remove(0); // Check if next public key corresponds to a friend that is ready + let is_ready = if let Some(tc_db_client) = router_db_client + .tc_db_client(next_public_key.clone()) + .await? + { + match tc_db_client.get_tc_status().await? { + TcStatus::ConsistentIn(..) | TcStatus::ConsistentOut(..) => true, + TcStatus::Inconsistent(..) => false, + } + } else { + // next public key points to a nonexistent friend! + false + } && router_state.liveness.is_online(&next_public_key); - // Directed to another friend - todo!(); - } + if is_ready { + // Queue request to friend and flush destination friend + router_db_client + .pending_requests_push_back(next_public_key.clone(), currency, request_send_funds) + .await?; + flush_friend( + router_db_client, + next_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + router_output, + ) + .await?; + } else { + // Return a cancel message and flush origin friend + router_db_client + .pending_backwards_push_back( + friend_public_key.clone(), + currency, + BackwardsOp::Cancel(CancelSendFundsOp { + request_id: request_send_funds.request_id.clone(), + }), + ) + .await?; - todo!(); + flush_friend( + router_db_client, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + router_output, + ) + .await?; + } + } + Ok(()) } async fn incoming_message_request_cancel( @@ -84,7 +128,8 @@ async fn incoming_message_request_cancel( identity_client: &mut IdentityClient, router_output: &mut RouterOutput, request_send_funds: RequestSendFundsOp, -) where +) -> Result<(), RouterError> +where RC: RouterDbClient, // TODO: Maybe not necessary: RC::TcDbClient: Transaction + Send, @@ -100,7 +145,8 @@ async fn incoming_message_response( identity_client: &mut IdentityClient, router_output: &mut RouterOutput, incoming_response: IncomingResponseSendFundsOp, -) where +) -> Result<(), RouterError> +where RC: RouterDbClient, RC::TcDbClient: Transaction + Send, ::McDbClient: Send, @@ -115,7 +161,8 @@ async fn incoming_message_cancel( identity_client: &mut IdentityClient, router_output: &mut RouterOutput, cancel_send_funds: IncomingCancelSendFundsOp, -) where +) -> Result<(), RouterError> +where RC: RouterDbClient, // TODO: Maybe not necessary: RC::TcDbClient: Transaction + Send, @@ -205,7 +252,10 @@ where router_state, friend_public_key.clone(), identity_client, + local_public_key, + max_operations_in_batch, &mut output, + currency, request_send_funds, ) .await @@ -243,7 +293,7 @@ where ) .await } - } + }?; } todo!(); } From def1c1fac17e0ab246e517a2892111ecac78ae15 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 4 Jan 2021 18:19:03 +0200 Subject: [PATCH 333/478] funder: Weakened bounds --- components/funder/src/router/handle_friend.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 45c3473e6..95b6f06af 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -131,9 +131,6 @@ async fn incoming_message_request_cancel( ) -> Result<(), RouterError> where RC: RouterDbClient, - // TODO: Maybe not necessary: - RC::TcDbClient: Transaction + Send, - ::McDbClient: Send, { todo!(); } @@ -148,8 +145,6 @@ async fn incoming_message_response( ) -> Result<(), RouterError> where RC: RouterDbClient, - RC::TcDbClient: Transaction + Send, - ::McDbClient: Send, { todo!(); } @@ -164,9 +159,6 @@ async fn incoming_message_cancel( ) -> Result<(), RouterError> where RC: RouterDbClient, - // TODO: Maybe not necessary: - RC::TcDbClient: Transaction + Send, - ::McDbClient: Send, { todo!(); } From 29b1d3c62b6accd916a2ac4d1c94bd7c7bf17573 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 8 Jan 2021 13:53:48 +0200 Subject: [PATCH 334/478] funder: impl incoming_message_request_cancel() --- components/funder/src/router/handle_friend.rs | 35 +++++++++++++++---- components/funder/src/token_channel/types.rs | 9 +++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 95b6f06af..e32cdce02 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -72,10 +72,7 @@ where .tc_db_client(next_public_key.clone()) .await? { - match tc_db_client.get_tc_status().await? { - TcStatus::ConsistentIn(..) | TcStatus::ConsistentOut(..) => true, - TcStatus::Inconsistent(..) => false, - } + tc_db_client.get_tc_status().await?.is_consistent() } else { // next public key points to a nonexistent friend! false @@ -123,16 +120,33 @@ where async fn incoming_message_request_cancel( mut router_db_client: &mut RC, - router_state: &mut RouterState, friend_public_key: PublicKey, identity_client: &mut IdentityClient, router_output: &mut RouterOutput, + currency: Currency, request_send_funds: RequestSendFundsOp, ) -> Result<(), RouterError> where RC: RouterDbClient, { - todo!(); + // Queue cancel to friend_public_key (Request origin) + if router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .ok_or(RouterError::InvalidDbState)? + .get_tc_status() + .await? + .is_consistent() + { + router_db_client + .pending_requests_push_back(friend_public_key.clone(), currency, request_send_funds) + .await?; + } else { + // We have just received a cancel message from this friend. + // We expect that this friend is consistent + return Err(RouterError::InvalidDbState); + } + Ok(()) } async fn incoming_message_response( @@ -160,6 +174,13 @@ async fn incoming_message_cancel( where RC: RouterDbClient, { + // TODO: + // - Check if request origin is local + // - If so, punt cancel + // - Otherwise, find request friend origin + // - If found, forward cancel to friend if possible + // - What if inconsistent? + // - Flush friend todo!(); } @@ -255,10 +276,10 @@ where IncomingMessage::RequestCancel(request_send_funds) => { incoming_message_request_cancel( router_db_client, - router_state, friend_public_key.clone(), identity_client, &mut output, + currency, request_send_funds, ) .await diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 35b4442b8..7a7303244 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -33,6 +33,15 @@ pub enum TcStatus { Inconsistent(ResetTerms, Option), // (local_reset_terms, Option bool { + match &self { + Self::ConsistentIn(..) | Self::ConsistentOut(..) => true, + Self::Inconsistent(..) => false, + } + } +} + pub trait TcDbClient { type McDbClient: McDbClient; fn mc_db_client(&mut self, currency: Currency) -> AsyncOpResult>; From 3ce01ed2c4eef69a4caa23540fcdb20b9b7c3e7f Mon Sep 17 00:00:00 2001 From: real Date: Fri, 8 Jan 2021 16:45:50 +0200 Subject: [PATCH 335/478] funder: Refactor send_request() --- components/funder/src/router/handle_route.rs | 96 +++++--------------- 1 file changed, 23 insertions(+), 73 deletions(-) diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index 4aadcb1cb..c43a1c209 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -79,81 +79,31 @@ pub async fn send_request( }; // Gather information about friend's channel and liveness: - let tc_status = tc_db_client.get_tc_status().await?; - let is_online = router_state.liveness.is_online(&friend_public_key); - - // If friend is ready (online + consistent): - // - push the request - // - If token is incoming: - // - Send an outoging token - // - Else (token is outgoing): - // - Request token - // Else (Friend is not ready): - // - Send a cancel - match (tc_status, is_online) { - (TcStatus::ConsistentIn(_), true) => { - // Push request: - router_db_client - .pending_user_requests_push_back(friend_public_key.clone(), currency, request) - .await?; - - // Create an outgoing move token if we have something to send. - let opt_move_token_request = collect_outgoing_move_token( - router_db_client, - identity_client, - local_public_key, - friend_public_key.clone(), - max_operations_in_batch, - ) + // let tc_status = tc_db_client.get_tc_status().await?; + // let is_online = router_state.liveness.is_online(&friend_public_key); + + // Check if friend is ready: + if tc_db_client.get_tc_status().await?.is_consistent() + && router_state.liveness.is_online(&friend_public_key) + { + // Push request: + router_db_client + .pending_user_requests_push_back(friend_public_key.clone(), currency, request) .await?; - if let Some(move_token_request) = opt_move_token_request { - // We have something to send to remote side - // Deduce index mutations according to move token: - let index_mutations = create_index_mutations_from_move_token( - router_db_client, - friend_public_key.clone(), - &move_token_request.move_token, - ) - .await?; - for index_mutation in index_mutations { - output.add_index_mutation(index_mutation); - } - - // Send move token request to remote side: - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(move_token_request), - ); - } - } - (TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in), true) => { - // Push request: - router_db_client - .pending_user_requests_push_back(friend_public_key.clone(), currency, request) - .await?; - - // Resend outgoing move token, - // possibly asking for the token if we have something to send - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(MoveTokenRequest { - move_token: move_token_out, - token_wanted: is_pending_move_token( - router_db_client, - friend_public_key.clone(), - ) - .await?, - }), - ); - } - _ => { - // Friend is not ready to accept a request. - // We cancel the request: - output.add_incoming_cancel(CancelSendFundsOp { - request_id: request.request_id, - }); - } + flush_friend( + router_db_client, + friend_public_key.clone(), + identity_client, + local_public_key, + max_operations_in_batch, + &mut output, + ) + .await?; + } else { + output.add_incoming_cancel(CancelSendFundsOp { + request_id: request.request_id, + }); } Ok(output) From df54ce1f1d9d04febd5d9783086e03effb5d1b6e Mon Sep 17 00:00:00 2001 From: real Date: Fri, 8 Jan 2021 16:46:16 +0200 Subject: [PATCH 336/478] funder: comments --- components/funder/src/router/handle_friend.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index e32cdce02..d6d7d7cd1 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -118,6 +118,8 @@ where Ok(()) } +/// An incoming request was received, but due to insufficient trust we can not +/// forward this request. We return a cancel message to the sender friend async fn incoming_message_request_cancel( mut router_db_client: &mut RC, friend_public_key: PublicKey, @@ -129,7 +131,6 @@ async fn incoming_message_request_cancel( where RC: RouterDbClient, { - // Queue cancel to friend_public_key (Request origin) if router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -138,6 +139,7 @@ where .await? .is_consistent() { + // Queue cancel to friend_public_key (Request origin) router_db_client .pending_requests_push_back(friend_public_key.clone(), currency, request_send_funds) .await?; @@ -160,6 +162,12 @@ async fn incoming_message_response( where RC: RouterDbClient, { + // TODO: + // - Check if the origin of this message is local (How to do this?) + // - If so, punt response and quit + // - Find the origin of the request. + // - If nonexistent, do nothing + // - If found and consistent, queue response todo!(); } From baef946252f76c1ba58198049df83104fda3c908 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 8 Jan 2021 16:48:06 +0200 Subject: [PATCH 337/478] funder: Removed unused imports --- components/funder/src/router/handle_config.rs | 4 +--- components/funder/src/router/handle_relays.rs | 4 +--- components/funder/src/router/handle_route.rs | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 93a4f0ea2..d4009fa74 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -31,9 +31,7 @@ use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::{ create_index_mutations_from_move_token, create_update_index_mutation, }; -use crate::router::utils::move_token::{ - collect_outgoing_move_token, collect_outgoing_move_token_allow_empty, is_pending_move_token, -}; +use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; diff --git a/components/funder/src/router/handle_relays.rs b/components/funder/src/router/handle_relays.rs index 29a8e7f95..46b764d00 100644 --- a/components/funder/src/router/handle_relays.rs +++ b/components/funder/src/router/handle_relays.rs @@ -32,9 +32,7 @@ use crate::mutual_credit::incoming::IncomingMessage; use crate::router::utils::index_mutation::{ create_index_mutations_from_move_token, create_update_index_mutation, }; -use crate::router::utils::move_token::{ - collect_outgoing_move_token, collect_outgoing_move_token_allow_empty, is_pending_move_token, -}; +use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index c43a1c209..6967f6c1b 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -31,9 +31,7 @@ use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::{ create_index_mutations_from_move_token, create_update_index_mutation, }; -use crate::router::utils::move_token::{ - collect_outgoing_move_token, collect_outgoing_move_token_allow_empty, is_pending_move_token, -}; +use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; From d1c19528946c0809fb6a3412278507214b138690 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 8 Jan 2021 21:24:24 +0200 Subject: [PATCH 338/478] funder: Update send_request(): Avoid request duplication and remember local origin --- components/funder/src/router/handle_route.rs | 20 +++++++++++++++++++- components/funder/src/router/types.rs | 8 ++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index 6967f6c1b..9d769f804 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -52,6 +52,17 @@ pub async fn send_request( let mut output = RouterOutput::new(); + if router_db_client + .is_local_request_exists(request.request_id.clone()) + .await? + { + // We already have a local request with the same id. Return back a cancel. + output.add_incoming_cancel(CancelSendFundsOp { + request_id: request.request_id, + }); + return Ok(output); + } + // We cut the first two public keys from the route: // Pop first route public key: let route_local_public_key = request.route.remove(0); @@ -71,7 +82,7 @@ pub async fn send_request( // Friend is not ready to accept a request. // We cancel the request: output.add_incoming_cancel(CancelSendFundsOp { - request_id: request.request_id, + request_id: request.request_id.clone(), }); return Ok(output); }; @@ -84,11 +95,18 @@ pub async fn send_request( if tc_db_client.get_tc_status().await?.is_consistent() && router_state.liveness.is_online(&friend_public_key) { + // Keep request_id: + let request_id = request.request_id.clone(); + // Push request: router_db_client .pending_user_requests_push_back(friend_public_key.clone(), currency, request) .await?; + // Mark request as created locally, so that we remember to punt the corresponding + // response/cancel message later. + router_db_client.add_local_request(request_id).await?; + flush_friend( router_db_client, friend_public_key.clone(), diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 205d4e166..6be367b91 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -147,6 +147,9 @@ pub trait RouterDbClient { ) -> AsyncOpResult; */ + fn add_local_request(&mut self, request_id: Uid) -> AsyncOpResult<()>; + fn remove_local_request(&mut self, request_id: Uid) -> AsyncOpResult<()>; + fn pending_backwards_pop_front( &mut self, friend_public_key: PublicKey, @@ -183,6 +186,11 @@ pub trait RouterDbClient { friend_public_key: PublicKey, ) -> AsyncOpResult>; + /// Check if a `request_id` is already in use. + /// Searches all local pending requests, and all local open transactions. + fn is_local_request_exists(&mut self, request_id: Uid) -> AsyncOpResult; + + // TODO: What happens if impossible to push, due to duplicate request id? fn pending_requests_push_back( &mut self, friend_public_key: PublicKey, From cca5424e1b6da6771c9f96ae9014471ed76a776d Mon Sep 17 00:00:00 2001 From: real Date: Fri, 8 Jan 2021 21:28:56 +0200 Subject: [PATCH 339/478] funder: incoming_message_request: Avoid request_id duplication during forwarding --- components/funder/src/router/handle_friend.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index d6d7d7cd1..49315d835 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -68,7 +68,7 @@ where let next_public_key = request_send_funds.route.remove(0); // Check if next public key corresponds to a friend that is ready - let is_ready = if let Some(tc_db_client) = router_db_client + let should_forward = if let Some(tc_db_client) = router_db_client .tc_db_client(next_public_key.clone()) .await? { @@ -76,9 +76,12 @@ where } else { // next public key points to a nonexistent friend! false - } && router_state.liveness.is_online(&next_public_key); + } && router_state.liveness.is_online(&next_public_key) + && !router_db_client + .is_local_request_exists(request_send_funds.request_id.clone()) + .await?; - if is_ready { + if should_forward { // Queue request to friend and flush destination friend router_db_client .pending_requests_push_back(next_public_key.clone(), currency, request_send_funds) From cf59e6c3980eb3c7e4287716fdf1326f4234551f Mon Sep 17 00:00:00 2001 From: real Date: Sat, 9 Jan 2021 13:46:12 +0200 Subject: [PATCH 340/478] funder: impl incoming_message_{response,cancel} --- .../funder/src/mutual_credit/incoming.rs | 2 + components/funder/src/router/handle_friend.rs | 134 +++++++++++++++--- components/funder/src/router/types.rs | 5 + 3 files changed, 125 insertions(+), 16 deletions(-) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index bfe07de07..9cc339e3f 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -19,6 +19,8 @@ use crate::types::create_pending_transaction; use super::types::McDbClient; +// TODO: Do we ever need the `pending_transaction` part for anything? +// If not, maybe we can remove it? #[derive(Debug)] pub struct IncomingResponseSendFundsOp { pub pending_transaction: PendingTransaction, diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 49315d835..0654d04dd 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -159,40 +159,136 @@ async fn incoming_message_response( router_state: &mut RouterState, friend_public_key: PublicKey, identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, router_output: &mut RouterOutput, + currency: Currency, incoming_response: IncomingResponseSendFundsOp, ) -> Result<(), RouterError> where RC: RouterDbClient, { - // TODO: - // - Check if the origin of this message is local (How to do this?) - // - If so, punt response and quit - // - Find the origin of the request. - // - If nonexistent, do nothing - // - If found and consistent, queue response - todo!(); + // Gather information about request's origin: + let opt_request_origin = router_db_client + .get_remote_pending_request_origin(incoming_response.incoming_response.request_id.clone()) + .await?; + let is_local_origin = router_db_client + .is_request_local_origin(incoming_response.incoming_response.request_id.clone()) + .await?; + + match (is_local_origin, opt_request_origin) { + (false, None) => { + // Request was probably originated from a friend that became inconsistent. + // We have nothing to do here. + } + (true, None) => { + // Request has originated locally + // We punt the response + router_output.add_incoming_response(incoming_response.incoming_response); + } + (false, Some(request_origin)) => { + // Request has originated from a friend. + // We assume that friend must be consistent, otherwise it would have not been found as + // an origin. + + // Push response: + router_db_client + .pending_backwards_push_back( + friend_public_key.clone(), + currency, + BackwardsOp::Response(incoming_response.incoming_response), + ) + .await?; + + // Attempt to send a move token if possible + flush_friend( + router_db_client, + friend_public_key.clone(), + identity_client, + local_public_key, + max_operations_in_batch, + router_output, + ) + .await?; + } + (true, Some(request_origin)) => { + // This means the request has both originated locally, and from a friend. + // Note that this only happen during a cycle request, but a cycle always begins and + // ends at the local node. + // Therefore, this should never happen when processing a friend incoming response. + unreachable!(); + } + } + Ok(()) } +// TODO: This function seems too similar to`incoming_message_response` async fn incoming_message_cancel( mut router_db_client: &mut RC, router_state: &mut RouterState, friend_public_key: PublicKey, identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + max_operations_in_batch: usize, router_output: &mut RouterOutput, - cancel_send_funds: IncomingCancelSendFundsOp, + currency: Currency, + incoming_cancel: IncomingCancelSendFundsOp, ) -> Result<(), RouterError> where RC: RouterDbClient, { - // TODO: - // - Check if request origin is local - // - If so, punt cancel - // - Otherwise, find request friend origin - // - If found, forward cancel to friend if possible - // - What if inconsistent? - // - Flush friend - todo!(); + // Gather information about request's origin: + let opt_request_origin = router_db_client + .get_remote_pending_request_origin(incoming_cancel.incoming_cancel.request_id.clone()) + .await?; + let is_local_origin = router_db_client + .is_request_local_origin(incoming_cancel.incoming_cancel.request_id.clone()) + .await?; + + match (is_local_origin, opt_request_origin) { + (false, None) => { + // Request was probably originated from a friend that became inconsistent. + // We have nothing to do here. + } + (true, None) => { + // Request has originated locally + // We punt the cancel + router_output.add_incoming_cancel(incoming_cancel.incoming_cancel); + } + (false, Some(request_origin)) => { + // Request has originated from a friend. + // We assume that friend must be consistent, otherwise it would have not been found as + // an origin. + + // Push cancel: + router_db_client + .pending_backwards_push_back( + friend_public_key.clone(), + currency, + BackwardsOp::Cancel(incoming_cancel.incoming_cancel), + ) + .await?; + + // Attempt to send a move token if possible + flush_friend( + router_db_client, + friend_public_key.clone(), + identity_client, + local_public_key, + max_operations_in_batch, + router_output, + ) + .await?; + } + (true, Some(request_origin)) => { + // This means the request has both originated locally, and from a friend. + // Note that this only happen during a cycle request, but a cycle always begins and + // ends at the local node. + // Therefore, this should never happen when processing a friend incoming cancel. + unreachable!(); + } + } + Ok(()) } async fn incoming_move_token_request( @@ -301,7 +397,10 @@ where router_state, friend_public_key.clone(), identity_client, + local_public_key, + max_operations_in_batch, &mut output, + currency, incoming_response, ) .await @@ -312,7 +411,10 @@ where router_state, friend_public_key.clone(), identity_client, + local_public_key, + max_operations_in_batch, &mut output, + currency, incoming_cancel, ) .await diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 6be367b91..26bf44086 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -209,11 +209,16 @@ pub trait RouterDbClient { currency: Currency, ) -> AsyncOpResult>; + /// Check if the origin of the request is any of the friends + /// If so, find the relevant friend fn get_remote_pending_request_origin( &mut self, request_id: Uid, ) -> AsyncOpResult>; + /// Check if this request has originated from the local node + fn is_request_local_origin(&mut self, request_id: Uid) -> AsyncOpResult; + fn add_currency_config( &mut self, friend_public_key: PublicKey, From b6a22fd7e2f6a82691a04846cb0b9e1323eafdb5 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 9 Jan 2021 13:46:57 +0200 Subject: [PATCH 341/478] funder: Removed todo statement --- components/funder/src/router/handle_friend.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 0654d04dd..e094f2830 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -421,7 +421,6 @@ where } }?; } - todo!(); } ReceiveMoveTokenOutput::ChainInconsistent(reset_terms) => todo!(), // (local_reset_token, local_reset_move_token_counter) } From c2941093fe99f6156bd76672f4d4e10544df4630 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 9 Jan 2021 13:56:41 +0200 Subject: [PATCH 342/478] funder: Added missing remove_local_request() invocations --- components/funder/src/router/handle_config.rs | 4 ++++ components/funder/src/router/handle_friend.rs | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index d4009fa74..0823180e1 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -157,6 +157,10 @@ pub async fn set_friend_offline( .pending_user_requests_pop_front(friend_public_key.clone()) .await? { + // Clear the request from local requests list + router_db_client + .remove_local_request(pending_user_request.request_id.clone()) + .await?; // Send outgoing cancel to user: output.add_incoming_cancel(CancelSendFundsOp { request_id: pending_user_request.request_id, diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index e094f2830..efb3fac7e 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -183,6 +183,12 @@ where } (true, None) => { // Request has originated locally + + // Clear the request from local requests list + router_db_client + .remove_local_request(incoming_response.incoming_response.request_id.clone()) + .await?; + // We punt the response router_output.add_incoming_response(incoming_response.incoming_response); } @@ -252,6 +258,12 @@ where } (true, None) => { // Request has originated locally + + // Clear the request from local requests list + router_db_client + .remove_local_request(incoming_cancel.incoming_cancel.request_id.clone()) + .await?; + // We punt the cancel router_output.add_incoming_cancel(incoming_cancel.incoming_cancel); } From a7f9ee72fe04a0b0107430020d40245889cc9d1c Mon Sep 17 00:00:00 2001 From: real Date: Sat, 9 Jan 2021 13:56:52 +0200 Subject: [PATCH 343/478] funder: TODO comments --- components/funder/src/router/handle_friend.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index efb3fac7e..a83e429f4 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -434,7 +434,16 @@ where }?; } } - ReceiveMoveTokenOutput::ChainInconsistent(reset_terms) => todo!(), // (local_reset_token, local_reset_move_token_counter) + ReceiveMoveTokenOutput::ChainInconsistent(reset_terms) => { + // TODO: + // - Cancel relevant requests: + // - User pending requests + // - pending requests + // - + // - Send our reset terms + // - + todo!(); + } } Ok(output) From b8b4581be9e700be979a280892f59bdc77d1be8c Mon Sep 17 00:00:00 2001 From: real Date: Sat, 9 Jan 2021 13:59:05 +0200 Subject: [PATCH 344/478] funder: router: Refactored liveness code to a separate file --- components/funder/src/router/handle_config.rs | 170 -------------- .../funder/src/router/handle_liveness.rs | 207 ++++++++++++++++++ components/funder/src/router/mod.rs | 1 + 3 files changed, 208 insertions(+), 170 deletions(-) create mode 100644 components/funder/src/router/handle_liveness.rs diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 0823180e1..7f5342e09 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -36,176 +36,6 @@ use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; -pub async fn set_friend_online( - router_db_client: &mut impl RouterDbClient, - router_state: &mut RouterState, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - friend_public_key: PublicKey, - max_operations_in_batch: usize, -) -> Result { - // First we make sure that the friend exists: - let mut output = RouterOutput::new(); - let tc_status = if let Some(tc_db_client) = router_db_client - .tc_db_client(friend_public_key.clone()) - .await? - { - tc_db_client.get_tc_status().await? - } else { - return Ok(output); - }; - - if router_state.liveness.is_online(&friend_public_key) { - // The friend is already marked as online! - return Err(RouterError::FriendAlreadyOnline); - } - router_state.liveness.set_online(friend_public_key.clone()); - - // Check if we have any relays information to send to the remote side: - if let (Some(generation), relays) = router_db_client - .get_last_sent_relays(friend_public_key.clone()) - .await? - { - // Add a message for sending relays: - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), - ); - } - - match tc_status { - TcStatus::ConsistentIn(_) => { - // Create an outgoing move token if we have something to send. - let opt_move_token_request = collect_outgoing_move_token( - router_db_client, - identity_client, - local_public_key, - friend_public_key.clone(), - max_operations_in_batch, - ) - .await?; - - if let Some(move_token_request) = opt_move_token_request { - // We have something to send to remote side: - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(move_token_request), - ); - } - } - TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { - // Resend outgoing move token, - // possibly asking for the token if we have something to send - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(MoveTokenRequest { - move_token: move_token_out, - token_wanted: is_pending_move_token( - router_db_client, - friend_public_key.clone(), - ) - .await?, - }), - ); - } - TcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { - // Resend reset terms - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::InconsistencyError(local_reset_terms), - ); - } - } - - // Add an index mutation for all open currencies: - let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); - while let Some(res) = open_currencies.next().await { - let open_currency = res?; - - output.add_index_mutation(create_update_index_mutation( - friend_public_key.clone(), - open_currency, - )?); - } - - Ok(output) -} - -pub async fn set_friend_offline( - router_db_client: &mut impl RouterDbClient, - router_state: &mut RouterState, - friend_public_key: PublicKey, -) -> Result { - // First we make sure that the friend exists: - let mut output = RouterOutput::new(); - if router_db_client - .tc_db_client(friend_public_key.clone()) - .await? - .is_none() - { - return Ok(output); - } - - if !router_state.liveness.is_online(&friend_public_key) { - // The friend is already marked as offline! - return Err(RouterError::FriendAlreadyOffline); - } - router_state.liveness.set_offline(&friend_public_key); - - // Cancel all pending user requests - while let Some((_currency, pending_user_request)) = router_db_client - .pending_user_requests_pop_front(friend_public_key.clone()) - .await? - { - // Clear the request from local requests list - router_db_client - .remove_local_request(pending_user_request.request_id.clone()) - .await?; - // Send outgoing cancel to user: - output.add_incoming_cancel(CancelSendFundsOp { - request_id: pending_user_request.request_id, - }); - } - - // Cancel all pending requests - while let Some((currency, pending_request)) = router_db_client - .pending_requests_pop_front(friend_public_key.clone()) - .await? - { - // Find from which friend this pending request has originated from. - // Due to inconsistencies, it is possible that this pending request has no origin. - let opt_request_origin = router_db_client - .get_remote_pending_request_origin(pending_request.request_id.clone()) - .await?; - - if let Some(request_origin) = opt_request_origin { - // Cancel request by queue-ing a cancel into the relevant friend's queue: - router_db_client - .pending_backwards_push_back( - request_origin.friend_public_key, - request_origin.currency, - BackwardsOp::Cancel(CancelSendFundsOp { - request_id: pending_request.request_id, - }), - ) - .await?; - } - } - - // Add index mutations - // We send index mutations to remove all currencies that are considered open - let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); - while let Some(res) = open_currencies.next().await { - let open_currency = res?; - output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { - public_key: friend_public_key.clone(), - currency: open_currency.currency, - })); - } - - Ok(output) -} - pub async fn add_currency( router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs new file mode 100644 index 000000000..a98b6eff0 --- /dev/null +++ b/components/funder/src/router/handle_liveness.rs @@ -0,0 +1,207 @@ +use std::collections::{HashMap, HashSet}; + +use futures::StreamExt; + +use derive_more::From; + +use common::async_rpc::OpError; +use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; + +use database::transaction::Transaction; + +use identity::IdentityClient; + +use proto::app_server::messages::RelayAddressPort; +use proto::crypto::{NodePort, PublicKey}; +use proto::funder::messages::{ + CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, + FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, + ResponseSendFundsOp, +}; +use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; +use proto::net::messages::NetAddress; + +use crypto::rand::{CryptoRandom, RandGen}; + +use crate::route::Route; +use crate::router::types::{ + BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, +}; +use crate::router::utils::flush::flush_friend; +use crate::router::utils::index_mutation::{ + create_index_mutations_from_move_token, create_update_index_mutation, +}; +use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; +use crate::token_channel::{ + handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, +}; + +pub async fn set_friend_online( + router_db_client: &mut impl RouterDbClient, + router_state: &mut RouterState, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + friend_public_key: PublicKey, + max_operations_in_batch: usize, +) -> Result { + // First we make sure that the friend exists: + let mut output = RouterOutput::new(); + let tc_status = if let Some(tc_db_client) = router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + { + tc_db_client.get_tc_status().await? + } else { + return Ok(output); + }; + + if router_state.liveness.is_online(&friend_public_key) { + // The friend is already marked as online! + return Err(RouterError::FriendAlreadyOnline); + } + router_state.liveness.set_online(friend_public_key.clone()); + + // Check if we have any relays information to send to the remote side: + if let (Some(generation), relays) = router_db_client + .get_last_sent_relays(friend_public_key.clone()) + .await? + { + // Add a message for sending relays: + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), + ); + } + + match tc_status { + TcStatus::ConsistentIn(_) => { + // Create an outgoing move token if we have something to send. + let opt_move_token_request = collect_outgoing_move_token( + router_db_client, + identity_client, + local_public_key, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + if let Some(move_token_request) = opt_move_token_request { + // We have something to send to remote side: + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(move_token_request), + ); + } + } + TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { + // Resend outgoing move token, + // possibly asking for the token if we have something to send + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(MoveTokenRequest { + move_token: move_token_out, + token_wanted: is_pending_move_token( + router_db_client, + friend_public_key.clone(), + ) + .await?, + }), + ); + } + TcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { + // Resend reset terms + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::InconsistencyError(local_reset_terms), + ); + } + } + + // Add an index mutation for all open currencies: + let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); + while let Some(res) = open_currencies.next().await { + let open_currency = res?; + + output.add_index_mutation(create_update_index_mutation( + friend_public_key.clone(), + open_currency, + )?); + } + + Ok(output) +} + +pub async fn set_friend_offline( + router_db_client: &mut impl RouterDbClient, + router_state: &mut RouterState, + friend_public_key: PublicKey, +) -> Result { + // First we make sure that the friend exists: + let mut output = RouterOutput::new(); + if router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .is_none() + { + return Ok(output); + } + + if !router_state.liveness.is_online(&friend_public_key) { + // The friend is already marked as offline! + return Err(RouterError::FriendAlreadyOffline); + } + router_state.liveness.set_offline(&friend_public_key); + + // Cancel all pending user requests + while let Some((_currency, pending_user_request)) = router_db_client + .pending_user_requests_pop_front(friend_public_key.clone()) + .await? + { + // Clear the request from local requests list + router_db_client + .remove_local_request(pending_user_request.request_id.clone()) + .await?; + // Send outgoing cancel to user: + output.add_incoming_cancel(CancelSendFundsOp { + request_id: pending_user_request.request_id, + }); + } + + // Cancel all pending requests + while let Some((currency, pending_request)) = router_db_client + .pending_requests_pop_front(friend_public_key.clone()) + .await? + { + // Find from which friend this pending request has originated from. + // Due to inconsistencies, it is possible that this pending request has no origin. + let opt_request_origin = router_db_client + .get_remote_pending_request_origin(pending_request.request_id.clone()) + .await?; + + if let Some(request_origin) = opt_request_origin { + // Cancel request by queue-ing a cancel into the relevant friend's queue: + router_db_client + .pending_backwards_push_back( + request_origin.friend_public_key, + request_origin.currency, + BackwardsOp::Cancel(CancelSendFundsOp { + request_id: pending_request.request_id, + }), + ) + .await?; + } + } + + // Add index mutations + // We send index mutations to remove all currencies that are considered open + let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); + while let Some(res) = open_currencies.next().await { + let open_currency = res?; + output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { + public_key: friend_public_key.clone(), + currency: open_currency.currency, + })); + } + + Ok(output) +} diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 0e72a80e0..63ee61afc 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -2,6 +2,7 @@ mod utils; mod handle_config; mod handle_friend; +mod handle_liveness; mod handle_relays; mod handle_route; From cbf3137d5c63d2d6deb5a78711eab84f31309001 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 9 Jan 2021 14:26:24 +0200 Subject: [PATCH 345/478] funder: Updated plan to handle index mutations --- components/funder/src/router/handle_friend.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index a83e429f4..3b7364bda 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -376,6 +376,8 @@ where } } ReceiveMoveTokenOutput::Received(move_token_received) => { + // TODO: Handle index mutations here. + todo!(); for (currency, incoming_message) in move_token_received.incoming_messages { match incoming_message { IncomingMessage::Request(request_send_funds) => { @@ -439,9 +441,12 @@ where // - Cancel relevant requests: // - User pending requests // - pending requests - // - + // + // - Handle index mutations? + // // - Send our reset terms - // - + // + // - Notify to the outside? todo!(); } } From 357cfb2d3b81b9b848bf2e00138aef2c1e66b8db Mon Sep 17 00:00:00 2001 From: real Date: Sun, 10 Jan 2021 12:13:56 +0200 Subject: [PATCH 346/478] funder: Function rename --- components/funder/src/router/handle_config.rs | 2 +- components/funder/src/router/handle_friend.rs | 2 +- components/funder/src/router/handle_liveness.rs | 2 +- components/funder/src/router/handle_relays.rs | 2 +- components/funder/src/router/handle_route.rs | 2 +- components/funder/src/router/utils/flush.rs | 4 ++-- components/funder/src/router/utils/index_mutation.rs | 5 +++-- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 7f5342e09..e11a4b359 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -29,7 +29,7 @@ use crate::router::types::{ }; use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::{ - create_index_mutations_from_move_token, create_update_index_mutation, + create_index_mutations_from_outgoing_move_token, create_update_index_mutation, }; use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::token_channel::{ diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 3b7364bda..788b1ead7 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -33,7 +33,7 @@ use crate::mutual_credit::incoming::{ }; use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::{ - create_index_mutations_from_move_token, create_update_index_mutation, + create_index_mutations_from_outgoing_move_token, create_update_index_mutation, }; use crate::router::utils::move_token::{ collect_outgoing_move_token, collect_outgoing_move_token_allow_empty, is_pending_move_token, diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index a98b6eff0..a19622084 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -29,7 +29,7 @@ use crate::router::types::{ }; use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::{ - create_index_mutations_from_move_token, create_update_index_mutation, + create_index_mutations_from_outgoing_move_token, create_update_index_mutation, }; use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::token_channel::{ diff --git a/components/funder/src/router/handle_relays.rs b/components/funder/src/router/handle_relays.rs index 46b764d00..948145eb9 100644 --- a/components/funder/src/router/handle_relays.rs +++ b/components/funder/src/router/handle_relays.rs @@ -30,7 +30,7 @@ use crate::router::types::{ use crate::mutual_credit::incoming::IncomingMessage; use crate::router::utils::index_mutation::{ - create_index_mutations_from_move_token, create_update_index_mutation, + create_index_mutations_from_outgoing_move_token, create_update_index_mutation, }; use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::token_channel::{ diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index 9d769f804..e7f809629 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -29,7 +29,7 @@ use crate::router::types::{ }; use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::{ - create_index_mutations_from_move_token, create_update_index_mutation, + create_index_mutations_from_outgoing_move_token, create_update_index_mutation, }; use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::token_channel::{ diff --git a/components/funder/src/router/utils/flush.rs b/components/funder/src/router/utils/flush.rs index 04456494a..3cf7a39fb 100644 --- a/components/funder/src/router/utils/flush.rs +++ b/components/funder/src/router/utils/flush.rs @@ -26,7 +26,7 @@ use crate::route::Route; use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; -use crate::router::utils::index_mutation::create_index_mutations_from_move_token; +use crate::router::utils::index_mutation::create_index_mutations_from_outgoing_move_token; use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; /// Attempt to send as much as possible through a token channel to remote side @@ -61,7 +61,7 @@ pub async fn flush_friend( // We have something to send to remote side: // Update index mutations: - let index_mutations = create_index_mutations_from_move_token( + let index_mutations = create_index_mutations_from_outgoing_move_token( router_db_client, friend_public_key.clone(), &move_token_request.move_token, diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index 23b9533d9..85cb13e29 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -67,8 +67,9 @@ pub fn create_update_index_mutation( })) } -/// Create a list of index mutations based on a MoveToken message. -pub async fn create_index_mutations_from_move_token( +/// Create a list of index mutations based on an outgoing MoveToken message. +/// Note that the outgoing MoveToken message was already applied. +pub async fn create_index_mutations_from_outgoing_move_token( router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, move_token: &MoveToken, From e2fe04a838cb1ab71f4ea1edd221971e4aa63402 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 10 Jan 2021 12:18:57 +0200 Subject: [PATCH 347/478] funder: Comment --- .../funder/src/router/utils/index_mutation.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index 85cb13e29..6b4f2965b 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -74,6 +74,19 @@ pub async fn create_index_mutations_from_outgoing_move_token( friend_public_key: PublicKey, move_token: &MoveToken, ) -> Result, RouterError> { + // Strategy: + // - For every currency in currencies diff: + // - If currency is gone, send a RemoveFriendCurrency + // - If currency exists, send UpdateFriendCurrency + // - For the currencies from currencies operations, that were not in the currencies diff: + // - If currency is gone: Impossible + // - If currency exists: send UpdateFriendCurrency + // + // This strategy is consolidated into the following simplified strategy: + // - For each mentioned currency (currencies_diff or currencies_operations): + // - If currency is gone, send a RemoveFriendCurrency + // - If currency exists, send UpdateFriendCurrency + // Collect all mentioned currencies: let currencies = { let mut currencies = HashSet::new(); From 69eaf0dab7c6adef3a977b09545cf0ab2092ca98 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 10 Jan 2021 12:47:04 +0200 Subject: [PATCH 348/478] funder: Added TODO comments --- components/funder/src/router/handle_friend.rs | 2 ++ components/funder/src/router/handle_route.rs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 788b1ead7..a10d730da 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -318,6 +318,8 @@ where RC::TcDbClient: Transaction + Send, ::McDbClient: Send, { + // TODO: Do not forward if requests not enabled? / Friend not enabled? + todo!(); let mut output = RouterOutput::new(); let receive_move_token_output = handle_in_move_token( router_db_client diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index e7f809629..f5d719343 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -45,6 +45,9 @@ pub async fn send_request( local_public_key: &PublicKey, max_operations_in_batch: usize, ) -> Result { + // TODO: Do not forward if requests not enabled? / Friend not enabled? + todo!(); + // Make sure that the provided route is valid: if !request.route.is_valid() { return Err(RouterError::InvalidRoute); From 94dbe8b553f38c20461cabe942636b36ad708556 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 10 Jan 2021 15:41:53 +0200 Subject: [PATCH 349/478] funder: Removed unused imports --- components/funder/src/router/handle_config.rs | 4 +--- components/funder/src/router/handle_friend.rs | 4 +--- components/funder/src/router/handle_liveness.rs | 4 +--- components/funder/src/router/handle_relays.rs | 4 +--- components/funder/src/router/handle_route.rs | 4 +--- 5 files changed, 5 insertions(+), 15 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index e11a4b359..5e4857d3a 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -28,9 +28,7 @@ use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; use crate::router::utils::flush::flush_friend; -use crate::router::utils::index_mutation::{ - create_index_mutations_from_outgoing_move_token, create_update_index_mutation, -}; +use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index a10d730da..5ce1c7126 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -32,9 +32,7 @@ use crate::mutual_credit::incoming::{ IncomingCancelSendFundsOp, IncomingMessage, IncomingResponseSendFundsOp, }; use crate::router::utils::flush::flush_friend; -use crate::router::utils::index_mutation::{ - create_index_mutations_from_outgoing_move_token, create_update_index_mutation, -}; +use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::{ collect_outgoing_move_token, collect_outgoing_move_token_allow_empty, is_pending_move_token, }; diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index a19622084..afca578f7 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -28,9 +28,7 @@ use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; use crate::router::utils::flush::flush_friend; -use crate::router::utils::index_mutation::{ - create_index_mutations_from_outgoing_move_token, create_update_index_mutation, -}; +use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, diff --git a/components/funder/src/router/handle_relays.rs b/components/funder/src/router/handle_relays.rs index 948145eb9..49351e0a5 100644 --- a/components/funder/src/router/handle_relays.rs +++ b/components/funder/src/router/handle_relays.rs @@ -29,9 +29,7 @@ use crate::router::types::{ }; use crate::mutual_credit::incoming::IncomingMessage; -use crate::router::utils::index_mutation::{ - create_index_mutations_from_outgoing_move_token, create_update_index_mutation, -}; +use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index f5d719343..98625c62e 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -28,9 +28,7 @@ use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; use crate::router::utils::flush::flush_friend; -use crate::router::utils::index_mutation::{ - create_index_mutations_from_outgoing_move_token, create_update_index_mutation, -}; +use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, From 1bf5f10b546b97e3ec0e61782bbe068487c0c631 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 10 Jan 2021 18:11:09 +0200 Subject: [PATCH 350/478] funder: collect_outgoing_move_token() now calculates index mutations --- .../funder/src/router/handle_liveness.rs | 7 +- components/funder/src/router/handle_relays.rs | 2 +- components/funder/src/router/types.rs | 1 + components/funder/src/router/utils/flush.rs | 10 +- .../funder/src/router/utils/index_mutation.rs | 19 +- .../funder/src/router/utils/move_token.rs | 211 +++++++++++++++++- 6 files changed, 236 insertions(+), 14 deletions(-) diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index afca578f7..d6938fdfb 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -74,7 +74,7 @@ pub async fn set_friend_online( match tc_status { TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. - let opt_move_token_request = collect_outgoing_move_token( + let opt_tuple = collect_outgoing_move_token( router_db_client, identity_client, local_public_key, @@ -83,7 +83,10 @@ pub async fn set_friend_online( ) .await?; - if let Some(move_token_request) = opt_move_token_request { + if let Some((move_token_request, _index_mutations)) = opt_tuple { + // We discard index_mutations calculation here, because we are going to add all + // open currencies anyways. + // We have something to send to remote side: output.add_friend_message( friend_public_key.clone(), diff --git a/components/funder/src/router/handle_relays.rs b/components/funder/src/router/handle_relays.rs index 49351e0a5..770c88cec 100644 --- a/components/funder/src/router/handle_relays.rs +++ b/components/funder/src/router/handle_relays.rs @@ -30,7 +30,7 @@ use crate::router::types::{ use crate::mutual_credit::incoming::IncomingMessage; use crate::router::utils::index_mutation::create_update_index_mutation; -use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; +use crate::router::utils::move_token::is_pending_move_token; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 26bf44086..d8761f829 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -23,6 +23,7 @@ pub enum RouterError { FriendAlreadyOffline, GenerationOverflow, BalanceOverflow, + InvalidState, InvalidRoute, InvalidDbState, UnexpectedTcStatus, diff --git a/components/funder/src/router/utils/flush.rs b/components/funder/src/router/utils/flush.rs index 3cf7a39fb..396ee6486 100644 --- a/components/funder/src/router/utils/flush.rs +++ b/components/funder/src/router/utils/flush.rs @@ -48,7 +48,7 @@ pub async fn flush_friend( { TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. - let opt_move_token_request = collect_outgoing_move_token( + let opt_tuple = collect_outgoing_move_token( router_db_client, identity_client, local_public_key, @@ -57,16 +57,10 @@ pub async fn flush_friend( ) .await?; - if let Some(move_token_request) = opt_move_token_request { + if let Some((move_token_request, index_mutations)) = opt_tuple { // We have something to send to remote side: // Update index mutations: - let index_mutations = create_index_mutations_from_outgoing_move_token( - router_db_client, - friend_public_key.clone(), - &move_token_request.move_token, - ) - .await?; for index_mutation in index_mutations { router_output.add_index_mutation(index_mutation); } diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index 6b4f2965b..6a45ed645 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -28,7 +28,7 @@ use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenCha /// Calculate receive capacity for a certain currency /// This is the number we are going to report to an index server -fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result { +pub fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result { if !currency_info.is_open { return Ok(0); } @@ -124,3 +124,20 @@ pub async fn create_index_mutations_from_outgoing_move_token( Ok(index_mutations) } + +/// Create a list of index mutations based on an incoming MoveToken message. +/// Note that the incoming MoveToken message was already applied. +pub async fn create_index_mutations_from_incoming_move_token( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + move_token: &MoveToken, +) -> Result, RouterError> { + // Strategy: + // - For every currency in currencies diff: + // - If currency is gone, send nothing (Because it was already gone before) + // - If currency exists, send UpdateFriendCurrency + // - For the currencies from currencies operations, that were not in the currencies diff: + // - If currency is gone: Impossible + // - If currency exists: send UpdateFriendCurrency + todo!(); +} diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index de6c3088a..67dcb56fe 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -10,7 +10,7 @@ use common::safe_arithmetic::{SafeSignedArithmetic, SafeUnsignedArithmetic}; use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; -use proto::crypto::{NodePort, PublicKey}; +use proto::crypto::{NodePort, PublicKey, Signature}; use proto::funder::messages::{ CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, @@ -24,6 +24,7 @@ use crate::route::Route; use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; +use crate::router::utils::index_mutation::calc_recv_capacity; use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; /* @@ -150,6 +151,210 @@ pub async fn collect_outgoing_move_token_allow_empty( }) } +/// Like MoveToken, but without the calculated `info_hash` and `signature` +#[derive(Debug)] +struct PreMoveToken { + pub currencies_operations: CurrenciesOperations, + pub currencies_diff: Vec, +} + +/// Like MoveTokenRequest, but wrapping PreMoveToken instead of MoveToken. +#[derive(Debug)] +struct PreMoveTokenRequest { + pub pre_move_token: PreMoveToken, + pub token_wanted: bool, +} + +/// Attempt to create an outgoing move token +/// Collect any information we need to send to remote friend: +/// +/// - Currencies operations (requests, responses, cancels) +/// - Currencies diff (Added and removed currencies) +/// +/// Without actually sending this information yet. +/// Return Ok(None) if we have nothing to send +async fn collect_outgoing_pre_move_token( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + max_operations_in_batch: usize, +) -> Result, RouterError> { + let currencies_operations = collect_currencies_operations( + router_db_client, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + let mut currencies_diff = router_db_client + .currencies_diff(friend_public_key.clone()) + .await?; + + Ok( + if currencies_operations.is_empty() && currencies_diff.is_empty() { + // There is nothing interesting to send to remote side + None + } else { + // We have something to send to remote side + Some(PreMoveTokenRequest { + pre_move_token: PreMoveToken { + currencies_operations, + currencies_diff, + }, + token_wanted: is_pending_currencies_operations(router_db_client, friend_public_key) + .await?, + }) + }, + ) +} + +async fn send_pre_move_token( + router_db_client: &mut impl RouterDbClient, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + friend_public_key: PublicKey, + pre_move_token_request: PreMoveTokenRequest, +) -> Result { + let move_token = handle_out_move_token( + router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .ok_or(RouterError::InvalidDbState)?, + identity_client, + pre_move_token_request.pre_move_token.currencies_operations, + pre_move_token_request.pre_move_token.currencies_diff, + local_public_key, + &friend_public_key, + ) + .await?; + + Ok(MoveTokenRequest { + move_token, + token_wanted: pre_move_token_request.token_wanted, + }) +} + +// TODO: Refactor this function. +// There are too many repeating parts. +pub async fn collect_outgoing_move_token( + router_db_client: &mut impl RouterDbClient, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + friend_public_key: PublicKey, + max_operations_in_batch: usize, +) -> Result)>, RouterError> { + let opt_pre_move_token_request = collect_outgoing_pre_move_token( + router_db_client, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + let pre_move_token_request = if let Some(pre_move_token_request) = opt_pre_move_token_request { + pre_move_token_request + } else { + return Ok(None); + }; + + // Collect all mentioned currencies: + let currencies = { + let mut currencies = HashSet::new(); + for currency in &pre_move_token_request.pre_move_token.currencies_diff { + currencies.insert(currency.clone()); + } + + for (currency, _operation) in &pre_move_token_request.pre_move_token.currencies_operations { + currencies.insert(currency.clone()); + } + currencies + }; + + // Record recv capacity for all interesting currencies + let recv_capacities_before = { + let mut recv_capacities_before = HashMap::::new(); + for currency in ¤cies { + let opt_currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await?; + let recv_capacity = if let Some(currency_info) = opt_currency_info { + calc_recv_capacity(¤cy_info)? + } else { + 0u128 + }; + + recv_capacities_before.insert(currency.clone(), recv_capacity); + } + recv_capacities_before + }; + + // Send MoveToken: + let move_token_request = send_pre_move_token( + router_db_client, + identity_client, + local_public_key, + friend_public_key.clone(), + pre_move_token_request, + ) + .await?; + + // Record recv capacity for all interesting currencies + let recv_capacities_after = { + let mut recv_capacities_after = HashMap::::new(); + for currency in ¤cies { + let opt_currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await?; + let recv_capacity = if let Some(currency_info) = opt_currency_info { + calc_recv_capacity(¤cy_info)? + } else { + 0u128 + }; + + recv_capacities_after.insert(currency.clone(), recv_capacity); + } + recv_capacities_after + }; + + // Compare recv capacities and create index mutations: + let mut index_mutations = Vec::new(); + + // TODO: + for currency in ¤cies { + let capacity_before = recv_capacities_before + .get(currency) + .ok_or(RouterError::InvalidState)?; + + let capacity_after = recv_capacities_after + .get(currency) + .ok_or(RouterError::InvalidState)?; + + // TODO: We already invoked get_currency_info() when we obtained capacity_after. + // This means we can be more efficient, possibly only calling get_currency_info() once. + let currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await? + .ok_or(RouterError::InvalidState)?; + + if capacity_before != capacity_after { + if *capacity_after == 0 { + index_mutations.push(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { + public_key: friend_public_key.clone(), + currency: currency.clone(), + })); + } else { + index_mutations.push(IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { + public_key: friend_public_key.clone(), + currency: currency.clone(), + recv_capacity: *capacity_after, + rate: currency_info.rate, + })); + } + } + } + + Ok(Some((move_token_request, index_mutations))) +} + +/* /// Attempt to create an outgoing move token /// Return Ok(None) if we have nothing to send pub async fn collect_outgoing_move_token( @@ -160,7 +365,8 @@ pub async fn collect_outgoing_move_token( max_operations_in_batch: usize, ) -> Result, RouterError> { let currencies_operations = collect_currencies_operations( - router_db_client, + + router_db_client, friend_public_key.clone(), max_operations_in_batch, ) @@ -196,6 +402,7 @@ pub async fn collect_outgoing_move_token( }, ) } +*/ /// Check if we have anything to send to a remove friend on a move token message, /// without performing any data mutations From 5d480fa7976436be3dbcb89bcef082e47549480b Mon Sep 17 00:00:00 2001 From: real Date: Sun, 10 Jan 2021 18:42:58 +0200 Subject: [PATCH 351/478] funder: Refactored collect_outgoing_move_token() --- .../funder/src/router/utils/move_token.rs | 197 +++++++++++------- 1 file changed, 120 insertions(+), 77 deletions(-) diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 67dcb56fe..9a11991d7 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -233,6 +233,96 @@ async fn send_pre_move_token( }) } +/// Collect all mentioned currencies from a PreMoveToken +fn get_mentioned_currencies(pre_move_token: &PreMoveToken) -> HashSet { + // Collect all mentioned currencies: + let mut currencies = HashSet::new(); + for currency in &pre_move_token.currencies_diff { + currencies.insert(currency.clone()); + } + + for (currency, _operation) in &pre_move_token.currencies_operations { + currencies.insert(currency.clone()); + } + + currencies +} + +async fn get_currencies_info( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currencies: &[Currency], +) -> Result, RouterError> { + let mut currencies_info = HashMap::::new(); + for currency in currencies.iter() { + let opt_currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await?; + + if let Some(currency_info) = opt_currency_info { + currencies_info.insert(currency.clone(), currency_info); + } + } + Ok(currencies_info) +} + +/// Get receive capacities for a given list of currencies +fn get_recv_capacities( + currencies_info: &HashMap, + friend_public_key: PublicKey, + currencies: &[Currency], +) -> Result, RouterError> { + let mut recv_capacities = HashMap::::new(); + for currency in currencies.iter() { + let recv_capacity = if let Some(currency_info) = currencies_info.get(currency) { + calc_recv_capacity(¤cy_info)? + } else { + 0u128 + }; + + recv_capacities.insert(currency.clone(), recv_capacity); + } + Ok(recv_capacities) +} + +fn diff_capacities( + friend_public_key: PublicKey, + capacities_before: &HashMap, + capacities_after: &HashMap, + currencies_info: &HashMap, +) -> Result, RouterError> { + let mut index_mutations = Vec::new(); + for (currency, capacity_before) in capacities_before { + let capacity_after = capacities_after + .get(¤cy) + .ok_or(RouterError::InvalidState)?; + + // let currency_info = currencies_info.get(currency + + if capacity_before != capacity_after { + if *capacity_after == 0 { + index_mutations.push(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { + public_key: friend_public_key.clone(), + currency: currency.clone(), + })); + } else { + // We should have this currency's info if the capacity after is nonzero: + let currency_info = currencies_info + .get(¤cy) + .ok_or(RouterError::InvalidState)?; + + index_mutations.push(IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { + public_key: friend_public_key.clone(), + currency: currency.clone(), + recv_capacity: *capacity_after, + rate: currency_info.rate.clone(), + })); + } + } + } + Ok(index_mutations) +} + // TODO: Refactor this function. // There are too many repeating parts. pub async fn collect_outgoing_move_token( @@ -256,35 +346,21 @@ pub async fn collect_outgoing_move_token( }; // Collect all mentioned currencies: - let currencies = { - let mut currencies = HashSet::new(); - for currency in &pre_move_token_request.pre_move_token.currencies_diff { - currencies.insert(currency.clone()); - } + let currencies = get_mentioned_currencies(&pre_move_token_request.pre_move_token); - for (currency, _operation) in &pre_move_token_request.pre_move_token.currencies_operations { - currencies.insert(currency.clone()); - } - currencies - }; + let currencies_info_before = get_currencies_info( + router_db_client, + friend_public_key.clone(), + currencies.iter().cloned().collect::>().as_slice(), + ) + .await?; // Record recv capacity for all interesting currencies - let recv_capacities_before = { - let mut recv_capacities_before = HashMap::::new(); - for currency in ¤cies { - let opt_currency_info = router_db_client - .get_currency_info(friend_public_key.clone(), currency.clone()) - .await?; - let recv_capacity = if let Some(currency_info) = opt_currency_info { - calc_recv_capacity(¤cy_info)? - } else { - 0u128 - }; - - recv_capacities_before.insert(currency.clone(), recv_capacity); - } - recv_capacities_before - }; + let recv_capacities_before = get_recv_capacities( + ¤cies_info_before, + friend_public_key.clone(), + currencies.iter().cloned().collect::>().as_slice(), + )?; // Send MoveToken: let move_token_request = send_pre_move_token( @@ -296,60 +372,27 @@ pub async fn collect_outgoing_move_token( ) .await?; - // Record recv capacity for all interesting currencies - let recv_capacities_after = { - let mut recv_capacities_after = HashMap::::new(); - for currency in ¤cies { - let opt_currency_info = router_db_client - .get_currency_info(friend_public_key.clone(), currency.clone()) - .await?; - let recv_capacity = if let Some(currency_info) = opt_currency_info { - calc_recv_capacity(¤cy_info)? - } else { - 0u128 - }; + let currencies_info_after = get_currencies_info( + router_db_client, + friend_public_key.clone(), + currencies.iter().cloned().collect::>().as_slice(), + ) + .await?; - recv_capacities_after.insert(currency.clone(), recv_capacity); - } - recv_capacities_after - }; + // Record recv capacity for all interesting currencies + let recv_capacities_after = get_recv_capacities( + ¤cies_info_after, + friend_public_key.clone(), + currencies.iter().cloned().collect::>().as_slice(), + )?; // Compare recv capacities and create index mutations: - let mut index_mutations = Vec::new(); - - // TODO: - for currency in ¤cies { - let capacity_before = recv_capacities_before - .get(currency) - .ok_or(RouterError::InvalidState)?; - - let capacity_after = recv_capacities_after - .get(currency) - .ok_or(RouterError::InvalidState)?; - - // TODO: We already invoked get_currency_info() when we obtained capacity_after. - // This means we can be more efficient, possibly only calling get_currency_info() once. - let currency_info = router_db_client - .get_currency_info(friend_public_key.clone(), currency.clone()) - .await? - .ok_or(RouterError::InvalidState)?; - - if capacity_before != capacity_after { - if *capacity_after == 0 { - index_mutations.push(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { - public_key: friend_public_key.clone(), - currency: currency.clone(), - })); - } else { - index_mutations.push(IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { - public_key: friend_public_key.clone(), - currency: currency.clone(), - recv_capacity: *capacity_after, - rate: currency_info.rate, - })); - } - } - } + let index_mutations = diff_capacities( + friend_public_key, + &recv_capacities_before, + &recv_capacities_after, + ¤cies_info_after, + )?; Ok(Some((move_token_request, index_mutations))) } From bcfb9a46709d554ee3a9f1e0a826addbf7b6fc3f Mon Sep 17 00:00:00 2001 From: real Date: Sun, 10 Jan 2021 18:43:13 +0200 Subject: [PATCH 352/478] funder: Removed TODO comment --- components/funder/src/router/utils/move_token.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 9a11991d7..55ad19470 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -323,8 +323,6 @@ fn diff_capacities( Ok(index_mutations) } -// TODO: Refactor this function. -// There are too many repeating parts. pub async fn collect_outgoing_move_token( router_db_client: &mut impl RouterDbClient, identity_client: &mut IdentityClient, From 3f7fce79f508db4db56b8445defc70a0ed1263c7 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 10 Jan 2021 21:32:39 +0200 Subject: [PATCH 353/478] funder: get_mentioned_currencies() now returns a Vec. --- .../funder/src/router/utils/move_token.rs | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 55ad19470..c487a416e 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -234,7 +234,7 @@ async fn send_pre_move_token( } /// Collect all mentioned currencies from a PreMoveToken -fn get_mentioned_currencies(pre_move_token: &PreMoveToken) -> HashSet { +fn get_mentioned_currencies(pre_move_token: &PreMoveToken) -> Vec { // Collect all mentioned currencies: let mut currencies = HashSet::new(); for currency in &pre_move_token.currencies_diff { @@ -245,7 +245,7 @@ fn get_mentioned_currencies(pre_move_token: &PreMoveToken) -> HashSet currencies.insert(currency.clone()); } - currencies + currencies.into_iter().collect() } async fn get_currencies_info( @@ -346,18 +346,14 @@ pub async fn collect_outgoing_move_token( // Collect all mentioned currencies: let currencies = get_mentioned_currencies(&pre_move_token_request.pre_move_token); - let currencies_info_before = get_currencies_info( - router_db_client, - friend_public_key.clone(), - currencies.iter().cloned().collect::>().as_slice(), - ) - .await?; + let currencies_info_before = + get_currencies_info(router_db_client, friend_public_key.clone(), ¤cies).await?; // Record recv capacity for all interesting currencies let recv_capacities_before = get_recv_capacities( ¤cies_info_before, friend_public_key.clone(), - currencies.iter().cloned().collect::>().as_slice(), + ¤cies, )?; // Send MoveToken: @@ -370,18 +366,14 @@ pub async fn collect_outgoing_move_token( ) .await?; - let currencies_info_after = get_currencies_info( - router_db_client, - friend_public_key.clone(), - currencies.iter().cloned().collect::>().as_slice(), - ) - .await?; + let currencies_info_after = + get_currencies_info(router_db_client, friend_public_key.clone(), ¤cies).await?; // Record recv capacity for all interesting currencies let recv_capacities_after = get_recv_capacities( ¤cies_info_after, friend_public_key.clone(), - currencies.iter().cloned().collect::>().as_slice(), + ¤cies, )?; // Compare recv capacities and create index mutations: From 3e0642c67117a9a4f17a8c98107bf305261acd17 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 10 Jan 2021 21:36:22 +0200 Subject: [PATCH 354/478] funder: Removed redundant comment --- components/funder/src/router/utils/move_token.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index c487a416e..754f00ad8 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -297,8 +297,6 @@ fn diff_capacities( .get(¤cy) .ok_or(RouterError::InvalidState)?; - // let currency_info = currencies_info.get(currency - if capacity_before != capacity_after { if *capacity_after == 0 { index_mutations.push(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { From 69cd33f27ebe63270203230cf957a250bceb1cb3 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 10 Jan 2021 21:44:01 +0200 Subject: [PATCH 355/478] funder: Removed comment --- .../funder/src/router/utils/move_token.rs | 50 ------------------- 1 file changed, 50 deletions(-) diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 754f00ad8..19ce89993 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -385,56 +385,6 @@ pub async fn collect_outgoing_move_token( Ok(Some((move_token_request, index_mutations))) } -/* -/// Attempt to create an outgoing move token -/// Return Ok(None) if we have nothing to send -pub async fn collect_outgoing_move_token( - router_db_client: &mut impl RouterDbClient, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - friend_public_key: PublicKey, - max_operations_in_batch: usize, -) -> Result, RouterError> { - let currencies_operations = collect_currencies_operations( - - router_db_client, - friend_public_key.clone(), - max_operations_in_batch, - ) - .await?; - - let mut currencies_diff = router_db_client - .currencies_diff(friend_public_key.clone()) - .await?; - - Ok( - if currencies_operations.is_empty() && currencies_diff.is_empty() { - // There is nothing interesting to send to remote side - None - } else { - // We have something to send to remote side - let move_token = handle_out_move_token( - router_db_client - .tc_db_client(friend_public_key.clone()) - .await? - .ok_or(RouterError::InvalidDbState)?, - identity_client, - currencies_operations, - currencies_diff, - local_public_key, - &friend_public_key, - ) - .await?; - Some(MoveTokenRequest { - move_token, - token_wanted: is_pending_currencies_operations(router_db_client, friend_public_key) - .await?, - }) - }, - ) -} -*/ - /// Check if we have anything to send to a remove friend on a move token message, /// without performing any data mutations pub async fn is_pending_move_token( From 525f10be15c01d9ecce7e9bc1e0feacc63722ce2 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 10 Jan 2021 22:29:59 +0200 Subject: [PATCH 356/478] funder: handle_in_move_token_index_mutations() --- components/funder/src/router/handle_config.rs | 4 +- components/funder/src/router/handle_friend.rs | 33 +++++--- .../funder/src/router/handle_liveness.rs | 6 +- components/funder/src/router/handle_route.rs | 4 +- components/funder/src/router/utils/flush.rs | 6 +- .../funder/src/router/utils/move_token.rs | 75 ++++++++++++++++++- .../funder/src/token_channel/token_channel.rs | 1 - 7 files changed, 108 insertions(+), 21 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 5e4857d3a..f2dd6fa62 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -29,7 +29,9 @@ use crate::router::types::{ }; use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_update_index_mutation; -use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; +use crate::router::utils::move_token::{ + handle_out_move_token_index_mutations, is_pending_move_token, +}; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 5ce1c7126..a0292613e 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -34,11 +34,10 @@ use crate::mutual_credit::incoming::{ use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::{ - collect_outgoing_move_token, collect_outgoing_move_token_allow_empty, is_pending_move_token, -}; -use crate::token_channel::{ - handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, + collect_outgoing_move_token_allow_empty, handle_in_move_token_index_mutations, + handle_out_move_token_index_mutations, is_pending_move_token, }; +use crate::token_channel::{ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError}; async fn incoming_message_request( mut router_db_client: &mut RC, @@ -319,15 +318,13 @@ where // TODO: Do not forward if requests not enabled? / Friend not enabled? todo!(); let mut output = RouterOutput::new(); - let receive_move_token_output = handle_in_move_token( - router_db_client - .tc_db_client(friend_public_key.clone()) - .await? - .ok_or(RouterError::InvalidDbState)?, + + let (receive_move_token_output, index_mutations) = handle_in_move_token_index_mutations( + router_db_client, identity_client, move_token_request.move_token, local_public_key, - &friend_public_key, + friend_public_key.clone(), ) .await?; @@ -339,6 +336,10 @@ where // Possibly send token to remote side (According to token_wanted) if move_token_request.token_wanted { + // TODO: What about index mutations here (Allow empty) + // How to elegantly create a separate version for creation of outgoing move token, + // allowing an empty move token? + todo!(); let out_move_token_request = collect_outgoing_move_token_allow_empty( router_db_client, identity_client, @@ -376,8 +377,6 @@ where } } ReceiveMoveTokenOutput::Received(move_token_received) => { - // TODO: Handle index mutations here. - todo!(); for (currency, incoming_message) in move_token_received.incoming_messages { match incoming_message { IncomingMessage::Request(request_send_funds) => { @@ -435,6 +434,11 @@ where } }?; } + + // TODO: Possibly send MoveToken back to friend in one of the following cases: + // - We have something to send + // - The friend has asked for the token back + todo!(); } ReceiveMoveTokenOutput::ChainInconsistent(reset_terms) => { // TODO: @@ -451,6 +455,11 @@ where } } + // Add index mutations: + for index_mutation in index_mutations { + output.add_index_mutation(index_mutation); + } + Ok(output) } diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index d6938fdfb..c3e0bc65c 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -29,7 +29,9 @@ use crate::router::types::{ }; use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_update_index_mutation; -use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; +use crate::router::utils::move_token::{ + handle_out_move_token_index_mutations, is_pending_move_token, +}; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; @@ -74,7 +76,7 @@ pub async fn set_friend_online( match tc_status { TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. - let opt_tuple = collect_outgoing_move_token( + let opt_tuple = handle_out_move_token_index_mutations( router_db_client, identity_client, local_public_key, diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index 98625c62e..cd3a941bf 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -29,7 +29,9 @@ use crate::router::types::{ }; use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_update_index_mutation; -use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; +use crate::router::utils::move_token::{ + handle_out_move_token_index_mutations, is_pending_move_token, +}; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; diff --git a/components/funder/src/router/utils/flush.rs b/components/funder/src/router/utils/flush.rs index 396ee6486..c544ad908 100644 --- a/components/funder/src/router/utils/flush.rs +++ b/components/funder/src/router/utils/flush.rs @@ -27,7 +27,9 @@ use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; use crate::router::utils::index_mutation::create_index_mutations_from_outgoing_move_token; -use crate::router::utils::move_token::{collect_outgoing_move_token, is_pending_move_token}; +use crate::router::utils::move_token::{ + handle_out_move_token_index_mutations, is_pending_move_token, +}; /// Attempt to send as much as possible through a token channel to remote side /// Assumes that the token channel is in consistent state (Incoming / Outgoing). @@ -48,7 +50,7 @@ pub async fn flush_friend( { TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. - let opt_tuple = collect_outgoing_move_token( + let opt_tuple = handle_out_move_token_index_mutations( router_db_client, identity_client, local_public_key, diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 19ce89993..d83920033 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -20,12 +20,17 @@ use proto::net::messages::NetAddress; use crypto::rand::{CryptoRandom, RandGen}; +use database::transaction::Transaction; + use crate::route::Route; use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; use crate::router::utils::index_mutation::calc_recv_capacity; -use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; +use crate::token_channel::{ + handle_in_move_token, handle_out_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, + TokenChannelError, +}; /* fn operations_vec_to_currencies_operations( @@ -111,6 +116,8 @@ async fn is_pending_currencies_operations( .await?) } +// TODO: Rewrite this function to also return index mutations. +// Should be very similar to `handle_in_move_token_index_mutations`. /// Attempt to create an outgoing move token /// May create an empty move token. pub async fn collect_outgoing_move_token_allow_empty( @@ -120,6 +127,7 @@ pub async fn collect_outgoing_move_token_allow_empty( friend_public_key: PublicKey, max_operations_in_batch: usize, ) -> Result { + todo!(); let currencies_operations = collect_currencies_operations( router_db_client, friend_public_key.clone(), @@ -321,7 +329,7 @@ fn diff_capacities( Ok(index_mutations) } -pub async fn collect_outgoing_move_token( +pub async fn handle_out_move_token_index_mutations( router_db_client: &mut impl RouterDbClient, identity_client: &mut IdentityClient, local_public_key: &PublicKey, @@ -399,3 +407,66 @@ pub async fn is_pending_move_token( .is_empty(), ) } + +pub async fn handle_in_move_token_index_mutations( + router_db_client: &mut RC, + identity_client: &mut IdentityClient, + move_token: MoveToken, + local_public_key: &PublicKey, + friend_public_key: PublicKey, +) -> Result<(ReceiveMoveTokenOutput, Vec), RouterError> +where + RC: RouterDbClient, + RC::TcDbClient: Transaction + Send, + ::McDbClient: Send, +{ + // Get list of interesting currencies: + let pre_move_token = PreMoveToken { + currencies_operations: move_token.currencies_operations.clone(), + currencies_diff: move_token.currencies_diff.clone(), + }; + let currencies = get_mentioned_currencies(&pre_move_token); + + // Record recv capacity for all interesting currencies + let currencies_info_before = + get_currencies_info(router_db_client, friend_public_key.clone(), ¤cies).await?; + + let recv_capacities_before = get_recv_capacities( + ¤cies_info_before, + friend_public_key.clone(), + ¤cies, + )?; + + // Handle incoming move token: + let receive_move_token_output = handle_in_move_token( + router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .ok_or(RouterError::InvalidDbState)?, + identity_client, + move_token, + local_public_key, + &friend_public_key, + ) + .await?; + + let currencies_info_after = + get_currencies_info(router_db_client, friend_public_key.clone(), ¤cies).await?; + + // Record recv capacity for all interesting currencies + let recv_capacities_after = get_recv_capacities( + ¤cies_info_after, + friend_public_key.clone(), + ¤cies, + )?; + + // Compare recv capacities and create index mutations: + let index_mutations = diff_capacities( + friend_public_key, + &recv_capacities_before, + &recv_capacities_after, + ¤cies_info_after, + )?; + + Ok((receive_move_token_output, index_mutations)) +} diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 69c63f044..78c59544c 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -237,7 +237,6 @@ pub async fn handle_in_move_token( remote_public_key: &PublicKey, ) -> Result where - // TODO: Can we somehow get rid of the Sync requirement for `B`? C: TcDbClient + Transaction + Send, C::McDbClient: Send, { From 00536dbf3d382c22650b1313c8348f6588717ff2 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 12 Jan 2021 16:49:58 +0200 Subject: [PATCH 357/478] funder: Updated handle_out_move_token... impl --- components/funder/src/router/handle_config.rs | 4 +- components/funder/src/router/handle_friend.rs | 34 +++-- .../funder/src/router/handle_liveness.rs | 4 +- components/funder/src/router/handle_route.rs | 4 +- components/funder/src/router/utils/flush.rs | 4 +- .../funder/src/router/utils/move_token.rs | 126 +++++++++++++----- 6 files changed, 115 insertions(+), 61 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index f2dd6fa62..7c334527e 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -29,9 +29,7 @@ use crate::router::types::{ }; use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_update_index_mutation; -use crate::router::utils::move_token::{ - handle_out_move_token_index_mutations, is_pending_move_token, -}; +use crate::router::utils::move_token::is_pending_move_token; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index a0292613e..c9c526f13 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -34,8 +34,8 @@ use crate::mutual_credit::incoming::{ use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::{ - collect_outgoing_move_token_allow_empty, handle_in_move_token_index_mutations, - handle_out_move_token_index_mutations, is_pending_move_token, + handle_in_move_token_index_mutations, handle_out_move_token_index_mutations_allow_empty, + is_pending_move_token, }; use crate::token_channel::{ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError}; @@ -328,6 +328,11 @@ where ) .await?; + // Add mutations: + for index_mutation in index_mutations { + output.add_index_mutation(index_mutation); + } + match receive_move_token_output { ReceiveMoveTokenOutput::Duplicate => { // We should have nothing else to send at this point, otherwise we would have already @@ -336,24 +341,25 @@ where // Possibly send token to remote side (According to token_wanted) if move_token_request.token_wanted { - // TODO: What about index mutations here (Allow empty) - // How to elegantly create a separate version for creation of outgoing move token, - // allowing an empty move token? - todo!(); - let out_move_token_request = collect_outgoing_move_token_allow_empty( - router_db_client, - identity_client, - local_public_key, - friend_public_key.clone(), - max_operations_in_batch, - ) - .await?; + let (out_move_token_request, index_mutations) = + handle_out_move_token_index_mutations_allow_empty( + router_db_client, + identity_client, + local_public_key, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; // TODO: Should we really check for liveness here? We just got a message from this // friend. Think about liveness design here. What if we ever forget to check for // liveness before adding a friend message? Maybe this should be checked in // different way, or a different layer? if router_state.liveness.is_online(&friend_public_key) { + // Add index mutations: + for index_mutation in index_mutations { + output.add_index_mutation(index_mutation); + } output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(out_move_token_request), diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index c3e0bc65c..37477704c 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -30,7 +30,7 @@ use crate::router::types::{ use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::{ - handle_out_move_token_index_mutations, is_pending_move_token, + handle_out_move_token_index_mutations_disallow_empty, is_pending_move_token, }; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, @@ -76,7 +76,7 @@ pub async fn set_friend_online( match tc_status { TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. - let opt_tuple = handle_out_move_token_index_mutations( + let opt_tuple = handle_out_move_token_index_mutations_disallow_empty( router_db_client, identity_client, local_public_key, diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index cd3a941bf..5291efa51 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -29,9 +29,7 @@ use crate::router::types::{ }; use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_update_index_mutation; -use crate::router::utils::move_token::{ - handle_out_move_token_index_mutations, is_pending_move_token, -}; +use crate::router::utils::move_token::is_pending_move_token; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; diff --git a/components/funder/src/router/utils/flush.rs b/components/funder/src/router/utils/flush.rs index c544ad908..24183c263 100644 --- a/components/funder/src/router/utils/flush.rs +++ b/components/funder/src/router/utils/flush.rs @@ -28,7 +28,7 @@ use crate::router::types::{ }; use crate::router::utils::index_mutation::create_index_mutations_from_outgoing_move_token; use crate::router::utils::move_token::{ - handle_out_move_token_index_mutations, is_pending_move_token, + handle_out_move_token_index_mutations_disallow_empty, is_pending_move_token, }; /// Attempt to send as much as possible through a token channel to remote side @@ -50,7 +50,7 @@ pub async fn flush_friend( { TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. - let opt_tuple = handle_out_move_token_index_mutations( + let opt_tuple = handle_out_move_token_index_mutations_disallow_empty( router_db_client, identity_client, local_public_key, diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index d83920033..b793d2065 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -116,6 +116,7 @@ async fn is_pending_currencies_operations( .await?) } +/* // TODO: Rewrite this function to also return index mutations. // Should be very similar to `handle_in_move_token_index_mutations`. /// Attempt to create an outgoing move token @@ -158,6 +159,7 @@ pub async fn collect_outgoing_move_token_allow_empty( token_wanted: is_pending_currencies_operations(router_db_client, friend_public_key).await?, }) } +*/ /// Like MoveToken, but without the calculated `info_hash` and `signature` #[derive(Debug)] @@ -185,7 +187,7 @@ async fn collect_outgoing_pre_move_token( router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, max_operations_in_batch: usize, -) -> Result, RouterError> { +) -> Result, RouterError> { let currencies_operations = collect_currencies_operations( router_db_client, friend_public_key.clone(), @@ -203,13 +205,9 @@ async fn collect_outgoing_pre_move_token( None } else { // We have something to send to remote side - Some(PreMoveTokenRequest { - pre_move_token: PreMoveToken { - currencies_operations, - currencies_diff, - }, - token_wanted: is_pending_currencies_operations(router_db_client, friend_public_key) - .await?, + Some(PreMoveToken { + currencies_operations, + currencies_diff, }) }, ) @@ -220,25 +218,22 @@ async fn send_pre_move_token( identity_client: &mut IdentityClient, local_public_key: &PublicKey, friend_public_key: PublicKey, - pre_move_token_request: PreMoveTokenRequest, -) -> Result { + pre_move_token: PreMoveToken, +) -> Result { let move_token = handle_out_move_token( router_db_client .tc_db_client(friend_public_key.clone()) .await? .ok_or(RouterError::InvalidDbState)?, identity_client, - pre_move_token_request.pre_move_token.currencies_operations, - pre_move_token_request.pre_move_token.currencies_diff, + pre_move_token.currencies_operations, + pre_move_token.currencies_diff, local_public_key, &friend_public_key, ) .await?; - Ok(MoveTokenRequest { - move_token, - token_wanted: pre_move_token_request.token_wanted, - }) + Ok(move_token) } /// Collect all mentioned currencies from a PreMoveToken @@ -329,28 +324,15 @@ fn diff_capacities( Ok(index_mutations) } -pub async fn handle_out_move_token_index_mutations( +async fn apply_out_pre_move_token( router_db_client: &mut impl RouterDbClient, identity_client: &mut IdentityClient, local_public_key: &PublicKey, friend_public_key: PublicKey, - max_operations_in_batch: usize, -) -> Result)>, RouterError> { - let opt_pre_move_token_request = collect_outgoing_pre_move_token( - router_db_client, - friend_public_key.clone(), - max_operations_in_batch, - ) - .await?; - - let pre_move_token_request = if let Some(pre_move_token_request) = opt_pre_move_token_request { - pre_move_token_request - } else { - return Ok(None); - }; - + pre_move_token: PreMoveToken, +) -> Result<(MoveTokenRequest, Vec), RouterError> { // Collect all mentioned currencies: - let currencies = get_mentioned_currencies(&pre_move_token_request.pre_move_token); + let currencies = get_mentioned_currencies(&pre_move_token); let currencies_info_before = get_currencies_info(router_db_client, friend_public_key.clone(), ¤cies).await?; @@ -363,12 +345,12 @@ pub async fn handle_out_move_token_index_mutations( )?; // Send MoveToken: - let move_token_request = send_pre_move_token( + let move_token = send_pre_move_token( router_db_client, identity_client, local_public_key, friend_public_key.clone(), - pre_move_token_request, + pre_move_token, ) .await?; @@ -384,13 +366,83 @@ pub async fn handle_out_move_token_index_mutations( // Compare recv capacities and create index mutations: let index_mutations = diff_capacities( - friend_public_key, + friend_public_key.clone(), &recv_capacities_before, &recv_capacities_after, ¤cies_info_after, )?; - Ok(Some((move_token_request, index_mutations))) + let move_token_request = MoveTokenRequest { + move_token, + token_wanted: is_pending_move_token(router_db_client, friend_public_key).await?, + }; + + Ok((move_token_request, index_mutations)) +} + +pub async fn handle_out_move_token_index_mutations_disallow_empty( + router_db_client: &mut impl RouterDbClient, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + friend_public_key: PublicKey, + max_operations_in_batch: usize, +) -> Result)>, RouterError> { + let opt_pre_move_token = collect_outgoing_pre_move_token( + router_db_client, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + let pre_move_token = if let Some(pre_move_token) = opt_pre_move_token { + pre_move_token + } else { + return Ok(None); + }; + + Ok(Some( + apply_out_pre_move_token( + router_db_client, + identity_client, + local_public_key, + friend_public_key, + pre_move_token, + ) + .await?, + )) +} + +pub async fn handle_out_move_token_index_mutations_allow_empty( + router_db_client: &mut impl RouterDbClient, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + friend_public_key: PublicKey, + max_operations_in_batch: usize, +) -> Result<(MoveTokenRequest, Vec), RouterError> { + let opt_pre_move_token = collect_outgoing_pre_move_token( + router_db_client, + friend_public_key.clone(), + max_operations_in_batch, + ) + .await?; + + let pre_move_token = if let Some(pre_move_token) = opt_pre_move_token { + pre_move_token + } else { + PreMoveToken { + currencies_operations: Vec::new(), + currencies_diff: Vec::new(), + } + }; + + apply_out_pre_move_token( + router_db_client, + identity_client, + local_public_key, + friend_public_key, + pre_move_token, + ) + .await } /// Check if we have anything to send to a remove friend on a move token message, From a946fccc8a67ddc3976b6665f1f83a2d9a927d36 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 12 Jan 2021 17:02:50 +0200 Subject: [PATCH 358/478] funder: Work on incoming_move_token_request() --- components/funder/src/router/handle_friend.rs | 74 +++++++++++++------ 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index c9c526f13..84c989829 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -35,7 +35,7 @@ use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::{ handle_in_move_token_index_mutations, handle_out_move_token_index_mutations_allow_empty, - is_pending_move_token, + handle_out_move_token_index_mutations_disallow_empty, is_pending_move_token, }; use crate::token_channel::{ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError}; @@ -307,7 +307,7 @@ async fn incoming_move_token_request( identity_client: &mut IdentityClient, local_public_key: &PublicKey, max_operations_in_batch: usize, - move_token_request: MoveTokenRequest, + in_move_token_request: MoveTokenRequest, ) -> Result where RC: RouterDbClient, @@ -322,7 +322,7 @@ where let (receive_move_token_output, index_mutations) = handle_in_move_token_index_mutations( router_db_client, identity_client, - move_token_request.move_token, + in_move_token_request.move_token, local_public_key, friend_public_key.clone(), ) @@ -340,7 +340,7 @@ where assert!(!is_pending_move_token(router_db_client, friend_public_key.clone()).await?); // Possibly send token to remote side (According to token_wanted) - if move_token_request.token_wanted { + if in_move_token_request.token_wanted { let (out_move_token_request, index_mutations) = handle_out_move_token_index_mutations_allow_empty( router_db_client, @@ -351,20 +351,17 @@ where ) .await?; - // TODO: Should we really check for liveness here? We just got a message from this - // friend. Think about liveness design here. What if we ever forget to check for - // liveness before adding a friend message? Maybe this should be checked in - // different way, or a different layer? - if router_state.liveness.is_online(&friend_public_key) { - // Add index mutations: - for index_mutation in index_mutations { - output.add_index_mutation(index_mutation); - } - output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(out_move_token_request), - ); + // We just got a message from remote side. Remote side should be online: + assert!(router_state.liveness.is_online(&friend_public_key)); + + // Add index mutations: + for index_mutation in index_mutations { + output.add_index_mutation(index_mutation); } + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(out_move_token_request), + ); } } ReceiveMoveTokenOutput::RetransmitOutgoing(move_token) => { @@ -441,10 +438,45 @@ where }?; } - // TODO: Possibly send MoveToken back to friend in one of the following cases: - // - We have something to send - // - The friend has asked for the token back - todo!(); + // Possibly send RequestMoveToken back to friend in one of the following cases: + let opt_res = if in_move_token_request.token_wanted { + // Remote side wants to have the token back, so we have to send a MoveTokenRequest + // to remote side, even if it is empty + Some( + handle_out_move_token_index_mutations_allow_empty( + router_db_client, + identity_client, + local_public_key, + friend_public_key, + max_operations_in_batch, + ) + .await?, + ) + } else { + // We only send a MoveTokenRequest to remote side if we have something to send: + handle_out_move_token_index_mutations_disallow_empty( + router_db_client, + identity_client, + local_public_key, + friend_public_key, + max_operations_in_batch, + ) + .await? + }; + + if let Some((out_move_token_request, index_mutations)) = opt_res { + // We just got a message from remote side. Remote side should be online: + assert!(router_state.liveness.is_online(&friend_public_key)); + + // Add index mutations: + for index_mutation in index_mutations { + output.add_index_mutation(index_mutation); + } + output.add_friend_message( + friend_public_key.clone(), + FriendMessage::MoveTokenRequest(out_move_token_request), + ); + } } ReceiveMoveTokenOutput::ChainInconsistent(reset_terms) => { // TODO: From cbf3093914bf5d10d2b272586b1f2dfadb236f8a Mon Sep 17 00:00:00 2001 From: real Date: Tue, 12 Jan 2021 17:08:39 +0200 Subject: [PATCH 359/478] funder: Moved TODO comment to another function --- components/funder/src/router/handle_friend.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 84c989829..735543429 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -53,6 +53,9 @@ async fn incoming_message_request( where RC: RouterDbClient, { + // TODO: Do not forward if requests not enabled? / Friend not enabled? + todo!(); + // - If directed to us, punt // - If directed to another friend: // - If friend exists and ready, forward to next hop @@ -315,8 +318,6 @@ where RC::TcDbClient: Transaction + Send, ::McDbClient: Send, { - // TODO: Do not forward if requests not enabled? / Friend not enabled? - todo!(); let mut output = RouterOutput::new(); let (receive_move_token_output, index_mutations) = handle_in_move_token_index_mutations( From 40826c4b41960bb3d5fdbd70945a9379237a2c15 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 12 Jan 2021 22:58:27 +0200 Subject: [PATCH 360/478] funder: Work on incoming_move_token_request() --- components/funder/src/router/handle_friend.rs | 199 ++++++++++++------ components/funder/src/router/handle_relays.rs | 2 +- components/funder/src/router/types.rs | 3 +- components/funder/src/router/utils/flush.rs | 2 +- .../funder/src/router/utils/index_mutation.rs | 6 + .../funder/src/router/utils/move_token.rs | 4 +- 6 files changed, 145 insertions(+), 71 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 735543429..30766b299 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -12,7 +12,7 @@ use database::transaction::Transaction; use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; -use proto::crypto::{NodePort, PublicKey}; +use proto::crypto::{NodePort, PublicKey, Uid}; use proto::funder::messages::{ CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, @@ -39,6 +39,43 @@ use crate::router::utils::move_token::{ }; use crate::token_channel::{ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError}; +/// Check if credit line between this node and a friend is ready +/// Works for sending requests in both directions +async fn is_credit_line_ready( + router_db_client: &mut impl RouterDbClient, + router_state: &RouterState, + friend_public_key: PublicKey, + currency: Currency, + request_id: Uid, +) -> Result { + // Friend must be online: + if !router_state.liveness.is_online(&friend_public_key) { + return Ok(false); + } + + // Currency must exist: + let currency_info = if let Some(currency_info) = router_db_client + .get_currency_info(friend_public_key, currency) + .await? + { + currency_info + } else { + return Ok(false); + }; + + if let Some(currency_info_local) = currency_info.opt_local { + if let Some(mc_balance) = currency_info_local.opt_remote { + // A mutual credit line is open for this currency + } else { + return Ok(false); + } + } else { + return Ok(false); + } + + Ok(currency_info.is_open || router_db_client.is_request_local_origin(request_id).await?) +} + async fn incoming_message_request( mut router_db_client: &mut RC, router_state: &mut RouterState, @@ -53,71 +90,108 @@ async fn incoming_message_request( where RC: RouterDbClient, { - // TODO: Do not forward if requests not enabled? / Friend not enabled? - todo!(); + // Make sure that we are ready to receive this request operation + // We might not be ready in the case of currency being closed. + if !is_credit_line_ready( + router_db_client, + &*router_state, + friend_public_key.clone(), + currency.clone(), + request_send_funds.request_id.clone(), + ) + .await? + { + // Return a cancel message and flush origin friend + router_db_client + .pending_backwards_push_back( + friend_public_key.clone(), + currency, + BackwardsOp::Cancel(CancelSendFundsOp { + request_id: request_send_funds.request_id.clone(), + }), + ) + .await?; - // - If directed to us, punt - // - If directed to another friend: - // - If friend exists and ready, forward to next hop - // - Otherwise, queue cancel + flush_friend( + router_db_client, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + router_output, + ) + .await?; + + return Ok(()); + } + + // If directed to us, punt if request_send_funds.route.is_empty() { // Directed to us. Punt: router_output.add_incoming_request(request_send_funds); - } else { - // Route is not empty. We need to forward the request to a friend - let next_public_key = request_send_funds.route.remove(0); - - // Check if next public key corresponds to a friend that is ready - let should_forward = if let Some(tc_db_client) = router_db_client - .tc_db_client(next_public_key.clone()) - .await? - { - tc_db_client.get_tc_status().await?.is_consistent() - } else { - // next public key points to a nonexistent friend! - false - } && router_state.liveness.is_online(&next_public_key) - && !router_db_client - .is_local_request_exists(request_send_funds.request_id.clone()) - .await?; + return Ok(()); + } - if should_forward { - // Queue request to friend and flush destination friend - router_db_client - .pending_requests_push_back(next_public_key.clone(), currency, request_send_funds) - .await?; - flush_friend( - router_db_client, - next_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - router_output, - ) + // - If directed to another friend: + // - If friend exists and ready, forward to next hop + // - Otherwise, queue cancel + // Route is not empty. We need to forward the request to a friend + let next_public_key = request_send_funds.route.remove(0); + + // Check if next public key corresponds to a friend that is ready + let should_forward = is_credit_line_ready( + router_db_client, + &*router_state, + next_public_key.clone(), + currency.clone(), + request_send_funds.request_id.clone(), + ) + .await? + && !router_db_client + .is_local_request_exists(request_send_funds.request_id.clone()) .await?; - } else { - // Return a cancel message and flush origin friend - router_db_client - .pending_backwards_push_back( - friend_public_key.clone(), - currency, - BackwardsOp::Cancel(CancelSendFundsOp { - request_id: request_send_funds.request_id.clone(), - }), - ) - .await?; - flush_friend( - router_db_client, - friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - router_output, + // Attempt to collect fees according to rate. If credits in fees jar are insufficient, do not + // forward, and cancel the request. + todo!(); + + if should_forward { + // Queue request to friend and flush destination friend + router_db_client + .pending_requests_push_back(next_public_key.clone(), currency, request_send_funds) + .await?; + flush_friend( + router_db_client, + next_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + router_output, + ) + .await?; + } else { + // Return a cancel message and flush origin friend + router_db_client + .pending_backwards_push_back( + friend_public_key.clone(), + currency, + BackwardsOp::Cancel(CancelSendFundsOp { + request_id: request_send_funds.request_id.clone(), + }), ) .await?; - } + + flush_friend( + router_db_client, + friend_public_key, + identity_client, + local_public_key, + max_operations_in_batch, + router_output, + ) + .await?; } + Ok(()) } @@ -137,7 +211,7 @@ where if router_db_client .tc_db_client(friend_public_key.clone()) .await? - .ok_or(RouterError::InvalidDbState)? + .ok_or(RouterError::InvalidState)? .get_tc_status() .await? .is_consistent() @@ -149,7 +223,7 @@ where } else { // We have just received a cancel message from this friend. // We expect that this friend is consistent - return Err(RouterError::InvalidDbState); + return Err(RouterError::InvalidState); } Ok(()) } @@ -448,7 +522,7 @@ where router_db_client, identity_client, local_public_key, - friend_public_key, + friend_public_key.clone(), max_operations_in_batch, ) .await?, @@ -459,7 +533,7 @@ where router_db_client, identity_client, local_public_key, - friend_public_key, + friend_public_key.clone(), max_operations_in_batch, ) .await? @@ -494,11 +568,6 @@ where } } - // Add index mutations: - for index_mutation in index_mutations { - output.add_index_mutation(index_mutation); - } - Ok(output) } diff --git a/components/funder/src/router/handle_relays.rs b/components/funder/src/router/handle_relays.rs index 770c88cec..c07a1927e 100644 --- a/components/funder/src/router/handle_relays.rs +++ b/components/funder/src/router/handle_relays.rs @@ -65,7 +65,7 @@ async fn update_friend_local_relays( let _ = router_db_client .tc_db_client(friend_public_key.clone()) .await? - .ok_or(RouterError::InvalidDbState)?; + .ok_or(RouterError::InvalidState)?; let sent_relays = router_db_client .get_sent_relays(friend_public_key.clone()) diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index d8761f829..57a32c729 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -23,9 +23,8 @@ pub enum RouterError { FriendAlreadyOffline, GenerationOverflow, BalanceOverflow, - InvalidState, InvalidRoute, - InvalidDbState, + InvalidState, UnexpectedTcStatus, TokenChannelError(TokenChannelError), OpError(OpError), diff --git a/components/funder/src/router/utils/flush.rs b/components/funder/src/router/utils/flush.rs index 24183c263..b58f1b221 100644 --- a/components/funder/src/router/utils/flush.rs +++ b/components/funder/src/router/utils/flush.rs @@ -44,7 +44,7 @@ pub async fn flush_friend( match router_db_client .tc_db_client(friend_public_key.clone()) .await? - .ok_or(RouterError::InvalidDbState)? + .ok_or(RouterError::InvalidState)? .get_tc_status() .await? { diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index 6a45ed645..5028c01ad 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -29,6 +29,12 @@ use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenCha /// Calculate receive capacity for a certain currency /// This is the number we are going to report to an index server pub fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result { + todo!(); + // TODO: + // Should also take into account: + // - Liveness + // - Open/Closed currencies + if !currency_info.is_open { return Ok(0); } diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index b793d2065..00cd46c40 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -224,7 +224,7 @@ async fn send_pre_move_token( router_db_client .tc_db_client(friend_public_key.clone()) .await? - .ok_or(RouterError::InvalidDbState)?, + .ok_or(RouterError::InvalidState)?, identity_client, pre_move_token.currencies_operations, pre_move_token.currencies_diff, @@ -494,7 +494,7 @@ where router_db_client .tc_db_client(friend_public_key.clone()) .await? - .ok_or(RouterError::InvalidDbState)?, + .ok_or(RouterError::InvalidState)?, identity_client, move_token, local_public_key, From 944f392dfc76ab5ccab5619d34ced4fe5dd8a4b2 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 16 Jan 2021 16:19:30 +0200 Subject: [PATCH 361/478] Initial redesign for request message --- .../funder/src/mutual_credit/incoming.rs | 4 +++- .../funder/src/mutual_credit/outgoing.rs | 4 +++- .../tests/request_cancel_send_funds.rs | 5 +---- .../tests/request_response_send_funds.rs | 5 +---- .../token_channel/tests/move_token_basic.rs | 2 -- components/funder/src/types.rs | 2 -- components/proto/src/funder/messages.rs | 19 +++++-------------- components/signature/src/canonical.rs | 4 ---- components/signature/src/signature_buff.rs | 4 ---- 9 files changed, 13 insertions(+), 36 deletions(-) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 9cc339e3f..c2c50d346 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -52,7 +52,7 @@ pub enum ProcessOperationError { RequestDoesNotExist, InvalidResponseSignature, InvalidSrcPlainLock, - DestPaymentExceedsTotal, + // DestPaymentExceedsTotal, OpError(OpError), } @@ -87,9 +87,11 @@ async fn process_request_send_funds( return Err(ProcessOperationError::InvalidRoute); } + /* if request_send_funds.dest_payment > request_send_funds.total_dest_payment { return Err(ProcessOperationError::DestPaymentExceedsTotal); } + */ // Make sure that we don't have this request as a pending request already: let opt_remote_pending_transaction = mc_client diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 77eb99138..5b29627e1 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -26,7 +26,7 @@ pub enum QueueOperationError { RequestDoesNotExist, InvalidResponseSignature, InvalidSrcPlainLock, - DestPaymentExceedsTotal, + // DestPaymentExceedsTotal, OpError(OpError), } @@ -62,9 +62,11 @@ async fn queue_request_send_funds( return Err(QueueOperationError::InvalidRoute); } + /* if request_send_funds.dest_payment > request_send_funds.total_dest_payment { return Err(QueueOperationError::DestPaymentExceedsTotal); } + */ // Calculate amount of credits to freeze let own_freeze_credits = request_send_funds diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index 7e5d1beec..3cd23f1d4 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -7,7 +7,7 @@ use crypto::identity::{Identity, SoftwareEd25519Identity}; use crypto::rand::RandGen; use crypto::test_utils::DummyRandom; -use proto::crypto::{HashResult, HmacResult, PlainLock, PrivateKey, PublicKey, Uid}; +use proto::crypto::{HashResult, PlainLock, PrivateKey, PublicKey, Uid}; use proto::funder::messages::{CancelSendFundsOp, Currency, FriendTcOp, RequestSendFundsOp}; use crate::mutual_credit::tests::utils::MockMutualCredit; @@ -41,16 +41,13 @@ async fn task_request_cancel_send_funds() { ]; let invoice_hash = HashResult::from(&[0; HashResult::len()]); let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); - let hmac = HmacResult::from(&[2; HmacResult::len()]); let request_send_funds = RequestSendFundsOp { request_id: request_id.clone(), src_hashed_lock: src_plain_lock.hash_lock(), route, dest_payment: 10, - total_dest_payment: 10, invoice_hash, - hmac, left_fees: 5, }; diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index ce47c74f6..b8c832adf 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -7,7 +7,7 @@ use crypto::identity::{Identity, SoftwareEd25519Identity}; use crypto::rand::RandGen; use crypto::test_utils::DummyRandom; -use proto::crypto::{HashResult, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid}; +use proto::crypto::{HashResult, PlainLock, PrivateKey, PublicKey, Signature, Uid}; use proto::funder::messages::{Currency, FriendTcOp, RequestSendFundsOp, ResponseSendFundsOp}; use signature::signature_buff::create_response_signature_buffer; @@ -42,16 +42,13 @@ async fn task_request_response_send_funds() { ]; let invoice_hash = HashResult::from(&[0; HashResult::len()]); let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); - let hmac = HmacResult::from(&[2; HmacResult::len()]); let request_send_funds = RequestSendFundsOp { request_id: request_id.clone(), src_hashed_lock: src_plain_lock.hash_lock(), route, dest_payment: 10, - total_dest_payment: 10, invoice_hash, - hmac, left_fees: 5, }; diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index a3996098a..b12bd4e2d 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -135,9 +135,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { src_hashed_lock: src_plain_lock.hash_lock(), route: vec![pk_a.clone()], dest_payment: 20u128, - total_dest_payment: 30u128, invoice_hash: HashResult::from(&[0; HashResult::len()]), - hmac: HmacResult::from(&[0; HmacResult::len()]), left_fees: 5u128, }; let pending_transaction = create_pending_transaction(&request_send_funds_op); diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 65794a6b9..2a8a3ae42 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -74,9 +74,7 @@ pub fn create_pending_transaction(request_send_funds: &RequestSendFundsOp) -> Pe src_hashed_lock: request_send_funds.src_hashed_lock.clone(), route: request_send_funds.route.clone(), dest_payment: request_send_funds.dest_payment, - total_dest_payment: request_send_funds.total_dest_payment, invoice_hash: request_send_funds.invoice_hash.clone(), - hmac: request_send_funds.hmac.clone(), left_fees: request_send_funds.left_fees, } } diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 46279759e..1f3cfd40f 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -14,7 +14,7 @@ use num_bigint::BigUint; use num_traits::cast::ToPrimitive; use crate::crypto::{ - HashResult, HashedLock, HmacResult, InvoiceId, PaymentId, PlainLock, PublicKey, Signature, Uid, + HashResult, HashedLock, InvoiceId, PaymentId, PlainLock, PublicKey, Signature, Uid, }; use crate::app_server::messages::{NamedRelayAddress, RelayAddress, RelayAddressPort}; @@ -80,15 +80,11 @@ pub struct RequestSendFundsOp { pub request_id: Uid, #[serde(with = "ser_b64")] pub src_hashed_lock: HashedLock, - #[serde(with = "ser_vec_b64")] - pub route: Vec, pub dest_payment: u128, - #[serde(with = "ser_string")] - pub total_dest_payment: u128, #[serde(with = "ser_b64")] pub invoice_hash: HashResult, - #[serde(with = "ser_b64")] - pub hmac: HmacResult, + #[serde(with = "ser_vec_b64")] + pub route: Vec, #[serde(with = "ser_string")] pub left_fees: u128, } @@ -434,16 +430,11 @@ pub struct PendingTransaction { pub request_id: Uid, #[serde(with = "ser_b64")] pub src_hashed_lock: HashedLock, - // pub route: FriendsRoute, - #[serde(with = "ser_vec_b64")] - pub route: Vec, pub dest_payment: u128, - #[serde(with = "ser_string")] - pub total_dest_payment: u128, #[serde(with = "ser_b64")] pub invoice_hash: HashResult, - #[serde(with = "ser_b64")] - pub hmac: HmacResult, + #[serde(with = "ser_vec_b64")] + pub route: Vec, #[serde(with = "ser_string")] pub left_fees: u128, } diff --git a/components/signature/src/canonical.rs b/components/signature/src/canonical.rs index ab46ce1a5..7089f9b99 100644 --- a/components/signature/src/canonical.rs +++ b/components/signature/src/canonical.rs @@ -172,11 +172,7 @@ impl CanonicalSerialize for RequestSendFundsOp { res_bytes .write_u128::(self.dest_payment) .unwrap(); - res_bytes - .write_u128::(self.total_dest_payment) - .unwrap(); res_bytes.extend_from_slice(&self.invoice_hash); - res_bytes.extend_from_slice(&self.hmac); res_bytes.write_u128::(self.left_fees).unwrap(); res_bytes } diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index a582b8a6d..6ee602530 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -47,7 +47,6 @@ where let mut inner_blob = Vec::new(); inner_blob.extend_from_slice(&pending_transaction.request_id); - inner_blob.extend_from_slice(&pending_transaction.hmac); inner_blob.extend_from_slice(&response_send_funds.src_plain_lock); inner_blob .write_u128::(pending_transaction.dest_payment) @@ -57,9 +56,6 @@ where sbuffer .write_u128::(response_send_funds.serial_num) .unwrap(); - sbuffer - .write_u128::(pending_transaction.total_dest_payment) - .unwrap(); sbuffer.extend_from_slice(&pending_transaction.invoice_hash); sbuffer.extend_from_slice(¤cy.canonical_serialize()); From 973ccb1fcc6bb2af5fab980e056401156f6b6fcf Mon Sep 17 00:00:00 2001 From: real Date: Sat, 16 Jan 2021 18:58:25 +0200 Subject: [PATCH 362/478] signature: Hash currency name before appending to signature buffer --- components/signature/src/signature_buff.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index 6ee602530..2c4d98eea 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -57,7 +57,7 @@ where .write_u128::(response_send_funds.serial_num) .unwrap(); sbuffer.extend_from_slice(&pending_transaction.invoice_hash); - sbuffer.extend_from_slice(¤cy.canonical_serialize()); + sbuffer.extend_from_slice(&hash::hash_buffer(¤cy.canonical_serialize())); sbuffer } From 63ec78223ff49088476b49460680b2db674894a8 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 18 Jan 2021 12:46:50 +0200 Subject: [PATCH 363/478] proto: Removed old tests --- components/proto/src/funder/messages.rs | 42 ------------------------- 1 file changed, 42 deletions(-) diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 1f3cfd40f..afd40bdc6 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -900,45 +900,3 @@ impl TokenInfo { } } */ - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_friends_is_route_valid() { - assert_eq!(is_route_valid(&[1]), false); // too short - assert_eq!(is_route_part_valid(&[1]), true); // long enough - assert_eq!(is_route_valid(&Vec::::new()), false); // empty route is invalid - assert_eq!(is_route_part_valid(&Vec::::new()), true); // partial routes may be empty - - // Test cases taken from https://github.com/freedomlayer/offset/pull/215#discussion_r292327613 - assert_eq!(is_route_valid(&[1, 2, 3, 4]), true); // usual route - assert_eq!(is_route_valid(&[1, 2, 3, 4, 1]), true); // cyclic route that is at least 3 nodes long, having first item equal the last item - assert_eq!(is_route_valid(&[1, 1]), false); // cyclic route that is too short (only 2 nodes long) - assert_eq!(is_route_valid(&[1, 2, 3, 2, 4]), false); // Should have no repetitions that are not the first and last nodes. - - assert_eq!(is_route_part_valid(&[1, 2, 3, 4]), true); // usual route - assert_eq!(is_route_part_valid(&[1, 2, 3, 4, 1]), false); // should have no cycles in a partial route - assert_eq!(is_route_part_valid(&[1, 1]), false); // should have no repetitions ins a partial route - assert_eq!(is_route_part_valid(&[1, 2, 3, 2, 4]), false); // should have no repetitions in a partial route - } - - use im::hashset::HashSet as ImHashSet; - - #[derive(Arbitrary, Clone)] - struct ExampleHashSet { - my_set: ImHashSet, - } - - /* - // Does not compile, see: - // https://github.com/bodil/im-rs/issues/118 - use std::collections::HashMap as ImHashMap; - - #[derive(Arbitrary, Clone)] - struct ExampleHashMap { - my_map: ImHashMap, - } - */ -} From d14f08826977454c5f12b909e6f0ae9cb8dc37cd Mon Sep 17 00:00:00 2001 From: real Date: Mon, 18 Jan 2021 12:52:28 +0200 Subject: [PATCH 364/478] proto: Updated fundamental operations --- .../funder/src/mutual_credit/outgoing.rs | 2 - .../tests/request_cancel_send_funds.rs | 1 + .../tests/request_response_send_funds.rs | 1 + .../token_channel/tests/move_token_basic.rs | 1 + components/funder/src/types.rs | 5 +++ components/proto/src/funder/messages.rs | 45 +++++++++++++++++++ 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 5b29627e1..8169a30f5 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -31,8 +31,6 @@ pub enum QueueOperationError { } /// A wrapper over a token channel, accumulating operations to be sent as one transaction. -// TODO: Remove later: -#[allow(unused)] pub async fn queue_operation( mc_client: &mut impl McDbClient, operation: FriendTcOp, diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs index 3cd23f1d4..504ccbd59 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs @@ -44,6 +44,7 @@ async fn task_request_cancel_send_funds() { let request_send_funds = RequestSendFundsOp { request_id: request_id.clone(), + currency: currency.clone(), src_hashed_lock: src_plain_lock.hash_lock(), route, dest_payment: 10, diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs index b8c832adf..437d405f1 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response_send_funds.rs @@ -45,6 +45,7 @@ async fn task_request_response_send_funds() { let request_send_funds = RequestSendFundsOp { request_id: request_id.clone(), + currency: currency.clone(), src_hashed_lock: src_plain_lock.hash_lock(), route, dest_payment: 10, diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index b12bd4e2d..8ea8087a0 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -132,6 +132,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { let src_plain_lock = PlainLock::from(&[0xaa; PlainLock::len()]); let request_send_funds_op = RequestSendFundsOp { request_id: Uid::from(&[0; Uid::len()]), + currency: currency1.clone(), src_hashed_lock: src_plain_lock.hash_lock(), route: vec![pk_a.clone()], dest_payment: 20u128, diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 2a8a3ae42..9bf45dccc 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -68,9 +68,14 @@ pub fn create_cancel_send_funds(request_id: Uid) -> CancelSendFundsOp { CancelSendFundsOp { request_id } } +// TODO: +// 1. Maybe take RequestSendFundOp by value, delegate cloning to external code. +// 2. Maybe PendingTransaction is just an alias for RequestSendFunds? Why do we have two +// structs? pub fn create_pending_transaction(request_send_funds: &RequestSendFundsOp) -> PendingTransaction { PendingTransaction { request_id: request_send_funds.request_id.clone(), + currency: request_send_funds.currency.clone(), src_hashed_lock: request_send_funds.src_hashed_lock.clone(), route: request_send_funds.route.clone(), dest_payment: request_send_funds.dest_payment, diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index afd40bdc6..73c09207f 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -76,43 +76,75 @@ pub struct FriendsRoute { #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct RequestSendFundsOp { + /// Id number of this request. Used to identify the whole transaction + /// over this route. #[serde(with = "ser_b64")] pub request_id: Uid, + /// Currency used for this request + #[serde(with = "ser_string")] + pub currency: Currency, + /// A hash lock created by the originator of this request #[serde(with = "ser_b64")] pub src_hashed_lock: HashedLock, + /// Amount paid to destination pub dest_payment: u128, + /// hash(hash(actionId) || hash(totalDestPayment) || hash(description) || hash(additional)) + /// TODO: Check if this scheme is safe? Do we need to use pbkdf instead? #[serde(with = "ser_b64")] pub invoice_hash: HashResult, + /// List of next nodes to transfer this request #[serde(with = "ser_vec_b64")] pub route: Vec, + /// Amount of fees left to give to mediators + /// Every mediator takes the amount of fees he wants and subtracts this + /// value accordingly. #[serde(with = "ser_string")] pub left_fees: u128, } #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct ResponseSendFundsOp { + /// Id number of this request. Used to identify the whole transaction + /// over this route. #[serde(with = "ser_b64")] pub request_id: Uid, #[serde(with = "ser_b64")] pub src_plain_lock: PlainLock, + /// Serial number used for this collection of invoice money. + /// This should be a u128 counter, increased by 1 for every collected + /// invoice. #[serde(with = "ser_string")] pub serial_num: u128, + /// Signature{key=destinationKey}( + /// hash("FUNDS_RESPONSE") || + /// hash(request_id || src_plain_lock || dest_payment) || + /// hash(currency) || + /// serialNum || + /// invoiceHash) + /// ) #[serde(with = "ser_b64")] pub signature: Signature, } #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct UnsignedResponseSendFundsOp { + /// Id number of this request. Used to identify the whole transaction + /// over this route. #[serde(with = "ser_b64")] pub request_id: Uid, #[serde(with = "ser_b64")] pub src_plain_lock: PlainLock, + /// Serial number used for this collection of invoice money. + /// This should be a u128 counter, increased by 1 for every collected + /// invoice. #[serde(with = "ser_string")] pub serial_num: u128, } #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct CancelSendFundsOp { + /// Id number of this request. Used to identify the whole transaction + /// over this route. #[serde(with = "ser_b64")] pub request_id: Uid, } @@ -426,15 +458,28 @@ pub struct Receipt { #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct PendingTransaction { + /// Id number of this request. Used to identify the whole transaction + /// over this route. #[serde(with = "ser_b64")] pub request_id: Uid, + /// Currency used for this request + #[serde(with = "ser_string")] + pub currency: Currency, + /// A hash lock created by the originator of this request #[serde(with = "ser_b64")] pub src_hashed_lock: HashedLock, + /// Amount paid to destination pub dest_payment: u128, + /// hash(hash(actionId) || hash(totalDestPayment) || hash(description) || hash(additional)) + /// TODO: Check if this scheme is safe? Do we need to use pbkdf instead? #[serde(with = "ser_b64")] pub invoice_hash: HashResult, + /// List of next nodes to transfer this request #[serde(with = "ser_vec_b64")] pub route: Vec, + /// Amount of fees left to give to mediators + /// Every mediator takes the amount of fees he wants and subtracts this + /// value accordingly. #[serde(with = "ser_string")] pub left_fees: u128, } From 3c56b9880f2322b7f7dcb154b8f7c619f9a7832b Mon Sep 17 00:00:00 2001 From: real Date: Mon, 18 Jan 2021 13:15:56 +0200 Subject: [PATCH 365/478] proto: Initial MoveToken redesign. Not compiling yet. --- components/proto/src/funder/messages.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 73c09207f..65110cdf4 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -178,6 +178,8 @@ pub enum FriendTcOp { RequestSendFunds(RequestSendFundsOp), ResponseSendFunds(ResponseSendFundsOp), CancelSendFunds(CancelSendFundsOp), + /// Add/remove currency + ToggleCurrency(Currency), } /* @@ -254,25 +256,22 @@ pub struct TokenInfo { pub move_token_counter: u128, } +/* #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct CurrencyOperations { #[serde(with = "ser_string")] - pub currency: Currency, pub operations: Vec, } +*/ // pub type CurrenciesOperations = HashMap>; -pub type CurrenciesOperations = Vec<(Currency, FriendTcOp)>; +// pub type CurrenciesOperations = Vec<(Currency, FriendTcOp)>; #[derive(Arbitrary, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct MoveToken { #[serde(with = "ser_b64")] pub old_token: Signature, - // pub currencies_operations: Vec, - pub currencies_operations: CurrenciesOperations, - pub currencies_diff: Vec, - #[serde(with = "ser_b64")] - pub info_hash: HashResult, + pub operations: Vec, #[serde(with = "ser_b64")] pub new_token: Signature, } From e66a70fbbc2c9e24e27c0c0314f80ff0735d6158 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 19 Jan 2021 13:31:58 +0200 Subject: [PATCH 366/478] funder: mutual_credit now works with own operation types --- components/funder/src/lib.rs | 12 ++- .../funder/src/mutual_credit/incoming.rs | 67 +++++++-------- components/funder/src/mutual_credit/mod.rs | 2 + .../funder/src/mutual_credit/outgoing.rs | 58 +++++++------ .../funder/src/mutual_credit/tests/mod.rs | 4 +- ...cancel_send_funds.rs => request_cancel.rs} | 27 +++--- ...onse_send_funds.rs => request_response.rs} | 31 +++---- .../funder/src/mutual_credit/tests/utils.rs | 6 +- components/funder/src/mutual_credit/types.rs | 56 ++++++++++++- components/funder/src/mutual_credit/utils.rs | 27 ++++++ components/signature/src/canonical.rs | 84 +------------------ components/signature/src/signature_buff.rs | 4 +- components/signature/src/verify.rs | 10 ++- 13 files changed, 194 insertions(+), 194 deletions(-) rename components/funder/src/mutual_credit/tests/{request_cancel_send_funds.rs => request_cancel.rs} (77%) rename components/funder/src/mutual_credit/tests/{request_response_send_funds.rs => request_response.rs} (80%) create mode 100644 components/funder/src/mutual_credit/utils.rs diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 58ce224b0..4684fc6f6 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -25,17 +25,15 @@ extern crate quickcheck_derive; // mod handler; #[allow(unused)] mod liveness; +#[allow(unused)] mod mutual_credit; mod route; // pub mod report; // mod state; -#[allow(unused)] -mod token_channel; - -#[allow(unused)] -mod router; -// -// For testing: +// #[allow(unused)] +// mod token_channel; +// #[allow(unused)] +// mod router; pub mod types; diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index c2c50d346..b73444190 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -7,38 +7,40 @@ use common::async_rpc::OpError; use common::safe_arithmetic::SafeSignedArithmetic; use proto::crypto::PublicKey; -use proto::funder::messages::{ - CancelSendFundsOp, Currency, FriendTcOp, PendingTransaction, RequestSendFundsOp, - ResponseSendFundsOp, -}; +use proto::funder::messages::{Currency, PendingTransaction}; use signature::signature_buff::create_response_signature_buffer; use crate::route::Route; -use crate::types::create_pending_transaction; -use super::types::McDbClient; +use crate::mutual_credit::types::{McCancel, McDbClient, McOp, McRequest, McResponse}; +use crate::mutual_credit::utils::{ + pending_transaction_from_mc_request, response_op_from_mc_response, +}; +// TODO: Possibly rename to something shorter. // TODO: Do we ever need the `pending_transaction` part for anything? // If not, maybe we can remove it? #[derive(Debug)] pub struct IncomingResponseSendFundsOp { + // TODO: Possibly rename to pending_request? pub pending_transaction: PendingTransaction, - pub incoming_response: ResponseSendFundsOp, + pub incoming_response: McResponse, } #[derive(Debug)] pub struct IncomingCancelSendFundsOp { + // TODO: Possibly rename to pending_request? pub pending_transaction: PendingTransaction, // TODO: incoming_cancel looks redundant, because we can already deduce request_id from // `pending_transaction`. Maybe remove it? - pub incoming_cancel: CancelSendFundsOp, + pub incoming_cancel: McCancel, } #[derive(Debug)] pub enum IncomingMessage { - Request(RequestSendFundsOp), - RequestCancel(RequestSendFundsOp), + Request(McRequest), + RequestCancel(McRequest), Response(IncomingResponseSendFundsOp), Cancel(IncomingCancelSendFundsOp), } @@ -58,29 +60,27 @@ pub enum ProcessOperationError { pub async fn process_operation( mc_client: &mut impl McDbClient, - friend_tc_op: FriendTcOp, + mc_op: McOp, currency: &Currency, remote_public_key: &PublicKey, remote_max_debt: u128, ) -> Result { - match friend_tc_op { - FriendTcOp::RequestSendFunds(request_send_funds) => { - process_request_send_funds(mc_client, request_send_funds, remote_max_debt).await + match mc_op { + McOp::Request(request) => { + process_request_send_funds(mc_client, request, currency, remote_max_debt).await } - FriendTcOp::ResponseSendFunds(response_send_funds) => { - process_response_send_funds(mc_client, response_send_funds, currency, remote_public_key) - .await - } - FriendTcOp::CancelSendFunds(cancel_send_funds) => { - process_cancel_send_funds(mc_client, cancel_send_funds).await + McOp::Response(response) => { + process_response_send_funds(mc_client, response, currency, remote_public_key).await } + McOp::Cancel(cancel) => process_cancel_send_funds(mc_client, cancel).await, } } /// Process an incoming RequestSendFundsOp async fn process_request_send_funds( mc_client: &mut impl McDbClient, - request_send_funds: RequestSendFundsOp, + request_send_funds: McRequest, + currency: &Currency, remote_max_debt: u128, ) -> Result { if !request_send_funds.route.is_part_valid() { @@ -133,7 +133,8 @@ async fn process_request_send_funds( }; // Add pending transaction: - let pending_transaction = create_pending_transaction(&request_send_funds); + let pending_transaction = + pending_transaction_from_mc_request(request_send_funds.clone(), currency.clone()); mc_client .insert_remote_pending_transaction(pending_transaction) @@ -148,7 +149,7 @@ async fn process_request_send_funds( async fn process_response_send_funds( mc_client: &mut impl McDbClient, - response_send_funds: ResponseSendFundsOp, + response: McResponse, currency: &Currency, remote_public_key: &PublicKey, ) -> Result { @@ -157,12 +158,12 @@ async fn process_response_send_funds( // Obtain pending request: let pending_transaction = mc_client - .get_local_pending_transaction(response_send_funds.request_id.clone()) + .get_local_pending_transaction(response.request_id.clone()) .await? .ok_or(ProcessOperationError::RequestDoesNotExist)?; // Verify src_plain_lock and dest_plain_lock: - if response_send_funds.src_plain_lock.hash_lock() != pending_transaction.src_hashed_lock { + if response.src_plain_lock.hash_lock() != pending_transaction.src_hashed_lock { return Err(ProcessOperationError::InvalidSrcPlainLock); } @@ -174,7 +175,7 @@ async fn process_response_send_funds( let response_signature_buffer = create_response_signature_buffer( currency, - response_send_funds.clone(), + response_op_from_mc_response(response.clone()), &pending_transaction, ); @@ -182,7 +183,7 @@ async fn process_response_send_funds( if !verify_signature( &response_signature_buffer, dest_public_key, - &response_send_funds.signature, + &response.signature, ) { return Err(ProcessOperationError::InvalidResponseSignature); } @@ -197,7 +198,7 @@ async fn process_response_send_funds( // Remove entry from local_pending hashmap: mc_client - .remove_local_pending_transaction(response_send_funds.request_id.clone()) + .remove_local_pending_transaction(response.request_id.clone()) .await?; // Decrease frozen credits: @@ -230,25 +231,25 @@ async fn process_response_send_funds( Ok(IncomingMessage::Response(IncomingResponseSendFundsOp { pending_transaction, - incoming_response: response_send_funds, + incoming_response: response, })) } async fn process_cancel_send_funds( mc_client: &mut impl McDbClient, - cancel_send_funds: CancelSendFundsOp, + cancel: McCancel, ) -> Result { // Make sure that id exists in local_pending hashmap, // and access saved request details. // Obtain pending request: let pending_transaction = mc_client - .get_local_pending_transaction(cancel_send_funds.request_id.clone()) + .get_local_pending_transaction(cancel.request_id.clone()) .await? .ok_or(ProcessOperationError::RequestDoesNotExist)?; mc_client - .remove_local_pending_transaction(cancel_send_funds.request_id.clone()) + .remove_local_pending_transaction(cancel.request_id.clone()) .await?; let freeze_credits = pending_transaction @@ -270,6 +271,6 @@ async fn process_cancel_send_funds( // Return cancel_send_funds: Ok(IncomingMessage::Cancel(IncomingCancelSendFundsOp { pending_transaction, - incoming_cancel: cancel_send_funds, + incoming_cancel: cancel, })) } diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index fa3389384..8b4f8fdd7 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -1,3 +1,5 @@ +mod utils; + pub mod incoming; pub mod outgoing; #[cfg(test)] diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 8169a30f5..4633099b3 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -7,14 +7,15 @@ use common::async_rpc::OpError; use common::safe_arithmetic::SafeSignedArithmetic; use proto::crypto::PublicKey; -use proto::funder::messages::{ - CancelSendFundsOp, Currency, FriendTcOp, RequestSendFundsOp, ResponseSendFundsOp, -}; +use proto::funder::messages::Currency; use signature::signature_buff::create_response_signature_buffer; -use crate::mutual_credit::types::McDbClient; use crate::route::Route; -use crate::types::create_pending_transaction; + +use crate::mutual_credit::types::{McCancel, McDbClient, McOp, McRequest, McResponse}; +use crate::mutual_credit::utils::{ + pending_transaction_from_mc_request, response_op_from_mc_response, +}; #[derive(Debug, From)] pub enum QueueOperationError { @@ -33,30 +34,26 @@ pub enum QueueOperationError { /// A wrapper over a token channel, accumulating operations to be sent as one transaction. pub async fn queue_operation( mc_client: &mut impl McDbClient, - operation: FriendTcOp, + operation: McOp, currency: &Currency, local_public_key: &PublicKey, ) -> Result<(), QueueOperationError> { // TODO: Maybe remove clone from here later: match operation { - FriendTcOp::RequestSendFunds(request_send_funds) => { - queue_request_send_funds(mc_client, request_send_funds).await - } - FriendTcOp::ResponseSendFunds(response_send_funds) => { - queue_response_send_funds(mc_client, response_send_funds, currency, local_public_key) - .await - } - FriendTcOp::CancelSendFunds(cancel_send_funds) => { - queue_cancel_send_funds(mc_client, cancel_send_funds).await + McOp::Request(request) => queue_request_send_funds(mc_client, request, currency).await, + McOp::Response(response) => { + queue_response_send_funds(mc_client, response, currency, local_public_key).await } + McOp::Cancel(cancel) => queue_cancel_send_funds(mc_client, cancel).await, } } async fn queue_request_send_funds( mc_client: &mut impl McDbClient, - request_send_funds: RequestSendFundsOp, + request: McRequest, + currency: &Currency, ) -> Result<(), QueueOperationError> { - if !request_send_funds.route.is_part_valid() { + if !request.route.is_part_valid() { return Err(QueueOperationError::InvalidRoute); } @@ -67,9 +64,9 @@ async fn queue_request_send_funds( */ // Calculate amount of credits to freeze - let own_freeze_credits = request_send_funds + let own_freeze_credits = request .dest_payment - .checked_add(request_send_funds.left_fees) + .checked_add(request.left_fees) .ok_or(QueueOperationError::CreditsCalcOverflow)?; let mc_balance = mc_client.get_balance().await?; @@ -82,7 +79,7 @@ async fn queue_request_send_funds( // Make sure that we don't have this request as a pending request already: if mc_client - .get_local_pending_transaction(request_send_funds.request_id.clone()) + .get_local_pending_transaction(request.request_id.clone()) .await? .is_some() { @@ -90,7 +87,8 @@ async fn queue_request_send_funds( } // Add pending transaction: - let pending_transaction = create_pending_transaction(&request_send_funds); + let pending_transaction = + pending_transaction_from_mc_request(request.clone(), currency.clone()); mc_client .insert_local_pending_transaction(pending_transaction) .await?; @@ -105,7 +103,7 @@ async fn queue_request_send_funds( async fn queue_response_send_funds( mc_client: &mut impl McDbClient, - response_send_funds: ResponseSendFundsOp, + response: McResponse, currency: &Currency, local_public_key: &PublicKey, ) -> Result<(), QueueOperationError> { @@ -114,20 +112,20 @@ async fn queue_response_send_funds( // Obtain pending request: let pending_transaction = mc_client - .get_remote_pending_transaction(response_send_funds.request_id.clone()) + .get_remote_pending_transaction(response.request_id.clone()) .await? .ok_or(QueueOperationError::RequestDoesNotExist)?; // TODO: Possibly get rid of clone() here for optimization later // Verify src_plain_lock and dest_plain_lock: - if response_send_funds.src_plain_lock.hash_lock() != pending_transaction.src_hashed_lock { + if response.src_plain_lock.hash_lock() != pending_transaction.src_hashed_lock { return Err(QueueOperationError::InvalidSrcPlainLock); } // verify signature: let response_signature_buffer = create_response_signature_buffer( currency, - response_send_funds.clone(), + response_op_from_mc_response(response.clone()), &pending_transaction, ); // The response was signed by the destination node: @@ -141,7 +139,7 @@ async fn queue_response_send_funds( if !verify_signature( &response_signature_buffer, dest_public_key, - &response_send_funds.signature, + &response.signature, ) { return Err(QueueOperationError::InvalidResponseSignature); } @@ -154,7 +152,7 @@ async fn queue_response_send_funds( // Remove entry from remote_pending hashmap: mc_client - .remove_remote_pending_transaction(response_send_funds.request_id) + .remove_remote_pending_transaction(response.request_id) .await?; // Decrease frozen credits @@ -196,14 +194,14 @@ async fn queue_response_send_funds( async fn queue_cancel_send_funds( mc_client: &mut impl McDbClient, - cancel_send_funds: CancelSendFundsOp, + cancel: McCancel, ) -> Result<(), QueueOperationError> { // Make sure that id exists in remote_pending hashmap, // and access saved request details. // Obtain pending request: let pending_transaction = mc_client - .get_remote_pending_transaction(cancel_send_funds.request_id.clone()) + .get_remote_pending_transaction(cancel.request_id.clone()) .await? .ok_or(QueueOperationError::RequestDoesNotExist)?; @@ -214,7 +212,7 @@ async fn queue_cancel_send_funds( // Remove entry from remote hashmap: mc_client - .remove_remote_pending_transaction(cancel_send_funds.request_id.clone()) + .remove_remote_pending_transaction(cancel.request_id.clone()) .await?; // Decrease frozen credits: diff --git a/components/funder/src/mutual_credit/tests/mod.rs b/components/funder/src/mutual_credit/tests/mod.rs index 35d5b9423..2a56d06e2 100644 --- a/components/funder/src/mutual_credit/tests/mod.rs +++ b/components/funder/src/mutual_credit/tests/mod.rs @@ -1,5 +1,5 @@ -mod request_cancel_send_funds; -mod request_response_send_funds; +mod request_cancel; +mod request_response; mod utils; pub use utils::MockMutualCredit; diff --git a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs b/components/funder/src/mutual_credit/tests/request_cancel.rs similarity index 77% rename from components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs rename to components/funder/src/mutual_credit/tests/request_cancel.rs index 504ccbd59..805faaa79 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel.rs @@ -8,15 +8,13 @@ use crypto::rand::RandGen; use crypto::test_utils::DummyRandom; use proto::crypto::{HashResult, PlainLock, PrivateKey, PublicKey, Uid}; -use proto::funder::messages::{CancelSendFundsOp, Currency, FriendTcOp, RequestSendFundsOp}; - -use crate::mutual_credit::tests::utils::MockMutualCredit; -use crate::mutual_credit::types::McDbClient; +use proto::funder::messages::Currency; use crate::mutual_credit::outgoing::queue_operation; -use crate::mutual_credit::tests::utils::process_operations_list; +use crate::mutual_credit::tests::utils::{process_operations_list, MockMutualCredit}; +use crate::mutual_credit::types::{McCancel, McDbClient, McOp, McRequest}; -async fn task_request_cancel_send_funds() { +async fn task_request_cancel() { let currency = Currency::try_from("FST".to_owned()).unwrap(); let mut rng = DummyRandom::new(&[1u8]); @@ -31,7 +29,7 @@ async fn task_request_cancel_send_funds() { let out_fees = 0.into(); let mut mc_transaction = MockMutualCredit::new(currency.clone(), balance, in_fees, out_fees); - // -----[RequestSendFunds]-------- + // -----[McRequest]-------- // ----------------------------- let request_id = Uid::from(&[3; Uid::len()]); let route = vec![ @@ -42,9 +40,8 @@ async fn task_request_cancel_send_funds() { let invoice_hash = HashResult::from(&[0; HashResult::len()]); let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); - let request_send_funds = RequestSendFundsOp { + let request = McRequest { request_id: request_id.clone(), - currency: currency.clone(), src_hashed_lock: src_plain_lock.hash_lock(), route, dest_payment: 10, @@ -54,7 +51,7 @@ async fn task_request_cancel_send_funds() { queue_operation( &mut mc_transaction, - FriendTcOp::RequestSendFunds(request_send_funds), + McOp::Request(request), ¤cy, &local_public_key, ) @@ -68,13 +65,13 @@ async fn task_request_cancel_send_funds() { assert_eq!(mc_balance.in_fees, 0.into()); assert_eq!(mc_balance.out_fees, 0.into()); - // -----[CancelSendFunds]-------- + // -----[McCancel]-------- // ------------------------------ - let cancel_send_funds = CancelSendFundsOp { request_id }; + let cancel = McCancel { request_id }; process_operations_list( &mut mc_transaction, - vec![FriendTcOp::CancelSendFunds(cancel_send_funds)], + vec![McOp::Cancel(cancel)], ¤cy, &remote_public_key, 100, @@ -91,8 +88,8 @@ async fn task_request_cancel_send_funds() { } #[test] -fn test_request_cancel_send_funds() { +fn test_request_cancel() { let test_executor = TestExecutor::new(); - let res = test_executor.run(task_request_cancel_send_funds()); + let res = test_executor.run(task_request_cancel()); assert!(res.is_output()); } diff --git a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs b/components/funder/src/mutual_credit/tests/request_response.rs similarity index 80% rename from components/funder/src/mutual_credit/tests/request_response_send_funds.rs rename to components/funder/src/mutual_credit/tests/request_response.rs index 437d405f1..30c5f922e 100644 --- a/components/funder/src/mutual_credit/tests/request_response_send_funds.rs +++ b/components/funder/src/mutual_credit/tests/request_response.rs @@ -8,16 +8,17 @@ use crypto::rand::RandGen; use crypto::test_utils::DummyRandom; use proto::crypto::{HashResult, PlainLock, PrivateKey, PublicKey, Signature, Uid}; -use proto::funder::messages::{Currency, FriendTcOp, RequestSendFundsOp, ResponseSendFundsOp}; +use proto::funder::messages::Currency; use signature::signature_buff::create_response_signature_buffer; use crate::mutual_credit::outgoing::queue_operation; use crate::mutual_credit::tests::utils::{process_operations_list, MockMutualCredit}; -use crate::mutual_credit::types::McDbClient; +use crate::mutual_credit::types::{McDbClient, McOp, McRequest, McResponse}; +use crate::mutual_credit::utils::{ + pending_transaction_from_mc_request, response_op_from_mc_response, +}; -use crate::types::create_pending_transaction; - -async fn task_request_response_send_funds() { +async fn task_request_response() { let currency = Currency::try_from("FST".to_owned()).unwrap(); let local_public_key = PublicKey::from(&[0xaa; PublicKey::len()]); @@ -43,9 +44,8 @@ async fn task_request_response_send_funds() { let invoice_hash = HashResult::from(&[0; HashResult::len()]); let src_plain_lock = PlainLock::from(&[1; PlainLock::len()]); - let request_send_funds = RequestSendFundsOp { + let request = McRequest { request_id: request_id.clone(), - currency: currency.clone(), src_hashed_lock: src_plain_lock.hash_lock(), route, dest_payment: 10, @@ -53,10 +53,11 @@ async fn task_request_response_send_funds() { left_fees: 5, }; - let pending_transaction = create_pending_transaction(&request_send_funds); + let pending_transaction = + pending_transaction_from_mc_request(request.clone(), currency.clone()); queue_operation( &mut mc_transaction, - FriendTcOp::RequestSendFunds(request_send_funds), + McOp::Request(request), ¤cy, &local_public_key, ) @@ -74,7 +75,7 @@ async fn task_request_response_send_funds() { // -------------------------------- let serial_num: u128 = 0; - let mut response_send_funds = ResponseSendFundsOp { + let mut response = McResponse { request_id: request_id.clone(), src_plain_lock: src_plain_lock.clone(), serial_num, @@ -83,14 +84,14 @@ async fn task_request_response_send_funds() { let sign_buffer = create_response_signature_buffer( ¤cy, - response_send_funds.clone(), + response_op_from_mc_response(response.clone()), &pending_transaction, ); - response_send_funds.signature = identity.sign(&sign_buffer); + response.signature = identity.sign(&sign_buffer); process_operations_list( &mut mc_transaction, - vec![FriendTcOp::ResponseSendFunds(response_send_funds)], + vec![McOp::Response(response)], ¤cy, &remote_public_key, 100, @@ -108,8 +109,8 @@ async fn task_request_response_send_funds() { } #[test] -fn test_request_response_send_funds() { +fn test_request_response() { let test_executor = TestExecutor::new(); - let res = test_executor.run(task_request_response_send_funds()); + let res = test_executor.run(task_request_response()); assert!(res.is_output()); } diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index 6ba63dc9b..b95267eff 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -5,10 +5,10 @@ use common::conn::BoxFuture; use common::u256::U256; use proto::crypto::{PublicKey, Uid}; -use proto::funder::messages::{Currency, FriendTcOp, McBalance, PendingTransaction}; +use proto::funder::messages::{Currency, McBalance, PendingTransaction}; use crate::mutual_credit::incoming::{process_operation, IncomingMessage, ProcessOperationError}; -use crate::mutual_credit::types::McDbClient; +use crate::mutual_credit::types::{McDbClient, McOp}; #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct McPendingTransactions { @@ -147,7 +147,7 @@ pub struct ProcessTransListError { pub async fn process_operations_list( mc_client: &mut impl McDbClient, - operations: Vec, + operations: Vec, currency: &Currency, remote_public_key: &PublicKey, remote_max_debt: u128, diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 441f3efad..82b62ece2 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -2,9 +2,63 @@ use common::async_rpc::AsyncOpResult; // use common::ser_utils::ser_string; use common::u256::U256; -use proto::crypto::Uid; +use proto::crypto::{HashResult, HashedLock, PlainLock, PublicKey, Signature, Uid}; use proto::funder::messages::{McBalance, PendingTransaction}; +#[derive(Debug, Clone)] +pub struct McRequest { + /// Id number of this request. Used to identify the whole transaction + /// over this route. + pub request_id: Uid, + /// A hash lock created by the originator of this request + pub src_hashed_lock: HashedLock, + /// Amount paid to destination + pub dest_payment: u128, + /// hash(hash(actionId) || hash(totalDestPayment) || hash(description) || hash(additional)) + /// TODO: Check if this scheme is safe? Do we need to use pbkdf instead? + pub invoice_hash: HashResult, + /// List of next nodes to transfer this request + pub route: Vec, + /// Amount of fees left to give to mediators + /// Every mediator takes the amount of fees he wants and subtracts this + /// value accordingly. + pub left_fees: u128, +} + +#[derive(Debug, Clone)] +pub struct McResponse { + /// Id number of this request. Used to identify the whole transaction + /// over this route. + pub request_id: Uid, + pub src_plain_lock: PlainLock, + /// Serial number used for this collection of invoice money. + /// This should be a u128 counter, increased by 1 for every collected + /// invoice. + pub serial_num: u128, + /// Signature{key=destinationKey}( + /// hash("FUNDS_RESPONSE") || + /// hash(request_id || src_plain_lock || dest_payment) || + /// hash(currency) || + /// serialNum || + /// invoiceHash) + /// ) + pub signature: Signature, +} + +#[derive(Debug, Clone)] +pub struct McCancel { + /// Id number of this request. Used to identify the whole transaction + /// over this route. + pub request_id: Uid, +} + +#[derive(Debug, Clone)] +pub enum McOp { + Request(McRequest), + Response(McResponse), + Cancel(McCancel), +} + pub trait McDbClient { fn get_balance(&mut self) -> AsyncOpResult; fn set_balance(&mut self, new_balance: i128) -> AsyncOpResult<()>; diff --git a/components/funder/src/mutual_credit/utils.rs b/components/funder/src/mutual_credit/utils.rs new file mode 100644 index 000000000..be73a8d6c --- /dev/null +++ b/components/funder/src/mutual_credit/utils.rs @@ -0,0 +1,27 @@ +use proto::funder::messages::{Currency, PendingTransaction, ResponseSendFundsOp}; + +use crate::mutual_credit::types::{McRequest, McResponse}; + +pub fn pending_transaction_from_mc_request( + request: McRequest, + currency: Currency, +) -> PendingTransaction { + PendingTransaction { + request_id: request.request_id, + currency, + src_hashed_lock: request.src_hashed_lock, + dest_payment: request.dest_payment, + invoice_hash: request.invoice_hash, + route: request.route, + left_fees: request.left_fees, + } +} + +pub fn response_op_from_mc_response(response: McResponse) -> ResponseSendFundsOp { + ResponseSendFundsOp { + request_id: response.request_id, + src_plain_lock: response.src_plain_lock, + serial_num: response.serial_num, + signature: response.signature, + } +} diff --git a/components/signature/src/canonical.rs b/components/signature/src/canonical.rs index 7089f9b99..2af0388a2 100644 --- a/components/signature/src/canonical.rs +++ b/components/signature/src/canonical.rs @@ -3,10 +3,7 @@ use byteorder::{BigEndian, WriteBytesExt}; use proto::app_server::messages::RelayAddress; use proto::crypto::PublicKey; -use proto::funder::messages::{ - CancelSendFundsOp, Currency, CurrencyOperations, FriendTcOp, McBalance, RequestSendFundsOp, - ResponseSendFundsOp, -}; +use proto::funder::messages::{Currency, McBalance}; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -154,85 +151,6 @@ impl CanonicalSerialize for Currency { } } -impl CanonicalSerialize for CurrencyOperations { - fn canonical_serialize(&self) -> Vec { - let mut res_bytes = Vec::new(); - res_bytes.extend_from_slice(&self.currency.canonical_serialize()); - res_bytes.extend_from_slice(&self.operations.canonical_serialize()); - res_bytes - } -} - -impl CanonicalSerialize for RequestSendFundsOp { - fn canonical_serialize(&self) -> Vec { - let mut res_bytes = Vec::new(); - res_bytes.extend_from_slice(&self.request_id); - res_bytes.extend_from_slice(&self.src_hashed_lock); - res_bytes.extend_from_slice(&self.route.canonical_serialize()); - res_bytes - .write_u128::(self.dest_payment) - .unwrap(); - res_bytes.extend_from_slice(&self.invoice_hash); - res_bytes.write_u128::(self.left_fees).unwrap(); - res_bytes - } -} - -impl CanonicalSerialize for ResponseSendFundsOp { - fn canonical_serialize(&self) -> Vec { - let mut res_bytes = Vec::new(); - res_bytes.extend_from_slice(&self.request_id); - res_bytes.extend_from_slice(&self.src_plain_lock); - res_bytes.write_u128::(self.serial_num).unwrap(); - res_bytes.extend_from_slice(&self.signature); - res_bytes - } -} - -impl CanonicalSerialize for CancelSendFundsOp { - fn canonical_serialize(&self) -> Vec { - let mut res_bytes = Vec::new(); - res_bytes.extend_from_slice(&self.request_id); - res_bytes - } -} - -impl CanonicalSerialize for FriendTcOp { - fn canonical_serialize(&self) -> Vec { - let mut res_bytes = Vec::new(); - match self { - FriendTcOp::RequestSendFunds(request_send_funds) => { - res_bytes.push(0u8); - res_bytes.append(&mut request_send_funds.canonical_serialize()) - } - FriendTcOp::ResponseSendFunds(response_send_funds) => { - res_bytes.push(1u8); - res_bytes.append(&mut response_send_funds.canonical_serialize()) - } - FriendTcOp::CancelSendFunds(cancel_send_funds) => { - res_bytes.push(2u8); - res_bytes.append(&mut cancel_send_funds.canonical_serialize()) - } - } - res_bytes - } -} - -/* -impl CanonicalSerialize for FriendsRoute { - fn canonical_serialize(&self) -> Vec { - let mut res_bytes = Vec::new(); - res_bytes - .write_u64::(usize_to_u64(self.public_keys.len()).unwrap()) - .unwrap(); - for public_key in &self.public_keys { - res_bytes.extend_from_slice(public_key); - } - res_bytes - } -} -*/ - /* impl CanonicalSerialize for Receipt { fn canonical_serialize(&self) -> Vec { diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index 2c4d98eea..c60508ffd 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -126,11 +126,11 @@ where } */ -pub fn move_token_signature_buff(move_token: &MoveToken) -> Vec { +pub fn move_token_signature_buff(move_token: &MoveToken, info_hash: &HashResult) -> Vec { let mut sig_buffer = Vec::new(); sig_buffer.extend_from_slice(&hash::hash_buffer(TOKEN_NEXT)); sig_buffer.extend_from_slice(&move_token.old_token); - sig_buffer.extend_from_slice(&move_token.info_hash); + sig_buffer.extend_from_slice(info_hash); sig_buffer } diff --git a/components/signature/src/verify.rs b/components/signature/src/verify.rs index 03d18e70d..7153f26f8 100644 --- a/components/signature/src/verify.rs +++ b/components/signature/src/verify.rs @@ -4,7 +4,7 @@ // use crypto::hash_lock::HashLock; use crypto::identity::verify_signature; -use proto::crypto::PublicKey; +use proto::crypto::{HashResult, PublicKey}; use proto::funder::messages::MoveToken; use proto::index_server::messages::MutationsUpdate; @@ -67,8 +67,12 @@ pub fn verify_commit(commit: &Commit, local_public_key: &PublicKey) -> bool { */ /// Verify that new_token is a valid signature over the rest of the fields. -pub fn verify_move_token(move_token: &MoveToken, public_key: &PublicKey) -> bool { - let sig_buffer = move_token_signature_buff(move_token); +pub fn verify_move_token( + move_token: &MoveToken, + info_hash: &HashResult, + public_key: &PublicKey, +) -> bool { + let sig_buffer = move_token_signature_buff(move_token, info_hash); verify_signature(&sig_buffer, public_key, &move_token.new_token) } From 08dbc635130de1d65c776dd74081d941793af266 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 19 Jan 2021 13:34:09 +0200 Subject: [PATCH 367/478] funder: Removed old comments --- components/funder/src/mutual_credit/outgoing.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 4633099b3..1579bc792 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -19,15 +19,12 @@ use crate::mutual_credit::utils::{ #[derive(Debug, From)] pub enum QueueOperationError { - // RemoteMaxDebtTooLarge, InvalidRoute, - // PkPairNotInRoute, CreditsCalcOverflow, RequestAlreadyExists, RequestDoesNotExist, InvalidResponseSignature, InvalidSrcPlainLock, - // DestPaymentExceedsTotal, OpError(OpError), } From 2a2e0506b1db3a5f0a3bd9a39dfb0381d98a2565 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 19 Jan 2021 18:35:29 +0200 Subject: [PATCH 368/478] funder: Work on porting token_channel to new design. WIP --- components/funder/src/lib.rs | 4 +- .../funder/src/token_channel/token_channel.rs | 59 +++++++++++++++---- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 4684fc6f6..ff98aae7d 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -30,8 +30,8 @@ mod mutual_credit; mod route; // pub mod report; // mod state; -// #[allow(unused)] -// mod token_channel; +#[allow(unused)] +mod token_channel; // #[allow(unused)] // mod router; diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 78c59544c..1f04345b1 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -19,8 +19,7 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddress; use proto::crypto::{HashResult, PublicKey, RandValue, Signature}; use proto::funder::messages::{ - CurrenciesOperations, Currency, CurrencyOperations, FriendTcOp, McBalance, MoveToken, - ResetBalance, ResetTerms, TokenInfo, + Currency, FriendTcOp, McBalance, MoveToken, ResetBalance, ResetTerms, TokenInfo, }; use signature::canonical::CanonicalSerialize; @@ -33,7 +32,7 @@ use database::transaction::{TransFunc, Transaction}; use crate::mutual_credit::incoming::{process_operation, IncomingMessage, ProcessOperationError}; use crate::mutual_credit::outgoing::{queue_operation, QueueOperationError}; -use crate::mutual_credit::types::McDbClient; +use crate::mutual_credit::types::{McCancel, McDbClient, McOp, McRequest, McResponse}; use crate::token_channel::types::{TcDbClient, TcStatus}; use crate::types::{create_hashed, MoveTokenHashed}; @@ -83,12 +82,16 @@ fn token_from_public_key(public_key: &PublicKey) -> Signature { /// To canonicalize the initial move token (Having an equal move token for both sides), we sort the /// two public keys in some way. pub fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKey) -> MoveToken { + /* let token_info = TokenInfo { // No balances yet: balances_hash: hash_buffer(&[]), move_token_counter: 0, }; + let info_hash = hash_token_info(&low_public_key, &high_public_key, &token_info); + */ + // This is a special initialization case. // Note that this is the only case where new_token is not a valid signature. // We do this because we want to have synchronization between the two sides of the token @@ -96,9 +99,7 @@ pub fn initial_move_token(low_public_key: &PublicKey, high_public_key: &PublicKe // doesn't have the private key). Therefore we use a dummy new_token instead. let move_token_out = MoveToken { old_token: token_from_public_key(&low_public_key), - currencies_operations: Vec::new(), - currencies_diff: Vec::new(), - info_hash: hash_token_info(&low_public_key, &high_public_key, &token_info), + operations: Vec::new(), new_token: token_from_public_key(&high_public_key), }; @@ -268,6 +269,7 @@ where if new_move_token.old_token == local_reset_terms.reset_token { // This is a reset move token! + /* // Simulate an outgoing move token with the correct `new_token`: let token_info = TokenInfo { balances_hash: hash_mc_infos(tc_client.list_local_reset_balances().map_ok( @@ -281,12 +283,12 @@ where .checked_sub(1) .ok_or(TokenChannelError::MoveTokenCounterOverflow)?, }; + */ let move_token_out = MoveToken { old_token: Signature::from(&[0; Signature::len()]), - currencies_operations: Vec::new(), - currencies_diff: Vec::new(), - info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), + operations: Vec::new(), + // info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), new_token: local_reset_terms.reset_token.clone(), }; @@ -719,11 +721,36 @@ async fn handle_incoming_token_match( )) } +#[derive(Debug, Clone)] +enum TcOp { + McOp(Currency, McOp), + ToggleCurrency(Currency), +} + +fn tc_op_from_friend_tc_op(friend_tc_op: FriendTcOp) -> TcOp { + let _ = match friend_tc_op { + FriendTcOp::RequestSendFunds(request_send_funds) => TcOp::McOp( + request_send_funds.currency, + McOp::Request(McRequest { + request_id: request_send_funds.request_id, + src_hashed_lock: request_send_funds.src_hashed_lock, + dest_payment: request_send_funds.dest_payment, + invoice_hash: request_send_funds.invoice_hash, + route: request_send_funds.route, + left_fees: request_send_funds.left_fees, + }), + ), + FriendTcOp::ResponseSendFunds(..) => todo!(), + FriendTcOp::CancelSendFunds(..) => todo!(), + FriendTcOp::ToggleCurrency(..) => todo!(), + }; + todo!(); +} + pub async fn handle_out_move_token( tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, - currencies_operations: CurrenciesOperations, - currencies_diff: Vec, + operations: Vec, local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result { @@ -735,6 +762,15 @@ pub async fn handle_out_move_token( } }; + for op in operations { + match op { + FriendTcOp::RequestSendFunds(request_send_funds) => {} + FriendTcOp::ResponseSendFunds(response_send_funds) => {} + FriendTcOp::CancelSendFunds(response_send_funds) => {} + FriendTcOp::ToggleCurrency(currency) => {} + } + } + // Handle currencies_diff: for diff_currency in ¤cies_diff { // Check if we need to add currency: @@ -755,6 +791,7 @@ pub async fn handle_out_move_token( .ok_or(TokenChannelError::InvalidDbState)? .get_balance() .await?; + if mc_balance.balance == 0 && mc_balance.remote_pending_debt == 0 && mc_balance.local_pending_debt == 0 From 1a7e19c15191ffda85de066073abc1b0803937f1 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 20 Jan 2021 11:34:24 +0200 Subject: [PATCH 369/478] funder: Work on FriendTcOp -> TcOp: WIP --- .../funder/src/token_channel/token_channel.rs | 51 ++++++++++++++++--- components/funder/src/token_channel/types.rs | 5 +- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 1f04345b1..df298ea27 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -727,8 +727,11 @@ enum TcOp { ToggleCurrency(Currency), } -fn tc_op_from_friend_tc_op(friend_tc_op: FriendTcOp) -> TcOp { - let _ = match friend_tc_op { +async fn tc_op_from_incoming_friend_tc_op( + tc_client: &mut impl TcDbClient, + friend_tc_op: FriendTcOp, +) -> Result, TokenChannelError> { + Ok(Some(match friend_tc_op { FriendTcOp::RequestSendFunds(request_send_funds) => TcOp::McOp( request_send_funds.currency, McOp::Request(McRequest { @@ -740,11 +743,45 @@ fn tc_op_from_friend_tc_op(friend_tc_op: FriendTcOp) -> TcOp { left_fees: request_send_funds.left_fees, }), ), - FriendTcOp::ResponseSendFunds(..) => todo!(), - FriendTcOp::CancelSendFunds(..) => todo!(), - FriendTcOp::ToggleCurrency(..) => todo!(), - }; - todo!(); + FriendTcOp::ResponseSendFunds(response_send_funds) => { + let currency = if let Some(currency) = tc_client + .get_currency(response_send_funds.request_id.clone()) + .await? + { + currency + } else { + return Ok(None); + }; + + TcOp::McOp( + currency, + McOp::Response(McResponse { + request_id: response_send_funds.request_id, + src_plain_lock: response_send_funds.src_plain_lock, + serial_num: response_send_funds.serial_num, + signature: response_send_funds.signature, + }), + ) + } + FriendTcOp::CancelSendFunds(cancel_send_funds) => { + let currency = if let Some(currency) = tc_client + .get_currency(cancel_send_funds.request_id.clone()) + .await? + { + currency + } else { + return Ok(None); + }; + + TcOp::McOp( + currency, + McOp::Cancel(McCancel { + request_id: cancel_send_funds.request_id, + }), + ) + } + FriendTcOp::ToggleCurrency(currency) => TcOp::ToggleCurrency(currency), + })) } pub async fn handle_out_move_token( diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 7a7303244..6203c0050 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -6,7 +6,9 @@ use common::async_rpc::{AsyncOpResult, AsyncOpStream}; use common::u256::U256; use proto::crypto::Signature; -use proto::funder::messages::{Currency, McBalance, MoveToken, ResetBalance, ResetTerms}; +use proto::funder::messages::{ + Currency, Currency, McBalance, MoveToken, ResetBalance, ResetTerms, Uid, +}; use database::interface::funder::CurrencyConfig; @@ -46,6 +48,7 @@ pub trait TcDbClient { type McDbClient: McDbClient; fn mc_db_client(&mut self, currency: Currency) -> AsyncOpResult>; + fn get_currency(&mut self, request_id: Uid) -> AsyncOpResult>; fn get_tc_status(&mut self) -> AsyncOpResult; fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; fn set_direction_outgoing( From ae73681eff410bc0d43b0681f74bdc23dfdd0d10 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 20 Jan 2021 12:37:41 +0200 Subject: [PATCH 370/478] funder: types: Fixed imports --- components/funder/src/token_channel/types.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 6203c0050..fb4f86557 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -5,10 +5,8 @@ use futures::channel::oneshot; use common::async_rpc::{AsyncOpResult, AsyncOpStream}; use common::u256::U256; -use proto::crypto::Signature; -use proto::funder::messages::{ - Currency, Currency, McBalance, MoveToken, ResetBalance, ResetTerms, Uid, -}; +use proto::crypto::{Signature, Uid}; +use proto::funder::messages::{Currency, McBalance, MoveToken, ResetBalance, ResetTerms}; use database::interface::funder::CurrencyConfig; From e8608ae28878180ba49b7c69e364d202da329313 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 20 Jan 2021 12:42:25 +0200 Subject: [PATCH 371/478] funder: Mock token_channel functions to compile with new design --- .../funder/src/token_channel/token_channel.rs | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index df298ea27..cb5ad5317 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -579,7 +579,10 @@ async fn handle_incoming_token_match( // This allows the genesis move token to occur smoothly, even though its signature // is not correct. // TODO: Check if the above statement is still true. - if !verify_move_token(&new_move_token, &remote_public_key) { + + // TODO: We need to be able to calculate info_hash here. + let info_hash = todo!(); + if !verify_move_token(&new_move_token, &info_hash, &remote_public_key) { return Ok(IncomingTokenMatchOutput::InvalidIncoming( InvalidIncoming::InvalidSignature, )); @@ -590,6 +593,10 @@ async fn handle_incoming_token_match( incoming_messages: Vec::new(), }; + todo!(); + + /* + // Handle active currencies: // currencies_diff represents a "xor" between the previous set of currencies and the new set of @@ -719,6 +726,7 @@ async fn handle_incoming_token_match( Ok(IncomingTokenMatchOutput::MoveTokenReceived( move_token_received, )) + */ } #[derive(Debug, Clone)] @@ -808,6 +816,9 @@ pub async fn handle_out_move_token( } } + todo!(); + + /* // Handle currencies_diff: for diff_currency in ¤cies_diff { // Check if we need to add currency: @@ -904,6 +915,7 @@ pub async fn handle_out_move_token( .await?; Ok(move_token) + */ } /// Apply a token channel reset, accepting remote side's @@ -911,11 +923,14 @@ pub async fn handle_out_move_token( pub async fn accept_remote_reset( tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, - currencies_operations: CurrenciesOperations, - currencies_diff: Vec, + operations: Vec, local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result { + todo!(); + + /* + // Make sure that we are in inconsistent state, // and that the remote side has already sent his reset terms: let (remote_reset_token, remote_reset_move_token_counter) = @@ -965,6 +980,7 @@ pub async fn accept_remote_reset( remote_public_key, ) .await + */ } /// Load the remote reset terms information from a remote side's inconsistency message From b7a48de6d4954b1cbf296dd27440b258ec25b1ee Mon Sep 17 00:00:00 2001 From: real Date: Wed, 20 Jan 2021 14:40:33 +0200 Subject: [PATCH 372/478] database: Fixed syntax error --- components/database/src/create.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index fd1052978..75c27b803 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -451,7 +451,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // (As opposed to requests that were received for the first time from a friend) tx.execute( "CREATE TABLE local_requests( - request_id BLOB NOT NULL PRIMARY KEY, + request_id BLOB NOT NULL PRIMARY KEY );", params![], )?; From f361af8719dd7ce8c3c439f880acfc79d6d3aba2 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 20 Jan 2021 14:41:54 +0200 Subject: [PATCH 373/478] database: Updated mutual_credits to include removal markers. --- components/database/src/create.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 75c27b803..49f6ba4e4 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -337,8 +337,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE local_currencies( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, - is_remove BOOL NOT NULL, - -- Is marked for removal? FOREIGN KEY(friend_public_key) REFERENCES consistent_channels(friend_public_key) ON DELETE CASCADE, @@ -381,10 +379,14 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { remote_pending_debt BLOB NOT NULL, in_fees BLOB NOT NULL, out_fees BLOB NOT NULL, - PRIMARY KEY(friend_public_key, currency) + is_local_remove BOOL NOT NULL, + -- Was marked for removal by local side? + is_remote_remove BOOL NOT NULL, + -- Was marked for removal by remote side? + PRIMARY KEY(friend_public_key, currency), FOREIGN KEY(friend_public_key, currency) REFERENCES local_currencies(friend_public_key, currency) - ON DELETE CASCADE + ON DELETE CASCADE, FOREIGN KEY(friend_public_key, currency) REFERENCES remote_currencies(friend_public_key, currency) ON DELETE CASCADE From 7ab54f17927855bcd541169d3fd19852e16b802b Mon Sep 17 00:00:00 2001 From: real Date: Wed, 20 Jan 2021 14:56:44 +0200 Subject: [PATCH 374/478] funder: token_channel: Work on handle_out_move_token() --- .../funder/src/token_channel/token_channel.rs | 159 ++++++++++++++++-- components/funder/src/token_channel/types.rs | 11 +- 2 files changed, 152 insertions(+), 18 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index cb5ad5317..53a39811e 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -19,7 +19,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddress; use proto::crypto::{HashResult, PublicKey, RandValue, Signature}; use proto::funder::messages::{ - Currency, FriendTcOp, McBalance, MoveToken, ResetBalance, ResetTerms, TokenInfo, + CancelSendFundsOp, Currency, FriendTcOp, McBalance, MoveToken, RequestSendFundsOp, + ResetBalance, ResetTerms, ResponseSendFundsOp, TokenInfo, }; use signature::canonical::CanonicalSerialize; @@ -45,7 +46,7 @@ pub enum TokenChannelError { CanNotRemoveCurrencyInUse, InvalidTokenChannelStatus, RequestSignatureError, - InvalidDbState, + InvalidState, OpError(OpError), QueueOperationError(QueueOperationError), } @@ -166,7 +167,7 @@ async fn local_balances_for_reset( while let Some(item) = reset_balances.next().await { let (currency, reset_balance) = item?; if let Some(_) = balances.insert(currency, reset_balance) { - return Err(TokenChannelError::InvalidDbState); + return Err(TokenChannelError::InvalidState); } } Ok(balances) @@ -624,7 +625,7 @@ async fn handle_incoming_token_match( let mc_balance = tc_client .mc_db_client(diff_currency.clone()) .await? - .ok_or(TokenChannelError::InvalidDbState)? + .ok_or(TokenChannelError::InvalidState)? .get_balance() .await?; if mc_balance.balance == 0 @@ -661,7 +662,7 @@ async fn handle_incoming_token_match( tc_client .mc_db_client(currency.clone()) .await? - .ok_or(TokenChannelError::InvalidDbState)?, + .ok_or(TokenChannelError::InvalidState)?, friend_tc_op.clone(), ¤cy, remote_public_key, @@ -730,7 +731,7 @@ async fn handle_incoming_token_match( } #[derive(Debug, Clone)] -enum TcOp { +pub enum TcOp { McOp(Currency, McOp), ToggleCurrency(Currency), } @@ -753,7 +754,7 @@ async fn tc_op_from_incoming_friend_tc_op( ), FriendTcOp::ResponseSendFunds(response_send_funds) => { let currency = if let Some(currency) = tc_client - .get_currency(response_send_funds.request_id.clone()) + .get_currency_local_request(response_send_funds.request_id.clone()) .await? { currency @@ -773,7 +774,7 @@ async fn tc_op_from_incoming_friend_tc_op( } FriendTcOp::CancelSendFunds(cancel_send_funds) => { let currency = if let Some(currency) = tc_client - .get_currency(cancel_send_funds.request_id.clone()) + .get_currency_local_request(cancel_send_funds.request_id.clone()) .await? { currency @@ -792,10 +793,35 @@ async fn tc_op_from_incoming_friend_tc_op( })) } +/* +fn friend_tc_op_from_outgoing_mc_op(mc_op: McOp, currency: Currency) -> FriendTcOp { + match mc_op { + McOp::Request(mc_request) => FriendTcOp::RequestSendFunds(RequestSendFundsOp { + request_id: mc_request.request_id, + currency, + src_hashed_lock: mc_request.src_hashed_lock, + dest_payment: mc_request.dest_payment, + invoice_hash: mc_request.invoice_hash, + route: mc_request.route, + left_fees: mc_request.left_fees, + }), + McOp::Response(mc_response) => FriendTcOp::ResponseSendFunds(ResponseSendFundsOp { + request_id: mc_response.request_id, + src_plain_lock: mc_response.src_plain_lock, + serial_num: mc_response.serial_num, + signature: mc_response.signature, + }), + McOp::Cancel(mc_cancel) => FriendTcOp::CancelSendFunds(CancelSendFundsOp { + request_id: mc_cancel.request_id, + }), + } +} +*/ + pub async fn handle_out_move_token( tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, - operations: Vec, + tc_ops: Vec, local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result { @@ -807,12 +833,111 @@ pub async fn handle_out_move_token( } }; - for op in operations { - match op { - FriendTcOp::RequestSendFunds(request_send_funds) => {} - FriendTcOp::ResponseSendFunds(response_send_funds) => {} - FriendTcOp::CancelSendFunds(response_send_funds) => {} - FriendTcOp::ToggleCurrency(currency) => {} + for tc_op in tc_ops.iter().cloned() { + match tc_op { + TcOp::McOp(currency, mc_op) => { + queue_operation( + tc_client + .mc_db_client(currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidState)?, + // TODO: In case a currency is removed, we need to remember to cancel all + // requests that are pending for this currency. Where should this happen? + mc_op, + ¤cy, + local_public_key, + ) + .await?; + + // If currency is marked for removal by any of the sides, and balance + pending + // credits are zero, we need to remove the currency. + if tc_client.is_local_currency_remove(currency.clone()).await? + || tc_client + .is_remote_currency_remove(currency.clone()) + .await? + { + // If the balances are zero, we remove the currency: + let mc_balance = tc_client + .mc_db_client(currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidState)? + .get_balance() + .await?; + + if mc_balance.balance == 0 + && mc_balance.remote_pending_debt == 0 + && mc_balance.local_pending_debt == 0 + { + // We may remove the currency if the balance and pending debts are exactly + // zero: + tc_client.remove_local_currency(currency.clone()).await?; + // TODO: Do We need to report outside that we removed this currency somehow? + // TODO: Somehow unite all code for removing local currencies. + } + } + } + TcOp::ToggleCurrency(currency) => { + // - If we don't have this currency locally configured: + // - Add the currency locally + // - Else (we have this currency locally): + // - If also enabled remotely: + // - Remove this currency if balance and pending debt is zero. + // - Else: + // - Remove this currency + + // Check if we need to add currency: + if !tc_client.is_local_currency(currency.clone()).await? { + // Add a new local currency. + tc_client.add_local_currency(currency.clone()).await?; + + // If we also have this currency as a remote currency, add a new mutual credit: + if tc_client.is_remote_currency(currency.clone()).await? { + tc_client.add_mutual_credit(currency.clone()); + } + } else { + // We have this currency locally: + if tc_client.is_remote_currency(currency.clone()).await? { + // Check if we already have this currency marked for removal + if tc_client.is_local_currency_remove(currency.clone()).await? { + // Currency is already marked for removal. + // We toggle the removal setting, setting the currency to be "not for + // removal". + tc_client + .unset_local_currency_remove(currency.clone()) + .await?; + } else { + // Currency was not marked for removal. + + // Mark the currency for removal: + tc_client + .set_local_currency_remove(currency.clone()) + .await?; + + // If the balances are zero, we remove the currency: + let mc_balance = tc_client + .mc_db_client(currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidState)? + .get_balance() + .await?; + + if mc_balance.balance == 0 + && mc_balance.remote_pending_debt == 0 + && mc_balance.local_pending_debt == 0 + { + // We may remove the currency if the balance and pending debts are exactly + // zero: + tc_client.remove_local_currency(currency.clone()).await?; + // TODO: Do We need to report outside that we removed this currency somehow? + // TODO: Somehow unite all code for removing local currencies. + } + } + } else { + tc_client.remove_remote_currency(currency.clone()).await?; + // TODO: Do We need to report outside that we removed this currency somehow? + } + } + } } } @@ -836,7 +961,7 @@ pub async fn handle_out_move_token( let mc_balance = tc_client .mc_db_client(diff_currency.clone()) .await? - .ok_or(TokenChannelError::InvalidDbState)? + .ok_or(TokenChannelError::InvalidState)? .get_balance() .await?; @@ -871,7 +996,7 @@ pub async fn handle_out_move_token( tc_client .mc_db_client(currency.clone()) .await? - .ok_or(TokenChannelError::InvalidDbState)?, + .ok_or(TokenChannelError::InvalidState)?, friend_tc_op.clone(), ¤cy, local_public_key, diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index fb4f86557..8be088bee 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -46,7 +46,8 @@ pub trait TcDbClient { type McDbClient: McDbClient; fn mc_db_client(&mut self, currency: Currency) -> AsyncOpResult>; - fn get_currency(&mut self, request_id: Uid) -> AsyncOpResult>; + /// Find currency used for a locally sent request + fn get_currency_local_request(&mut self, request_id: Uid) -> AsyncOpResult>; fn get_tc_status(&mut self) -> AsyncOpResult; fn set_direction_incoming(&mut self, move_token_hashed: MoveTokenHashed) -> AsyncOpResult<()>; fn set_direction_outgoing( @@ -109,6 +110,14 @@ pub trait TcDbClient { fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; + fn is_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult; + fn set_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn unset_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; + + fn is_remote_currency_remove(&mut self, currency: Currency) -> AsyncOpResult; + fn set_remote_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn unset_remote_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; + fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult; fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult; From bb1510a4958d265575cce7c68a496ec8ef0adb5a Mon Sep 17 00:00:00 2001 From: real Date: Wed, 20 Jan 2021 15:07:33 +0200 Subject: [PATCH 375/478] funder: work on handle_out_move_token() --- .../funder/src/token_channel/token_channel.rs | 128 +++++------------- 1 file changed, 35 insertions(+), 93 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 53a39811e..6e1b487bf 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -793,30 +793,35 @@ async fn tc_op_from_incoming_friend_tc_op( })) } -/* -fn friend_tc_op_from_outgoing_mc_op(mc_op: McOp, currency: Currency) -> FriendTcOp { - match mc_op { - McOp::Request(mc_request) => FriendTcOp::RequestSendFunds(RequestSendFundsOp { - request_id: mc_request.request_id, - currency, - src_hashed_lock: mc_request.src_hashed_lock, - dest_payment: mc_request.dest_payment, - invoice_hash: mc_request.invoice_hash, - route: mc_request.route, - left_fees: mc_request.left_fees, - }), - McOp::Response(mc_response) => FriendTcOp::ResponseSendFunds(ResponseSendFundsOp { - request_id: mc_response.request_id, - src_plain_lock: mc_response.src_plain_lock, - serial_num: mc_response.serial_num, - signature: mc_response.signature, - }), - McOp::Cancel(mc_cancel) => FriendTcOp::CancelSendFunds(CancelSendFundsOp { - request_id: mc_cancel.request_id, - }), +fn friend_tc_op_from_outgoing_tc_op(tc_op: TcOp) -> FriendTcOp { + match tc_op { + TcOp::McOp(currency, McOp::Request(mc_request)) => { + FriendTcOp::RequestSendFunds(RequestSendFundsOp { + request_id: mc_request.request_id, + currency, + src_hashed_lock: mc_request.src_hashed_lock, + dest_payment: mc_request.dest_payment, + invoice_hash: mc_request.invoice_hash, + route: mc_request.route, + left_fees: mc_request.left_fees, + }) + } + TcOp::McOp(_currency, McOp::Response(mc_response)) => { + FriendTcOp::ResponseSendFunds(ResponseSendFundsOp { + request_id: mc_response.request_id, + src_plain_lock: mc_response.src_plain_lock, + serial_num: mc_response.serial_num, + signature: mc_response.signature, + }) + } + TcOp::McOp(_currency, McOp::Cancel(mc_cancel)) => { + FriendTcOp::CancelSendFunds(CancelSendFundsOp { + request_id: mc_cancel.request_id, + }) + } + TcOp::ToggleCurrency(currency) => FriendTcOp::ToggleCurrency(currency), } } -*/ pub async fn handle_out_move_token( tc_client: &mut impl TcDbClient, @@ -941,69 +946,6 @@ pub async fn handle_out_move_token( } } - todo!(); - - /* - // Handle currencies_diff: - for diff_currency in ¤cies_diff { - // Check if we need to add currency: - if !tc_client.is_local_currency(diff_currency.clone()).await? { - // Add a new local currency. - tc_client.add_local_currency(diff_currency.clone()).await?; - - // If we also have this currency as a remote currency, add a new mutual credit: - if tc_client.is_remote_currency(diff_currency.clone()).await? { - tc_client.add_mutual_credit(diff_currency.clone()); - } - } else { - let is_remote_currency = tc_client.is_remote_currency(diff_currency.clone()).await?; - if is_remote_currency { - let mc_balance = tc_client - .mc_db_client(diff_currency.clone()) - .await? - .ok_or(TokenChannelError::InvalidState)? - .get_balance() - .await?; - - if mc_balance.balance == 0 - && mc_balance.remote_pending_debt == 0 - && mc_balance.local_pending_debt == 0 - { - // We may remove the currency if the balance and pending debts are exactly - // zero: - tc_client - .remove_local_currency(diff_currency.clone()) - .await?; - // TODO: Do We need to report outside that we removed this currency somehow? - // TODO: Somehow unite all code for removing local currencies. - } else { - // We are not allowed to remove this currency! - // TODO: Should be an error instead? - return Err(TokenChannelError::CanNotRemoveCurrencyInUse); - } - } else { - tc_client - .remove_remote_currency(diff_currency.clone()) - .await?; - // TODO: Do We need to report outside that we removed this currency somehow? - } - } - } - - // Update mutual credits: - for (currency, friend_tc_op) in ¤cies_operations { - queue_operation( - tc_client - .mc_db_client(currency.clone()) - .await? - .ok_or(TokenChannelError::InvalidState)?, - friend_tc_op.clone(), - ¤cy, - local_public_key, - ) - .await?; - } - let new_move_token_counter = tc_client .get_move_token_counter() .await? @@ -1016,31 +958,31 @@ pub async fn handle_out_move_token( move_token_counter: new_move_token_counter, }; + let info_hash = hash_token_info(local_public_key, remote_public_key, &token_info); + let mut move_token = MoveToken { old_token: move_token_in.new_token, - currencies_operations, - currencies_diff, - info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), + operations: tc_ops + .into_iter() + .map(|tc_op| friend_tc_op_from_outgoing_tc_op(tc_op)) + .collect(), // Still not known: new_token: Signature::from(&[0; Signature::len()]), }; // Fill in signature: - let signature_buff = move_token_signature_buff(&move_token); + let signature_buff = move_token_signature_buff(&move_token, &info_hash); move_token.new_token = identity_client .request_signature(signature_buff) .await .map_err(|_| TokenChannelError::RequestSignatureError)?; - // Set the direction to be outgoing: - // TODO: This should also save the last incoming move token, in an atomic way. - // Should probably be implemented inside the database code. + // Set the direction to be outgoing, and save last incoming token in an atomic way: tc_client .set_direction_outgoing(move_token.clone(), new_move_token_counter) .await?; Ok(move_token) - */ } /// Apply a token channel reset, accepting remote side's From e4d2ddad6c37f8697cd1031008bfb4deb953bc06 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 22 Jan 2021 13:20:23 +0200 Subject: [PATCH 376/478] funder: Initial work on new currency add/remove design --- .../funder/src/token_channel/token_channel.rs | 263 +++++++++--------- components/funder/src/token_channel/types.rs | 13 +- components/proto/src/funder/messages.rs | 2 - 3 files changed, 126 insertions(+), 152 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 6e1b487bf..ad5b6f6c6 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -731,9 +731,9 @@ async fn handle_incoming_token_match( } #[derive(Debug, Clone)] -pub enum TcOp { - McOp(Currency, McOp), - ToggleCurrency(Currency), +pub struct TcOp { + pub currency: Currency, + pub mc_op: McOp, } async fn tc_op_from_incoming_friend_tc_op( @@ -741,9 +741,9 @@ async fn tc_op_from_incoming_friend_tc_op( friend_tc_op: FriendTcOp, ) -> Result, TokenChannelError> { Ok(Some(match friend_tc_op { - FriendTcOp::RequestSendFunds(request_send_funds) => TcOp::McOp( - request_send_funds.currency, - McOp::Request(McRequest { + FriendTcOp::RequestSendFunds(request_send_funds) => TcOp { + currency: request_send_funds.currency, + mc_op: McOp::Request(McRequest { request_id: request_send_funds.request_id, src_hashed_lock: request_send_funds.src_hashed_lock, dest_payment: request_send_funds.dest_payment, @@ -751,7 +751,7 @@ async fn tc_op_from_incoming_friend_tc_op( route: request_send_funds.route, left_fees: request_send_funds.left_fees, }), - ), + }, FriendTcOp::ResponseSendFunds(response_send_funds) => { let currency = if let Some(currency) = tc_client .get_currency_local_request(response_send_funds.request_id.clone()) @@ -762,15 +762,15 @@ async fn tc_op_from_incoming_friend_tc_op( return Ok(None); }; - TcOp::McOp( + TcOp { currency, - McOp::Response(McResponse { + mc_op: McOp::Response(McResponse { request_id: response_send_funds.request_id, src_plain_lock: response_send_funds.src_plain_lock, serial_num: response_send_funds.serial_num, signature: response_send_funds.signature, }), - ) + } } FriendTcOp::CancelSendFunds(cancel_send_funds) => { let currency = if let Some(currency) = tc_client @@ -782,44 +782,36 @@ async fn tc_op_from_incoming_friend_tc_op( return Ok(None); }; - TcOp::McOp( + TcOp { currency, - McOp::Cancel(McCancel { + mc_op: McOp::Cancel(McCancel { request_id: cancel_send_funds.request_id, }), - ) + } } - FriendTcOp::ToggleCurrency(currency) => TcOp::ToggleCurrency(currency), })) } fn friend_tc_op_from_outgoing_tc_op(tc_op: TcOp) -> FriendTcOp { - match tc_op { - TcOp::McOp(currency, McOp::Request(mc_request)) => { - FriendTcOp::RequestSendFunds(RequestSendFundsOp { - request_id: mc_request.request_id, - currency, - src_hashed_lock: mc_request.src_hashed_lock, - dest_payment: mc_request.dest_payment, - invoice_hash: mc_request.invoice_hash, - route: mc_request.route, - left_fees: mc_request.left_fees, - }) - } - TcOp::McOp(_currency, McOp::Response(mc_response)) => { - FriendTcOp::ResponseSendFunds(ResponseSendFundsOp { - request_id: mc_response.request_id, - src_plain_lock: mc_response.src_plain_lock, - serial_num: mc_response.serial_num, - signature: mc_response.signature, - }) - } - TcOp::McOp(_currency, McOp::Cancel(mc_cancel)) => { - FriendTcOp::CancelSendFunds(CancelSendFundsOp { - request_id: mc_cancel.request_id, - }) - } - TcOp::ToggleCurrency(currency) => FriendTcOp::ToggleCurrency(currency), + match tc_op.mc_op { + McOp::Request(mc_request) => FriendTcOp::RequestSendFunds(RequestSendFundsOp { + request_id: mc_request.request_id, + currency: tc_op.currency, + src_hashed_lock: mc_request.src_hashed_lock, + dest_payment: mc_request.dest_payment, + invoice_hash: mc_request.invoice_hash, + route: mc_request.route, + left_fees: mc_request.left_fees, + }), + McOp::Response(mc_response) => FriendTcOp::ResponseSendFunds(ResponseSendFundsOp { + request_id: mc_response.request_id, + src_plain_lock: mc_response.src_plain_lock, + serial_num: mc_response.serial_num, + signature: mc_response.signature, + }), + McOp::Cancel(mc_cancel) => FriendTcOp::CancelSendFunds(CancelSendFundsOp { + request_id: mc_cancel.request_id, + }), } } @@ -839,111 +831,106 @@ pub async fn handle_out_move_token( }; for tc_op in tc_ops.iter().cloned() { - match tc_op { - TcOp::McOp(currency, mc_op) => { - queue_operation( - tc_client - .mc_db_client(currency.clone()) - .await? - .ok_or(TokenChannelError::InvalidState)?, - // TODO: In case a currency is removed, we need to remember to cancel all - // requests that are pending for this currency. Where should this happen? - mc_op, - ¤cy, - local_public_key, - ) - .await?; + queue_operation( + tc_client + .mc_db_client(tc_op.currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidState)?, + tc_op.mc_op, + &tc_op.currency, + local_public_key, + ) + .await?; - // If currency is marked for removal by any of the sides, and balance + pending - // credits are zero, we need to remove the currency. - if tc_client.is_local_currency_remove(currency.clone()).await? - || tc_client - .is_remote_currency_remove(currency.clone()) - .await? - { - // If the balances are zero, we remove the currency: - let mc_balance = tc_client - .mc_db_client(currency.clone()) - .await? - .ok_or(TokenChannelError::InvalidState)? - .get_balance() - .await?; + // If currency is marked for removal locally and all credits are zero, we need to remove the currency. + if tc_client + .is_local_currency_remove(tc_op.currency.clone()) + .await? + { + // If the balances are zero, we remove the currency: + let mc_balance = tc_client + .mc_db_client(tc_op.currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidState)? + .get_balance() + .await?; - if mc_balance.balance == 0 - && mc_balance.remote_pending_debt == 0 - && mc_balance.local_pending_debt == 0 - { - // We may remove the currency if the balance and pending debts are exactly - // zero: - tc_client.remove_local_currency(currency.clone()).await?; - // TODO: Do We need to report outside that we removed this currency somehow? - // TODO: Somehow unite all code for removing local currencies. - } - } + if mc_balance.balance == 0 + && mc_balance.remote_pending_debt == 0 + && mc_balance.local_pending_debt == 0 + { + // We may remove the currency if the balance and pending debts are exactly + // zero: + tc_client + .remove_local_currency(tc_op.currency.clone()) + .await?; + // TODO: Do We need to report outside that we removed this currency somehow? + // TODO: Somehow unite all code for removing local currencies. } - TcOp::ToggleCurrency(currency) => { - // - If we don't have this currency locally configured: - // - Add the currency locally - // - Else (we have this currency locally): - // - If also enabled remotely: - // - Remove this currency if balance and pending debt is zero. - // - Else: - // - Remove this currency - - // Check if we need to add currency: - if !tc_client.is_local_currency(currency.clone()).await? { - // Add a new local currency. - tc_client.add_local_currency(currency.clone()).await?; - - // If we also have this currency as a remote currency, add a new mutual credit: - if tc_client.is_remote_currency(currency.clone()).await? { - tc_client.add_mutual_credit(currency.clone()); - } - } else { - // We have this currency locally: - if tc_client.is_remote_currency(currency.clone()).await? { - // Check if we already have this currency marked for removal - if tc_client.is_local_currency_remove(currency.clone()).await? { - // Currency is already marked for removal. - // We toggle the removal setting, setting the currency to be "not for - // removal". - tc_client - .unset_local_currency_remove(currency.clone()) - .await?; - } else { - // Currency was not marked for removal. - - // Mark the currency for removal: - tc_client - .set_local_currency_remove(currency.clone()) - .await?; - - // If the balances are zero, we remove the currency: - let mc_balance = tc_client - .mc_db_client(currency.clone()) - .await? - .ok_or(TokenChannelError::InvalidState)? - .get_balance() - .await?; - - if mc_balance.balance == 0 - && mc_balance.remote_pending_debt == 0 - && mc_balance.local_pending_debt == 0 - { - // We may remove the currency if the balance and pending debts are exactly - // zero: - tc_client.remove_local_currency(currency.clone()).await?; - // TODO: Do We need to report outside that we removed this currency somehow? - // TODO: Somehow unite all code for removing local currencies. - } - } + } + /* + TcOp::ToggleCurrency(currency) => { + // - If we don't have this currency locally configured: + // - Add the currency locally + // - Else (we have this currency locally): + // - If also enabled remotely: + // - Remove this currency if balance and pending debt is zero. + // - Else: + // - Remove this currency + + // Check if we need to add currency: + if !tc_client.is_local_currency(currency.clone()).await? { + // Add a new local currency. + tc_client.add_local_currency(currency.clone()).await?; + + // If we also have this currency as a remote currency, add a new mutual credit: + if tc_client.is_remote_currency(currency.clone()).await? { + tc_client.add_mutual_credit(currency.clone()); + } + } else { + // We have this currency locally: + if tc_client.is_remote_currency(currency.clone()).await? { + // Check if we already have this currency marked for removal + if tc_client.is_local_currency_remove(currency.clone()).await? { + // Currency is already marked for removal. + // We toggle the removal setting, setting the currency to be "not for + // removal". + tc_client + .unset_local_currency_remove(currency.clone()) + .await?; } else { - tc_client.remove_remote_currency(currency.clone()).await?; - // TODO: Do We need to report outside that we removed this currency somehow? + // Currency was not marked for removal. + + // Mark the currency for removal: + tc_client + .set_local_currency_remove(currency.clone()) + .await?; + + // If the balances are zero, we remove the currency: + let mc_balance = tc_client + .mc_db_client(currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidState)? + .get_balance() + .await?; + + if mc_balance.balance == 0 + && mc_balance.remote_pending_debt == 0 + && mc_balance.local_pending_debt == 0 + { + // We may remove the currency if the balance and pending debts are exactly + // zero: + tc_client.remove_local_currency(currency.clone()).await?; + // TODO: Do We need to report outside that we removed this currency somehow? + // TODO: Somehow unite all code for removing local currencies. + } } + } else { + tc_client.remove_remote_currency(currency.clone()).await?; + // TODO: Do We need to report outside that we removed this currency somehow? } } - } + }*/ } let new_move_token_counter = tc_client diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 8be088bee..499afbe01 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -107,22 +107,11 @@ pub trait TcDbClient { /// Only relevant for inconsistent channels fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, ResetBalance)>; - fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; - fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; - fn is_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult; fn set_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; fn unset_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; - fn is_remote_currency_remove(&mut self, currency: Currency) -> AsyncOpResult; - fn set_remote_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; - fn unset_remote_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; - + fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult; fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult; - - fn add_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; - fn remove_remote_currency(&mut self, currency: Currency) -> AsyncOpResult; - - fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()>; } diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 65110cdf4..89d243975 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -178,8 +178,6 @@ pub enum FriendTcOp { RequestSendFunds(RequestSendFundsOp), ResponseSendFunds(ResponseSendFundsOp), CancelSendFunds(CancelSendFundsOp), - /// Add/remove currency - ToggleCurrency(Currency), } /* From 112e210e07ab76a9bca15648bb9f3e56837b8c6d Mon Sep 17 00:00:00 2001 From: real Date: Fri, 22 Jan 2021 13:50:28 +0200 Subject: [PATCH 377/478] funder: TODO comment --- components/funder/src/token_channel/token_channel.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index ad5b6f6c6..7edfd5a37 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -830,6 +830,7 @@ pub async fn handle_out_move_token( } }; + // TODO: If mutual credit does not exist yet, we might need to create it here. for tc_op in tc_ops.iter().cloned() { queue_operation( tc_client From 2ad962cfd81c4b6a4ed9862fd3e98e953ab61a6d Mon Sep 17 00:00:00 2001 From: real Date: Fri, 22 Jan 2021 14:36:43 +0200 Subject: [PATCH 378/478] database: Updated to currencies design --- components/database/src/create.rs | 53 +++++-------------------------- 1 file changed, 8 insertions(+), 45 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 49f6ba4e4..9dbfc92bf 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -121,8 +121,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, rate BLOB NOT NULL, + -- TODO: Unpack rate to its components here. remote_max_debt BLOB NOT NULL, + local_max_debt BLOB NOT NULL, is_open BOOL NOT NULL, + is_remove BOOL NOT NULL, + -- Was marked for removal locally? PRIMARY KEY(friend_public_key, currency), FOREIGN KEY(friend_public_key) REFERENCES friends(friend_public_key) @@ -333,43 +337,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { params![], )?; - tx.execute( - "CREATE TABLE local_currencies( - friend_public_key BLOB NOT NULL, - currency TEXT NOT NULL, - FOREIGN KEY(friend_public_key) - REFERENCES consistent_channels(friend_public_key) - ON DELETE CASCADE, - FOREIGN KEY(friend_public_key, currency) - REFERENCES currency_configs(friend_public_key, currency) - ON DELETE CASCADE, - PRIMARY KEY(friend_public_key, currency) - );", - params![], - )?; - - tx.execute( - "CREATE UNIQUE INDEX idx_local_currencies ON local_currencies(friend_public_key, currency);", - params![], - )?; - - tx.execute( - "CREATE TABLE remote_currencies( - friend_public_key BLOB NOT NULL, - currency TEXT NOT NULL, - FOREIGN KEY(friend_public_key) - REFERENCES consistent_channels(friend_public_key) - ON DELETE CASCADE, - PRIMARY KEY(friend_public_key, currency) - );", - params![], - )?; - - tx.execute( - "CREATE UNIQUE INDEX idx_remote_currencies ON remote_currencies(friend_public_key, currency);", - params![], - )?; - tx.execute( "CREATE TABLE mutual_credits( friend_public_key BLOB NOT NULL, @@ -379,16 +346,12 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { remote_pending_debt BLOB NOT NULL, in_fees BLOB NOT NULL, out_fees BLOB NOT NULL, - is_local_remove BOOL NOT NULL, - -- Was marked for removal by local side? - is_remote_remove BOOL NOT NULL, - -- Was marked for removal by remote side? PRIMARY KEY(friend_public_key, currency), - FOREIGN KEY(friend_public_key, currency) - REFERENCES local_currencies(friend_public_key, currency) + FOREIGN KEY(friend_public_key) + REFERENCES consistent_channels(friend_public_key) ON DELETE CASCADE, - FOREIGN KEY(friend_public_key, currency) - REFERENCES remote_currencies(friend_public_key, currency) + FOREIGN KEY(friend_public_key, currency) + REFERENCES currency_configs(friend_public_key, currency) ON DELETE CASCADE );", params![], From 034846e01ce285e5012763a832d2c255677cf68d Mon Sep 17 00:00:00 2001 From: real Date: Fri, 22 Jan 2021 16:55:01 +0200 Subject: [PATCH 379/478] database: Unpacked rate column into mul + add integers --- components/database/src/create.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 9dbfc92bf..b5bf3c4e2 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -120,8 +120,10 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE currency_configs( friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, - rate BLOB NOT NULL, - -- TODO: Unpack rate to its components here. + rate_mul INTEGER NOT NULL + CHECK(rate_mul >= 0 AND rate_mul < 0x100000000), + rate_add INTEGER NOT NULL + CHECK(rate_add >= 0 AND rate_add < 0x100000000), remote_max_debt BLOB NOT NULL, local_max_debt BLOB NOT NULL, is_open BOOL NOT NULL, From 3781bffba1ff20e2bb452b1ffa388c16ef0d5596 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 22 Jan 2021 16:58:41 +0200 Subject: [PATCH 380/478] funder: comments --- components/funder/src/mutual_credit/outgoing.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 1579bc792..8034edcfb 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -28,14 +28,13 @@ pub enum QueueOperationError { OpError(OpError), } -/// A wrapper over a token channel, accumulating operations to be sent as one transaction. +/// Queue a single operation mutual credit operation pub async fn queue_operation( mc_client: &mut impl McDbClient, operation: McOp, currency: &Currency, local_public_key: &PublicKey, ) -> Result<(), QueueOperationError> { - // TODO: Maybe remove clone from here later: match operation { McOp::Request(request) => queue_request_send_funds(mc_client, request, currency).await, McOp::Response(response) => { @@ -54,12 +53,6 @@ async fn queue_request_send_funds( return Err(QueueOperationError::InvalidRoute); } - /* - if request_send_funds.dest_payment > request_send_funds.total_dest_payment { - return Err(QueueOperationError::DestPaymentExceedsTotal); - } - */ - // Calculate amount of credits to freeze let own_freeze_credits = request .dest_payment From cd59b5a3f1838e53af20c51d765004743a70c7e5 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 22 Jan 2021 20:24:50 +0200 Subject: [PATCH 381/478] funder: Some ideas for handle_out_move_token(). WIP --- components/database/src/transaction.rs | 2 +- .../funder/src/mutual_credit/outgoing.rs | 14 ++--- .../funder/src/token_channel/token_channel.rs | 52 +++++++++++++++++++ 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/components/database/src/transaction.rs b/components/database/src/transaction.rs index 386749dfb..6f705cb4e 100644 --- a/components/database/src/transaction.rs +++ b/components/database/src/transaction.rs @@ -23,7 +23,7 @@ where { /// Begin a new transaction. /// Transaction ends at the end of the closure scope. - /// If the returned boolean is true, the transaction was successful. Otherwise, the transaction + /// If the returned value is Ok(..), the transaction was successful. Otherwise, the transaction /// was canceled. fn transaction<'a, F, T, E>(&'a mut self, f: F) -> BoxFuture<'a, Result> where diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 8034edcfb..e4fbc261a 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -28,6 +28,7 @@ pub enum QueueOperationError { OpError(OpError), } +/* /// Queue a single operation mutual credit operation pub async fn queue_operation( mc_client: &mut impl McDbClient, @@ -36,15 +37,16 @@ pub async fn queue_operation( local_public_key: &PublicKey, ) -> Result<(), QueueOperationError> { match operation { - McOp::Request(request) => queue_request_send_funds(mc_client, request, currency).await, + McOp::Request(request) => queue_request(mc_client, request, currency).await, McOp::Response(response) => { - queue_response_send_funds(mc_client, response, currency, local_public_key).await + queue_response(mc_client, response, currency, local_public_key).await } - McOp::Cancel(cancel) => queue_cancel_send_funds(mc_client, cancel).await, + McOp::Cancel(cancel) => queue_cancel(mc_client, cancel).await, } } +*/ -async fn queue_request_send_funds( +pub async fn queue_request( mc_client: &mut impl McDbClient, request: McRequest, currency: &Currency, @@ -91,7 +93,7 @@ async fn queue_request_send_funds( Ok(()) } -async fn queue_response_send_funds( +pub async fn queue_response( mc_client: &mut impl McDbClient, response: McResponse, currency: &Currency, @@ -182,7 +184,7 @@ async fn queue_response_send_funds( Ok(()) } -async fn queue_cancel_send_funds( +pub async fn queue_cancel( mc_client: &mut impl McDbClient, cancel: McCancel, ) -> Result<(), QueueOperationError> { diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 7edfd5a37..313a3de94 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -815,6 +815,58 @@ fn friend_tc_op_from_outgoing_tc_op(tc_op: TcOp) -> FriendTcOp { } } +pub struct OutMoveToken<'a, C> { + pub tc_client: &'a mut C, + tc_ops: Vec, +} + +impl<'a, C> OutMoveToken<'a, C> +where + C: TcDbClient, +{ + pub fn new(tc_client: &'a mut C) -> Self { + Self { + tc_client, + tc_ops: Vec::new(), + } + } + + pub async fn queue_request( + &mut self, + currency: Currency, + mc_request: McRequest, + ) -> Result<(), TokenChannelError> { + // TODO: Request might fail due to `local_max_debt`. + // Should we return a cancel message in this case? + todo!(); + } + + pub async fn queue_response( + &mut self, + currency: Currency, + mc_response: McResponse, + ) -> Result<(), TokenChannelError> { + todo!(); + } + + pub async fn queue_cancel( + &mut self, + currency: Currency, + mc_cancel: McCancel, + ) -> Result<(), TokenChannelError> { + todo!(); + } + + pub async fn finalize( + self, + identity_client: &mut IdentityClient, + local_public_key: &PublicKey, + remote_public_key: &PublicKey, + ) -> Result { + todo!(); + } +} + pub async fn handle_out_move_token( tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, From 95b52e394820ecf10703cff6ed5440fba49dd89f Mon Sep 17 00:00:00 2001 From: real Date: Sat, 23 Jan 2021 13:31:25 +0200 Subject: [PATCH 382/478] funder: mutual_credit: Added local_max_debt to queue_request() --- components/funder/src/lib.rs | 4 ++-- .../funder/src/mutual_credit/incoming.rs | 8 ++------ .../funder/src/mutual_credit/outgoing.rs | 20 +++++++++++++++++-- .../src/mutual_credit/tests/request_cancel.rs | 14 +++++-------- .../mutual_credit/tests/request_response.rs | 15 ++++++-------- .../funder/src/token_channel/token_channel.rs | 9 ++++----- 6 files changed, 37 insertions(+), 33 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index ff98aae7d..4684fc6f6 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -30,8 +30,8 @@ mod mutual_credit; mod route; // pub mod report; // mod state; -#[allow(unused)] -mod token_channel; +// #[allow(unused)] +// mod token_channel; // #[allow(unused)] // mod router; diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index b73444190..7913374db 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -115,17 +115,13 @@ async fn process_request_send_funds( .checked_add(own_freeze_credits) .ok_or(ProcessOperationError::CreditsCalcOverflow)?; - // Check that local_pending_debt - balance <= local_max_debt: + // Check that balance + remote_pending_debt - remote_max_debt > 0: let add = mc_balance .balance .checked_add_unsigned(new_remote_pending_debt) .ok_or(ProcessOperationError::CreditsCalcOverflow)?; - let incoming_message = if add - .checked_sub_unsigned(remote_max_debt) - .ok_or(ProcessOperationError::CreditsCalcOverflow)? - > 0 - { + let incoming_message = if add.saturating_sub_unsigned(remote_max_debt) > 0 { // Insufficient trust: IncomingMessage::RequestCancel(request_send_funds.clone()) } else { diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index e4fbc261a..44dd46c10 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -50,7 +50,8 @@ pub async fn queue_request( mc_client: &mut impl McDbClient, request: McRequest, currency: &Currency, -) -> Result<(), QueueOperationError> { + local_max_debt: u128, +) -> Result, QueueOperationError> { if !request.route.is_part_valid() { return Err(QueueOperationError::InvalidRoute); } @@ -69,6 +70,21 @@ pub async fn queue_request( .checked_add(own_freeze_credits) .ok_or(QueueOperationError::CreditsCalcOverflow)?; + // Make sure that we don't get into too much debt: + // Check that balance - local_pending_debt + local_max_debt >= 0 + // balance - local_pending_debt >= - local_max_debt + let sub = mc_balance + .balance + .checked_sub_unsigned(new_local_pending_debt) + .ok_or(QueueOperationError::CreditsCalcOverflow)?; + + if sub.saturating_add_unsigned(local_max_debt) < 0 { + // Too much local debt: + return Ok(Err(McCancel { + request_id: request.request_id, + })); + } + // Make sure that we don't have this request as a pending request already: if mc_client .get_local_pending_transaction(request.request_id.clone()) @@ -90,7 +106,7 @@ pub async fn queue_request( .set_local_pending_debt(new_local_pending_debt) .await?; - Ok(()) + Ok(Ok(())) } pub async fn queue_response( diff --git a/components/funder/src/mutual_credit/tests/request_cancel.rs b/components/funder/src/mutual_credit/tests/request_cancel.rs index 805faaa79..52ed2b310 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel.rs @@ -10,7 +10,7 @@ use crypto::test_utils::DummyRandom; use proto::crypto::{HashResult, PlainLock, PrivateKey, PublicKey, Uid}; use proto::funder::messages::Currency; -use crate::mutual_credit::outgoing::queue_operation; +use crate::mutual_credit::outgoing::queue_request; use crate::mutual_credit::tests::utils::{process_operations_list, MockMutualCredit}; use crate::mutual_credit::types::{McCancel, McDbClient, McOp, McRequest}; @@ -49,14 +49,10 @@ async fn task_request_cancel() { left_fees: 5, }; - queue_operation( - &mut mc_transaction, - McOp::Request(request), - ¤cy, - &local_public_key, - ) - .await - .unwrap(); + let local_max_debt = u128::MAX; + queue_request(&mut mc_transaction, request, ¤cy, local_max_debt) + .await + .unwrap(); let mc_balance = mc_transaction.get_balance().await.unwrap(); assert_eq!(mc_balance.balance, 0); diff --git a/components/funder/src/mutual_credit/tests/request_response.rs b/components/funder/src/mutual_credit/tests/request_response.rs index 30c5f922e..d8aa4df87 100644 --- a/components/funder/src/mutual_credit/tests/request_response.rs +++ b/components/funder/src/mutual_credit/tests/request_response.rs @@ -11,7 +11,8 @@ use proto::crypto::{HashResult, PlainLock, PrivateKey, PublicKey, Signature, Uid use proto::funder::messages::Currency; use signature::signature_buff::create_response_signature_buffer; -use crate::mutual_credit::outgoing::queue_operation; +use crate::mutual_credit::outgoing::queue_request; + use crate::mutual_credit::tests::utils::{process_operations_list, MockMutualCredit}; use crate::mutual_credit::types::{McDbClient, McOp, McRequest, McResponse}; use crate::mutual_credit::utils::{ @@ -55,14 +56,10 @@ async fn task_request_response() { let pending_transaction = pending_transaction_from_mc_request(request.clone(), currency.clone()); - queue_operation( - &mut mc_transaction, - McOp::Request(request), - ¤cy, - &local_public_key, - ) - .await - .unwrap(); + let local_max_debt = u128::MAX; + queue_request(&mut mc_transaction, request, ¤cy, local_max_debt) + .await + .unwrap(); let mc_balance = mc_transaction.get_balance().await.unwrap(); assert_eq!(mc_balance.balance, 0); diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 313a3de94..37f18da82 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -815,19 +815,18 @@ fn friend_tc_op_from_outgoing_tc_op(tc_op: TcOp) -> FriendTcOp { } } -pub struct OutMoveToken<'a, C> { - pub tc_client: &'a mut C, +pub struct OutMoveToken { tc_ops: Vec, } -impl<'a, C> OutMoveToken<'a, C> +impl OutMoveToken where C: TcDbClient, { - pub fn new(tc_client: &'a mut C) -> Self { + pub fn new(local_max_debt: usize) -> Self { Self { - tc_client, tc_ops: Vec::new(), + local_max_debt, } } From b129d48fd55cc06ef76fcd28bc666ba9e8c8d9f7 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 23 Jan 2021 14:35:22 +0200 Subject: [PATCH 383/478] funder: queue_response(): Removed redundant argument --- components/funder/src/mutual_credit/outgoing.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 44dd46c10..c8decf865 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -112,7 +112,6 @@ pub async fn queue_request( pub async fn queue_response( mc_client: &mut impl McDbClient, response: McResponse, - currency: &Currency, local_public_key: &PublicKey, ) -> Result<(), QueueOperationError> { // Make sure that id exists in remote_pending hashmap, @@ -132,7 +131,7 @@ pub async fn queue_response( // verify signature: let response_signature_buffer = create_response_signature_buffer( - currency, + &pending_transaction.currency, response_op_from_mc_response(response.clone()), &pending_transaction, ); From 3e9ad93371af68c4be4279f52cec635b81213bdd Mon Sep 17 00:00:00 2001 From: real Date: Sat, 23 Jan 2021 14:36:10 +0200 Subject: [PATCH 384/478] funder: Work on OutMoveToken. Not done yet. --- .../funder/src/token_channel/token_channel.rs | 65 ++++++++++++++----- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 37f18da82..adaef44ef 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -32,7 +32,9 @@ use signature::verify::verify_move_token; use database::transaction::{TransFunc, Transaction}; use crate::mutual_credit::incoming::{process_operation, IncomingMessage, ProcessOperationError}; -use crate::mutual_credit::outgoing::{queue_operation, QueueOperationError}; +use crate::mutual_credit::outgoing::{ + queue_cancel, queue_request, queue_response, QueueOperationError, +}; use crate::mutual_credit::types::{McCancel, McDbClient, McOp, McRequest, McResponse}; use crate::token_channel::types::{TcDbClient, TcStatus}; @@ -819,41 +821,74 @@ pub struct OutMoveToken { tc_ops: Vec, } -impl OutMoveToken -where - C: TcDbClient, -{ +impl OutMoveToken { pub fn new(local_max_debt: usize) -> Self { - Self { - tc_ops: Vec::new(), - local_max_debt, - } + Self { tc_ops: Vec::new() } } pub async fn queue_request( &mut self, + tc_client: &mut impl TcDbClient, currency: Currency, mc_request: McRequest, - ) -> Result<(), TokenChannelError> { - // TODO: Request might fail due to `local_max_debt`. - // Should we return a cancel message in this case? - todo!(); + local_max_debt: u128, + ) -> Result, TokenChannelError> { + // TODO: Remember to clean up all relevant pending requests when a currency is removed. + // Otherwise we might get to this state: + let mc_client = tc_client + .mc_db_client(currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidState)?; + // queue_request might fail due to `local_max_debt`. + let res = queue_request(mc_client, mc_request.clone(), ¤cy, local_max_debt).await?; + + self.tc_ops.push(TcOp { + currency, + mc_op: McOp::Request(mc_request), + }); + + Ok(res) } pub async fn queue_response( &mut self, + tc_client: &mut impl TcDbClient, currency: Currency, mc_response: McResponse, + local_public_key: &PublicKey, ) -> Result<(), TokenChannelError> { - todo!(); + let mc_client = tc_client + .mc_db_client(currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidState)?; + queue_response(mc_client, mc_response.clone(), local_public_key).await?; + + self.tc_ops.push(TcOp { + currency, + mc_op: McOp::Response(mc_response), + }); + + Ok(()) } pub async fn queue_cancel( &mut self, + tc_client: &mut impl TcDbClient, currency: Currency, mc_cancel: McCancel, ) -> Result<(), TokenChannelError> { - todo!(); + let mc_client = tc_client + .mc_db_client(currency.clone()) + .await? + .ok_or(TokenChannelError::InvalidState)?; + queue_cancel(mc_client, mc_cancel.clone()).await?; + + self.tc_ops.push(TcOp { + currency, + mc_op: McOp::Cancel(mc_cancel), + }); + + Ok(()) } pub async fn finalize( From 5218be1d60aa344bc9e7439a0be5e7f56f652685 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 23 Jan 2021 15:07:39 +0200 Subject: [PATCH 385/478] funder: Some work on OutMoveToken. WIP --- components/funder/src/lib.rs | 5 +- components/funder/src/token_channel/mod.rs | 6 +- .../funder/src/token_channel/token_channel.rs | 104 ++++++++++++++++-- 3 files changed, 98 insertions(+), 17 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 4684fc6f6..46f6c9544 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -30,11 +30,10 @@ mod mutual_credit; mod route; // pub mod report; // mod state; -// #[allow(unused)] -// mod token_channel; +#[allow(unused)] +mod token_channel; // #[allow(unused)] // mod router; - pub mod types; // #[cfg(test)] diff --git a/components/funder/src/token_channel/mod.rs b/components/funder/src/token_channel/mod.rs index d7509bd43..c4b9c8b5c 100644 --- a/components/funder/src/token_channel/mod.rs +++ b/components/funder/src/token_channel/mod.rs @@ -5,9 +5,9 @@ mod types; mod tests; pub use self::token_channel::{ - accept_remote_reset, handle_in_move_token, handle_out_move_token, initial_move_token, - load_remote_reset_terms, reset_balance_to_mc_balance, MoveTokenReceived, - ReceiveMoveTokenOutput, TokenChannelError, + accept_remote_reset, handle_in_move_token, initial_move_token, load_remote_reset_terms, + reset_balance_to_mc_balance, MoveTokenReceived, OutMoveToken, ReceiveMoveTokenOutput, + TokenChannelError, }; pub use types::{TcDbClient, TcStatus}; diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index adaef44ef..83e085070 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -817,28 +817,41 @@ fn friend_tc_op_from_outgoing_tc_op(tc_op: TcOp) -> FriendTcOp { } } -pub struct OutMoveToken { +pub struct OutMoveToken<'a, C> { + tc_client: &'a mut C, tc_ops: Vec, } -impl OutMoveToken { - pub fn new(local_max_debt: usize) -> Self { - Self { tc_ops: Vec::new() } +// TODO: What interface should we expose to the outside world to be able to use tc_client? +impl<'a, C> OutMoveToken<'a, C> +where + C: TcDbClient, +{ + pub fn new(tc_client: &'a mut C) -> Self { + Self { + tc_client, + tc_ops: Vec::new(), + } } pub async fn queue_request( &mut self, - tc_client: &mut impl TcDbClient, currency: Currency, mc_request: McRequest, local_max_debt: u128, ) -> Result, TokenChannelError> { // TODO: Remember to clean up all relevant pending requests when a currency is removed. // Otherwise we might get to this state: - let mc_client = tc_client + let mc_client = self + .tc_client .mc_db_client(currency.clone()) .await? .ok_or(TokenChannelError::InvalidState)?; + + // Add mutual credit if currency config exists. + // Note that the above statement might fail, and we might need to handle it. + todo!(); + // queue_request might fail due to `local_max_debt`. let res = queue_request(mc_client, mc_request.clone(), ¤cy, local_max_debt).await?; @@ -847,17 +860,24 @@ impl OutMoveToken { mc_op: McOp::Request(mc_request), }); + todo!(); + + // Remove mutual credit if all balances are zero. + + // Possible remove a currency config if mutual credit was removed, and currency is set for + // removal. + Ok(res) } pub async fn queue_response( &mut self, - tc_client: &mut impl TcDbClient, currency: Currency, mc_response: McResponse, local_public_key: &PublicKey, ) -> Result<(), TokenChannelError> { - let mc_client = tc_client + let mc_client = self + .tc_client .mc_db_client(currency.clone()) .await? .ok_or(TokenChannelError::InvalidState)?; @@ -868,16 +888,22 @@ impl OutMoveToken { mc_op: McOp::Response(mc_response), }); + todo!(); + + // Remove mutual credit if all balances are zero. + + // Possible remove a currency config if mutual credit was removed, and currency is set for + // removal. Ok(()) } pub async fn queue_cancel( &mut self, - tc_client: &mut impl TcDbClient, currency: Currency, mc_cancel: McCancel, ) -> Result<(), TokenChannelError> { - let mc_client = tc_client + let mc_client = self + .tc_client .mc_db_client(currency.clone()) .await? .ok_or(TokenChannelError::InvalidState)?; @@ -888,6 +914,13 @@ impl OutMoveToken { mc_op: McOp::Cancel(mc_cancel), }); + todo!(); + + // Remove mutual credit if all balances are zero. + + // Possible remove a currency config if mutual credit was removed, and currency is set for + // removal. + Ok(()) } @@ -897,10 +930,58 @@ impl OutMoveToken { local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result { - todo!(); + // We expect that our current state is incoming: + // TODO: Should we check this at the constructor? + let move_token_in = match self.tc_client.get_tc_status().await? { + TcStatus::ConsistentIn(move_token_in) => move_token_in, + TcStatus::ConsistentOut(..) | TcStatus::Inconsistent(..) => { + return Err(TokenChannelError::InvalidTokenChannelStatus); + } + }; + + let new_move_token_counter = self + .tc_client + .get_move_token_counter() + .await? + .checked_add(1) + .ok_or(TokenChannelError::MoveTokenCounterOverflow)?; + let mc_balances = self.tc_client.list_balances(); + + let token_info = TokenInfo { + balances_hash: hash_mc_infos(mc_balances).await?, + move_token_counter: new_move_token_counter, + }; + + let info_hash = hash_token_info(local_public_key, remote_public_key, &token_info); + + let mut move_token = MoveToken { + old_token: move_token_in.new_token, + operations: self + .tc_ops + .into_iter() + .map(|tc_op| friend_tc_op_from_outgoing_tc_op(tc_op)) + .collect(), + // Still not known: + new_token: Signature::from(&[0; Signature::len()]), + }; + + // Fill in signature: + let signature_buff = move_token_signature_buff(&move_token, &info_hash); + move_token.new_token = identity_client + .request_signature(signature_buff) + .await + .map_err(|_| TokenChannelError::RequestSignatureError)?; + + // Set the direction to be outgoing, and save last incoming token in an atomic way: + self.tc_client + .set_direction_outgoing(move_token.clone(), new_move_token_counter) + .await?; + + Ok(move_token) } } +/* pub async fn handle_out_move_token( tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, @@ -1058,6 +1139,7 @@ pub async fn handle_out_move_token( Ok(move_token) } +*/ /// Apply a token channel reset, accepting remote side's /// reset terms. From 495ced995a878d219b71b011f45e2124756049db Mon Sep 17 00:00:00 2001 From: real Date: Mon, 25 Jan 2021 15:00:45 +0200 Subject: [PATCH 386/478] funder: Work on OutMoveToken::queue_requets() --- .../funder/src/token_channel/token_channel.rs | 108 +++++++++++------- components/funder/src/token_channel/types.rs | 14 ++- 2 files changed, 79 insertions(+), 43 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 83e085070..d6f1f8f03 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -817,70 +817,96 @@ fn friend_tc_op_from_outgoing_tc_op(tc_op: TcOp) -> FriendTcOp { } } -pub struct OutMoveToken<'a, C> { - tc_client: &'a mut C, +pub struct OutMoveToken { tc_ops: Vec, } -// TODO: What interface should we expose to the outside world to be able to use tc_client? -impl<'a, C> OutMoveToken<'a, C> -where - C: TcDbClient, -{ - pub fn new(tc_client: &'a mut C) -> Self { - Self { - tc_client, - tc_ops: Vec::new(), - } +impl OutMoveToken { + pub fn new() -> Self { + Self { tc_ops: Vec::new() } } pub async fn queue_request( &mut self, + tc_client: &mut impl TcDbClient, currency: Currency, mc_request: McRequest, - local_max_debt: u128, ) -> Result, TokenChannelError> { - // TODO: Remember to clean up all relevant pending requests when a currency is removed. - // Otherwise we might get to this state: - let mc_client = self - .tc_client - .mc_db_client(currency.clone()) - .await? - .ok_or(TokenChannelError::InvalidState)?; + // Token channel must be in consistent incoming state + assert!(matches!( + tc_client.get_tc_status().await?, + TcStatus::ConsistentIn(..) + )); - // Add mutual credit if currency config exists. - // Note that the above statement might fail, and we might need to handle it. - todo!(); + // Try to get currency config: + let currency_config = + if let Some(currency_config) = tc_client.get_currency_config(currency.clone()).await? { + currency_config + } else { + return Ok(Err(McCancel { + request_id: mc_request.request_id, + })); + }; + + let mc_client = if let Some(mc_client) = tc_client.mc_db_client(currency.clone()).await? { + mc_client + } else { + // We need to create a new mutual credit + tc_client.add_local_currency(currency.clone()).await?; + tc_client + .mc_db_client(currency.clone()) + .await? + .expect("Invalid state") + }; // queue_request might fail due to `local_max_debt`. - let res = queue_request(mc_client, mc_request.clone(), ¤cy, local_max_debt).await?; + if let Err(mc_cancel) = queue_request( + mc_client, + mc_request.clone(), + ¤cy, + currency_config.local_max_debt, + ) + .await? + { + return Ok(Err(mc_cancel)); + } self.tc_ops.push(TcOp { - currency, + currency: currency.clone(), mc_op: McOp::Request(mc_request), }); - todo!(); + // Get resulting balances (After queue-ing the request): + let balances = mc_client.get_balance().await?; - // Remove mutual credit if all balances are zero. - - // Possible remove a currency config if mutual credit was removed, and currency is set for - // removal. + if tc_client.is_local_currency_remove(currency.clone()).await? { + // We are expecting to remove this currency + // If balance and pending credits are zero, we might be able to remove this + // currency: + if balances.balance == 0 + && balances.local_pending_debt == 0 + && balances.remote_pending_debt == 0 + { + tc_client.remove_local_currency(currency.clone()).await?; + // TODO: What to do with in_fees / out_fees? Do they need to be documented somehow? + // Will be documented in database code? + } + } - Ok(res) + Ok(Ok(())) } pub async fn queue_response( &mut self, + tc_client: &mut impl TcDbClient, currency: Currency, mc_response: McResponse, local_public_key: &PublicKey, ) -> Result<(), TokenChannelError> { - let mc_client = self - .tc_client + let mc_client = tc_client .mc_db_client(currency.clone()) .await? - .ok_or(TokenChannelError::InvalidState)?; + .expect("Invalid State"); queue_response(mc_client, mc_response.clone(), local_public_key).await?; self.tc_ops.push(TcOp { @@ -899,11 +925,11 @@ where pub async fn queue_cancel( &mut self, + tc_client: &mut impl TcDbClient, currency: Currency, mc_cancel: McCancel, ) -> Result<(), TokenChannelError> { - let mc_client = self - .tc_client + let mc_client = tc_client .mc_db_client(currency.clone()) .await? .ok_or(TokenChannelError::InvalidState)?; @@ -926,26 +952,26 @@ where pub async fn finalize( self, + tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result { // We expect that our current state is incoming: // TODO: Should we check this at the constructor? - let move_token_in = match self.tc_client.get_tc_status().await? { + let move_token_in = match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => move_token_in, TcStatus::ConsistentOut(..) | TcStatus::Inconsistent(..) => { return Err(TokenChannelError::InvalidTokenChannelStatus); } }; - let new_move_token_counter = self - .tc_client + let new_move_token_counter = tc_client .get_move_token_counter() .await? .checked_add(1) .ok_or(TokenChannelError::MoveTokenCounterOverflow)?; - let mc_balances = self.tc_client.list_balances(); + let mc_balances = tc_client.list_balances(); let token_info = TokenInfo { balances_hash: hash_mc_infos(mc_balances).await?, @@ -973,7 +999,7 @@ where .map_err(|_| TokenChannelError::RequestSignatureError)?; // Set the direction to be outgoing, and save last incoming token in an atomic way: - self.tc_client + tc_client .set_direction_outgoing(move_token.clone(), new_move_token_counter) .await?; diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 499afbe01..c2b1c6e82 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -42,6 +42,13 @@ impl TcStatus { } } +#[derive(Debug)] +pub struct TcCurrencyConfig { + pub remote_max_debt: u128, + pub local_max_debt: u128, + pub is_remove: bool, +} + pub trait TcDbClient { type McDbClient: McDbClient; fn mc_db_client(&mut self, currency: Currency) -> AsyncOpResult>; @@ -93,8 +100,11 @@ pub trait TcDbClient { fn get_move_token_counter(&mut self) -> AsyncOpResult; // fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; - /// Get currency's configured remote max debt - fn get_remote_max_debt(&mut self, currency: Currency) -> AsyncOpResult; + /// Get currency's config + fn get_currency_config( + &mut self, + currency: Currency, + ) -> AsyncOpResult>; /// Return a sorted async iterator of all balances fn list_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; From 8b1abca95f98198334690ff6a02ea8fbd01ddcc1 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 25 Jan 2021 15:02:48 +0200 Subject: [PATCH 387/478] funder: Comments --- components/funder/src/token_channel/types.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index c2b1c6e82..43d7a5be2 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -118,9 +118,11 @@ pub trait TcDbClient { fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, ResetBalance)>; fn is_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult; + // TODO: Should these functions be at the router module? fn set_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; fn unset_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; + // TODO: Rename these functions? fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult; fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult; From 20a76cbf256db336d4a6a9038af332b5241c560e Mon Sep 17 00:00:00 2001 From: real Date: Mon, 25 Jan 2021 18:13:49 +0200 Subject: [PATCH 388/478] funder: Work on OutMoveToken --- .../funder/src/token_channel/token_channel.rs | 86 +++++++------------ components/funder/src/token_channel/types.rs | 29 +++---- 2 files changed, 41 insertions(+), 74 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index d6f1f8f03..f7969c39f 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -831,28 +831,19 @@ impl OutMoveToken { tc_client: &mut impl TcDbClient, currency: Currency, mc_request: McRequest, - ) -> Result, TokenChannelError> { - // Token channel must be in consistent incoming state + ) -> Result, TokenChannelError> { + // Token channel must be at a consistent incoming state assert!(matches!( tc_client.get_tc_status().await?, TcStatus::ConsistentIn(..) )); - // Try to get currency config: - let currency_config = - if let Some(currency_config) = tc_client.get_currency_config(currency.clone()).await? { - currency_config - } else { - return Ok(Err(McCancel { - request_id: mc_request.request_id, - })); - }; - + let local_max_debt = tc_client.get_local_max_debt(currency.clone()).await?; let mc_client = if let Some(mc_client) = tc_client.mc_db_client(currency.clone()).await? { mc_client } else { // We need to create a new mutual credit - tc_client.add_local_currency(currency.clone()).await?; + tc_client.add_mutual_credit(currency.clone()).await?; tc_client .mc_db_client(currency.clone()) .await? @@ -860,13 +851,8 @@ impl OutMoveToken { }; // queue_request might fail due to `local_max_debt`. - if let Err(mc_cancel) = queue_request( - mc_client, - mc_request.clone(), - ¤cy, - currency_config.local_max_debt, - ) - .await? + if let Err(mc_cancel) = + queue_request(mc_client, mc_request.clone(), ¤cy, local_max_debt).await? { return Ok(Err(mc_cancel)); } @@ -877,23 +863,7 @@ impl OutMoveToken { }); // Get resulting balances (After queue-ing the request): - let balances = mc_client.get_balance().await?; - - if tc_client.is_local_currency_remove(currency.clone()).await? { - // We are expecting to remove this currency - // If balance and pending credits are zero, we might be able to remove this - // currency: - if balances.balance == 0 - && balances.local_pending_debt == 0 - && balances.remote_pending_debt == 0 - { - tc_client.remove_local_currency(currency.clone()).await?; - // TODO: What to do with in_fees / out_fees? Do they need to be documented somehow? - // Will be documented in database code? - } - } - - Ok(Ok(())) + Ok(Ok(mc_client.get_balance().await?)) } pub async fn queue_response( @@ -902,11 +872,18 @@ impl OutMoveToken { currency: Currency, mc_response: McResponse, local_public_key: &PublicKey, - ) -> Result<(), TokenChannelError> { + ) -> Result { + // Token channel must be at a consistent incoming state + assert!(matches!( + tc_client.get_tc_status().await?, + TcStatus::ConsistentIn(..) + )); + let mc_client = tc_client .mc_db_client(currency.clone()) .await? .expect("Invalid State"); + queue_response(mc_client, mc_response.clone(), local_public_key).await?; self.tc_ops.push(TcOp { @@ -914,13 +891,7 @@ impl OutMoveToken { mc_op: McOp::Response(mc_response), }); - todo!(); - - // Remove mutual credit if all balances are zero. - - // Possible remove a currency config if mutual credit was removed, and currency is set for - // removal. - Ok(()) + Ok(mc_client.get_balance().await?) } pub async fn queue_cancel( @@ -928,7 +899,13 @@ impl OutMoveToken { tc_client: &mut impl TcDbClient, currency: Currency, mc_cancel: McCancel, - ) -> Result<(), TokenChannelError> { + ) -> Result { + // Token channel must be at a consistent incoming state + assert!(matches!( + tc_client.get_tc_status().await?, + TcStatus::ConsistentIn(..) + )); + let mc_client = tc_client .mc_db_client(currency.clone()) .await? @@ -940,14 +917,7 @@ impl OutMoveToken { mc_op: McOp::Cancel(mc_cancel), }); - todo!(); - - // Remove mutual credit if all balances are zero. - - // Possible remove a currency config if mutual credit was removed, and currency is set for - // removal. - - Ok(()) + Ok(mc_client.get_balance().await?) } pub async fn finalize( @@ -957,8 +927,12 @@ impl OutMoveToken { local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result { - // We expect that our current state is incoming: - // TODO: Should we check this at the constructor? + // Token channel must be at a consistent incoming state + assert!(matches!( + tc_client.get_tc_status().await?, + TcStatus::ConsistentIn(..) + )); + let move_token_in = match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => move_token_in, TcStatus::ConsistentOut(..) | TcStatus::Inconsistent(..) => { diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 43d7a5be2..123ade36a 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -42,13 +42,6 @@ impl TcStatus { } } -#[derive(Debug)] -pub struct TcCurrencyConfig { - pub remote_max_debt: u128, - pub local_max_debt: u128, - pub is_remove: bool, -} - pub trait TcDbClient { type McDbClient: McDbClient; fn mc_db_client(&mut self, currency: Currency) -> AsyncOpResult>; @@ -100,11 +93,11 @@ pub trait TcDbClient { fn get_move_token_counter(&mut self) -> AsyncOpResult; // fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; - /// Get currency's config - fn get_currency_config( - &mut self, - currency: Currency, - ) -> AsyncOpResult>; + /// Get currency's remote max debt (A value that was set locally) + fn get_remote_max_debt(&mut self, currency: Currency) -> AsyncOpResult; + + /// Get currency's local max debt (A value that was set locally) + fn get_local_max_debt(&mut self, currency: Currency) -> AsyncOpResult; /// Return a sorted async iterator of all balances fn list_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; @@ -117,13 +110,13 @@ pub trait TcDbClient { /// Only relevant for inconsistent channels fn list_remote_reset_balances(&mut self) -> AsyncOpStream<(Currency, ResetBalance)>; - fn is_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult; + // fn is_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult; // TODO: Should these functions be at the router module? - fn set_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; - fn unset_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; + // fn set_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; + // fn unset_local_currency_remove(&mut self, currency: Currency) -> AsyncOpResult<()>; // TODO: Rename these functions? - fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; - fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult; - fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult; + // fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; + fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult; + // fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult; } From aaee3f77572638e6fdbf7d6bf42cf9d0fa8182bd Mon Sep 17 00:00:00 2001 From: real Date: Mon, 25 Jan 2021 18:14:24 +0200 Subject: [PATCH 389/478] funder: Removed comment --- .../funder/src/token_channel/token_channel.rs | 160 ------------------ 1 file changed, 160 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index f7969c39f..014b1edbf 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -981,166 +981,6 @@ impl OutMoveToken { } } -/* -pub async fn handle_out_move_token( - tc_client: &mut impl TcDbClient, - identity_client: &mut IdentityClient, - tc_ops: Vec, - local_public_key: &PublicKey, - remote_public_key: &PublicKey, -) -> Result { - // We expect that our current state is incoming: - let move_token_in = match tc_client.get_tc_status().await? { - TcStatus::ConsistentIn(move_token_in) => move_token_in, - TcStatus::ConsistentOut(..) | TcStatus::Inconsistent(..) => { - return Err(TokenChannelError::InvalidTokenChannelStatus); - } - }; - - // TODO: If mutual credit does not exist yet, we might need to create it here. - for tc_op in tc_ops.iter().cloned() { - queue_operation( - tc_client - .mc_db_client(tc_op.currency.clone()) - .await? - .ok_or(TokenChannelError::InvalidState)?, - tc_op.mc_op, - &tc_op.currency, - local_public_key, - ) - .await?; - - // If currency is marked for removal locally and all credits are zero, we need to remove the currency. - if tc_client - .is_local_currency_remove(tc_op.currency.clone()) - .await? - { - // If the balances are zero, we remove the currency: - let mc_balance = tc_client - .mc_db_client(tc_op.currency.clone()) - .await? - .ok_or(TokenChannelError::InvalidState)? - .get_balance() - .await?; - - if mc_balance.balance == 0 - && mc_balance.remote_pending_debt == 0 - && mc_balance.local_pending_debt == 0 - { - // We may remove the currency if the balance and pending debts are exactly - // zero: - tc_client - .remove_local_currency(tc_op.currency.clone()) - .await?; - // TODO: Do We need to report outside that we removed this currency somehow? - // TODO: Somehow unite all code for removing local currencies. - } - } - /* - TcOp::ToggleCurrency(currency) => { - // - If we don't have this currency locally configured: - // - Add the currency locally - // - Else (we have this currency locally): - // - If also enabled remotely: - // - Remove this currency if balance and pending debt is zero. - // - Else: - // - Remove this currency - - // Check if we need to add currency: - if !tc_client.is_local_currency(currency.clone()).await? { - // Add a new local currency. - tc_client.add_local_currency(currency.clone()).await?; - - // If we also have this currency as a remote currency, add a new mutual credit: - if tc_client.is_remote_currency(currency.clone()).await? { - tc_client.add_mutual_credit(currency.clone()); - } - } else { - // We have this currency locally: - if tc_client.is_remote_currency(currency.clone()).await? { - // Check if we already have this currency marked for removal - if tc_client.is_local_currency_remove(currency.clone()).await? { - // Currency is already marked for removal. - // We toggle the removal setting, setting the currency to be "not for - // removal". - tc_client - .unset_local_currency_remove(currency.clone()) - .await?; - } else { - // Currency was not marked for removal. - - // Mark the currency for removal: - tc_client - .set_local_currency_remove(currency.clone()) - .await?; - - // If the balances are zero, we remove the currency: - let mc_balance = tc_client - .mc_db_client(currency.clone()) - .await? - .ok_or(TokenChannelError::InvalidState)? - .get_balance() - .await?; - - if mc_balance.balance == 0 - && mc_balance.remote_pending_debt == 0 - && mc_balance.local_pending_debt == 0 - { - // We may remove the currency if the balance and pending debts are exactly - // zero: - tc_client.remove_local_currency(currency.clone()).await?; - // TODO: Do We need to report outside that we removed this currency somehow? - // TODO: Somehow unite all code for removing local currencies. - } - } - } else { - tc_client.remove_remote_currency(currency.clone()).await?; - // TODO: Do We need to report outside that we removed this currency somehow? - } - } - }*/ - } - - let new_move_token_counter = tc_client - .get_move_token_counter() - .await? - .checked_add(1) - .ok_or(TokenChannelError::MoveTokenCounterOverflow)?; - let mc_balances = tc_client.list_balances(); - - let token_info = TokenInfo { - balances_hash: hash_mc_infos(mc_balances).await?, - move_token_counter: new_move_token_counter, - }; - - let info_hash = hash_token_info(local_public_key, remote_public_key, &token_info); - - let mut move_token = MoveToken { - old_token: move_token_in.new_token, - operations: tc_ops - .into_iter() - .map(|tc_op| friend_tc_op_from_outgoing_tc_op(tc_op)) - .collect(), - // Still not known: - new_token: Signature::from(&[0; Signature::len()]), - }; - - // Fill in signature: - let signature_buff = move_token_signature_buff(&move_token, &info_hash); - move_token.new_token = identity_client - .request_signature(signature_buff) - .await - .map_err(|_| TokenChannelError::RequestSignatureError)?; - - // Set the direction to be outgoing, and save last incoming token in an atomic way: - tc_client - .set_direction_outgoing(move_token.clone(), new_move_token_counter) - .await?; - - Ok(move_token) -} -*/ - /// Apply a token channel reset, accepting remote side's /// reset terms. pub async fn accept_remote_reset( From a530535970d5bba19e53a73122a3e21eba89cabc Mon Sep 17 00:00:00 2001 From: real Date: Mon, 25 Jan 2021 19:26:02 +0200 Subject: [PATCH 390/478] funder: Work on handle_incoming_token_match() --- .../funder/src/token_channel/token_channel.rs | 139 ++++++++---------- components/funder/src/token_channel/types.rs | 22 ++- 2 files changed, 83 insertions(+), 78 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 014b1edbf..d7d8ba958 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -573,7 +573,7 @@ enum IncomingTokenMatchOutput { async fn handle_incoming_token_match( tc_client: &mut impl TcDbClient, - new_move_token: MoveToken, // remote_max_debts: &ImHashMap, + new_move_token: MoveToken, local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result { @@ -583,6 +583,7 @@ async fn handle_incoming_token_match( // is not correct. // TODO: Check if the above statement is still true. + // TODO: Verify signature after we perform all operations and able to calculate `info_hash`. // TODO: We need to be able to calculate info_hash here. let info_hash = todo!(); if !verify_move_token(&new_move_token, &info_hash, &remote_public_key) { @@ -596,77 +597,68 @@ async fn handle_incoming_token_match( incoming_messages: Vec::new(), }; - todo!(); - - /* + // Attempt to apply operations for every currency: + for friend_tc_op in new_move_token.operations.iter().cloned() { + let tc_op = + if let Some(tc_op) = tc_op_from_incoming_friend_tc_op(tc_client, friend_tc_op).await? { + tc_op + } else { + return Ok(IncomingTokenMatchOutput::InvalidIncoming( + InvalidIncoming::InvalidOperation, + )); + }; - // Handle active currencies: - - // currencies_diff represents a "xor" between the previous set of currencies and the new set of - // currencies. - // - // - Add to remote currencies every currency that is in the xor set, but not in the current - // set. - // - Remove from remote currencies currencies that satisfy the following requirements: - // - (1) in the xor set. - // - (2) in the remote set - // - (3) (Not in the local set) or (in the local set with balance zero and zero pending debts) - for diff_currency in &new_move_token.currencies_diff { - // Check if we need to add currency: - if !tc_client.is_remote_currency(diff_currency.clone()).await? { - // Add a new remote currency. - tc_client.add_remote_currency(diff_currency.clone()).await?; - - // If we also have this currency as a local currency, add a new mutual credit: - if tc_client.is_local_currency(diff_currency.clone()).await? { - tc_client.add_mutual_credit(diff_currency.clone()); - } + let remote_max_debt = if let Some(remote_max_debt) = tc_client + .get_currency_config(tc_op.currency.clone()) + .await? + .map(|currency_config| currency_config.remote_max_debt) + { + remote_max_debt } else { - let is_local_currency = tc_client.is_local_currency(diff_currency.clone()).await?; - if is_local_currency { - let mc_balance = tc_client - .mc_db_client(diff_currency.clone()) - .await? - .ok_or(TokenChannelError::InvalidState)? - .get_balance() - .await?; - if mc_balance.balance == 0 - && mc_balance.remote_pending_debt == 0 - && mc_balance.local_pending_debt == 0 - { - // We may remove the currency if the balance and pending debts are exactly - // zero: - tc_client - .remove_remote_currency(diff_currency.clone()) - .await?; - // TODO: Do We need to report outside that we removed this currency somehow? - // TODO: Somehow unite all code for removing remote currencies. - } else { - // We are not allowed to remove this currency! + // Currency is not configured. + match tc_op.mc_op { + McOp::Request(mc_request) => { + // In case of a request, we cancel it: + move_token_received.incoming_messages.push(( + tc_op.currency.clone(), + IncomingMessage::RequestCancel(mc_request), + )); + continue; + } + McOp::Response(..) | McOp::Cancel(..) => { return Ok(IncomingTokenMatchOutput::InvalidIncoming( - InvalidIncoming::CanNotRemoveCurrencyInUse, + InvalidIncoming::InvalidOperation, )); } - } else { - tc_client - .remove_remote_currency(diff_currency.clone()) - .await?; - // TODO: Do We need to report outside that we removed this currency somehow? } - } - } + }; - // Attempt to apply operations for every currency: - for (currency, friend_tc_op) in &new_move_token.currencies_operations { - let remote_max_debt = tc_client.get_remote_max_debt(currency.clone()).await?; + let mc_client = + if let Some(mc_client) = tc_client.mc_db_client(tc_op.currency.clone()).await? { + mc_client + } else { + match &tc_op.mc_op { + McOp::Request(..) => { + // An incoming request might allow opening a mutual credit, in case we have a matching + // currency configuration. Otherwise, the request should be cancelled. + tc_client.add_mutual_credit(tc_op.currency.clone()).await?; + tc_client + .mc_db_client(tc_op.currency.clone()) + .await? + .expect("Invalid state") + } + McOp::Response(..) | McOp::Cancel(..) => { + return Ok(IncomingTokenMatchOutput::InvalidIncoming( + InvalidIncoming::InvalidOperation, + )); + } + } + }; let res = process_operation( - tc_client - .mc_db_client(currency.clone()) - .await? - .ok_or(TokenChannelError::InvalidState)?, - friend_tc_op.clone(), - ¤cy, + mc_client, + tc_op.mc_op, + &tc_op.currency, remote_public_key, remote_max_debt, ) @@ -681,20 +673,15 @@ async fn handle_incoming_token_match( } }; - /* - // We apply mutations on this token channel, to verify stated balance values - // let mut check_mutual_credit = mutual_credit.clone(); - let move_token_received_currency = MoveTokenReceivedCurrency { - currency: currency.clone(), - incoming_messages, - }; - */ - move_token_received .incoming_messages - .push((currency.clone(), incoming_message)); + .push((tc_op.currency.clone(), incoming_message)); } + todo!(); + + /* + let move_token_counter = tc_client.get_move_token_counter().await?; let new_move_token_counter = move_token_counter .checked_add(1) @@ -838,7 +825,11 @@ impl OutMoveToken { TcStatus::ConsistentIn(..) )); - let local_max_debt = tc_client.get_local_max_debt(currency.clone()).await?; + let local_max_debt = tc_client + .get_currency_config(currency.clone()) + .await? + .expect("Invalid state") + .local_max_debt; let mc_client = if let Some(mc_client) = tc_client.mc_db_client(currency.clone()).await? { mc_client } else { diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 123ade36a..ce64501d3 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -42,6 +42,12 @@ impl TcStatus { } } +#[derive(Debug)] +pub struct TcCurrencyConfig { + pub local_max_debt: u128, + pub remote_max_debt: u128, +} + pub trait TcDbClient { type McDbClient: McDbClient; fn mc_db_client(&mut self, currency: Currency) -> AsyncOpResult>; @@ -93,11 +99,19 @@ pub trait TcDbClient { fn get_move_token_counter(&mut self) -> AsyncOpResult; // fn set_move_token_counter(&mut self, move_token_counter: u128) -> AsyncOpResult<()>; - /// Get currency's remote max debt (A value that was set locally) - fn get_remote_max_debt(&mut self, currency: Currency) -> AsyncOpResult; + // fn is_currency_config(&mut self, currency: Currency) -> AsyncOpResult; + + // /// Get currency's remote max debt (A value that was set locally) + // fn get_remote_max_debt(&mut self, currency: Currency) -> AsyncOpResult; - /// Get currency's local max debt (A value that was set locally) - fn get_local_max_debt(&mut self, currency: Currency) -> AsyncOpResult; + // /// Get currency's local max debt (A value that was set locally) + // fn get_local_max_debt(&mut self, currency: Currency) -> AsyncOpResult; + + /// Get currency's configuration + fn get_currency_config( + &mut self, + currency: Currency, + ) -> AsyncOpResult>; /// Return a sorted async iterator of all balances fn list_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; From 99ac70b56386ed353737ca8bdf0cec16a54f53c5 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 25 Jan 2021 19:27:55 +0200 Subject: [PATCH 391/478] funder: impl handle_incoming_token_match() --- .../funder/src/token_channel/token_channel.rs | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index d7d8ba958..0a0d4ce94 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -561,7 +561,6 @@ async fn hash_mc_infos( enum InvalidIncoming { InvalidSignature, InvalidOperation, - InvalidTokenInfo, CanNotRemoveCurrencyInUse, } @@ -583,15 +582,6 @@ async fn handle_incoming_token_match( // is not correct. // TODO: Check if the above statement is still true. - // TODO: Verify signature after we perform all operations and able to calculate `info_hash`. - // TODO: We need to be able to calculate info_hash here. - let info_hash = todo!(); - if !verify_move_token(&new_move_token, &info_hash, &remote_public_key) { - return Ok(IncomingTokenMatchOutput::InvalidIncoming( - InvalidIncoming::InvalidSignature, - )); - } - // Aggregate incoming messages: let mut move_token_received = MoveTokenReceived { incoming_messages: Vec::new(), @@ -678,10 +668,6 @@ async fn handle_incoming_token_match( .push((tc_op.currency.clone(), incoming_message)); } - todo!(); - - /* - let move_token_counter = tc_client.get_move_token_counter().await?; let new_move_token_counter = move_token_counter .checked_add(1) @@ -701,9 +687,10 @@ async fn handle_incoming_token_match( let info_hash = hash_token_info(remote_public_key, local_public_key, &token_info); - if new_move_token.info_hash != info_hash { + // Verify signature: + if !verify_move_token(&new_move_token, &info_hash, &remote_public_key) { return Ok(IncomingTokenMatchOutput::InvalidIncoming( - InvalidIncoming::InvalidTokenInfo, + InvalidIncoming::InvalidSignature, )); } @@ -716,7 +703,6 @@ async fn handle_incoming_token_match( Ok(IncomingTokenMatchOutput::MoveTokenReceived( move_token_received, )) - */ } #[derive(Debug, Clone)] From 8cb5a6658c390cc383c67cbfd22aeee404fd56ea Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 10:56:21 +0200 Subject: [PATCH 392/478] funder: Return error instead of expect() --- components/funder/src/token_channel/token_channel.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 0a0d4ce94..0edecfc1d 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -635,7 +635,7 @@ async fn handle_incoming_token_match( tc_client .mc_db_client(tc_op.currency.clone()) .await? - .expect("Invalid state") + .ok_or(TokenChannelError::InvalidState)? } McOp::Response(..) | McOp::Cancel(..) => { return Ok(IncomingTokenMatchOutput::InvalidIncoming( @@ -814,7 +814,7 @@ impl OutMoveToken { let local_max_debt = tc_client .get_currency_config(currency.clone()) .await? - .expect("Invalid state") + .ok_or(TokenChannelError::InvalidState)? .local_max_debt; let mc_client = if let Some(mc_client) = tc_client.mc_db_client(currency.clone()).await? { mc_client @@ -824,7 +824,7 @@ impl OutMoveToken { tc_client .mc_db_client(currency.clone()) .await? - .expect("Invalid state") + .ok_or(TokenChannelError::InvalidState)? }; // queue_request might fail due to `local_max_debt`. @@ -859,7 +859,7 @@ impl OutMoveToken { let mc_client = tc_client .mc_db_client(currency.clone()) .await? - .expect("Invalid State"); + .ok_or(TokenChannelError::InvalidState)?; queue_response(mc_client, mc_response.clone(), local_public_key).await?; From 4ee779cbb36cc14b17cd31f75e9daa94300933ae Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 10:57:26 +0200 Subject: [PATCH 393/478] funder: comment --- components/funder/src/token_channel/token_channel.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 0edecfc1d..c8b672426 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -48,6 +48,7 @@ pub enum TokenChannelError { CanNotRemoveCurrencyInUse, InvalidTokenChannelStatus, RequestSignatureError, + // TODO: Should we panic instead of returning InvalidState error? InvalidState, OpError(OpError), QueueOperationError(QueueOperationError), From 0ec2900eaf2b837fff20f7863dee954a9f687037 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 11:03:41 +0200 Subject: [PATCH 394/478] funder: impl accept_remote_reset() --- .../funder/src/token_channel/token_channel.rs | 34 +++++++------------ components/funder/src/types.rs | 4 +-- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index c8b672426..48e8ad0ee 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -400,7 +400,7 @@ async fn handle_in_move_token_dir_in( move_token_in: MoveTokenHashed, new_move_token: MoveToken, ) -> Result { - if move_token_in == create_hashed(&new_move_token, &move_token_in.token_info) { + if move_token_in == create_hashed(&new_move_token, move_token_in.token_info.clone()) { // Duplicate Ok(ReceiveMoveTokenOutput::Duplicate) } else { @@ -696,7 +696,7 @@ async fn handle_incoming_token_match( } // Set direction to outgoing, with the newly received move token: - let new_move_token_hashed = create_hashed(&new_move_token, &token_info); + let new_move_token_hashed = create_hashed(&new_move_token, token_info); tc_client .set_direction_incoming(new_move_token_hashed) .await?; @@ -968,11 +968,7 @@ pub async fn accept_remote_reset( local_public_key: &PublicKey, remote_public_key: &PublicKey, ) -> Result { - todo!(); - - /* - - // Make sure that we are in inconsistent state, + // Make sure that we are in an inconsistent state, // and that the remote side has already sent his reset terms: let (remote_reset_token, remote_reset_move_token_counter) = match tc_client.get_tc_status().await? { @@ -1001,27 +997,23 @@ pub async fn accept_remote_reset( let move_token_in = MoveToken { old_token: Signature::from(&[0; Signature::len()]), - currencies_operations: Vec::new(), - currencies_diff: Vec::new(), - info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), + operations: Vec::new(), new_token: remote_reset_token.clone(), }; tc_client - .set_incoming_from_inconsistent(create_hashed(&move_token_in, &token_info)) + .set_incoming_from_inconsistent(create_hashed(&move_token_in, token_info)) .await?; // Create an outgoing move token, to be sent to the remote side: - handle_out_move_token( - tc_client, - identity_client, - currencies_operations, - currencies_diff, - local_public_key, - remote_public_key, - ) - .await - */ + OutMoveToken::new() + .finalize( + tc_client, + identity_client, + local_public_key, + remote_public_key, + ) + .await } /// Load the remote reset terms information from a remote side's inconsistency message diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index 9bf45dccc..ca6f9f2d3 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -164,10 +164,10 @@ where /// Create a hashed version of the MoveToken. /// Hashed version contains the hash of the operations instead of the operations themselves, /// hence it is usually shorter. -pub fn create_hashed(move_token: &MoveToken, token_info: &TokenInfo) -> MoveTokenHashed { +pub fn create_hashed(move_token: &MoveToken, token_info: TokenInfo) -> MoveTokenHashed { MoveTokenHashed { old_token: move_token.old_token.clone(), - token_info: token_info.clone(), + token_info, new_token: move_token.new_token.clone(), } } From 8e9abdcab4c15ce872adeceed05e3a89992ec5a6 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 11:05:30 +0200 Subject: [PATCH 395/478] funder: Updated comment --- components/funder/src/token_channel/token_channel.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 48e8ad0ee..c68d403af 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -332,14 +332,10 @@ where } } -// TODO: Think abou the security implications of the implementation here. -// Some previous ideas: -// - Use a random generator to randomly generate an identity client. -// - Sign over a blob that contains: -// - hash(prefix ("SOME_STRING")) -// - Both public keys. -// - local_reset_move_token_counter - +// Sign over a blob that contains: +// - hash(prefix ("SOME_STRING")) +// - Both public keys. +// - local_reset_move_token_counter /// Generate a reset token, to be used by remote side if he wants to accept the reset terms. async fn create_reset_token( identity_client: &mut IdentityClient, From a2c36dca5fd9348d57d92f8cbbea322015837ce8 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 11:06:09 +0200 Subject: [PATCH 396/478] funder: Removed redundant comment --- .../funder/src/token_channel/token_channel.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index c68d403af..fb5585568 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -273,26 +273,9 @@ where if new_move_token.old_token == local_reset_terms.reset_token { // This is a reset move token! - /* - // Simulate an outgoing move token with the correct `new_token`: - let token_info = TokenInfo { - balances_hash: hash_mc_infos(tc_client.list_local_reset_balances().map_ok( - |(currency, mc_balance)| { - (currency, reset_balance_to_mc_balance(mc_balance)) - }, - )) - .await?, - move_token_counter: local_reset_terms - .move_token_counter - .checked_sub(1) - .ok_or(TokenChannelError::MoveTokenCounterOverflow)?, - }; - */ - let move_token_out = MoveToken { old_token: Signature::from(&[0; Signature::len()]), operations: Vec::new(), - // info_hash: hash_token_info(local_public_key, remote_public_key, &token_info), new_token: local_reset_terms.reset_token.clone(), }; From 48ce04d8798e8595de31b7ea57ea9cb6d54b17f9 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 13:20:36 +0200 Subject: [PATCH 397/478] funder: Work on token_channel tests --- .../funder/src/token_channel/tests/mod.rs | 4 +- .../funder/src/token_channel/tests/utils.rs | 75 ++++++++----------- components/funder/src/token_channel/types.rs | 4 +- 3 files changed, 35 insertions(+), 48 deletions(-) diff --git a/components/funder/src/token_channel/tests/mod.rs b/components/funder/src/token_channel/tests/mod.rs index d4c845de9..09389a78f 100644 --- a/components/funder/src/token_channel/tests/mod.rs +++ b/components/funder/src/token_channel/tests/mod.rs @@ -1,5 +1,5 @@ -mod inconsistency_resolve; -mod move_token_basic; +// mod inconsistency_resolve; +// mod move_token_basic; mod utils; // TODO: Add more tests diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 2f5726a22..1c8f5a2ba 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -9,7 +9,7 @@ use common::conn::BoxFuture; use common::safe_arithmetic::SafeSignedArithmetic; use common::u256::U256; -use proto::crypto::{PublicKey, Signature}; +use proto::crypto::{PublicKey, Signature, Uid}; use proto::funder::messages::{ Currency, McBalance, MoveToken, ResetBalance, ResetTerms, TokenInfo, }; @@ -23,7 +23,7 @@ use crypto::hash::hash_buffer; use crypto::identity::compare_public_key; use crate::mutual_credit::tests::MockMutualCredit; -use crate::token_channel::types::TcStatus; +use crate::token_channel::types::{TcCurrencyConfig, TcStatus}; use crate::token_channel::{initial_move_token, reset_balance_to_mc_balance, TcDbClient}; use crate::types::{create_hashed, MoveTokenHashed}; @@ -38,8 +38,6 @@ pub struct TcConsistent { mutual_credits: HashMap, direction: MockTcDirection, move_token_counter: u128, - local_currencies: HashSet, - remote_currencies: HashSet, } #[derive(Debug, Clone)] @@ -51,9 +49,8 @@ pub enum MockTcStatus { #[derive(Debug, Clone)] pub struct MockTokenChannel { status: MockTcStatus, - /// Remote max debt, configured for each currency - /// (And possibly for currencies that are not yet active) - pub remote_max_debts: HashMap, + /// All currency configurations, as seen from the TokenChannel + pub currency_configs: HashMap, } impl MockTokenChannel { @@ -70,10 +67,8 @@ impl MockTokenChannel { None, ), move_token_counter, - local_currencies: HashSet::new(), - remote_currencies: HashSet::new(), }), - remote_max_debts: HashMap::new(), + currency_configs: HashMap::new(), } } else { // We are the second sender @@ -87,12 +82,10 @@ impl MockTokenChannel { MockTokenChannel { status: MockTcStatus::Consistent(TcConsistent { mutual_credits: HashMap::new(), - direction: MockTcDirection::In(create_hashed(&move_token_in, &token_info)), + direction: MockTcDirection::In(create_hashed(&move_token_in, token_info)), move_token_counter, - local_currencies: HashSet::new(), - remote_currencies: HashSet::new(), }), - remote_max_debts: HashMap::new(), + currency_configs: HashMap::new(), } } } @@ -124,16 +117,19 @@ fn calc_reset_balance(mock_token_channel: &MockMutualCredit) -> ResetBalance { impl TcDbClient for MockTokenChannel { type McDbClient = MockMutualCredit; - // TODO: Maybe take into account other return values, like None, instead of unwrapping? fn mc_db_client(&mut self, currency: Currency) -> AsyncOpResult> { match &mut self.status { - MockTcStatus::Consistent(tc_consistent) => Box::pin(future::ready(Ok(Some( - tc_consistent.mutual_credits.get_mut(¤cy).unwrap(), - )))), - _ => unreachable!(), + MockTcStatus::Consistent(tc_consistent) => Box::pin(future::ready(Ok(tc_consistent + .mutual_credits + .get_mut(¤cy)))), + MockTcStatus::Inconsistent(..) => Box::pin(future::ready(Ok(None))), } } + fn get_currency_local_request(&mut self, request_id: Uid) -> AsyncOpResult> { + todo!(); + } + fn get_tc_status(&mut self) -> AsyncOpResult { let res = Ok(match &self.status { MockTcStatus::Consistent(tc_consistent) => match &tc_consistent.direction { @@ -296,19 +292,19 @@ impl TcDbClient for MockTokenChannel { }) .collect(); + /* let currencies_set: HashSet<_> = local_reset_terms .reset_balances .iter() .map(|(currency, _)| currency) .cloned() .collect(); + */ self.status = MockTcStatus::Consistent(TcConsistent { mutual_credits, direction: MockTcDirection::Out(move_token, None), move_token_counter: local_reset_terms.move_token_counter.checked_sub(1).unwrap(), - local_currencies: currencies_set.clone(), - remote_currencies: currencies_set, }); Box::pin(future::ready(Ok(()))) @@ -344,12 +340,14 @@ impl TcDbClient for MockTokenChannel { }) .collect(); + /* let currencies_set: HashSet<_> = remote_reset_terms .reset_balances .iter() .map(|(currency, _)| currency) .cloned() .collect(); + */ self.status = MockTcStatus::Consistent(TcConsistent { mutual_credits, @@ -358,8 +356,6 @@ impl TcDbClient for MockTokenChannel { .move_token_counter .checked_sub(1) .unwrap(), - local_currencies: currencies_set.clone(), - remote_currencies: currencies_set, }); Box::pin(future::ready(Ok(()))) @@ -372,11 +368,14 @@ impl TcDbClient for MockTokenChannel { }))) } - fn get_remote_max_debt(&mut self, currency: Currency) -> AsyncOpResult { - Box::pin(future::ready(Ok(*self - .remote_max_debts + fn get_currency_config( + &mut self, + currency: Currency, + ) -> AsyncOpResult> { + Box::pin(future::ready(Ok(self + .currency_configs .get(¤cy) - .unwrap()))) + .cloned()))) } /// Return a sorted async iterator of all balances @@ -436,23 +435,8 @@ impl TcDbClient for MockTokenChannel { Box::pin(stream::iter(balances_vec.into_iter().map(|item| Ok(item)))) } - fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult { - let local_currencies = match &self.status { - MockTcStatus::Consistent(tc_consistent) => &tc_consistent.local_currencies, - MockTcStatus::Inconsistent(..) => unreachable!(), - }; - Box::pin(future::ready(Ok(local_currencies.contains(¤cy)))) - } - - fn is_remote_currency(&mut self, currency: Currency) -> AsyncOpResult { - let remote_currencies = match &self.status { - MockTcStatus::Consistent(tc_consistent) => &tc_consistent.remote_currencies, - MockTcStatus::Inconsistent(..) => unreachable!(), - }; - Box::pin(future::ready(Ok(remote_currencies.contains(¤cy)))) - } - - fn add_local_currency(&mut self, currency: Currency) -> AsyncOpResult { + /* + fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()> { Box::pin(future::ready(Ok(match &mut self.status { MockTcStatus::Consistent(tc_consistent) => { tc_consistent.local_currencies.insert(currency) @@ -460,7 +444,9 @@ impl TcDbClient for MockTokenChannel { MockTcStatus::Inconsistent(..) => unreachable!(), }))) } + */ + /* fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult { Box::pin(future::ready(Ok(match &mut self.status { MockTcStatus::Consistent(tc_consistent) => { @@ -487,6 +473,7 @@ impl TcDbClient for MockTokenChannel { MockTcStatus::Inconsistent(..) => unreachable!(), }))) } + */ fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()> { let balance = 0; diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index ce64501d3..e29e3c072 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -42,7 +42,7 @@ impl TcStatus { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TcCurrencyConfig { pub local_max_debt: u128, pub remote_max_debt: u128, @@ -131,6 +131,6 @@ pub trait TcDbClient { // TODO: Rename these functions? // fn is_local_currency(&mut self, currency: Currency) -> AsyncOpResult; - fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult; + fn add_mutual_credit(&mut self, currency: Currency) -> AsyncOpResult<()>; // fn remove_local_currency(&mut self, currency: Currency) -> AsyncOpResult; } From 0e041e90d3281a82ce1a2763dc84082ade807feb Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 14:06:46 +0200 Subject: [PATCH 398/478] funder: Derived Eq for McRequest, McResponse, McCancel --- components/funder/src/mutual_credit/types.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 82b62ece2..3c2a0eabe 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -5,7 +5,7 @@ use common::u256::U256; use proto::crypto::{HashResult, HashedLock, PlainLock, PublicKey, Signature, Uid}; use proto::funder::messages::{McBalance, PendingTransaction}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct McRequest { /// Id number of this request. Used to identify the whole transaction /// over this route. @@ -25,7 +25,7 @@ pub struct McRequest { pub left_fees: u128, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct McResponse { /// Id number of this request. Used to identify the whole transaction /// over this route. @@ -45,7 +45,7 @@ pub struct McResponse { pub signature: Signature, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct McCancel { /// Id number of this request. Used to identify the whole transaction /// over this route. From 7e1dafef39ea32d3eb705c7014c7e499a7a7007d Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 14:30:03 +0200 Subject: [PATCH 399/478] funder: Work on token channel move_token_basic test --- .../funder/src/token_channel/tests/mod.rs | 2 +- .../token_channel/tests/move_token_basic.rs | 167 +++++++++++------- 2 files changed, 101 insertions(+), 68 deletions(-) diff --git a/components/funder/src/token_channel/tests/mod.rs b/components/funder/src/token_channel/tests/mod.rs index 09389a78f..b3a5012bb 100644 --- a/components/funder/src/token_channel/tests/mod.rs +++ b/components/funder/src/token_channel/tests/mod.rs @@ -1,5 +1,5 @@ // mod inconsistency_resolve; -// mod move_token_basic; +mod move_token_basic; mod utils; // TODO: Add more tests diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index 8ea8087a0..e0f621dc6 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use std::convert::TryFrom; use futures::task::SpawnExt; @@ -16,17 +15,18 @@ use signature::signature_buff::create_response_signature_buffer; use proto::crypto::{ HashResult, HashedLock, HmacResult, PlainLock, PrivateKey, PublicKey, Signature, Uid, }; -use proto::funder::messages::{ - Currency, CurrencyOperations, FriendTcOp, RequestSendFundsOp, ResponseSendFundsOp, -}; +use proto::funder::messages::{Currency, FriendTcOp, RequestSendFundsOp, ResponseSendFundsOp}; use identity::{create_identity, IdentityClient}; use crate::mutual_credit::incoming::IncomingMessage; +use crate::mutual_credit::types::{McRequest, McResponse}; + use crate::token_channel::tests::utils::MockTokenChannel; +use crate::token_channel::types::TcCurrencyConfig; use crate::token_channel::{ - accept_remote_reset, handle_in_move_token, handle_out_move_token, reset_balance_to_mc_balance, - MoveTokenReceived, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, + accept_remote_reset, handle_in_move_token, reset_balance_to_mc_balance, MoveTokenReceived, + OutMoveToken, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; use crate::types::create_pending_transaction; @@ -69,20 +69,17 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .spawn(identity_server_b.then(|_| future::ready(()))) .unwrap(); + /* // Send a MoveToken message from b to a, adding a currency: // -------------------------------------------------------- - let currencies_operations = Vec::new(); - let currencies_diff = vec![currency1.clone()]; - let move_token = handle_out_move_token( - &mut tc_b_a, - &mut identity_client_b, - currencies_operations, - currencies_diff, - &pk_b, - &pk_a, - ) - .await - .unwrap(); + // let currencies_operations = Vec::new(); + // let currencies_diff = vec![currency1.clone()]; + + let out_move_token = OutMoveToken::new(); + let move_token = out_move_token + .finalize(&mut tc_b_a, &mut identity_client_b, &pk_b, &pk_a) + .await + .unwrap(); // Receive the MoveToken message at a: // ----------------------------------- @@ -126,26 +123,55 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .await, Ok(ReceiveMoveTokenOutput::Received(_)) )); + */ + + // Add currency config at b, to be able to send a request to a: + // --------------------------------------------------------------------------------- + tc_b_a.currency_configs.insert( + currency1.clone(), + TcCurrencyConfig { + local_max_debt: u128::MAX, + remote_max_debt: 0, + }, + ); // Send a MoveToken message from b to a, sending a request send funds message: // --------------------------------------------------------------------------- let src_plain_lock = PlainLock::from(&[0xaa; PlainLock::len()]); - let request_send_funds_op = RequestSendFundsOp { + let mc_request = McRequest { request_id: Uid::from(&[0; Uid::len()]), - currency: currency1.clone(), - src_hashed_lock: src_plain_lock.hash_lock(), - route: vec![pk_a.clone()], + src_hashed_lock: src_plain_lock.clone().hash_lock(), dest_payment: 20u128, invoice_hash: HashResult::from(&[0; HashResult::len()]), + route: vec![pk_a.clone()], left_fees: 5u128, }; - let pending_transaction = create_pending_transaction(&request_send_funds_op); - let currencies_operations = vec![( - currency1.clone(), - FriendTcOp::RequestSendFunds(request_send_funds_op.clone()), - )]; - let currencies_diff = vec![]; + // TODO: How can this be done more elegantly? + let pending_transaction = { + let request_send_funds_op = RequestSendFundsOp { + request_id: mc_request.request_id.clone(), + currency: currency1.clone(), + src_hashed_lock: mc_request.src_hashed_lock.clone(), + dest_payment: mc_request.dest_payment.clone(), + invoice_hash: mc_request.invoice_hash.clone(), + route: mc_request.route.clone(), + left_fees: mc_request.left_fees, + }; + create_pending_transaction(&request_send_funds_op) + }; + + let mut out_move_token = OutMoveToken::new(); + let mc_balance = out_move_token + .queue_request(&mut tc_b_a, currency1.clone(), mc_request.clone()) + .await + .unwrap(); + let move_token = out_move_token + .finalize(&mut tc_b_a, &mut identity_client_b, &pk_b, &pk_a) + .await + .unwrap(); + + /* let move_token = handle_out_move_token( &mut tc_b_a, &mut identity_client_b, @@ -156,6 +182,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { ) .await .unwrap(); + */ { // Assert balances: @@ -176,7 +203,13 @@ async fn task_move_token_basic(test_executor: TestExecutor) { // Add a remote max debt to a, so that `a` will be able to receive credits from `b`: // --------------------------------------------------------------------------------- - tc_a_b.remote_max_debts.insert(currency1.clone(), 100u128); + tc_a_b.currency_configs.insert( + currency1.clone(), + TcCurrencyConfig { + local_max_debt: u128::MAX, + remote_max_debt: 100u128, + }, + ); // Receive the MoveToken message at a: // ---------------------------------- @@ -201,53 +234,53 @@ async fn task_move_token_basic(test_executor: TestExecutor) { assert_eq!(incoming_messages.len(), 1); let (currency, incoming_message) = incoming_messages.pop().unwrap(); assert_eq!(currency, currency1); - let received_request_send_funds_op = match incoming_message { - IncomingMessage::Request(request_send_funds_op) => request_send_funds_op, + let received_mc_request = match incoming_message { + IncomingMessage::Request(received_mc_request) => received_mc_request, _ => unreachable!(), }; - assert_eq!(received_request_send_funds_op, request_send_funds_op); + assert_eq!(received_mc_request, mc_request); // Send a MoveToken message from a to b, sending a response send funds message: // ---------------------------------------------------------------------------- - let mut response_send_funds_op = ResponseSendFundsOp { - // Matches earlier's request_id: - request_id: Uid::from(&[0; Uid::len()]), - src_plain_lock, - serial_num: 0, - // Temporary signature value, calculated later: - signature: Signature::from(&[0; Signature::len()]), + + // TODO: How to do this more elegantly? + let mc_response = { + let mut mc_response = McResponse { + request_id: Uid::from(&[0; Uid::len()]), + src_plain_lock, + serial_num: 0, + // Temporary signature value, calculated later: + signature: Signature::from(&[0; Signature::len()]), + }; + let response_send_funds_op = ResponseSendFundsOp { + request_id: mc_response.request_id.clone(), + src_plain_lock: mc_response.src_plain_lock.clone(), + serial_num: mc_response.serial_num.clone(), + signature: mc_response.signature.clone(), + }; + + // Sign the response: + let sign_buffer = create_response_signature_buffer( + ¤cy1, + response_send_funds_op.clone(), + &pending_transaction, + ); + mc_response.signature = identity_client_a + .request_signature(sign_buffer) + .await + .unwrap(); + mc_response }; - // Sign the response: - let sign_buffer = create_response_signature_buffer( - ¤cy1, - response_send_funds_op.clone(), - &pending_transaction, - ); - response_send_funds_op.signature = identity_client_a - .request_signature(sign_buffer) + let mut out_move_token = OutMoveToken::new(); + let _mc_balance = out_move_token + .queue_response(&mut tc_a_b, currency1.clone(), mc_response, &pk_a) + .await + .unwrap(); + let move_token = out_move_token + .finalize(&mut tc_a_b, &mut identity_client_a, &pk_a, &pk_b) .await .unwrap(); - - let currencies_operations = vec![( - currency1.clone(), - FriendTcOp::ResponseSendFunds(response_send_funds_op.clone()), - )]; - let currencies_diff = vec![]; - let move_token = handle_out_move_token( - &mut tc_a_b, - &mut identity_client_a, - currencies_operations, - currencies_diff, - &pk_a, - &pk_b, - ) - .await - .unwrap(); - - // Insert remote_max_debt for currency1, to allow handling incoming operations for this currency. - // --------------------------------------------------------------------------------------------- - tc_b_a.remote_max_debts.insert(currency1.clone(), 20u128); // Receive the MoveToken message at b: // ---------------------------------- From b7a7870def7a9f3bf3ea15a3ca7fa89cbcefdaa2 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 14:40:11 +0200 Subject: [PATCH 400/478] funder: token_channel: Restored move_token_basic test --- .../token_channel/tests/move_token_basic.rs | 2 +- .../funder/src/token_channel/tests/utils.rs | 20 ++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index e0f621dc6..184c5c6e1 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -207,7 +207,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { currency1.clone(), TcCurrencyConfig { local_max_debt: u128::MAX, - remote_max_debt: 100u128, + remote_max_debt: 25u128, // 20 credits payment + 5 credits fees }, ); diff --git a/components/funder/src/token_channel/tests/utils.rs b/components/funder/src/token_channel/tests/utils.rs index 1c8f5a2ba..cd5d32e6f 100644 --- a/components/funder/src/token_channel/tests/utils.rs +++ b/components/funder/src/token_channel/tests/utils.rs @@ -127,7 +127,25 @@ impl TcDbClient for MockTokenChannel { } fn get_currency_local_request(&mut self, request_id: Uid) -> AsyncOpResult> { - todo!(); + let tc_consistent = match &self.status { + MockTcStatus::Consistent(tc_consistent) => tc_consistent, + _ => unreachable!(), + }; + + // Find the first mutual credit that contains this request, and return the corresponding + // currency. + for (currency, mutual_credit) in &tc_consistent.mutual_credits { + if mutual_credit + .pending_transactions + .local + .contains_key(&request_id) + { + return Box::pin(future::ready(Ok(Some(currency.clone())))); + } + } + + // Nothing was found: + Box::pin(future::ready(Ok(None))) } fn get_tc_status(&mut self) -> AsyncOpResult { From 94849394dd8a11eb62d9bf5fed3a813691a3ef9a Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 14:53:54 +0200 Subject: [PATCH 401/478] funder: Marked test local var as unused --- components/funder/src/token_channel/tests/move_token_basic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index 184c5c6e1..ffceeeac7 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -162,7 +162,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { }; let mut out_move_token = OutMoveToken::new(); - let mc_balance = out_move_token + let _mc_balance = out_move_token .queue_request(&mut tc_b_a, currency1.clone(), mc_request.clone()) .await .unwrap(); From 2b7b44c379374e8e4474d8031955ce625da10670 Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 18:10:55 +0200 Subject: [PATCH 402/478] funder: mutual_credit: PendingTransaction refactoring --- components/funder/src/lib.rs | 4 +- .../funder/src/mutual_credit/incoming.rs | 38 ++++------- components/funder/src/mutual_credit/mod.rs | 2 +- .../funder/src/mutual_credit/outgoing.rs | 16 +++-- .../mutual_credit/tests/request_response.rs | 15 ++--- .../funder/src/mutual_credit/tests/utils.rs | 8 +-- components/funder/src/mutual_credit/types.rs | 35 +++++++++- components/funder/src/mutual_credit/utils.rs | 32 ++++++--- .../token_channel/tests/move_token_basic.rs | 11 +++- components/funder/src/types.rs | 15 +++-- components/proto/src/funder/messages.rs | 2 + components/signature/src/signature_buff.rs | 66 +++++++++---------- 12 files changed, 145 insertions(+), 99 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 46f6c9544..2ce7e0425 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -30,8 +30,8 @@ mod mutual_credit; mod route; // pub mod report; // mod state; -#[allow(unused)] -mod token_channel; +// #[allow(unused)] +// mod token_channel; // #[allow(unused)] // mod router; pub mod types; diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 7913374db..0b41eea0c 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -7,16 +7,16 @@ use common::async_rpc::OpError; use common::safe_arithmetic::SafeSignedArithmetic; use proto::crypto::PublicKey; -use proto::funder::messages::{Currency, PendingTransaction}; +use proto::funder::messages::Currency; use signature::signature_buff::create_response_signature_buffer; use crate::route::Route; -use crate::mutual_credit::types::{McCancel, McDbClient, McOp, McRequest, McResponse}; -use crate::mutual_credit::utils::{ - pending_transaction_from_mc_request, response_op_from_mc_response, +use crate::mutual_credit::types::{ + McCancel, McDbClient, McOp, McRequest, McResponse, PendingTransaction, }; +use crate::mutual_credit::utils::{mc_response_signature_buffer, response_op_from_mc_response}; // TODO: Possibly rename to something shorter. // TODO: Do we ever need the `pending_transaction` part for anything? @@ -79,32 +79,26 @@ pub async fn process_operation( /// Process an incoming RequestSendFundsOp async fn process_request_send_funds( mc_client: &mut impl McDbClient, - request_send_funds: McRequest, + request: McRequest, currency: &Currency, remote_max_debt: u128, ) -> Result { - if !request_send_funds.route.is_part_valid() { + if !request.route.is_part_valid() { return Err(ProcessOperationError::InvalidRoute); } - /* - if request_send_funds.dest_payment > request_send_funds.total_dest_payment { - return Err(ProcessOperationError::DestPaymentExceedsTotal); - } - */ - // Make sure that we don't have this request as a pending request already: let opt_remote_pending_transaction = mc_client - .get_remote_pending_transaction(request_send_funds.request_id.clone()) + .get_remote_pending_transaction(request.request_id.clone()) .await?; if opt_remote_pending_transaction.is_some() { return Err(ProcessOperationError::RequestAlreadyExists); } // Calculate amount of credits to freeze - let own_freeze_credits = request_send_funds + let own_freeze_credits = request .dest_payment - .checked_add(request_send_funds.left_fees) + .checked_add(request.left_fees) .ok_or(ProcessOperationError::CreditsCalcOverflow)?; // Make sure we can freeze the credits @@ -123,14 +117,13 @@ async fn process_request_send_funds( let incoming_message = if add.saturating_sub_unsigned(remote_max_debt) > 0 { // Insufficient trust: - IncomingMessage::RequestCancel(request_send_funds.clone()) + IncomingMessage::RequestCancel(request.clone()) } else { - IncomingMessage::Request(request_send_funds.clone()) + IncomingMessage::Request(request.clone()) }; // Add pending transaction: - let pending_transaction = - pending_transaction_from_mc_request(request_send_funds.clone(), currency.clone()); + let pending_transaction = PendingTransaction::from(request.clone()); mc_client .insert_remote_pending_transaction(pending_transaction) @@ -169,11 +162,8 @@ async fn process_response_send_funds( pending_transaction.route.last().unwrap() }; - let response_signature_buffer = create_response_signature_buffer( - currency, - response_op_from_mc_response(response.clone()), - &pending_transaction, - ); + let response_signature_buffer = + mc_response_signature_buffer(¤cy, &response, &pending_transaction); // Verify response funds signature: if !verify_signature( diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index 8b4f8fdd7..0abfe8902 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -1,4 +1,4 @@ -mod utils; +pub mod utils; pub mod incoming; pub mod outgoing; diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index c8decf865..863381bb8 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -12,10 +12,10 @@ use signature::signature_buff::create_response_signature_buffer; use crate::route::Route; -use crate::mutual_credit::types::{McCancel, McDbClient, McOp, McRequest, McResponse}; -use crate::mutual_credit::utils::{ - pending_transaction_from_mc_request, response_op_from_mc_response, +use crate::mutual_credit::types::{ + McCancel, McDbClient, McOp, McRequest, McResponse, PendingTransaction, }; +use crate::mutual_credit::utils::{mc_response_signature_buffer, response_op_from_mc_response}; #[derive(Debug, From)] pub enum QueueOperationError { @@ -95,8 +95,7 @@ pub async fn queue_request( } // Add pending transaction: - let pending_transaction = - pending_transaction_from_mc_request(request.clone(), currency.clone()); + let pending_transaction = PendingTransaction::from(request.clone()); mc_client .insert_local_pending_transaction(pending_transaction) .await?; @@ -112,6 +111,7 @@ pub async fn queue_request( pub async fn queue_response( mc_client: &mut impl McDbClient, response: McResponse, + currency: &Currency, local_public_key: &PublicKey, ) -> Result<(), QueueOperationError> { // Make sure that id exists in remote_pending hashmap, @@ -130,11 +130,17 @@ pub async fn queue_response( } // verify signature: + let response_signature_buffer = + mc_response_signature_buffer(¤cy, &response, &pending_transaction); + + /* let response_signature_buffer = create_response_signature_buffer( &pending_transaction.currency, response_op_from_mc_response(response.clone()), &pending_transaction, ); + */ + // The response was signed by the destination node: let dest_public_key = if pending_transaction.route.is_empty() { local_public_key diff --git a/components/funder/src/mutual_credit/tests/request_response.rs b/components/funder/src/mutual_credit/tests/request_response.rs index d8aa4df87..b1a6c707d 100644 --- a/components/funder/src/mutual_credit/tests/request_response.rs +++ b/components/funder/src/mutual_credit/tests/request_response.rs @@ -14,10 +14,8 @@ use signature::signature_buff::create_response_signature_buffer; use crate::mutual_credit::outgoing::queue_request; use crate::mutual_credit::tests::utils::{process_operations_list, MockMutualCredit}; -use crate::mutual_credit::types::{McDbClient, McOp, McRequest, McResponse}; -use crate::mutual_credit::utils::{ - pending_transaction_from_mc_request, response_op_from_mc_response, -}; +use crate::mutual_credit::types::{McDbClient, McOp, McRequest, McResponse, PendingTransaction}; +use crate::mutual_credit::utils::{mc_response_signature_buffer, response_op_from_mc_response}; async fn task_request_response() { let currency = Currency::try_from("FST".to_owned()).unwrap(); @@ -54,8 +52,7 @@ async fn task_request_response() { left_fees: 5, }; - let pending_transaction = - pending_transaction_from_mc_request(request.clone(), currency.clone()); + let pending_transaction = PendingTransaction::from(request.clone()); let local_max_debt = u128::MAX; queue_request(&mut mc_transaction, request, ¤cy, local_max_debt) .await @@ -79,11 +76,7 @@ async fn task_request_response() { signature: Signature::from(&[0; Signature::len()]), }; - let sign_buffer = create_response_signature_buffer( - ¤cy, - response_op_from_mc_response(response.clone()), - &pending_transaction, - ); + let sign_buffer = mc_response_signature_buffer(¤cy, &response, &pending_transaction); response.signature = identity.sign(&sign_buffer); process_operations_list( diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index b95267eff..d48d6f282 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -5,12 +5,12 @@ use common::conn::BoxFuture; use common::u256::U256; use proto::crypto::{PublicKey, Uid}; -use proto::funder::messages::{Currency, McBalance, PendingTransaction}; +use proto::funder::messages::{Currency, McBalance}; use crate::mutual_credit::incoming::{process_operation, IncomingMessage, ProcessOperationError}; -use crate::mutual_credit::types::{McDbClient, McOp}; +use crate::mutual_credit::types::{McDbClient, McOp, PendingTransaction}; -#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct McPendingTransactions { /// Pending transactions that were opened locally and not yet completed pub local: HashMap, @@ -27,7 +27,7 @@ impl McPendingTransactions { } } -#[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct MockMutualCredit { /// Currency in use (How much is one credit worth?) pub currency: Currency, diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 3c2a0eabe..35f658877 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -3,7 +3,27 @@ use common::async_rpc::AsyncOpResult; use common::u256::U256; use proto::crypto::{HashResult, HashedLock, PlainLock, PublicKey, Signature, Uid}; -use proto::funder::messages::{McBalance, PendingTransaction}; +use proto::funder::messages::McBalance; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PendingTransaction { + /// Id number of this request. Used to identify the whole transaction + /// over this route. + pub request_id: Uid, + /// A hash lock created by the originator of this request + pub src_hashed_lock: HashedLock, + /// Amount paid to destination + pub dest_payment: u128, + /// hash(hash(actionId) || hash(totalDestPayment) || hash(description) || hash(additional)) + /// TODO: Check if this scheme is safe? Do we need to use pbkdf instead? + pub invoice_hash: HashResult, + /// List of next nodes to transfer this request + pub route: Vec, + /// Amount of fees left to give to mediators + /// Every mediator takes the amount of fees he wants and subtracts this + /// value accordingly. + pub left_fees: u128, +} #[derive(Debug, Clone, PartialEq, Eq)] pub struct McRequest { @@ -85,3 +105,16 @@ pub trait McDbClient { ) -> AsyncOpResult<()>; fn remove_remote_pending_transaction(&mut self, request_id: Uid) -> AsyncOpResult<()>; } + +impl From for PendingTransaction { + fn from(mc_request: McRequest) -> Self { + Self { + request_id: mc_request.request_id, + src_hashed_lock: mc_request.src_hashed_lock, + dest_payment: mc_request.dest_payment, + invoice_hash: mc_request.invoice_hash, + route: mc_request.route, + left_fees: mc_request.left_fees, + } + } +} diff --git a/components/funder/src/mutual_credit/utils.rs b/components/funder/src/mutual_credit/utils.rs index be73a8d6c..333967047 100644 --- a/components/funder/src/mutual_credit/utils.rs +++ b/components/funder/src/mutual_credit/utils.rs @@ -1,21 +1,19 @@ -use proto::funder::messages::{Currency, PendingTransaction, ResponseSendFundsOp}; +use proto::funder::messages::{Currency, ResponseSendFundsOp}; -use crate::mutual_credit::types::{McRequest, McResponse}; +use signature::signature_buff::create_response_signature_buffer; -pub fn pending_transaction_from_mc_request( - request: McRequest, - currency: Currency, -) -> PendingTransaction { +use crate::mutual_credit::types::{McRequest, McResponse, PendingTransaction}; + +/* +pub fn pending_transaction_from_mc_request(request: McRequest) -> PendingTransaction { PendingTransaction { request_id: request.request_id, - currency, src_hashed_lock: request.src_hashed_lock, dest_payment: request.dest_payment, invoice_hash: request.invoice_hash, - route: request.route, - left_fees: request.left_fees, } } +*/ pub fn response_op_from_mc_response(response: McResponse) -> ResponseSendFundsOp { ResponseSendFundsOp { @@ -25,3 +23,19 @@ pub fn response_op_from_mc_response(response: McResponse) -> ResponseSendFundsOp signature: response.signature, } } + +/// Calculate a response signature +pub fn mc_response_signature_buffer( + currency: &Currency, + mc_response: &McResponse, + pending_transaction: &PendingTransaction, +) -> Vec { + create_response_signature_buffer( + &pending_transaction.request_id, + currency, + pending_transaction.dest_payment, + &pending_transaction.invoice_hash, + &mc_response.src_plain_lock, + mc_response.serial_num, + ) +} diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index ffceeeac7..815a77270 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -20,7 +20,8 @@ use proto::funder::messages::{Currency, FriendTcOp, RequestSendFundsOp, Response use identity::{create_identity, IdentityClient}; use crate::mutual_credit::incoming::IncomingMessage; -use crate::mutual_credit::types::{McRequest, McResponse}; +use crate::mutual_credit::types::{McRequest, McResponse, PendingTransaction}; +use crate::mutual_credit::utils::mc_response_signature_buffer; use crate::token_channel::tests::utils::MockTokenChannel; use crate::token_channel::types::TcCurrencyConfig; @@ -28,7 +29,6 @@ use crate::token_channel::{ accept_remote_reset, handle_in_move_token, reset_balance_to_mc_balance, MoveTokenReceived, OutMoveToken, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; -use crate::types::create_pending_transaction; async fn task_move_token_basic(test_executor: TestExecutor) { let currency1 = Currency::try_from("FST1".to_owned()).unwrap(); @@ -147,6 +147,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { left_fees: 5u128, }; + /* // TODO: How can this be done more elegantly? let pending_transaction = { let request_send_funds_op = RequestSendFundsOp { @@ -160,6 +161,9 @@ async fn task_move_token_basic(test_executor: TestExecutor) { }; create_pending_transaction(&request_send_funds_op) }; + */ + + let pending_transaction = PendingTransaction::from(mc_request.clone()); let mut out_move_token = OutMoveToken::new(); let _mc_balance = out_move_token @@ -260,6 +264,9 @@ async fn task_move_token_basic(test_executor: TestExecutor) { }; // Sign the response: + let sign_buffer = + mc_response_signature_buffer(¤cy1, &mc_response, &pending_transaction); + let sign_buffer = create_response_signature_buffer( ¤cy1, response_send_funds_op.clone(), diff --git a/components/funder/src/types.rs b/components/funder/src/types.rs index ca6f9f2d3..2939aee47 100644 --- a/components/funder/src/types.rs +++ b/components/funder/src/types.rs @@ -1,18 +1,17 @@ use common::conn::{BoxFuture, BoxStream, ConnPairVec}; use common::ser_utils::ser_b64; -use proto::crypto::{DhPublicKey, PlainLock, PublicKey, Signature, Uid}; +use proto::crypto::{DhPublicKey, PublicKey, Signature, Uid}; use proto::app_server::messages::RelayAddress; use proto::funder::messages::{ - CancelSendFundsOp, ChannelerUpdateFriend, Currency, FriendMessage, FunderIncomingControl, - FunderOutgoingControl, MoveToken, PendingTransaction, RequestSendFundsOp, ResponseSendFundsOp, - TokenInfo, UnsignedResponseSendFundsOp, + CancelSendFundsOp, ChannelerUpdateFriend, FriendMessage, FunderIncomingControl, + FunderOutgoingControl, MoveToken, TokenInfo, }; -use signature::signature_buff::create_response_signature_buffer; +// use signature::signature_buff::create_response_signature_buffer; -use identity::IdentityClient; +// use identity::IdentityClient; use crypto::dh::DhStaticPrivateKey; @@ -33,6 +32,7 @@ trait RelayClient { ) -> BoxStream<'_, ConnPairVec>; } +/* pub async fn create_response_send_funds<'a>( currency: &Currency, pending_transaction: &'a PendingTransaction, @@ -63,11 +63,13 @@ pub async fn create_response_send_funds<'a>( signature, } } +*/ pub fn create_cancel_send_funds(request_id: Uid) -> CancelSendFundsOp { CancelSendFundsOp { request_id } } +/* // TODO: // 1. Maybe take RequestSendFundOp by value, delegate cloning to external code. // 2. Maybe PendingTransaction is just an alias for RequestSendFunds? Why do we have two @@ -83,6 +85,7 @@ pub fn create_pending_transaction(request_send_funds: &RequestSendFundsOp) -> Pe left_fees: request_send_funds.left_fees, } } +*/ /* #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 89d243975..c006c9b45 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -453,6 +453,7 @@ pub struct Receipt { } */ +/* #[derive(Arbitrary, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct PendingTransaction { /// Id number of this request. Used to identify the whole transaction @@ -480,6 +481,7 @@ pub struct PendingTransaction { #[serde(with = "ser_string")] pub left_fees: u128, } +*/ // ================================================================== // ================================================================== diff --git a/components/signature/src/signature_buff.rs b/components/signature/src/signature_buff.rs index c60508ffd..1c42d979e 100644 --- a/components/signature/src/signature_buff.rs +++ b/components/signature/src/signature_buff.rs @@ -4,10 +4,8 @@ use crypto::hash; use common::int_convert::usize_to_u64; -use proto::crypto::{HashResult, PublicKey}; -use proto::funder::messages::{ - Currency, MoveToken, PendingTransaction, TokenInfo, UnsignedResponseSendFundsOp, -}; +use proto::crypto::{HashResult, PlainLock, PublicKey, Uid}; +use proto::funder::messages::{Currency, MoveToken, TokenInfo}; use proto::index_server::messages::MutationsUpdate; use crate::canonical::CanonicalSerialize; @@ -15,49 +13,49 @@ use crate::canonical::CanonicalSerialize; pub const FUNDS_RESPONSE_PREFIX: &[u8] = b"FUND_RESPONSE"; pub const FUNDS_CANCEL_PREFIX: &[u8] = b"FUND_CANCEL"; -// TODO: -// - We probably don't need the "unsigned" version, -// - Take response_send_funds as a reference. +/* + pub request_id: Uid, + pub currency: Currency, + pub dest_payment: u128, + pub invoice_hash: HashResult, + pub src_plain_lock: PlainLock, + pub serial_num: u128, + +*/ + /// Create the buffer we sign over at the Response funds. /// Note that the signature is not just over the Response funds bytes. The signed buffer also /// contains information from the Request funds. -pub fn create_response_signature_buffer( +pub fn create_response_signature_buffer( + request_id: &Uid, currency: &Currency, - response_send_funds: RSF, - pending_transaction: &PendingTransaction, -) -> Vec -where - RSF: Into, -{ + dest_payment: u128, + invoice_hash: &HashResult, + src_plain_lock: &PlainLock, + serial_num: u128, +) -> Vec { /* - # Signature{key=destinationKey}( - # sha512/256("FUNDS_RESPONSE") || - # sha512/256(requestId || hmac || srcPlainLock || destPayment) - # serialNum || - # totalDestPayment || - # invoiceHash || - # currency [Implicitly known by the mutual credit] - # ) - */ - - let response_send_funds: UnsignedResponseSendFundsOp = response_send_funds.into(); + /// Signature{key=destinationKey}( + /// hash("FUNDS_RESPONSE") || + /// hash(request_id || src_plain_lock || dest_payment) || + /// hash(currency) || + /// serialNum || + /// invoiceHash) + /// ) + */ let mut sbuffer = Vec::new(); sbuffer.extend_from_slice(&hash::hash_buffer(FUNDS_RESPONSE_PREFIX)); let mut inner_blob = Vec::new(); - inner_blob.extend_from_slice(&pending_transaction.request_id); - inner_blob.extend_from_slice(&response_send_funds.src_plain_lock); - inner_blob - .write_u128::(pending_transaction.dest_payment) - .unwrap(); + inner_blob.extend_from_slice(request_id); + inner_blob.extend_from_slice(src_plain_lock); + inner_blob.write_u128::(dest_payment).unwrap(); sbuffer.extend_from_slice(&hash::hash_buffer(&inner_blob)); - sbuffer - .write_u128::(response_send_funds.serial_num) - .unwrap(); - sbuffer.extend_from_slice(&pending_transaction.invoice_hash); sbuffer.extend_from_slice(&hash::hash_buffer(¤cy.canonical_serialize())); + sbuffer.write_u128::(serial_num).unwrap(); + sbuffer.extend_from_slice(invoice_hash); sbuffer } From 8c62c422a1115ab66d01d93c1358e1e9f93b98ab Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 18:35:57 +0200 Subject: [PATCH 403/478] funder: token_channel: PendingTransaction refactor --- components/funder/src/lib.rs | 4 ++-- .../funder/src/token_channel/tests/move_token_basic.rs | 5 ----- components/funder/src/token_channel/token_channel.rs | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 2ce7e0425..46f6c9544 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -30,8 +30,8 @@ mod mutual_credit; mod route; // pub mod report; // mod state; -// #[allow(unused)] -// mod token_channel; +#[allow(unused)] +mod token_channel; // #[allow(unused)] // mod router; pub mod types; diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index 815a77270..43f6401c2 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -267,11 +267,6 @@ async fn task_move_token_basic(test_executor: TestExecutor) { let sign_buffer = mc_response_signature_buffer(¤cy1, &mc_response, &pending_transaction); - let sign_buffer = create_response_signature_buffer( - ¤cy1, - response_send_funds_op.clone(), - &pending_transaction, - ); mc_response.signature = identity_client_a .request_signature(sign_buffer) .await diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index fb5585568..7586a3532 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -841,7 +841,7 @@ impl OutMoveToken { .await? .ok_or(TokenChannelError::InvalidState)?; - queue_response(mc_client, mc_response.clone(), local_public_key).await?; + queue_response(mc_client, mc_response.clone(), ¤cy, local_public_key).await?; self.tc_ops.push(TcOp { currency, From 011e9e5acb69f3866a4506602f37d75dbd1486ef Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 18:37:07 +0200 Subject: [PATCH 404/478] funder: removed redundant comments --- .../token_channel/tests/move_token_basic.rs | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index 43f6401c2..d9b3c0669 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -147,22 +147,6 @@ async fn task_move_token_basic(test_executor: TestExecutor) { left_fees: 5u128, }; - /* - // TODO: How can this be done more elegantly? - let pending_transaction = { - let request_send_funds_op = RequestSendFundsOp { - request_id: mc_request.request_id.clone(), - currency: currency1.clone(), - src_hashed_lock: mc_request.src_hashed_lock.clone(), - dest_payment: mc_request.dest_payment.clone(), - invoice_hash: mc_request.invoice_hash.clone(), - route: mc_request.route.clone(), - left_fees: mc_request.left_fees, - }; - create_pending_transaction(&request_send_funds_op) - }; - */ - let pending_transaction = PendingTransaction::from(mc_request.clone()); let mut out_move_token = OutMoveToken::new(); @@ -246,8 +230,6 @@ async fn task_move_token_basic(test_executor: TestExecutor) { // Send a MoveToken message from a to b, sending a response send funds message: // ---------------------------------------------------------------------------- - - // TODO: How to do this more elegantly? let mc_response = { let mut mc_response = McResponse { request_id: Uid::from(&[0; Uid::len()]), @@ -256,12 +238,6 @@ async fn task_move_token_basic(test_executor: TestExecutor) { // Temporary signature value, calculated later: signature: Signature::from(&[0; Signature::len()]), }; - let response_send_funds_op = ResponseSendFundsOp { - request_id: mc_response.request_id.clone(), - src_plain_lock: mc_response.src_plain_lock.clone(), - serial_num: mc_response.serial_num.clone(), - signature: mc_response.signature.clone(), - }; // Sign the response: let sign_buffer = From 559862a447e37f946ba0543b5a7527087c96d4bb Mon Sep 17 00:00:00 2001 From: real Date: Tue, 26 Jan 2021 23:53:51 +0200 Subject: [PATCH 405/478] funder: queue_request(): return Cancel instead of fatal error --- .../funder/src/mutual_credit/outgoing.rs | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 863381bb8..147c4a63d 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -20,7 +20,6 @@ use crate::mutual_credit::utils::{mc_response_signature_buffer, response_op_from #[derive(Debug, From)] pub enum QueueOperationError { InvalidRoute, - CreditsCalcOverflow, RequestAlreadyExists, RequestDoesNotExist, InvalidResponseSignature, @@ -57,26 +56,45 @@ pub async fn queue_request( } // Calculate amount of credits to freeze - let own_freeze_credits = request - .dest_payment - .checked_add(request.left_fees) - .ok_or(QueueOperationError::CreditsCalcOverflow)?; + let own_freeze_credits = + if let Some(own_freeze_credits) = request.dest_payment.checked_add(request.left_fees) { + own_freeze_credits + } else { + // Freeze calculation overflow: + return Ok(Err(McCancel { + request_id: request.request_id, + })); + }; let mc_balance = mc_client.get_balance().await?; // Make sure we can freeze the credits - let new_local_pending_debt = mc_balance + let new_local_pending_debt = if let Some(new_local_pending_debt) = mc_balance .local_pending_debt .checked_add(own_freeze_credits) - .ok_or(QueueOperationError::CreditsCalcOverflow)?; + { + new_local_pending_debt + } else { + // Freeze calculation overflow: + return Ok(Err(McCancel { + request_id: request.request_id, + })); + }; // Make sure that we don't get into too much debt: // Check that balance - local_pending_debt + local_max_debt >= 0 // balance - local_pending_debt >= - local_max_debt - let sub = mc_balance + let sub = if let Some(sub) = mc_balance .balance .checked_sub_unsigned(new_local_pending_debt) - .ok_or(QueueOperationError::CreditsCalcOverflow)?; + { + sub + } else { + // balance - local_pending_debt underflow: + return Ok(Err(McCancel { + request_id: request.request_id, + })); + }; if sub.saturating_add_unsigned(local_max_debt) < 0 { // Too much local debt: From cd22eb787a49a4f8d9df77cca2cb1ae477cdf7ad Mon Sep 17 00:00:00 2001 From: real Date: Wed, 27 Jan 2021 00:14:12 +0200 Subject: [PATCH 406/478] funder: queue_request(): Cancel instead of unrecoverable error --- components/funder/src/mutual_credit/outgoing.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 147c4a63d..8bee82b0b 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -109,7 +109,10 @@ pub async fn queue_request( .await? .is_some() { - return Err(QueueOperationError::RequestAlreadyExists); + // Request already exists: + return Ok(Err(McCancel { + request_id: request.request_id, + })); } // Add pending transaction: From 38176dd739102bf6ce397a9a90ff8486e47e8550 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 27 Jan 2021 00:15:31 +0200 Subject: [PATCH 407/478] funder: TODO comments --- components/funder/src/mutual_credit/outgoing.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 8bee82b0b..d2b668ada 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -182,6 +182,7 @@ pub async fn queue_response( let freeze_credits = pending_transaction .dest_payment .checked_add(pending_transaction.left_fees) + // TODO: Return unrecoverable error instead? .unwrap(); // Remove entry from remote_pending hashmap: @@ -194,6 +195,7 @@ pub async fn queue_response( let new_remote_pending_debt = mc_balance .remote_pending_debt .checked_sub(freeze_credits) + // TODO: Return unrecoverable error instead? .unwrap(); // Above unwrap() should never fail. This was already checked when a request message was // received. @@ -208,6 +210,7 @@ pub async fn queue_response( mc_balance .in_fees .checked_add(pending_transaction.left_fees.into()) + // TODO: Return unrecoverable error instead? .unwrap(), ) .await?; @@ -217,6 +220,7 @@ pub async fn queue_response( let new_balance = mc_balance .balance .checked_add_unsigned(freeze_credits) + // TODO: Return unrecoverable error instead? .unwrap(); // Above unwrap() should never fail. This was already checked when a request message was // received. @@ -242,6 +246,7 @@ pub async fn queue_cancel( let freeze_credits = pending_transaction .dest_payment .checked_add(pending_transaction.left_fees) + // TODO: Return unrecoverable error instead? .unwrap(); // Remove entry from remote hashmap: @@ -254,6 +259,7 @@ pub async fn queue_cancel( let new_remote_pending_debt = mc_balance .remote_pending_debt .checked_sub(freeze_credits) + // TODO: Return unrecoverable error instead? .unwrap(); mc_client From a59a5231e632e0a55faa358aa1d1d8d26a785a52 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 27 Jan 2021 00:20:25 +0200 Subject: [PATCH 408/478] funder: Removed comment --- components/funder/src/mutual_credit/outgoing.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index d2b668ada..5ad26b3f5 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -154,14 +154,6 @@ pub async fn queue_response( let response_signature_buffer = mc_response_signature_buffer(¤cy, &response, &pending_transaction); - /* - let response_signature_buffer = create_response_signature_buffer( - &pending_transaction.currency, - response_op_from_mc_response(response.clone()), - &pending_transaction, - ); - */ - // The response was signed by the destination node: let dest_public_key = if pending_transaction.route.is_empty() { local_public_key From dd37cd37e1cad866b005232e2f30535601866b44 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 29 Jan 2021 17:06:36 +0200 Subject: [PATCH 409/478] funder: Return unrecoverable error instead of panic --- .../funder/src/mutual_credit/outgoing.rs | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/components/funder/src/mutual_credit/outgoing.rs b/components/funder/src/mutual_credit/outgoing.rs index 5ad26b3f5..c817eb521 100644 --- a/components/funder/src/mutual_credit/outgoing.rs +++ b/components/funder/src/mutual_credit/outgoing.rs @@ -24,6 +24,8 @@ pub enum QueueOperationError { RequestDoesNotExist, InvalidResponseSignature, InvalidSrcPlainLock, + InvalidState, + CreditsCalcOverflow, OpError(OpError), } @@ -158,7 +160,10 @@ pub async fn queue_response( let dest_public_key = if pending_transaction.route.is_empty() { local_public_key } else { - pending_transaction.route.last().unwrap() + pending_transaction + .route + .last() + .ok_or(QueueOperationError::InvalidState)? }; // Verify response funds signature: @@ -174,8 +179,7 @@ pub async fn queue_response( let freeze_credits = pending_transaction .dest_payment .checked_add(pending_transaction.left_fees) - // TODO: Return unrecoverable error instead? - .unwrap(); + .ok_or(QueueOperationError::CreditsCalcOverflow)?; // Remove entry from remote_pending hashmap: mc_client @@ -187,10 +191,8 @@ pub async fn queue_response( let new_remote_pending_debt = mc_balance .remote_pending_debt .checked_sub(freeze_credits) - // TODO: Return unrecoverable error instead? - .unwrap(); - // Above unwrap() should never fail. This was already checked when a request message was - // received. + .ok_or(QueueOperationError::CreditsCalcOverflow)?; + // The above should never fail, as it was already checked when a request message was received. mc_client .set_remote_pending_debt(new_remote_pending_debt) @@ -202,8 +204,7 @@ pub async fn queue_response( mc_balance .in_fees .checked_add(pending_transaction.left_fees.into()) - // TODO: Return unrecoverable error instead? - .unwrap(), + .ok_or(QueueOperationError::CreditsCalcOverflow)?, ) .await?; @@ -212,9 +213,8 @@ pub async fn queue_response( let new_balance = mc_balance .balance .checked_add_unsigned(freeze_credits) - // TODO: Return unrecoverable error instead? - .unwrap(); - // Above unwrap() should never fail. This was already checked when a request message was + .ok_or(QueueOperationError::CreditsCalcOverflow)?; + // The above should never fail. This was already checked when a request message was // received. mc_client.set_balance(new_balance).await?; @@ -238,8 +238,7 @@ pub async fn queue_cancel( let freeze_credits = pending_transaction .dest_payment .checked_add(pending_transaction.left_fees) - // TODO: Return unrecoverable error instead? - .unwrap(); + .ok_or(QueueOperationError::CreditsCalcOverflow)?; // Remove entry from remote hashmap: mc_client @@ -251,8 +250,7 @@ pub async fn queue_cancel( let new_remote_pending_debt = mc_balance .remote_pending_debt .checked_sub(freeze_credits) - // TODO: Return unrecoverable error instead? - .unwrap(); + .ok_or(QueueOperationError::CreditsCalcOverflow)?; mc_client .set_remote_pending_debt(new_remote_pending_debt) From fcf3bcbaa236bb1b558f7f742e789d9be1cf45f0 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 29 Jan 2021 17:15:24 +0200 Subject: [PATCH 410/478] funder: TODO comments --- components/funder/src/mutual_credit/incoming.rs | 4 ++++ components/funder/src/token_channel/token_channel.rs | 3 +++ 2 files changed, 7 insertions(+) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 0b41eea0c..5ff1fe450 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -65,6 +65,10 @@ pub async fn process_operation( remote_public_key: &PublicKey, remote_max_debt: u128, ) -> Result { + // TODO: Add a special way to represent inconsistency in return value. + // Possibly only use error for unrecoverable errors. + todo!(); + match mc_op { McOp::Request(request) => { process_request_send_funds(mc_client, request, currency, remote_max_debt).await diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 7586a3532..3f7595293 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -634,6 +634,9 @@ async fn handle_incoming_token_match( ) .await; + // TODO: Should check kind of return error in a more detailed way. + // We need to decide whether the error is recoverable or not. + todo!(); let incoming_message = match res { Ok(incoming_message) => incoming_message, Err(_) => { From 89b189a035c4bacebcedc7a96b04f3fb7921b5ca Mon Sep 17 00:00:00 2001 From: real Date: Sun, 31 Jan 2021 17:11:03 +0200 Subject: [PATCH 411/478] funder: More precise handling of inconsistencies vs unrecoverable errors --- .../funder/src/mutual_credit/incoming.rs | 152 ++++++++++++------ .../src/mutual_credit/tests/request_cancel.rs | 7 +- .../mutual_credit/tests/request_response.rs | 7 +- .../funder/src/mutual_credit/tests/utils.rs | 28 ++-- .../funder/src/token_channel/token_channel.rs | 22 +-- 5 files changed, 137 insertions(+), 79 deletions(-) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index 5ff1fe450..e4dab52bb 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -45,15 +45,22 @@ pub enum IncomingMessage { Cancel(IncomingCancelSendFundsOp), } +#[derive(Debug)] +pub enum ProcessOutput { + Incoming(IncomingMessage), + Inconsistency, +} + #[derive(Debug, From)] pub enum ProcessOperationError { /// The Route contains some public key twice. - InvalidRoute, - CreditsCalcOverflow, - RequestAlreadyExists, - RequestDoesNotExist, - InvalidResponseSignature, - InvalidSrcPlainLock, + // InvalidRoute, + // CreditsCalcOverflow, + // RequestAlreadyExists, + // RequestDoesNotExist, + // InvalidResponseSignature, + // InvalidSrcPlainLock, + InvalidState, // DestPaymentExceedsTotal, OpError(OpError), } @@ -64,11 +71,7 @@ pub async fn process_operation( currency: &Currency, remote_public_key: &PublicKey, remote_max_debt: u128, -) -> Result { - // TODO: Add a special way to represent inconsistency in return value. - // Possibly only use error for unrecoverable errors. - todo!(); - +) -> Result { match mc_op { McOp::Request(request) => { process_request_send_funds(mc_client, request, currency, remote_max_debt).await @@ -86,38 +89,62 @@ async fn process_request_send_funds( request: McRequest, currency: &Currency, remote_max_debt: u128, -) -> Result { - if !request.route.is_part_valid() { - return Err(ProcessOperationError::InvalidRoute); - } - +) -> Result { // Make sure that we don't have this request as a pending request already: - let opt_remote_pending_transaction = mc_client + if mc_client .get_remote_pending_transaction(request.request_id.clone()) - .await?; - if opt_remote_pending_transaction.is_some() { - return Err(ProcessOperationError::RequestAlreadyExists); + .await? + .is_some() + { + // Request already exists + return Ok(ProcessOutput::Inconsistency); + } + + if !request.route.is_part_valid() { + // Invalid route. We cancel the request + return Ok(ProcessOutput::Incoming(IncomingMessage::RequestCancel( + request, + ))); } // Calculate amount of credits to freeze - let own_freeze_credits = request - .dest_payment - .checked_add(request.left_fees) - .ok_or(ProcessOperationError::CreditsCalcOverflow)?; + let own_freeze_credits = + if let Some(own_freeze_credits) = request.dest_payment.checked_add(request.left_fees) { + own_freeze_credits + } else { + // Credits calculation overflow. We cancel the request: + return Ok(ProcessOutput::Incoming(IncomingMessage::RequestCancel( + request, + ))); + }; // Make sure we can freeze the credits let mc_balance = mc_client.get_balance().await?; - let new_remote_pending_debt = mc_balance + let new_remote_pending_debt = if let Some(new_remote_pending_debt) = mc_balance .remote_pending_debt .checked_add(own_freeze_credits) - .ok_or(ProcessOperationError::CreditsCalcOverflow)?; + { + new_remote_pending_debt + } else { + // Credits calculation overflow. We cancel the request: + return Ok(ProcessOutput::Incoming(IncomingMessage::RequestCancel( + request, + ))); + }; // Check that balance + remote_pending_debt - remote_max_debt > 0: - let add = mc_balance + let add = if let Some(add) = mc_balance .balance .checked_add_unsigned(new_remote_pending_debt) - .ok_or(ProcessOperationError::CreditsCalcOverflow)?; + { + add + } else { + // Credits calculation overflow. We cancel the request: + return Ok(ProcessOutput::Incoming(IncomingMessage::RequestCancel( + request, + ))); + }; let incoming_message = if add.saturating_sub_unsigned(remote_max_debt) > 0 { // Insufficient trust: @@ -137,7 +164,7 @@ async fn process_request_send_funds( .set_remote_pending_debt(new_remote_pending_debt) .await?; - Ok(incoming_message) + Ok(ProcessOutput::Incoming(incoming_message)) } async fn process_response_send_funds( @@ -145,25 +172,34 @@ async fn process_response_send_funds( response: McResponse, currency: &Currency, remote_public_key: &PublicKey, -) -> Result { +) -> Result { // Make sure that id exists in local_pending hashmap, // and access saved request details. // Obtain pending request: - let pending_transaction = mc_client + let pending_transaction = if let Some(pending_transaction) = mc_client .get_local_pending_transaction(response.request_id.clone()) .await? - .ok_or(ProcessOperationError::RequestDoesNotExist)?; + { + pending_transaction + } else { + // Request does not exist + return Ok(ProcessOutput::Inconsistency); + }; // Verify src_plain_lock and dest_plain_lock: if response.src_plain_lock.hash_lock() != pending_transaction.src_hashed_lock { - return Err(ProcessOperationError::InvalidSrcPlainLock); + // Invalid src plain lock + return Ok(ProcessOutput::Inconsistency); } let dest_public_key = if pending_transaction.route.is_empty() { remote_public_key } else { - pending_transaction.route.last().unwrap() + pending_transaction + .route + .last() + .ok_or(ProcessOperationError::InvalidState)? }; let response_signature_buffer = @@ -175,15 +211,16 @@ async fn process_response_send_funds( dest_public_key, &response.signature, ) { - return Err(ProcessOperationError::InvalidResponseSignature); + // Invalid response signature + return Ok(ProcessOutput::Inconsistency); } // Calculate amount of credits that were frozen: let freeze_credits = pending_transaction .dest_payment .checked_add(pending_transaction.left_fees) - .unwrap(); - // Note: The unwrap() above should never fail, because this was already checked during the + .ok_or(ProcessOperationError::InvalidState)?; + // Note: The above should never fail, because this was already checked during the // request message processing. // Remove entry from local_pending hashmap: @@ -196,7 +233,7 @@ async fn process_response_send_funds( let new_local_pending_debt = mc_balance .local_pending_debt .checked_sub(freeze_credits) - .unwrap(); + .ok_or(ProcessOperationError::InvalidState)?; mc_client .set_local_pending_debt(new_local_pending_debt) .await?; @@ -207,7 +244,7 @@ async fn process_response_send_funds( mc_balance .out_fees .checked_add(pending_transaction.left_fees.into()) - .unwrap(), + .ok_or(ProcessOperationError::InvalidState)?, ) .await?; @@ -216,27 +253,34 @@ async fn process_response_send_funds( let new_balance = mc_balance .balance .checked_sub_unsigned(freeze_credits) - .unwrap(); + .ok_or(ProcessOperationError::InvalidState)?; mc_client.set_balance(new_balance).await?; - Ok(IncomingMessage::Response(IncomingResponseSendFundsOp { - pending_transaction, - incoming_response: response, - })) + Ok(ProcessOutput::Incoming(IncomingMessage::Response( + IncomingResponseSendFundsOp { + pending_transaction, + incoming_response: response, + }, + ))) } async fn process_cancel_send_funds( mc_client: &mut impl McDbClient, cancel: McCancel, -) -> Result { +) -> Result { // Make sure that id exists in local_pending hashmap, // and access saved request details. // Obtain pending request: - let pending_transaction = mc_client + let pending_transaction = if let Some(pending_transaction) = mc_client .get_local_pending_transaction(cancel.request_id.clone()) .await? - .ok_or(ProcessOperationError::RequestDoesNotExist)?; + { + pending_transaction + } else { + // Request does not exist + return Ok(ProcessOutput::Inconsistency); + }; mc_client .remove_local_pending_transaction(cancel.request_id.clone()) @@ -245,22 +289,24 @@ async fn process_cancel_send_funds( let freeze_credits = pending_transaction .dest_payment .checked_add(pending_transaction.left_fees) - .unwrap(); + .ok_or(ProcessOperationError::InvalidState)?; let mc_balance = mc_client.get_balance().await?; // Decrease frozen credits: let new_local_pending_debt = mc_balance .local_pending_debt .checked_sub(freeze_credits) - .unwrap(); + .ok_or(ProcessOperationError::InvalidState)?; mc_client .set_local_pending_debt(new_local_pending_debt) .await?; // Return cancel_send_funds: - Ok(IncomingMessage::Cancel(IncomingCancelSendFundsOp { - pending_transaction, - incoming_cancel: cancel, - })) + Ok(ProcessOutput::Incoming(IncomingMessage::Cancel( + IncomingCancelSendFundsOp { + pending_transaction, + incoming_cancel: cancel, + }, + ))) } diff --git a/components/funder/src/mutual_credit/tests/request_cancel.rs b/components/funder/src/mutual_credit/tests/request_cancel.rs index 52ed2b310..f36090cb2 100644 --- a/components/funder/src/mutual_credit/tests/request_cancel.rs +++ b/components/funder/src/mutual_credit/tests/request_cancel.rs @@ -11,7 +11,9 @@ use proto::crypto::{HashResult, PlainLock, PrivateKey, PublicKey, Uid}; use proto::funder::messages::Currency; use crate::mutual_credit::outgoing::queue_request; -use crate::mutual_credit::tests::utils::{process_operations_list, MockMutualCredit}; +use crate::mutual_credit::tests::utils::{ + process_operations_list, MockMutualCredit, ProcessListOutput, +}; use crate::mutual_credit::types::{McCancel, McDbClient, McOp, McRequest}; async fn task_request_cancel() { @@ -65,7 +67,7 @@ async fn task_request_cancel() { // ------------------------------ let cancel = McCancel { request_id }; - process_operations_list( + let list_output = process_operations_list( &mut mc_transaction, vec![McOp::Cancel(cancel)], ¤cy, @@ -74,6 +76,7 @@ async fn task_request_cancel() { ) .await .unwrap(); + assert!(matches!(list_output, ProcessListOutput::IncomingList(..))); let mc_balance = mc_transaction.get_balance().await.unwrap(); assert_eq!(mc_balance.balance, 0); diff --git a/components/funder/src/mutual_credit/tests/request_response.rs b/components/funder/src/mutual_credit/tests/request_response.rs index b1a6c707d..7051742ff 100644 --- a/components/funder/src/mutual_credit/tests/request_response.rs +++ b/components/funder/src/mutual_credit/tests/request_response.rs @@ -13,7 +13,9 @@ use signature::signature_buff::create_response_signature_buffer; use crate::mutual_credit::outgoing::queue_request; -use crate::mutual_credit::tests::utils::{process_operations_list, MockMutualCredit}; +use crate::mutual_credit::tests::utils::{ + process_operations_list, MockMutualCredit, ProcessListOutput, +}; use crate::mutual_credit::types::{McDbClient, McOp, McRequest, McResponse, PendingTransaction}; use crate::mutual_credit::utils::{mc_response_signature_buffer, response_op_from_mc_response}; @@ -79,7 +81,7 @@ async fn task_request_response() { let sign_buffer = mc_response_signature_buffer(¤cy, &response, &pending_transaction); response.signature = identity.sign(&sign_buffer); - process_operations_list( + let list_output = process_operations_list( &mut mc_transaction, vec![McOp::Response(response)], ¤cy, @@ -88,6 +90,7 @@ async fn task_request_response() { ) .await .unwrap(); + assert!(matches!(list_output, ProcessListOutput::IncomingList(..))); // We expect that the balance has updated: let mc_balance = mc_transaction.get_balance().await.unwrap(); diff --git a/components/funder/src/mutual_credit/tests/utils.rs b/components/funder/src/mutual_credit/tests/utils.rs index d48d6f282..999697e7a 100644 --- a/components/funder/src/mutual_credit/tests/utils.rs +++ b/components/funder/src/mutual_credit/tests/utils.rs @@ -7,7 +7,9 @@ use common::u256::U256; use proto::crypto::{PublicKey, Uid}; use proto::funder::messages::{Currency, McBalance}; -use crate::mutual_credit::incoming::{process_operation, IncomingMessage, ProcessOperationError}; +use crate::mutual_credit::incoming::{ + process_operation, IncomingMessage, ProcessOperationError, ProcessOutput, +}; use crate::mutual_credit::types::{McDbClient, McOp, PendingTransaction}; #[derive(Clone, Debug, PartialEq, Eq)] @@ -139,11 +141,18 @@ impl McDbClient for MockMutualCredit { } } +/* #[derive(Debug)] pub struct ProcessTransListError { index: usize, process_trans_error: ProcessOperationError, } +*/ + +pub enum ProcessListOutput { + IncomingList(Vec), + Inconsistency, +} pub async fn process_operations_list( mc_client: &mut impl McDbClient, @@ -151,8 +160,8 @@ pub async fn process_operations_list( currency: &Currency, remote_public_key: &PublicKey, remote_max_debt: u128, -) -> Result, ProcessTransListError> { - let mut outputs = Vec::new(); +) -> Result { + let mut incoming_list = Vec::new(); for (index, friend_tc_op) in operations.into_iter().enumerate() { match process_operation( @@ -162,16 +171,13 @@ pub async fn process_operations_list( remote_public_key, remote_max_debt, ) - .await + .await? { - Err(e) => { - return Err(ProcessTransListError { - index, - process_trans_error: e, - }) + ProcessOutput::Incoming(incoming_message) => incoming_list.push(incoming_message), + ProcessOutput::Inconsistency => { + return Ok(ProcessListOutput::Inconsistency); } - Ok(incoming_message) => outputs.push(incoming_message), } } - Ok(outputs) + Ok(ProcessListOutput::IncomingList(incoming_list)) } diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 3f7595293..70908164f 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -31,7 +31,9 @@ use signature::verify::verify_move_token; use database::transaction::{TransFunc, Transaction}; -use crate::mutual_credit::incoming::{process_operation, IncomingMessage, ProcessOperationError}; +use crate::mutual_credit::incoming::{ + process_operation, IncomingMessage, ProcessOperationError, ProcessOutput, +}; use crate::mutual_credit::outgoing::{ queue_cancel, queue_request, queue_response, QueueOperationError, }; @@ -625,24 +627,22 @@ async fn handle_incoming_token_match( } }; - let res = process_operation( + let process_output = process_operation( mc_client, tc_op.mc_op, &tc_op.currency, remote_public_key, remote_max_debt, ) - .await; - - // TODO: Should check kind of return error in a more detailed way. - // We need to decide whether the error is recoverable or not. - todo!(); - let incoming_message = match res { - Ok(incoming_message) => incoming_message, - Err(_) => { + .await?; + + let incoming_message = match process_output { + ProcessOutput::Incoming(incoming_message) => incoming_message, + ProcessOutput::Inconsistency => { + // TODO: Possibly rename returned error here? return Ok(IncomingTokenMatchOutput::InvalidIncoming( InvalidIncoming::InvalidOperation, - )) + )); } }; From c6133aac36993f80412288ba6b310973f624dd72 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 31 Jan 2021 17:12:35 +0200 Subject: [PATCH 412/478] funder: Removed redundant comments --- components/funder/src/mutual_credit/incoming.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/components/funder/src/mutual_credit/incoming.rs b/components/funder/src/mutual_credit/incoming.rs index e4dab52bb..fc04696c8 100644 --- a/components/funder/src/mutual_credit/incoming.rs +++ b/components/funder/src/mutual_credit/incoming.rs @@ -53,15 +53,7 @@ pub enum ProcessOutput { #[derive(Debug, From)] pub enum ProcessOperationError { - /// The Route contains some public key twice. - // InvalidRoute, - // CreditsCalcOverflow, - // RequestAlreadyExists, - // RequestDoesNotExist, - // InvalidResponseSignature, - // InvalidSrcPlainLock, InvalidState, - // DestPaymentExceedsTotal, OpError(OpError), } From f49d0c7610184da206c8e18908323c01a98b6c29 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 31 Jan 2021 17:18:45 +0200 Subject: [PATCH 413/478] funder: Removed old comment --- components/funder/src/token_channel/token_channel.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 70908164f..240fd950f 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -50,7 +50,6 @@ pub enum TokenChannelError { CanNotRemoveCurrencyInUse, InvalidTokenChannelStatus, RequestSignatureError, - // TODO: Should we panic instead of returning InvalidState error? InvalidState, OpError(OpError), QueueOperationError(QueueOperationError), From f236278106532217e1bd37c47540e467008d2bf9 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 31 Jan 2021 17:21:21 +0200 Subject: [PATCH 414/478] funder: token_channel: Cleaned up error types --- components/funder/src/token_channel/token_channel.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 240fd950f..c37d91a2f 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -47,8 +47,6 @@ use crate::types::{create_hashed, MoveTokenHashed}; pub enum TokenChannelError { InvalidTransaction(ProcessOperationError), MoveTokenCounterOverflow, - CanNotRemoveCurrencyInUse, - InvalidTokenChannelStatus, RequestSignatureError, InvalidState, OpError(OpError), @@ -542,7 +540,6 @@ async fn hash_mc_infos( enum InvalidIncoming { InvalidSignature, InvalidOperation, - CanNotRemoveCurrencyInUse, } #[derive(Debug)] @@ -895,7 +892,7 @@ impl OutMoveToken { let move_token_in = match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(move_token_in) => move_token_in, TcStatus::ConsistentOut(..) | TcStatus::Inconsistent(..) => { - return Err(TokenChannelError::InvalidTokenChannelStatus); + return Err(TokenChannelError::InvalidState); } }; @@ -957,7 +954,7 @@ pub async fn accept_remote_reset( | TcStatus::ConsistentOut(..) | TcStatus::Inconsistent(_, None) => { // We don't have the remote side's reset terms yet: - return Err(TokenChannelError::InvalidTokenChannelStatus); + return Err(TokenChannelError::InvalidState); } TcStatus::Inconsistent(_local_reset_terms, Some(remote_reset_terms)) => ( remote_reset_terms.reset_token, From 83f0c766a3fead7e3cd4a86b29c0031e674ebb62 Mon Sep 17 00:00:00 2001 From: real Date: Sun, 31 Jan 2021 18:10:43 +0200 Subject: [PATCH 415/478] funder: Added TODO comment --- components/funder/src/token_channel/token_channel.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index c37d91a2f..27ef817ec 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -970,7 +970,13 @@ pub async fn accept_remote_reset( .await?, move_token_counter: remote_reset_move_token_counter .checked_sub(1) - .ok_or(TokenChannelError::MoveTokenCounterOverflow)?, + // TODO: This error is not correct. We need to find a way to not allow remote side to + // somehow resolve this issue, possibly not allowing remote side to send a + // reset_move_token_counter = 0. + .ok_or((|| { + todo!(); + TokenChannelError::MoveTokenCounterOverflow + })())?, }; let move_token_in = MoveToken { From 471a439803b7c2163aca2d13632510c79a6c9eec Mon Sep 17 00:00:00 2001 From: real Date: Wed, 3 Feb 2021 12:01:51 +0200 Subject: [PATCH 416/478] funder: Verify proposed remote reset move token --- .../funder/src/token_channel/token_channel.rs | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 27ef817ec..a77d36d58 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -970,13 +970,9 @@ pub async fn accept_remote_reset( .await?, move_token_counter: remote_reset_move_token_counter .checked_sub(1) - // TODO: This error is not correct. We need to find a way to not allow remote side to - // somehow resolve this issue, possibly not allowing remote side to send a - // reset_move_token_counter = 0. - .ok_or((|| { - todo!(); - TokenChannelError::MoveTokenCounterOverflow - })())?, + // We check in `load_remote_reset_terms()` that the proposed `reset_move_token_counter` + // is nonzero. + .ok_or(TokenChannelError::InvalidState)?, }; let move_token_in = MoveToken { @@ -1010,8 +1006,11 @@ pub async fn load_remote_reset_terms( remote_public_key: &PublicKey, ) -> Result, TokenChannelError> { // Check our current state: - let ret_val = match tc_client.get_tc_status().await? { + let (opt_local_reset_terms, last_move_token_counter) = match tc_client.get_tc_status().await? { TcStatus::ConsistentIn(..) | TcStatus::ConsistentOut(..) => { + // Obtain last seen incoming/outgoing move_token_counter: + let last_move_token_counter = tc_client.get_move_token_counter().await?; + // Change our token channel status to inconsistent: let (local_reset_token, local_reset_move_token_counter) = set_inconsistent( tc_client, @@ -1021,15 +1020,31 @@ pub async fn load_remote_reset_terms( ) .await?; - Some(ResetTerms { - reset_token: local_reset_token, - move_token_counter: local_reset_move_token_counter, - reset_balances: local_balances_for_reset(tc_client).await?, - }) + ( + Some(ResetTerms { + reset_token: local_reset_token, + move_token_counter: local_reset_move_token_counter, + reset_balances: local_balances_for_reset(tc_client).await?, + }), + last_move_token_counter, + ) } - TcStatus::Inconsistent(..) => None, + TcStatus::Inconsistent(local_reset_terms, _remote_reset_terms) => ( + None, + local_reset_terms + .move_token_counter + .checked_sub(2) + .ok_or(TokenChannelError::InvalidState)?, + ), }; + // Make sure that the proposed `move_token_counter` is valid. + // It must be strictly larger than the last move token we have seen. + if remote_reset_terms.move_token_counter > last_move_token_counter { + // In case `move_token_counter` is invalid, we ignore the proposed reset terms. + return Ok(opt_local_reset_terms); + } + // Set remote reset terms: tc_client .set_inconsistent_remote_terms( @@ -1044,5 +1059,5 @@ pub async fn load_remote_reset_terms( .await?; } - Ok(ret_val) + Ok(opt_local_reset_terms) } From 100777db8380a675c5baaec471275ad14045f5d5 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 3 Feb 2021 13:16:35 +0200 Subject: [PATCH 417/478] funder: TODO comment --- components/funder/src/token_channel/token_channel.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index a77d36d58..785f0bc50 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -1033,6 +1033,7 @@ pub async fn load_remote_reset_terms( None, local_reset_terms .move_token_counter + // TODO: The minus 2 here is a strange hack, maybe there is a better design for this? .checked_sub(2) .ok_or(TokenChannelError::InvalidState)?, ), From 465d784819883206cae05293acaa63708a35383c Mon Sep 17 00:00:00 2001 From: real Date: Wed, 3 Feb 2021 13:30:04 +0200 Subject: [PATCH 418/478] funder: Move TcOp to types submodule --- components/funder/src/token_channel/token_channel.rs | 8 +------- components/funder/src/token_channel/types.rs | 8 +++++++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 785f0bc50..99afbc746 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -39,7 +39,7 @@ use crate::mutual_credit::outgoing::{ }; use crate::mutual_credit::types::{McCancel, McDbClient, McOp, McRequest, McResponse}; -use crate::token_channel::types::{TcDbClient, TcStatus}; +use crate::token_channel::types::{TcDbClient, TcOp, TcStatus}; use crate::types::{create_hashed, MoveTokenHashed}; /// Unrecoverable TokenChannel error @@ -684,12 +684,6 @@ async fn handle_incoming_token_match( )) } -#[derive(Debug, Clone)] -pub struct TcOp { - pub currency: Currency, - pub mc_op: McOp, -} - async fn tc_op_from_incoming_friend_tc_op( tc_client: &mut impl TcDbClient, friend_tc_op: FriendTcOp, diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index e29e3c072..100da85cf 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -10,9 +10,15 @@ use proto::funder::messages::{Currency, McBalance, MoveToken, ResetBalance, Rese use database::interface::funder::CurrencyConfig; -use crate::mutual_credit::types::McDbClient; +use crate::mutual_credit::types::{McDbClient, McOp}; use crate::types::MoveTokenHashed; +#[derive(Debug, Clone)] +pub struct TcOp { + pub currency: Currency, + pub mc_op: McOp, +} + #[derive(Debug)] pub enum TcOpError { SendOpFailed, From a094d6168314cd37eab9ba18dd062c14aa3bd5a6 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 3 Feb 2021 17:51:08 +0200 Subject: [PATCH 419/478] funder: mutual_credit: Updated exposed interface --- components/funder/src/mutual_credit/mod.rs | 4 +++- components/funder/src/token_channel/mod.rs | 2 +- components/funder/src/token_channel/tests/move_token_basic.rs | 2 +- components/funder/src/token_channel/token_channel.rs | 2 +- components/funder/src/token_channel/types.rs | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/components/funder/src/mutual_credit/mod.rs b/components/funder/src/mutual_credit/mod.rs index 0abfe8902..78392a01e 100644 --- a/components/funder/src/mutual_credit/mod.rs +++ b/components/funder/src/mutual_credit/mod.rs @@ -5,7 +5,9 @@ pub mod outgoing; #[cfg(test)] pub mod tests; -pub mod types; +mod types; + +pub use types::{McCancel, McDbClient, McOp, McRequest, McResponse, PendingTransaction}; #[cfg(test)] pub use tests::MockMutualCredit; diff --git a/components/funder/src/token_channel/mod.rs b/components/funder/src/token_channel/mod.rs index c4b9c8b5c..c9c897f8e 100644 --- a/components/funder/src/token_channel/mod.rs +++ b/components/funder/src/token_channel/mod.rs @@ -10,4 +10,4 @@ pub use self::token_channel::{ TokenChannelError, }; -pub use types::{TcDbClient, TcStatus}; +pub use types::{TcDbClient, TcOp, TcStatus}; diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index d9b3c0669..c769501a7 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -20,8 +20,8 @@ use proto::funder::messages::{Currency, FriendTcOp, RequestSendFundsOp, Response use identity::{create_identity, IdentityClient}; use crate::mutual_credit::incoming::IncomingMessage; -use crate::mutual_credit::types::{McRequest, McResponse, PendingTransaction}; use crate::mutual_credit::utils::mc_response_signature_buffer; +use crate::mutual_credit::{McRequest, McResponse, PendingTransaction}; use crate::token_channel::tests::utils::MockTokenChannel; use crate::token_channel::types::TcCurrencyConfig; diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 99afbc746..cae3ce0e6 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -37,7 +37,7 @@ use crate::mutual_credit::incoming::{ use crate::mutual_credit::outgoing::{ queue_cancel, queue_request, queue_response, QueueOperationError, }; -use crate::mutual_credit::types::{McCancel, McDbClient, McOp, McRequest, McResponse}; +use crate::mutual_credit::{McCancel, McDbClient, McOp, McRequest, McResponse}; use crate::token_channel::types::{TcDbClient, TcOp, TcStatus}; use crate::types::{create_hashed, MoveTokenHashed}; diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 100da85cf..1107d97a9 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -10,7 +10,7 @@ use proto::funder::messages::{Currency, McBalance, MoveToken, ResetBalance, Rese use database::interface::funder::CurrencyConfig; -use crate::mutual_credit::types::{McDbClient, McOp}; +use crate::mutual_credit::{McDbClient, McOp}; use crate::types::MoveTokenHashed; #[derive(Debug, Clone)] From d053f99b06300a05dee18821e1a45d673eae9370 Mon Sep 17 00:00:00 2001 From: real Date: Wed, 3 Feb 2021 18:50:14 +0200 Subject: [PATCH 420/478] funder: Some work on router. Not done yet --- components/funder/src/lib.rs | 4 +- components/funder/src/router/mod.rs | 10 +- components/funder/src/router/types.rs | 25 ++-- components/funder/src/router/utils/flush.rs | 6 +- .../funder/src/router/utils/index_mutation.rs | 6 +- .../funder/src/router/utils/move_token.rs | 133 +++++++++++++++--- .../funder/src/token_channel/token_channel.rs | 4 + 7 files changed, 140 insertions(+), 48 deletions(-) diff --git a/components/funder/src/lib.rs b/components/funder/src/lib.rs index 46f6c9544..50d8dadc1 100644 --- a/components/funder/src/lib.rs +++ b/components/funder/src/lib.rs @@ -31,9 +31,9 @@ mod route; // pub mod report; // mod state; #[allow(unused)] +mod router; +#[allow(unused)] mod token_channel; -// #[allow(unused)] -// mod router; pub mod types; // #[cfg(test)] diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 63ee61afc..510d18796 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -1,9 +1,9 @@ mod utils; -mod handle_config; -mod handle_friend; -mod handle_liveness; -mod handle_relays; -mod handle_route; +// mod handle_config; +// mod handle_friend; +// mod handle_liveness; +// mod handle_relays; +// mod handle_route; mod types; diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 57a32c729..8b15f65c4 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -15,6 +15,7 @@ use proto::funder::messages::{ }; use proto::index_server::messages::IndexMutation; +use crate::mutual_credit::{McCancel, McRequest, McResponse}; use crate::token_channel::TokenChannelError; #[derive(Debug, From)] @@ -38,8 +39,8 @@ pub struct RouterState { #[derive(Debug)] pub enum BackwardsOp { - Response(ResponseSendFundsOp), - Cancel(CancelSendFundsOp), + Response(Currency, McResponse), + Cancel(Currency, McCancel), } #[derive(Debug)] @@ -167,13 +168,13 @@ pub trait RouterDbClient { fn pending_user_requests_pop_front( &mut self, friend_public_key: PublicKey, - ) -> AsyncOpResult>; + ) -> AsyncOpResult>; fn pending_user_requests_push_back( &mut self, friend_public_key: PublicKey, currency: Currency, - request_op: RequestSendFundsOp, + mc_request: McRequest, ) -> AsyncOpResult<()>; fn pending_user_requests_is_empty( @@ -184,7 +185,7 @@ pub trait RouterDbClient { fn pending_requests_pop_front( &mut self, friend_public_key: PublicKey, - ) -> AsyncOpResult>; + ) -> AsyncOpResult>; /// Check if a `request_id` is already in use. /// Searches all local pending requests, and all local open transactions. @@ -195,7 +196,7 @@ pub trait RouterDbClient { &mut self, friend_public_key: PublicKey, currency: Currency, - request_op: RequestSendFundsOp, + mc_request: McRequest, ) -> AsyncOpResult<()>; fn pending_requests_is_empty(&mut self, friend_public_key: PublicKey) -> AsyncOpResult; @@ -288,9 +289,9 @@ pub struct RouterOutput { pub friends_messages: HashMap>, pub index_mutations: Vec, pub updated_remote_relays: Vec, - pub incoming_requests: Vec, - pub incoming_responses: Vec, - pub incoming_cancels: Vec, + pub incoming_requests: Vec, + pub incoming_responses: Vec, + pub incoming_cancels: Vec, } impl RouterOutput { @@ -319,15 +320,15 @@ impl RouterOutput { // TODO: Add updated remote relays? - pub fn add_incoming_request(&mut self, request: RequestSendFundsOp) { + pub fn add_incoming_request(&mut self, request: McRequest) { self.incoming_requests.push(request); } - pub fn add_incoming_response(&mut self, response: ResponseSendFundsOp) { + pub fn add_incoming_response(&mut self, response: McResponse) { self.incoming_responses.push(response); } - pub fn add_incoming_cancel(&mut self, cancel: CancelSendFundsOp) { + pub fn add_incoming_cancel(&mut self, cancel: McCancel) { self.incoming_cancels.push(cancel); } } diff --git a/components/funder/src/router/utils/flush.rs b/components/funder/src/router/utils/flush.rs index b58f1b221..fb74bc3d0 100644 --- a/components/funder/src/router/utils/flush.rs +++ b/components/funder/src/router/utils/flush.rs @@ -12,15 +12,15 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; use proto::crypto::{NodePort, PublicKey}; use proto::funder::messages::{ - CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, - FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, + RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; use crypto::rand::{CryptoRandom, RandGen}; -use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; +use crate::token_channel::{TcDbClient, TcStatus, TokenChannelError}; use crate::route::Route; use crate::router::types::{ diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index 5028c01ad..f2cb54b1a 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -12,8 +12,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; use proto::crypto::{NodePort, PublicKey}; use proto::funder::messages::{ - CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, - FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, + RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -24,7 +24,7 @@ use crate::route::Route; use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; -use crate::token_channel::{handle_out_move_token, TcDbClient, TcStatus, TokenChannelError}; +use crate::token_channel::{TcDbClient, TcStatus, TokenChannelError}; /// Calculate receive capacity for a certain currency /// This is the number we are going to report to an index server diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 00cd46c40..a34a0b6a2 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -12,8 +12,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; use proto::crypto::{NodePort, PublicKey, Signature}; use proto::funder::messages::{ - CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, - FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, + RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -22,13 +22,14 @@ use crypto::rand::{CryptoRandom, RandGen}; use database::transaction::Transaction; +use crate::mutual_credit::{McCancel, McRequest, McResponse}; use crate::route::Route; use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; use crate::router::utils::index_mutation::calc_recv_capacity; use crate::token_channel::{ - handle_in_move_token, handle_out_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, + handle_in_move_token, OutMoveToken, ReceiveMoveTokenOutput, TcDbClient, TcOp, TcStatus, TokenChannelError, }; @@ -45,59 +46,143 @@ fn operations_vec_to_currencies_operations( } */ +async fn queue_backwards_op( + router_db_client: &mut impl RouterDbClient, + out_move_token: &mut OutMoveToken, + local_public_key: &PublicKey, + friend_public_key: PublicKey, + backwards_op: BackwardsOp, +) -> Result<(), RouterError> { + let tc_db_client = if let Some(tc_db_client) = router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + { + tc_db_client + } else { + return Err(RouterError::InvalidState); + }; + let friend_tc_op = match backwards_op { + BackwardsOp::Response(currency, mc_response) => { + out_move_token + .queue_response(tc_db_client, currency, mc_response, local_public_key) + .await?; + } + BackwardsOp::Cancel(currency, mc_cancel) => { + out_move_token + .queue_cancel(tc_db_client, currency, mc_cancel) + .await?; + } + }; + Ok(()) +} + +async fn queue_request( + router_db_client: &mut impl RouterDbClient, + out_move_token: &mut OutMoveToken, + local_public_key: &PublicKey, + friend_public_key: PublicKey, + currency: Currency, + mc_request: McRequest, +) -> Result<(), RouterError> { + let tc_db_client = if let Some(tc_db_client) = router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + { + tc_db_client + } else { + return Err(RouterError::InvalidState); + }; + + let res = out_move_token + .queue_request(tc_db_client, currency, mc_request) + .await?; + + match res { + Ok(mc_balance) => { + // TODO: Remove currency if balance and pending credits are zero and the user has + // requested to remove currency. + todo!(); + } + Err(mc_cancel) => { + // TODO: Queue cancel message + todo!(); + } + } + todo!(); +} + async fn collect_currencies_operations( router_db_client: &mut impl RouterDbClient, + local_public_key: &PublicKey, friend_public_key: PublicKey, max_operations_in_batch: usize, -) -> Result { - let mut operations_vec = Vec::<(Currency, FriendTcOp)>::new(); +) -> Result { + // Create a structure that aggregates operations to be sent in a single MoveToken message: + let mut out_move_token = OutMoveToken::new(); // Collect any pending responses and cancels: while let Some((currency, backwards_op)) = router_db_client .pending_backwards_pop_front(friend_public_key.clone()) .await? { - let friend_tc_op = match backwards_op { - BackwardsOp::Response(response_op) => FriendTcOp::ResponseSendFunds(response_op), - BackwardsOp::Cancel(cancel_op) => FriendTcOp::CancelSendFunds(cancel_op), - }; - operations_vec.push((currency, friend_tc_op)); + queue_backwards_op( + router_db_client, + &mut out_move_token, + local_public_key, + friend_public_key.clone(), + backwards_op, + ) + .await?; // Make sure we do not exceed maximum amount of operations: - if operations_vec.len() >= max_operations_in_batch { - return Ok(operations_vec); + if out_move_token.len() >= max_operations_in_batch { + return Ok(out_move_token); } } // Collect any pending user requests: - while let Some((currency, request_op)) = router_db_client + while let Some((currency, mc_request)) = router_db_client .pending_user_requests_pop_front(friend_public_key.clone()) .await? { - let friend_tc_op = FriendTcOp::RequestSendFunds(request_op); - operations_vec.push((currency, friend_tc_op)); + queue_request( + router_db_client, + &mut out_move_token, + local_public_key, + friend_public_key.clone(), + currency, + mc_request, + ) + .await?; // Make sure we do not exceed maximum amount of operations: - if operations_vec.len() >= max_operations_in_batch { - return Ok(operations_vec); + if out_move_token.len() >= max_operations_in_batch { + return Ok(out_move_token); } } // Collect any pending requests: - while let Some((currency, request_op)) = router_db_client + while let Some((currency, mc_request)) = router_db_client .pending_requests_pop_front(friend_public_key.clone()) .await? { - let friend_tc_op = FriendTcOp::RequestSendFunds(request_op); - operations_vec.push((currency, friend_tc_op)); + queue_request( + router_db_client, + &mut out_move_token, + local_public_key, + friend_public_key.clone(), + currency, + mc_request, + ) + .await?; // Make sure we do not exceed maximum amount of operations: - if operations_vec.len() >= max_operations_in_batch { - return Ok(operations_vec); + if out_move_token.len() >= max_operations_in_batch { + return Ok(out_move_token); } } - Ok(operations_vec) + Ok(out_move_token) } /// Do we have more pending currencies operations? @@ -168,12 +253,14 @@ struct PreMoveToken { pub currencies_diff: Vec, } +/* /// Like MoveTokenRequest, but wrapping PreMoveToken instead of MoveToken. #[derive(Debug)] struct PreMoveTokenRequest { pub pre_move_token: PreMoveToken, pub token_wanted: bool, } +*/ /// Attempt to create an outgoing move token /// Collect any information we need to send to remote friend: diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index cae3ce0e6..f8860de04 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -772,6 +772,10 @@ impl OutMoveToken { Self { tc_ops: Vec::new() } } + pub fn len(&self) -> usize { + self.tc_ops.len() + } + pub async fn queue_request( &mut self, tc_client: &mut impl TcDbClient, From 342b0d927c726928162dc660456807cfaa0bf2cf Mon Sep 17 00:00:00 2001 From: real Date: Fri, 5 Feb 2021 13:22:32 +0200 Subject: [PATCH 421/478] funder: Updated CurrencyInfo. WIP --- components/funder/src/router/types.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 8b15f65c4..267eb359b 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -43,29 +43,22 @@ pub enum BackwardsOp { Cancel(Currency, McCancel), } -#[derive(Debug)] -pub struct CurrencyInfoLocal { - /// Is locally marked for removal? - pub is_remove: bool, - /// Was set by remote side too? - pub opt_remote: Option, -} - #[derive(Debug)] pub struct CurrencyInfo { - // TODO: Maybe remove this field? - /// Currency name - pub currency: Currency, /// Currency rate: This is how much it costs to the remote friend to send credits through us. pub rate: Rate, /// Maximum amount of debt we allow to the remote side. This is the maximum rich we can get /// from this currency relationship. pub remote_max_debt: u128, + /// Maximum amount of debt we are willing to get into. + pub local_max_debt: u128, /// Do we allow requests to go through this currency? /// TODO: Find out exactly what this means. pub is_open: bool, - /// Was the remote side told about this currency? - pub opt_local: Option, + /// Is locally marked for removal? + pub is_remove: bool, + /// Is mutual credit open? Show balances + pub opt_mutual_credit: Option, } /* From 90771e7e7d28477e9d249ae057fb545b42dc73c4 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 5 Feb 2021 13:23:08 +0200 Subject: [PATCH 422/478] funder: impl sketch for queue_request(). WIP --- components/funder/src/router/utils/move_token.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index a34a0b6a2..a42b48d2c 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -101,6 +101,13 @@ async fn queue_request( Ok(mc_balance) => { // TODO: Remove currency if balance and pending credits are zero and the user has // requested to remove currency. + if mc_balance.local_pending_debt == 0 + && mc_balance.remote_pending_debt == 0 + && mc_balance.balance == 0 + { + // TODO: If user has requested to remove currency, then remove. + todo!(); + } todo!(); } Err(mc_cancel) => { From 8352ee7bbd2b9aeeb03c32c8d520fe2330d894e8 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 5 Feb 2021 14:31:10 +0200 Subject: [PATCH 423/478] database: Removed redundant column --- components/database/src/create.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index b5bf3c4e2..2b2a3ca73 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -809,8 +809,6 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { amount BLOB NOT NULL, in_fees BLOB NOT NULL, out_fees BLOB NOT NULL, - event_type TEXT CHECK (event_type IN ('P', 'I', 'F')) NOT NULL, - -- Event type: P: Payment, I: Invoice, F: Friend inconsistency PRIMARY KEY(counter, currency) FOREIGN KEY(counter) From 91c4c42a773b51a1c261f7f3f309ea2c8bbf45fd Mon Sep 17 00:00:00 2001 From: real Date: Fri, 5 Feb 2021 14:31:40 +0200 Subject: [PATCH 424/478] database: Renamed tables --- components/database/src/create.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 2b2a3ca73..f30e5f1f1 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -868,7 +868,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // A case of friend inconsistency or friend removal tx.execute( - "CREATE TABLE friend_inconsistency_events ( + "CREATE TABLE friend_events ( counter BLOB NOT NULL PRIMARY KEY, event_type TEXT CHECK (event_type == 'F') DEFAULT 'F' @@ -885,7 +885,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { // Balances (per currency) in case of friend inconsistency event. // Friend inconsistency can be one of: 1. Channel reset, 2. Friend removal, 3. currency removal tx.execute( - "CREATE TABLE friend_inconsistency_event_balances ( + "CREATE TABLE friend_event_balances ( counter BLOB NOT NULL, currency TEXT NOT NULL, old_balance BLOB NOT NULL, From efa82927cd8a8f153cb680a4a4ccc62c1a66925c Mon Sep 17 00:00:00 2001 From: real Date: Fri, 5 Feb 2021 14:32:25 +0200 Subject: [PATCH 425/478] funder: queue_request(): WIP --- .../funder/src/router/utils/move_token.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index a42b48d2c..984542435 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -94,21 +94,28 @@ async fn queue_request( }; let res = out_move_token - .queue_request(tc_db_client, currency, mc_request) + .queue_request(tc_db_client, currency.clone(), mc_request) .await?; match res { Ok(mc_balance) => { - // TODO: Remove currency if balance and pending credits are zero and the user has - // requested to remove currency. - if mc_balance.local_pending_debt == 0 + let currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await? + // If currency does not exist, we should have already cancelled this request. + .ok_or(RouterError::InvalidState)?; + + // If currency is marked for removal, and all balances are zero, remove currency: + if currency_info.is_remove + && mc_balance.local_pending_debt == 0 && mc_balance.remote_pending_debt == 0 && mc_balance.balance == 0 { - // TODO: If user has requested to remove currency, then remove. + // TODO: + // - Remove currency + // - Add event of currency removal, remembering the values of `in_fees` and `out_fees`? todo!(); } - todo!(); } Err(mc_cancel) => { // TODO: Queue cancel message From 9f3e3206a2975672235f00e0d55b12f6e092401a Mon Sep 17 00:00:00 2001 From: real Date: Fri, 5 Feb 2021 16:21:10 +0200 Subject: [PATCH 426/478] database: Comment --- components/database/src/create.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index f30e5f1f1..81469c528 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -883,7 +883,7 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { )?; // Balances (per currency) in case of friend inconsistency event. - // Friend inconsistency can be one of: 1. Channel reset, 2. Friend removal, 3. currency removal + // Can be one of: 1. Channel reset, 2. Friend removal, 3. currency removal tx.execute( "CREATE TABLE friend_event_balances ( counter BLOB NOT NULL, From 9e8b4bc022c2ab16f938bee028a30ffaf2af7150 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 5 Feb 2021 16:21:58 +0200 Subject: [PATCH 427/478] proto: Removed old comment --- components/proto/src/funder/messages.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index c006c9b45..0f45366dc 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -210,7 +210,6 @@ pub struct McBalance { /// Frozen credits by the remote side #[serde(with = "ser_string")] pub remote_pending_debt: u128, - // TODO: in_fees and out_fees should be u256, not u128! /// Fees that were received from remote side #[serde(with = "ser_string")] pub in_fees: U256, From 3e5d5d4f86eda7cc18055f292f0c0905c6ce7112 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 5 Feb 2021 16:22:53 +0200 Subject: [PATCH 428/478] funder: Added TODO comment --- components/funder/src/router/handle_friend.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 30766b299..cc51d2bf2 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -216,10 +216,14 @@ where .await? .is_consistent() { + // TODO: Something is strange here. Are we actually queueing a cancel message or something + // else? + // Queue cancel to friend_public_key (Request origin) router_db_client .pending_requests_push_back(friend_public_key.clone(), currency, request_send_funds) .await?; + todo!(); } else { // We have just received a cancel message from this friend. // We expect that this friend is consistent From f9b23c047cbedb764432ae6b33e3b3695a16ee6a Mon Sep 17 00:00:00 2001 From: real Date: Fri, 5 Feb 2021 16:23:31 +0200 Subject: [PATCH 429/478] funder: Initial queue_request() impl. WIP --- components/funder/src/router/types.rs | 41 +++++++++++ .../funder/src/router/utils/move_token.rs | 73 ++++++++++++++++--- 2 files changed, 105 insertions(+), 9 deletions(-) diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 267eb359b..6979bd065 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use derive_more::From; use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; +use common::u256::U256; use crate::liveness::Liveness; use crate::token_channel::TcDbClient; @@ -70,6 +71,25 @@ pub struct FriendInfo { } */ +#[derive(Debug)] +pub struct FriendBalance { + /// Amount of credits this side has against the remote side. + /// The other side keeps the negation of this value. + pub balance: i128, + /// Fees that were received from remote side + pub in_fees: U256, + /// Fees that were given to remote side + pub out_fees: U256, +} + +#[derive(Debug)] +pub struct FriendBalanceDiff { + /// Old balance (Before event occured) + pub old_balance: FriendBalance, + /// New balance (after event occured) + pub new_balance: FriendBalance, +} + #[derive(Debug)] pub struct RequestOrigin { pub friend_public_key: PublicKey, @@ -240,6 +260,13 @@ pub trait RouterDbClient { remote_max_debt: u128, ) -> AsyncOpResult<()>; + fn set_local_max_debt( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + local_max_debt: u128, + ) -> AsyncOpResult<()>; + fn open_currency( &mut self, friend_public_key: PublicKey, @@ -252,6 +279,12 @@ pub trait RouterDbClient { currency: Currency, ) -> AsyncOpResult<()>; + fn remove_currency( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + ) -> AsyncOpResult<()>; + /* /// Get a list of configured currencies that were not yet added as local currencies fn currencies_to_add(&mut self, friend_public_key: PublicKey) -> AsyncOpResult>; @@ -275,6 +308,14 @@ pub trait RouterDbClient { /// - Not present in remote currencies /// - Present in remote currencies but have a zero balance fn currencies_diff(&mut self, friend_public_key: PublicKey) -> AsyncOpResult>; + + /// Add a friend event + /// Can be one of: 1. Channel reset, 2. Friend removal, 3. currency removal + fn add_friend_event( + &mut self, + friend_public_key: PublicKey, + balances_diff: HashMap, + ) -> AsyncOpResult<()>; } #[derive(Debug)] diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 984542435..8cce05221 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -25,7 +25,8 @@ use database::transaction::Transaction; use crate::mutual_credit::{McCancel, McRequest, McResponse}; use crate::route::Route; use crate::router::types::{ - BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, + BackwardsOp, CurrencyInfo, FriendBalance, FriendBalanceDiff, RouterDbClient, RouterError, + RouterOutput, RouterState, SentRelay, }; use crate::router::utils::index_mutation::calc_recv_capacity; use crate::token_channel::{ @@ -83,6 +84,7 @@ async fn queue_request( friend_public_key: PublicKey, currency: Currency, mc_request: McRequest, + router_output: &mut RouterOutput, ) -> Result<(), RouterError> { let tc_db_client = if let Some(tc_db_client) = router_db_client .tc_db_client(friend_public_key.clone()) @@ -94,7 +96,7 @@ async fn queue_request( }; let res = out_move_token - .queue_request(tc_db_client, currency.clone(), mc_request) + .queue_request(tc_db_client, currency.clone(), mc_request.clone()) .await?; match res { @@ -111,18 +113,68 @@ async fn queue_request( && mc_balance.remote_pending_debt == 0 && mc_balance.balance == 0 { - // TODO: - // - Remove currency - // - Add event of currency removal, remembering the values of `in_fees` and `out_fees`? - todo!(); + // Remove currency: + router_db_client + .remove_currency(friend_public_key.clone(), currency.clone()) + .await?; + + // Add event of currency removal (Friend event) + let balances_diff = { + let mut balances_diff = HashMap::new(); + let friend_balance_diff = FriendBalanceDiff { + old_balance: FriendBalance { + balance: 0, + in_fees: mc_balance.in_fees, + out_fees: mc_balance.out_fees, + }, + new_balance: FriendBalance { + balance: 0, + // TODO: Are we calculating in_fees and out_fees correctly here? + in_fees: 0.into(), + out_fees: 0.into(), + }, + }; + balances_diff.insert(currency.clone(), friend_balance_diff); + balances_diff + }; + router_db_client + .add_friend_event(friend_public_key.clone(), balances_diff) + .await?; } } Err(mc_cancel) => { - // TODO: Queue cancel message - todo!(); + // We need to send a cancel message to the origin + if router_db_client + .is_request_local_origin(mc_request.request_id.clone()) + .await? + { + // Request is of local origin + router_output.add_incoming_cancel(McCancel { + request_id: mc_request.request_id.clone(), + }); + } else { + if let Some(request_origin) = router_db_client + .get_remote_pending_request_origin(mc_request.request_id.clone()) + .await? + { + // Request is of remote origin + router_db_client.pending_backwards_push_back( + request_origin.friend_public_key.clone(), + request_origin.currency.clone(), + BackwardsOp::Cancel( + request_origin.currency.clone(), + McCancel { + request_id: mc_request.request_id.clone(), + }, + ), + ); + } else { + // Request is orphan, nothing to do here + } + } } } - todo!(); + Ok(()) } async fn collect_currencies_operations( @@ -130,6 +182,7 @@ async fn collect_currencies_operations( local_public_key: &PublicKey, friend_public_key: PublicKey, max_operations_in_batch: usize, + router_output: &mut RouterOutput, ) -> Result { // Create a structure that aggregates operations to be sent in a single MoveToken message: let mut out_move_token = OutMoveToken::new(); @@ -166,6 +219,7 @@ async fn collect_currencies_operations( friend_public_key.clone(), currency, mc_request, + router_output, ) .await?; @@ -187,6 +241,7 @@ async fn collect_currencies_operations( friend_public_key.clone(), currency, mc_request, + router_output, ) .await?; From fb67fab07ad9cc6687c2dbe2eed122b090116236 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 6 Feb 2021 14:46:27 +0200 Subject: [PATCH 430/478] funder: Added OutMoveToken::is_empty() --- components/funder/src/token_channel/token_channel.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index f8860de04..a92990f69 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -776,6 +776,10 @@ impl OutMoveToken { self.tc_ops.len() } + pub fn is_empty(&self) -> bool { + self.tc_ops.is_empty() + } + pub async fn queue_request( &mut self, tc_client: &mut impl TcDbClient, From 4b1854f4ccbb5601a91ce351666e339f0866381c Mon Sep 17 00:00:00 2001 From: real Date: Sat, 6 Feb 2021 14:47:10 +0200 Subject: [PATCH 431/478] funder: router: move_token.rs: WIP --- .../funder/src/router/utils/move_token.rs | 74 +++++++++---------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 8cce05221..22af4ef51 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -77,6 +77,8 @@ async fn queue_backwards_op( Ok(()) } +/// Queue a request to an `out_move_token`. +/// Handles failure by returning a cancel message to the relevant origin. async fn queue_request( router_db_client: &mut impl RouterDbClient, out_move_token: &mut OutMoveToken, @@ -331,6 +333,8 @@ struct PreMoveTokenRequest { } */ +/* + /// Attempt to create an outgoing move token /// Collect any information we need to send to remote friend: /// @@ -341,33 +345,29 @@ struct PreMoveTokenRequest { /// Return Ok(None) if we have nothing to send async fn collect_outgoing_pre_move_token( router_db_client: &mut impl RouterDbClient, + local_public_key: &PublicKey, friend_public_key: PublicKey, max_operations_in_batch: usize, -) -> Result, RouterError> { - let currencies_operations = collect_currencies_operations( + router_output: &mut RouterOutput, +) -> Result, RouterError> { + let out_move_token = collect_currencies_operations( router_db_client, + local_public_key, friend_public_key.clone(), max_operations_in_batch, + router_output, ) .await?; - let mut currencies_diff = router_db_client - .currencies_diff(friend_public_key.clone()) - .await?; - - Ok( - if currencies_operations.is_empty() && currencies_diff.is_empty() { - // There is nothing interesting to send to remote side - None - } else { - // We have something to send to remote side - Some(PreMoveToken { - currencies_operations, - currencies_diff, - }) - }, - ) + Ok(if out_move_token.is_empty() { + // There is nothing interesting to send to remote side + None + } else { + // We have something to send to remote side + Some(out_move_token) + }) } +*/ async fn send_pre_move_token( router_db_client: &mut impl RouterDbClient, @@ -480,12 +480,12 @@ fn diff_capacities( Ok(index_mutations) } -async fn apply_out_pre_move_token( +async fn apply_out_move_token( router_db_client: &mut impl RouterDbClient, identity_client: &mut IdentityClient, local_public_key: &PublicKey, friend_public_key: PublicKey, - pre_move_token: PreMoveToken, + out_move_token: OutMoveToken, ) -> Result<(MoveTokenRequest, Vec), RouterError> { // Collect all mentioned currencies: let currencies = get_mentioned_currencies(&pre_move_token); @@ -542,27 +542,29 @@ pub async fn handle_out_move_token_index_mutations_disallow_empty( local_public_key: &PublicKey, friend_public_key: PublicKey, max_operations_in_batch: usize, + router_output: &mut RouterOutput, ) -> Result)>, RouterError> { - let opt_pre_move_token = collect_outgoing_pre_move_token( + let out_move_token = collect_currencies_operations( router_db_client, + local_public_key, friend_public_key.clone(), max_operations_in_batch, + router_output, ) .await?; - let pre_move_token = if let Some(pre_move_token) = opt_pre_move_token { - pre_move_token - } else { + // Do nothing if we have nothing to send to remote side: + if out_move_token.is_empty() { return Ok(None); - }; + } Ok(Some( - apply_out_pre_move_token( + apply_out_move_token( router_db_client, identity_client, local_public_key, friend_public_key, - pre_move_token, + out_move_token, ) .await?, )) @@ -574,29 +576,23 @@ pub async fn handle_out_move_token_index_mutations_allow_empty( local_public_key: &PublicKey, friend_public_key: PublicKey, max_operations_in_batch: usize, + router_output: &mut RouterOutput, ) -> Result<(MoveTokenRequest, Vec), RouterError> { - let opt_pre_move_token = collect_outgoing_pre_move_token( + let out_move_token = collect_currencies_operations( router_db_client, + local_public_key, friend_public_key.clone(), max_operations_in_batch, + router_output, ) .await?; - let pre_move_token = if let Some(pre_move_token) = opt_pre_move_token { - pre_move_token - } else { - PreMoveToken { - currencies_operations: Vec::new(), - currencies_diff: Vec::new(), - } - }; - - apply_out_pre_move_token( + apply_out_move_token( router_db_client, identity_client, local_public_key, friend_public_key, - pre_move_token, + out_move_token, ) .await } From f955333e00fc90326814e1db1389e4cebff1ce1f Mon Sep 17 00:00:00 2001 From: real Date: Sat, 6 Feb 2021 19:08:00 +0200 Subject: [PATCH 432/478] proto: Added UpdateFriendCurrency.send_capacity --- components/proto/src/index_server/messages.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/proto/src/index_server/messages.rs b/components/proto/src/index_server/messages.rs index a1594a9ec..36cde1dc0 100644 --- a/components/proto/src/index_server/messages.rs +++ b/components/proto/src/index_server/messages.rs @@ -85,7 +85,9 @@ pub struct UpdateFriendCurrency { pub public_key: PublicKey, /// Currency being updated pub currency: Currency, - /// To denote local requests closed, assign 0 to recvCapacity + /// Maximum amount of credit that can be pushed from us to remote friend. + pub send_capacity: u128, + /// Maximum amount of credit that can be pushed from remote friend to us. pub recv_capacity: u128, /// The rate we charge for forwarding messages to another friend from this friend. /// For example, in the following diagram we are X and A is the friend we are updating: From 3074b4d18f4a03c4d60dc8a057c9bd79682a0fb6 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 6 Feb 2021 19:08:16 +0200 Subject: [PATCH 433/478] funder: Some work on router. Not done yet --- .../funder/src/router/utils/index_mutation.rs | 17 ++- components/funder/src/router/utils/mod.rs | 2 +- .../funder/src/router/utils/move_token.rs | 109 +++++++++++------- .../token_channel/tests/move_token_basic.rs | 4 +- .../funder/src/token_channel/token_channel.rs | 28 ++++- 5 files changed, 106 insertions(+), 54 deletions(-) diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index f2cb54b1a..2c3c317a2 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -26,15 +26,16 @@ use crate::router::types::{ }; use crate::token_channel::{TcDbClient, TcStatus, TokenChannelError}; -/// Calculate receive capacity for a certain currency +/// Calculate send and receive capacity for a certain currency /// This is the number we are going to report to an index server -pub fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result { +pub fn calc_capacities(currency_info: &CurrencyInfo) -> Result<(u128, u128), RouterError> { todo!(); // TODO: // Should also take into account: // - Liveness // - Open/Closed currencies + /* if !currency_info.is_open { return Ok(0); } @@ -57,17 +58,20 @@ pub fn calc_recv_capacity(currency_info: &CurrencyInfo) -> Result Result { - let recv_capacity = calc_recv_capacity(¤cy_info)?; + let (send_capacity, recv_capacity) = calc_capacities(¤cy_info)?; Ok(IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { public_key: friend_public_key, - currency: currency_info.currency, + currency, + send_capacity, recv_capacity, rate: currency_info.rate, })) @@ -106,6 +110,10 @@ pub async fn create_index_mutations_from_outgoing_move_token( currencies }; + // TODO: Sort currencies set here, to get deterministic result. + // Possibly use a function instead of inlining here. + todo!(); + let mut index_mutations = Vec::new(); // Create all index mutations: @@ -117,6 +125,7 @@ pub async fn create_index_mutations_from_outgoing_move_token( // Currency exists index_mutations.push(create_update_index_mutation( friend_public_key.clone(), + currency.clone(), currency_info, )?); } else { diff --git a/components/funder/src/router/utils/mod.rs b/components/funder/src/router/utils/mod.rs index 5bb7b7705..ff8b8e871 100644 --- a/components/funder/src/router/utils/mod.rs +++ b/components/funder/src/router/utils/mod.rs @@ -1,3 +1,3 @@ -pub mod flush; +// pub mod flush; pub mod index_mutation; pub mod move_token; diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 22af4ef51..44a14d214 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -28,7 +28,7 @@ use crate::router::types::{ BackwardsOp, CurrencyInfo, FriendBalance, FriendBalanceDiff, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; -use crate::router::utils::index_mutation::calc_recv_capacity; +use crate::router::utils::index_mutation::calc_capacities; use crate::token_channel::{ handle_in_move_token, OutMoveToken, ReceiveMoveTokenOutput, TcDbClient, TcOp, TcStatus, TokenChannelError, @@ -317,12 +317,14 @@ pub async fn collect_outgoing_move_token_allow_empty( } */ +/* /// Like MoveToken, but without the calculated `info_hash` and `signature` #[derive(Debug)] struct PreMoveToken { pub currencies_operations: CurrenciesOperations, pub currencies_diff: Vec, } +*/ /* /// Like MoveTokenRequest, but wrapping PreMoveToken instead of MoveToken. @@ -367,7 +369,7 @@ async fn collect_outgoing_pre_move_token( Some(out_move_token) }) } -*/ + async fn send_pre_move_token( router_db_client: &mut impl RouterDbClient, @@ -391,7 +393,9 @@ async fn send_pre_move_token( Ok(move_token) } +*/ +/* /// Collect all mentioned currencies from a PreMoveToken fn get_mentioned_currencies(pre_move_token: &PreMoveToken) -> Vec { // Collect all mentioned currencies: @@ -406,6 +410,7 @@ fn get_mentioned_currencies(pre_move_token: &PreMoveToken) -> Vec { currencies.into_iter().collect() } +*/ async fn get_currencies_info( router_db_client: &mut impl RouterDbClient, @@ -434,7 +439,7 @@ fn get_recv_capacities( let mut recv_capacities = HashMap::::new(); for currency in currencies.iter() { let recv_capacity = if let Some(currency_info) = currencies_info.get(currency) { - calc_recv_capacity(¤cy_info)? + calc_capacities(¤cy_info)? } else { 0u128 }; @@ -480,6 +485,45 @@ fn diff_capacities( Ok(index_mutations) } +fn create_index_mutations( + friend_public_key: PublicKey, + currencies_info: &HashMap, +) -> Result, RouterError> { + let mut index_mutations = Vec::new(); + + // Sort currencies_info, to have deterministic results + let currencies_info_vec = { + let mut currencies_info_vec: Vec<(&Currency, &CurrencyInfo)> = currencies_info + .iter() + .map(|(currency, currency_info)| (currency, currency_info)) + .collect(); + currencies_info_vec.sort_by(|(c_a, c_a_inf), (c_b, c_b_inf)| c_a.cmp(c_b)); + currencies_info_vec + }; + + // Create an `IndexMutation` for every currency_info: + for (currency, currency_info) in currencies_info_vec { + let (send_capacity, recv_capacity) = calc_capacities(currency_info)?; + if send_capacity == 0 && recv_capacity == 0 { + index_mutations.push(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { + public_key: friend_public_key.clone(), + currency: currency.clone(), + })); + } else { + // UpdateFriendCurrency + index_mutations.push(IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { + public_key: friend_public_key.clone(), + currency: currency.clone(), + send_capacity, + recv_capacity, + rate: currency_info.rate.clone(), + })); + } + } + + Ok(index_mutations) +} + async fn apply_out_move_token( router_db_client: &mut impl RouterDbClient, identity_client: &mut IdentityClient, @@ -487,46 +531,31 @@ async fn apply_out_move_token( friend_public_key: PublicKey, out_move_token: OutMoveToken, ) -> Result<(MoveTokenRequest, Vec), RouterError> { - // Collect all mentioned currencies: - let currencies = get_mentioned_currencies(&pre_move_token); - - let currencies_info_before = - get_currencies_info(router_db_client, friend_public_key.clone(), ¤cies).await?; + let tc_client = router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .ok_or(RouterError::InvalidState)?; - // Record recv capacity for all interesting currencies - let recv_capacities_before = get_recv_capacities( - ¤cies_info_before, - friend_public_key.clone(), - ¤cies, - )?; + // Send move token: + let (move_token, mentioned_currencies) = out_move_token + .finalize( + tc_client, + identity_client, + local_public_key, + &friend_public_key, + ) + .await?; - // Send MoveToken: - let move_token = send_pre_move_token( + // Get currency info for all mentioned currencies: + let currencies_info = get_currencies_info( router_db_client, - identity_client, - local_public_key, friend_public_key.clone(), - pre_move_token, + &mentioned_currencies, ) .await?; - let currencies_info_after = - get_currencies_info(router_db_client, friend_public_key.clone(), ¤cies).await?; - - // Record recv capacity for all interesting currencies - let recv_capacities_after = get_recv_capacities( - ¤cies_info_after, - friend_public_key.clone(), - ¤cies, - )?; - - // Compare recv capacities and create index mutations: - let index_mutations = diff_capacities( - friend_public_key.clone(), - &recv_capacities_before, - &recv_capacities_after, - ¤cies_info_after, - )?; + // For each currency, create index mutations based on currency information: + let index_mutations = create_index_mutations(friend_public_key.clone(), ¤cies_info)?; let move_token_request = MoveTokenRequest { move_token, @@ -603,13 +632,7 @@ pub async fn is_pending_move_token( router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, ) -> Result { - Ok( - is_pending_currencies_operations(router_db_client, friend_public_key.clone()).await? - || !router_db_client - .currencies_diff(friend_public_key.clone()) - .await? - .is_empty(), - ) + Ok(is_pending_currencies_operations(router_db_client, friend_public_key.clone()).await?) } pub async fn handle_in_move_token_index_mutations( diff --git a/components/funder/src/token_channel/tests/move_token_basic.rs b/components/funder/src/token_channel/tests/move_token_basic.rs index c769501a7..07fd138b3 100644 --- a/components/funder/src/token_channel/tests/move_token_basic.rs +++ b/components/funder/src/token_channel/tests/move_token_basic.rs @@ -154,7 +154,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .queue_request(&mut tc_b_a, currency1.clone(), mc_request.clone()) .await .unwrap(); - let move_token = out_move_token + let (move_token, _mentioned_currencies) = out_move_token .finalize(&mut tc_b_a, &mut identity_client_b, &pk_b, &pk_a) .await .unwrap(); @@ -255,7 +255,7 @@ async fn task_move_token_basic(test_executor: TestExecutor) { .queue_response(&mut tc_a_b, currency1.clone(), mc_response, &pk_a) .await .unwrap(); - let move_token = out_move_token + let (move_token, _mentioned_currencies) = out_move_token .finalize(&mut tc_a_b, &mut identity_client_a, &pk_a, &pk_b) .await .unwrap(); diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index a92990f69..2cd307391 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -1,5 +1,5 @@ use std::cmp::Ordering; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::convert::TryFrom; use std::fmt::Debug; use std::marker::PhantomData; @@ -763,6 +763,21 @@ fn friend_tc_op_from_outgoing_tc_op(tc_op: TcOp) -> FriendTcOp { } } +fn mentioned_currencies(tc_ops: &[TcOp]) -> Vec { + let mentioned_set: HashSet = tc_ops + .iter() + .map(|tc_op| &tc_op.currency) + .cloned() + .collect(); + + let mut mentioned_vec: Vec = mentioned_set.into_iter().collect(); + + // We sort the mentioned currencies to have deterministic output: + mentioned_vec.sort(); + + mentioned_vec +} + pub struct OutMoveToken { tc_ops: Vec, } @@ -878,13 +893,15 @@ impl OutMoveToken { Ok(mc_client.get_balance().await?) } + // TODO: Possibly rename to "send" or something related? + /// Create MoveToken, and apply to token channel pub async fn finalize( self, tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, local_public_key: &PublicKey, remote_public_key: &PublicKey, - ) -> Result { + ) -> Result<(MoveToken, Vec), TokenChannelError> { // Token channel must be at a consistent incoming state assert!(matches!( tc_client.get_tc_status().await?, @@ -912,6 +929,9 @@ impl OutMoveToken { let info_hash = hash_token_info(local_public_key, remote_public_key, &token_info); + // Get all mentioned currencies in this move token message: + let mentioned_currencies = mentioned_currencies(&self.tc_ops[..]); + let mut move_token = MoveToken { old_token: move_token_in.new_token, operations: self @@ -935,7 +955,7 @@ impl OutMoveToken { .set_direction_outgoing(move_token.clone(), new_move_token_counter) .await?; - Ok(move_token) + Ok((move_token, mentioned_currencies)) } } @@ -947,7 +967,7 @@ pub async fn accept_remote_reset( operations: Vec, local_public_key: &PublicKey, remote_public_key: &PublicKey, -) -> Result { +) -> Result<(MoveToken, Vec), TokenChannelError> { // Make sure that we are in an inconsistent state, // and that the remote side has already sent his reset terms: let (remote_reset_token, remote_reset_move_token_counter) = From 29f09a00d07e0eaa9a8adb929e23b81cd4d01851 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 6 Feb 2021 19:19:21 +0200 Subject: [PATCH 434/478] funder: router: Work on IndexMutation-s creation --- .../funder/src/router/utils/move_token.rs | 56 +++++++++---------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 44a14d214..17e3ce63b 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -647,23 +647,6 @@ where RC::TcDbClient: Transaction + Send, ::McDbClient: Send, { - // Get list of interesting currencies: - let pre_move_token = PreMoveToken { - currencies_operations: move_token.currencies_operations.clone(), - currencies_diff: move_token.currencies_diff.clone(), - }; - let currencies = get_mentioned_currencies(&pre_move_token); - - // Record recv capacity for all interesting currencies - let currencies_info_before = - get_currencies_info(router_db_client, friend_public_key.clone(), ¤cies).await?; - - let recv_capacities_before = get_recv_capacities( - ¤cies_info_before, - friend_public_key.clone(), - ¤cies, - )?; - // Handle incoming move token: let receive_move_token_output = handle_in_move_token( router_db_client @@ -677,23 +660,34 @@ where ) .await?; - let currencies_info_after = - get_currencies_info(router_db_client, friend_public_key.clone(), ¤cies).await?; + // Get list of mentioned currencies: + let mentioned_currencies = if let ReceiveMoveTokenOutput::Received(move_token_received) = + &receive_move_token_output + { + let mentioned_currencies_set: HashSet<_> = move_token_received + .incoming_messages + .iter() + .map(|(currency, _incoming_message)| currency) + .cloned() + .collect(); + let mut mentioned_currencies_vec: Vec<_> = mentioned_currencies_set.into_iter().collect(); + // Sort currencies to make sure we get deterministic results: + mentioned_currencies_vec.sort(); + mentioned_currencies_vec + } else { + Vec::new() + }; - // Record recv capacity for all interesting currencies - let recv_capacities_after = get_recv_capacities( - ¤cies_info_after, + // Get currency info for all mentioned currencies: + let currencies_info = get_currencies_info( + router_db_client, friend_public_key.clone(), - ¤cies, - )?; + &mentioned_currencies, + ) + .await?; - // Compare recv capacities and create index mutations: - let index_mutations = diff_capacities( - friend_public_key, - &recv_capacities_before, - &recv_capacities_after, - ¤cies_info_after, - )?; + // For each currency, create index mutations based on currency information: + let index_mutations = create_index_mutations(friend_public_key.clone(), ¤cies_info)?; Ok((receive_move_token_output, index_mutations)) } From c441e74dcc40024ce997e56ea40f2b66ce31a011 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 6 Feb 2021 22:37:26 +0200 Subject: [PATCH 435/478] funder: restored move_token submodule. WIP --- components/funder/src/router/utils/flush.rs | 2 +- components/funder/src/router/utils/index_mutation.rs | 2 ++ components/funder/src/router/utils/move_token.rs | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/components/funder/src/router/utils/flush.rs b/components/funder/src/router/utils/flush.rs index fb74bc3d0..355607505 100644 --- a/components/funder/src/router/utils/flush.rs +++ b/components/funder/src/router/utils/flush.rs @@ -26,7 +26,7 @@ use crate::route::Route; use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; -use crate::router::utils::index_mutation::create_index_mutations_from_outgoing_move_token; +// use crate::router::utils::index_mutation::create_index_mutations_from_outgoing_move_token; use crate::router::utils::move_token::{ handle_out_move_token_index_mutations_disallow_empty, is_pending_move_token, }; diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index 2c3c317a2..e070144a7 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -77,6 +77,7 @@ pub fn create_update_index_mutation( })) } +/* /// Create a list of index mutations based on an outgoing MoveToken message. /// Note that the outgoing MoveToken message was already applied. pub async fn create_index_mutations_from_outgoing_move_token( @@ -139,6 +140,7 @@ pub async fn create_index_mutations_from_outgoing_move_token( Ok(index_mutations) } +*/ /// Create a list of index mutations based on an incoming MoveToken message. /// Note that the incoming MoveToken message was already applied. diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 17e3ce63b..16bd9f7eb 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -430,6 +430,7 @@ async fn get_currencies_info( Ok(currencies_info) } +/* /// Get receive capacities for a given list of currencies fn get_recv_capacities( currencies_info: &HashMap, @@ -484,6 +485,7 @@ fn diff_capacities( } Ok(index_mutations) } +*/ fn create_index_mutations( friend_public_key: PublicKey, From b80123b340e4116b2bb1f772008f0fd5654cc431 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 6 Feb 2021 22:39:05 +0200 Subject: [PATCH 436/478] funder: Removed old comments --- .../funder/src/router/utils/move_token.rs | 165 ------------------ 1 file changed, 165 deletions(-) diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 16bd9f7eb..f704a9d7b 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -34,19 +34,6 @@ use crate::token_channel::{ TokenChannelError, }; -/* -fn operations_vec_to_currencies_operations( - operations_vec: Vec<(Currency, FriendTcOp)>, -) -> CurrenciesOperations { - let mut currencies_operations = HashMap::>::new(); - for (currency, tc_op) in operations_vec { - let entry = currencies_operations.entry(currency).or_insert(Vec::new()); - (*entry).push(tc_op); - } - currencies_operations -} -*/ - async fn queue_backwards_op( router_db_client: &mut impl RouterDbClient, out_move_token: &mut OutMoveToken, @@ -317,101 +304,6 @@ pub async fn collect_outgoing_move_token_allow_empty( } */ -/* -/// Like MoveToken, but without the calculated `info_hash` and `signature` -#[derive(Debug)] -struct PreMoveToken { - pub currencies_operations: CurrenciesOperations, - pub currencies_diff: Vec, -} -*/ - -/* -/// Like MoveTokenRequest, but wrapping PreMoveToken instead of MoveToken. -#[derive(Debug)] -struct PreMoveTokenRequest { - pub pre_move_token: PreMoveToken, - pub token_wanted: bool, -} -*/ - -/* - -/// Attempt to create an outgoing move token -/// Collect any information we need to send to remote friend: -/// -/// - Currencies operations (requests, responses, cancels) -/// - Currencies diff (Added and removed currencies) -/// -/// Without actually sending this information yet. -/// Return Ok(None) if we have nothing to send -async fn collect_outgoing_pre_move_token( - router_db_client: &mut impl RouterDbClient, - local_public_key: &PublicKey, - friend_public_key: PublicKey, - max_operations_in_batch: usize, - router_output: &mut RouterOutput, -) -> Result, RouterError> { - let out_move_token = collect_currencies_operations( - router_db_client, - local_public_key, - friend_public_key.clone(), - max_operations_in_batch, - router_output, - ) - .await?; - - Ok(if out_move_token.is_empty() { - // There is nothing interesting to send to remote side - None - } else { - // We have something to send to remote side - Some(out_move_token) - }) -} - - -async fn send_pre_move_token( - router_db_client: &mut impl RouterDbClient, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - friend_public_key: PublicKey, - pre_move_token: PreMoveToken, -) -> Result { - let move_token = handle_out_move_token( - router_db_client - .tc_db_client(friend_public_key.clone()) - .await? - .ok_or(RouterError::InvalidState)?, - identity_client, - pre_move_token.currencies_operations, - pre_move_token.currencies_diff, - local_public_key, - &friend_public_key, - ) - .await?; - - Ok(move_token) -} -*/ - -/* -/// Collect all mentioned currencies from a PreMoveToken -fn get_mentioned_currencies(pre_move_token: &PreMoveToken) -> Vec { - // Collect all mentioned currencies: - let mut currencies = HashSet::new(); - for currency in &pre_move_token.currencies_diff { - currencies.insert(currency.clone()); - } - - for (currency, _operation) in &pre_move_token.currencies_operations { - currencies.insert(currency.clone()); - } - - currencies.into_iter().collect() -} -*/ - async fn get_currencies_info( router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, @@ -430,63 +322,6 @@ async fn get_currencies_info( Ok(currencies_info) } -/* -/// Get receive capacities for a given list of currencies -fn get_recv_capacities( - currencies_info: &HashMap, - friend_public_key: PublicKey, - currencies: &[Currency], -) -> Result, RouterError> { - let mut recv_capacities = HashMap::::new(); - for currency in currencies.iter() { - let recv_capacity = if let Some(currency_info) = currencies_info.get(currency) { - calc_capacities(¤cy_info)? - } else { - 0u128 - }; - - recv_capacities.insert(currency.clone(), recv_capacity); - } - Ok(recv_capacities) -} - -fn diff_capacities( - friend_public_key: PublicKey, - capacities_before: &HashMap, - capacities_after: &HashMap, - currencies_info: &HashMap, -) -> Result, RouterError> { - let mut index_mutations = Vec::new(); - for (currency, capacity_before) in capacities_before { - let capacity_after = capacities_after - .get(¤cy) - .ok_or(RouterError::InvalidState)?; - - if capacity_before != capacity_after { - if *capacity_after == 0 { - index_mutations.push(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { - public_key: friend_public_key.clone(), - currency: currency.clone(), - })); - } else { - // We should have this currency's info if the capacity after is nonzero: - let currency_info = currencies_info - .get(¤cy) - .ok_or(RouterError::InvalidState)?; - - index_mutations.push(IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { - public_key: friend_public_key.clone(), - currency: currency.clone(), - recv_capacity: *capacity_after, - rate: currency_info.rate.clone(), - })); - } - } - } - Ok(index_mutations) -} -*/ - fn create_index_mutations( friend_public_key: PublicKey, currencies_info: &HashMap, From fad80fa07c0748d57c501e8d9bbddf17d72a9091 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 6 Feb 2021 23:01:00 +0200 Subject: [PATCH 437/478] proto: TODO comment --- components/proto/src/funder/messages.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/proto/src/funder/messages.rs b/components/proto/src/funder/messages.rs index 0f45366dc..14285ed42 100644 --- a/components/proto/src/funder/messages.rs +++ b/components/proto/src/funder/messages.rs @@ -198,6 +198,7 @@ impl Into for ResponseSendFundsOp { } } +// TODO: Why is this struct in offset-proto? #[derive(Arbitrary, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct McBalance { /// Amount of credits this side has against the remote side. From 7806a18ef38c9eb631486b1984431906b49f0e36 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 6 Feb 2021 23:01:39 +0200 Subject: [PATCH 438/478] funder: Work on calc_capacities() --- components/funder/src/router/types.rs | 1 - .../funder/src/router/utils/index_mutation.rs | 40 ++++++++++++------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 6979bd065..46b463724 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -24,7 +24,6 @@ pub enum RouterError { FriendAlreadyOnline, FriendAlreadyOffline, GenerationOverflow, - BalanceOverflow, InvalidRoute, InvalidState, UnexpectedTcStatus, diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index e070144a7..42bf59b28 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -12,7 +12,7 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; use proto::crypto::{NodePort, PublicKey}; use proto::funder::messages::{ - CancelSendFundsOp, Currency, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, + CancelSendFundsOp, Currency, FriendMessage, FriendTcOp, McBalance, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; @@ -29,36 +29,46 @@ use crate::token_channel::{TcDbClient, TcStatus, TokenChannelError}; /// Calculate send and receive capacity for a certain currency /// This is the number we are going to report to an index server pub fn calc_capacities(currency_info: &CurrencyInfo) -> Result<(u128, u128), RouterError> { - todo!(); // TODO: // Should also take into account: // - Liveness // - Open/Closed currencies + // Maybe from the outside? + todo!(); - /* if !currency_info.is_open { - return Ok(0); + return Ok((0, 0)); } - let info_local = if let Some(info_local) = ¤cy_info.opt_local { - info_local + let mc_balance = if let Some(mc_balance) = ¤cy_info.opt_mutual_credit { + mc_balance.clone() } else { - return Ok(0); + McBalance { + balance: 0, + local_pending_debt: 0, + remote_pending_debt: 0, + in_fees: 0.into(), + out_fees: 0.into(), + } }; - let mc_balance = if let Some(mc_balance) = &info_local.opt_remote { + // local_max_debt + (balance - local_pending_debt) + let send_capacity = currency_info.local_max_debt.saturating_add_signed( mc_balance - } else { - return Ok(0); - }; + .balance + .checked_sub_unsigned(mc_balance.local_pending_debt) + .ok_or(RouterError::InvalidState)?, + ); - Ok(currency_info.remote_max_debt.saturating_sub_signed( + // remote_max_debt - (balance + remote_pending_debt) + let recv_capacity = currency_info.remote_max_debt.saturating_sub_signed( mc_balance .balance .checked_add_unsigned(mc_balance.remote_pending_debt) - .ok_or(RouterError::BalanceOverflow)?, - )) - */ + .ok_or(RouterError::InvalidState)?, + ); + + Ok((send_capacity, recv_capacity)) } /// Create one update index mutation, based on a given currency info. From bc14a3c1b4ef0e7127bc0510d3c48f78bfd27fb0 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 6 Feb 2021 23:19:03 +0200 Subject: [PATCH 439/478] funder: Removed todo!() statement from calc_capacities() --- components/funder/src/router/utils/index_mutation.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index 42bf59b28..53d23cb21 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -29,12 +29,7 @@ use crate::token_channel::{TcDbClient, TcStatus, TokenChannelError}; /// Calculate send and receive capacity for a certain currency /// This is the number we are going to report to an index server pub fn calc_capacities(currency_info: &CurrencyInfo) -> Result<(u128, u128), RouterError> { - // TODO: - // Should also take into account: - // - Liveness - // - Open/Closed currencies - // Maybe from the outside? - todo!(); + // TODO: Should also take into account liveness? Maybe from the outside? if !currency_info.is_open { return Ok((0, 0)); From 24af88d4fa7ee9aeb129971a711906b648e99701 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 13:25:17 +0200 Subject: [PATCH 440/478] funder: Restored flush submodule --- components/funder/src/router/utils/flush.rs | 1 + components/funder/src/router/utils/mod.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/funder/src/router/utils/flush.rs b/components/funder/src/router/utils/flush.rs index 355607505..1dbc65ee9 100644 --- a/components/funder/src/router/utils/flush.rs +++ b/components/funder/src/router/utils/flush.rs @@ -56,6 +56,7 @@ pub async fn flush_friend( local_public_key, friend_public_key.clone(), max_operations_in_batch, + router_output, ) .await?; diff --git a/components/funder/src/router/utils/mod.rs b/components/funder/src/router/utils/mod.rs index ff8b8e871..5bb7b7705 100644 --- a/components/funder/src/router/utils/mod.rs +++ b/components/funder/src/router/utils/mod.rs @@ -1,3 +1,3 @@ -// pub mod flush; +pub mod flush; pub mod index_mutation; pub mod move_token; From 0f8f016ef7d6d2550c8041a66bc6dd9ddc0e55e3 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 13:34:27 +0200 Subject: [PATCH 441/478] funder: handle_liveness submodule now compiles --- .../funder/src/router/handle_liveness.rs | 36 ++++++++++++------- components/funder/src/router/mod.rs | 2 +- components/funder/src/router/types.rs | 6 ++-- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index 37477704c..c02f731cb 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -14,9 +14,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; use proto::crypto::{NodePort, PublicKey}; use proto::funder::messages::{ - CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, - FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, - ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, + RelaysUpdate, RequestSendFundsOp, ResetTerms, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -27,14 +26,18 @@ use crate::route::Route; use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; + +use crate::mutual_credit::McCancel; + +use crate::token_channel::{ + handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, +}; + use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::{ handle_out_move_token_index_mutations_disallow_empty, is_pending_move_token, }; -use crate::token_channel::{ - handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, -}; pub async fn set_friend_online( router_db_client: &mut impl RouterDbClient, @@ -82,12 +85,15 @@ pub async fn set_friend_online( local_public_key, friend_public_key.clone(), max_operations_in_batch, + &mut output, ) .await?; if let Some((move_token_request, _index_mutations)) = opt_tuple { // We discard index_mutations calculation here, because we are going to add all // open currencies anyways. + // TODO: Reconsider index mutations here. + todo!(); // We have something to send to remote side: output.add_friend_message( @@ -123,11 +129,12 @@ pub async fn set_friend_online( // Add an index mutation for all open currencies: let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); while let Some(res) = open_currencies.next().await { - let open_currency = res?; + let (open_currency, open_currency_info) = res?; output.add_index_mutation(create_update_index_mutation( friend_public_key.clone(), open_currency, + open_currency_info, )?); } @@ -165,7 +172,7 @@ pub async fn set_friend_offline( .remove_local_request(pending_user_request.request_id.clone()) .await?; // Send outgoing cancel to user: - output.add_incoming_cancel(CancelSendFundsOp { + output.add_incoming_cancel(McCancel { request_id: pending_user_request.request_id, }); } @@ -187,9 +194,12 @@ pub async fn set_friend_offline( .pending_backwards_push_back( request_origin.friend_public_key, request_origin.currency, - BackwardsOp::Cancel(CancelSendFundsOp { - request_id: pending_request.request_id, - }), + BackwardsOp::Cancel( + currency, + McCancel { + request_id: pending_request.request_id, + }, + ), ) .await?; } @@ -199,10 +209,10 @@ pub async fn set_friend_offline( // We send index mutations to remove all currencies that are considered open let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); while let Some(res) = open_currencies.next().await { - let open_currency = res?; + let (open_currency, _open_currency_info) = res?; output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { public_key: friend_public_key.clone(), - currency: open_currency.currency, + currency: open_currency, })); } diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 510d18796..88ff56e7c 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -2,7 +2,7 @@ mod utils; // mod handle_config; // mod handle_friend; -// mod handle_liveness; +mod handle_liveness; // mod handle_relays; // mod handle_route; diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 46b463724..94e000deb 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -213,8 +213,10 @@ pub trait RouterDbClient { fn pending_requests_is_empty(&mut self, friend_public_key: PublicKey) -> AsyncOpResult; - fn list_open_currencies(&mut self, friend_public_key: PublicKey) - -> AsyncOpStream; + fn list_open_currencies( + &mut self, + friend_public_key: PublicKey, + ) -> AsyncOpStream<(Currency, CurrencyInfo)>; fn get_currency_info( &mut self, From 6d2652e5d4084859ef17cf2c85fd2aa562964b28 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 13:48:38 +0200 Subject: [PATCH 442/478] funder: Updated create_update_index_mutation -> create_index_mutation --- .../funder/src/router/handle_liveness.rs | 16 +++++------ .../funder/src/router/utils/index_mutation.rs | 27 ++++++++++++------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index c02f731cb..c2186c527 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -34,7 +34,7 @@ use crate::token_channel::{ }; use crate::router::utils::flush::flush_friend; -use crate::router::utils::index_mutation::create_update_index_mutation; +use crate::router::utils::index_mutation::create_index_mutation; use crate::router::utils::move_token::{ handle_out_move_token_index_mutations_disallow_empty, is_pending_move_token, }; @@ -92,8 +92,6 @@ pub async fn set_friend_online( if let Some((move_token_request, _index_mutations)) = opt_tuple { // We discard index_mutations calculation here, because we are going to add all // open currencies anyways. - // TODO: Reconsider index mutations here. - todo!(); // We have something to send to remote side: output.add_friend_message( @@ -131,11 +129,13 @@ pub async fn set_friend_online( while let Some(res) = open_currencies.next().await { let (open_currency, open_currency_info) = res?; - output.add_index_mutation(create_update_index_mutation( - friend_public_key.clone(), - open_currency, - open_currency_info, - )?); + let index_mutation = + create_index_mutation(friend_public_key.clone(), open_currency, open_currency_info)?; + + // We only add currencies with non zero send/recv capacity + if matches!(IndexMutation::UpdateFriendCurrency, index_mutation) { + output.add_index_mutation(index_mutation); + } } Ok(output) diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index 53d23cb21..f1092b735 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -66,20 +66,29 @@ pub fn calc_capacities(currency_info: &CurrencyInfo) -> Result<(u128, u128), Rou Ok((send_capacity, recv_capacity)) } -/// Create one update index mutation, based on a given currency info. -pub fn create_update_index_mutation( +/// Create one index mutation, based on a given currency info. +/// Returns IndexMutation::UpdateFriendCurrency if there is any send/recv capacity. +/// Otherwise, returns IndexMutation::RemoveFriendCurrency +pub fn create_index_mutation( friend_public_key: PublicKey, currency: Currency, currency_info: CurrencyInfo, ) -> Result { let (send_capacity, recv_capacity) = calc_capacities(¤cy_info)?; - Ok(IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { - public_key: friend_public_key, - currency, - send_capacity, - recv_capacity, - rate: currency_info.rate, - })) + Ok(if send_capacity == 0 && recv_capacity == 0 { + IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { + public_key: friend_public_key, + currency, + }) + } else { + IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { + public_key: friend_public_key, + currency, + send_capacity, + recv_capacity, + rate: currency_info.rate, + }) + }) } /* From 16ab314cf323b693d0f95223b40643ac78d693e0 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 13:49:37 +0200 Subject: [PATCH 443/478] funder: Restored handle_relays submodule --- components/funder/src/router/handle_relays.rs | 6 ++---- components/funder/src/router/mod.rs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/components/funder/src/router/handle_relays.rs b/components/funder/src/router/handle_relays.rs index c07a1927e..3eb14ffc5 100644 --- a/components/funder/src/router/handle_relays.rs +++ b/components/funder/src/router/handle_relays.rs @@ -14,9 +14,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; use proto::crypto::{NodePort, PublicKey}; use proto::funder::messages::{ - CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, - FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, - ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, + RelaysUpdate, RequestSendFundsOp, ResetTerms, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -29,7 +28,6 @@ use crate::router::types::{ }; use crate::mutual_credit::incoming::IncomingMessage; -use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::is_pending_move_token; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 88ff56e7c..54c405454 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -3,7 +3,7 @@ mod utils; // mod handle_config; // mod handle_friend; mod handle_liveness; -// mod handle_relays; +mod handle_relays; // mod handle_route; mod types; From eb53695eebd87c5d89544b35410a8992d2404be4 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 13:58:36 +0200 Subject: [PATCH 444/478] funder: router: Restored handle_config submodule --- components/funder/src/router/handle_config.rs | 36 +++++++++++++------ components/funder/src/router/mod.rs | 2 +- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 7c334527e..3a9eace11 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -14,9 +14,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; use proto::crypto::{NodePort, PublicKey}; use proto::funder::messages::{ - CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, - FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, - ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, + RelaysUpdate, RequestSendFundsOp, ResetTerms, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -28,7 +27,7 @@ use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; use crate::router::utils::flush::flush_friend; -use crate::router::utils::index_mutation::create_update_index_mutation; +use crate::router::utils::index_mutation::create_index_mutation; use crate::router::utils::move_token::is_pending_move_token; use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, @@ -159,11 +158,18 @@ pub async fn set_remote_max_debt( .set_remote_max_debt(friend_public_key.clone(), currency.clone(), remote_max_debt) .await?; + // TODO: It is possible that the capacity was already zero, and when we changed + // remote_max_debt the capacity has somehow stayed zero. In that case we will not need to + // resend an index mutation. Currently we do send. It wastes bandwidth, but it is still + // correct. Maybe in the future we can decide more elegantly when to send an index + // mutation. + // Create an index mutation if needed: if currency_info.is_open { // Currency is open: - output.add_index_mutation(create_update_index_mutation( + output.add_index_mutation(create_index_mutation( friend_public_key.clone(), + currency, currency_info, )?); } @@ -171,6 +177,14 @@ pub async fn set_remote_max_debt( Ok(output) } +pub async fn set_local_max_debt( + router_db_client: &mut impl RouterDbClient, + friend_public_key: PublicKey, + currency: Currency, + remote_max_debt: u128, +) -> Result { + todo!(); +} pub async fn open_currency( router_db_client: &mut impl RouterDbClient, @@ -198,14 +212,14 @@ pub async fn open_currency( // Open currency: router_db_client - .open_currency(friend_public_key.clone(), currency) + .open_currency(friend_public_key.clone(), currency.clone()) .await?; - // Add index mutation: - output.add_index_mutation(create_update_index_mutation( - friend_public_key, - currency_info, - )?); + let index_mutation = create_index_mutation(friend_public_key, currency, currency_info)?; + if matches!(index_mutation, IndexMutation::UpdateFriendCurrency(..)) { + // Add index mutation: + output.add_index_mutation(index_mutation); + } } } diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 54c405454..33d126a31 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -1,6 +1,6 @@ mod utils; -// mod handle_config; +mod handle_config; // mod handle_friend; mod handle_liveness; mod handle_relays; From 94d02c41416abd292c84ac2c564eec489932d899 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 14:22:05 +0200 Subject: [PATCH 445/478] funder: Updated backwards_ops queues interface --- components/funder/src/router/handle_liveness.rs | 11 ++++++++--- components/funder/src/router/types.rs | 3 +-- components/funder/src/router/utils/move_token.rs | 3 +-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index c2186c527..5e45b95ae 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -183,19 +183,24 @@ pub async fn set_friend_offline( .await? { // Find from which friend this pending request has originated from. - // Due to inconsistencies, it is possible that this pending request has no origin. + // Due to inconsistencies, it is possible that this pending request has no origin (An + // orphan request) let opt_request_origin = router_db_client .get_remote_pending_request_origin(pending_request.request_id.clone()) .await?; if let Some(request_origin) = opt_request_origin { + // Currency should be the same! + if currency != request_origin.currency { + return Err(RouterError::InvalidState); + } + // Cancel request by queue-ing a cancel into the relevant friend's queue: router_db_client .pending_backwards_push_back( request_origin.friend_public_key, - request_origin.currency, BackwardsOp::Cancel( - currency, + request_origin.currency, McCancel { request_id: pending_request.request_id, }, diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 94e000deb..a81edce53 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -166,12 +166,11 @@ pub trait RouterDbClient { fn pending_backwards_pop_front( &mut self, friend_public_key: PublicKey, - ) -> AsyncOpResult>; + ) -> AsyncOpResult>; fn pending_backwards_push_back( &mut self, friend_public_key: PublicKey, - currency: Currency, backwards_op: BackwardsOp, ) -> AsyncOpResult<()>; diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index f704a9d7b..f8b5607b8 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -149,7 +149,6 @@ async fn queue_request( // Request is of remote origin router_db_client.pending_backwards_push_back( request_origin.friend_public_key.clone(), - request_origin.currency.clone(), BackwardsOp::Cancel( request_origin.currency.clone(), McCancel { @@ -177,7 +176,7 @@ async fn collect_currencies_operations( let mut out_move_token = OutMoveToken::new(); // Collect any pending responses and cancels: - while let Some((currency, backwards_op)) = router_db_client + while let Some(backwards_op) = router_db_client .pending_backwards_pop_front(friend_public_key.clone()) .await? { From c4e9267f0fc5f83599a50529ba4995ec93f8c26d Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 14:38:02 +0200 Subject: [PATCH 446/478] funder: router: Some work on restoring handle_friend submodule --- components/funder/src/router/handle_friend.rs | 67 +++++++++++-------- components/funder/src/router/mod.rs | 2 +- components/funder/src/router/types.rs | 18 ++--- 3 files changed, 50 insertions(+), 37 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index cc51d2bf2..03abdad57 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -14,9 +14,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; use proto::crypto::{NodePort, PublicKey, Uid}; use proto::funder::messages::{ - CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, - FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, - ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, + RelaysUpdate, RequestSendFundsOp, ResetTerms, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -31,8 +30,8 @@ use crate::router::types::{ use crate::mutual_credit::incoming::{ IncomingCancelSendFundsOp, IncomingMessage, IncomingResponseSendFundsOp, }; +use crate::mutual_credit::{McCancel, McRequest}; use crate::router::utils::flush::flush_friend; -use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::{ handle_in_move_token_index_mutations, handle_out_move_token_index_mutations_allow_empty, handle_out_move_token_index_mutations_disallow_empty, is_pending_move_token, @@ -63,16 +62,7 @@ async fn is_credit_line_ready( return Ok(false); }; - if let Some(currency_info_local) = currency_info.opt_local { - if let Some(mc_balance) = currency_info_local.opt_remote { - // A mutual credit line is open for this currency - } else { - return Ok(false); - } - } else { - return Ok(false); - } - + // Note: We bypass `is_open` check if the request is of local origin: Ok(currency_info.is_open || router_db_client.is_request_local_origin(request_id).await?) } @@ -84,7 +74,6 @@ async fn incoming_message_request( local_public_key: &PublicKey, max_operations_in_batch: usize, router_output: &mut RouterOutput, - currency: Currency, mut request_send_funds: RequestSendFundsOp, ) -> Result<(), RouterError> where @@ -96,7 +85,7 @@ where router_db_client, &*router_state, friend_public_key.clone(), - currency.clone(), + request_send_funds.currency.clone(), request_send_funds.request_id.clone(), ) .await? @@ -105,10 +94,12 @@ where router_db_client .pending_backwards_push_back( friend_public_key.clone(), - currency, - BackwardsOp::Cancel(CancelSendFundsOp { - request_id: request_send_funds.request_id.clone(), - }), + BackwardsOp::Cancel( + request_send_funds.currency, + McCancel { + request_id: request_send_funds.request_id.clone(), + }, + ), ) .await?; @@ -128,7 +119,15 @@ where // If directed to us, punt if request_send_funds.route.is_empty() { // Directed to us. Punt: - router_output.add_incoming_request(request_send_funds); + let mc_request = McRequest { + request_id: request_send_funds.request_id, + src_hashed_lock: request_send_funds.src_hashed_lock, + dest_payment: request_send_funds.dest_payment, + invoice_hash: request_send_funds.invoice_hash, + route: request_send_funds.route, + left_fees: request_send_funds.left_fees, + }; + router_output.add_incoming_request(request_send_funds.currency, mc_request); return Ok(()); } @@ -143,7 +142,7 @@ where router_db_client, &*router_state, next_public_key.clone(), - currency.clone(), + request_send_funds.currency.clone(), request_send_funds.request_id.clone(), ) .await? @@ -156,9 +155,21 @@ where todo!(); if should_forward { + let mc_request = McRequest { + request_id: request_send_funds.request_id, + src_hashed_lock: request_send_funds.src_hashed_lock, + dest_payment: request_send_funds.dest_payment, + invoice_hash: request_send_funds.invoice_hash, + route: request_send_funds.route, + left_fees: request_send_funds.left_fees, + }; // Queue request to friend and flush destination friend router_db_client - .pending_requests_push_back(next_public_key.clone(), currency, request_send_funds) + .pending_requests_push_back( + next_public_key.clone(), + request_send_funds.currency, + mc_request, + ) .await?; flush_friend( router_db_client, @@ -174,10 +185,12 @@ where router_db_client .pending_backwards_push_back( friend_public_key.clone(), - currency, - BackwardsOp::Cancel(CancelSendFundsOp { - request_id: request_send_funds.request_id.clone(), - }), + BackwardsOp::Cancel( + request_send_funds.currency, + McCancel { + request_id: request_send_funds.request_id.clone(), + }, + ), ) .await?; diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 33d126a31..55f0a81f0 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -1,7 +1,7 @@ mod utils; mod handle_config; -// mod handle_friend; +mod handle_friend; mod handle_liveness; mod handle_relays; // mod handle_route; diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index a81edce53..fd7007645 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -323,9 +323,9 @@ pub struct RouterOutput { pub friends_messages: HashMap>, pub index_mutations: Vec, pub updated_remote_relays: Vec, - pub incoming_requests: Vec, - pub incoming_responses: Vec, - pub incoming_cancels: Vec, + pub incoming_requests: Vec<(Currency, McRequest)>, + pub incoming_responses: Vec<(Currency, McResponse)>, + pub incoming_cancels: Vec<(Currency, McCancel)>, } impl RouterOutput { @@ -354,15 +354,15 @@ impl RouterOutput { // TODO: Add updated remote relays? - pub fn add_incoming_request(&mut self, request: McRequest) { - self.incoming_requests.push(request); + pub fn add_incoming_request(&mut self, currency: Currency, request: McRequest) { + self.incoming_requests.push((currency, request)); } - pub fn add_incoming_response(&mut self, response: McResponse) { - self.incoming_responses.push(response); + pub fn add_incoming_response(&mut self, currency: Currency, response: McResponse) { + self.incoming_responses.push((currency, response)); } - pub fn add_incoming_cancel(&mut self, cancel: McCancel) { - self.incoming_cancels.push(cancel); + pub fn add_incoming_cancel(&mut self, currency: Currency, cancel: McCancel) { + self.incoming_cancels.push((currency, cancel)); } } From 69e29b1d228dde621265456ba6f00088ca0afdcb Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 16:12:58 +0200 Subject: [PATCH 447/478] funder: Fixed calls to add_incoming_cancel() --- components/funder/src/router/handle_liveness.rs | 11 +++++++---- components/funder/src/router/utils/move_token.rs | 9 ++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index 5e45b95ae..fad2fdd4a 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -163,7 +163,7 @@ pub async fn set_friend_offline( router_state.liveness.set_offline(&friend_public_key); // Cancel all pending user requests - while let Some((_currency, pending_user_request)) = router_db_client + while let Some((currency, pending_user_request)) = router_db_client .pending_user_requests_pop_front(friend_public_key.clone()) .await? { @@ -172,9 +172,12 @@ pub async fn set_friend_offline( .remove_local_request(pending_user_request.request_id.clone()) .await?; // Send outgoing cancel to user: - output.add_incoming_cancel(McCancel { - request_id: pending_user_request.request_id, - }); + output.add_incoming_cancel( + currency, + McCancel { + request_id: pending_user_request.request_id, + }, + ); } // Cancel all pending requests diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index f8b5607b8..7f79afa98 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -138,9 +138,12 @@ async fn queue_request( .await? { // Request is of local origin - router_output.add_incoming_cancel(McCancel { - request_id: mc_request.request_id.clone(), - }); + router_output.add_incoming_cancel( + currency, + McCancel { + request_id: mc_request.request_id.clone(), + }, + ); } else { if let Some(request_origin) = router_db_client .get_remote_pending_request_origin(mc_request.request_id.clone()) From 9e67fdde99aa9e6be3d175cbd47e95ea59b22249 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 16:36:14 +0200 Subject: [PATCH 448/478] funder: Restored handle_friend submodule --- components/funder/src/mutual_credit/types.rs | 37 +++++++- components/funder/src/router/handle_friend.rs | 86 ++++++++----------- 2 files changed, 71 insertions(+), 52 deletions(-) diff --git a/components/funder/src/mutual_credit/types.rs b/components/funder/src/mutual_credit/types.rs index 35f658877..340d28277 100644 --- a/components/funder/src/mutual_credit/types.rs +++ b/components/funder/src/mutual_credit/types.rs @@ -1,9 +1,10 @@ use common::async_rpc::AsyncOpResult; -// use common::ser_utils::ser_string; use common::u256::U256; use proto::crypto::{HashResult, HashedLock, PlainLock, PublicKey, Signature, Uid}; -use proto::funder::messages::McBalance; +use proto::funder::messages::{ + CancelSendFundsOp, McBalance, RequestSendFundsOp, ResponseSendFundsOp, +}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct PendingTransaction { @@ -118,3 +119,35 @@ impl From for PendingTransaction { } } } + +impl From for McRequest { + fn from(request_send_funds: RequestSendFundsOp) -> Self { + Self { + request_id: request_send_funds.request_id, + src_hashed_lock: request_send_funds.src_hashed_lock, + dest_payment: request_send_funds.dest_payment, + invoice_hash: request_send_funds.invoice_hash, + route: request_send_funds.route, + left_fees: request_send_funds.left_fees, + } + } +} + +impl From for McResponse { + fn from(response_send_funds: ResponseSendFundsOp) -> Self { + Self { + request_id: response_send_funds.request_id, + src_plain_lock: response_send_funds.src_plain_lock, + serial_num: response_send_funds.serial_num, + signature: response_send_funds.signature, + } + } +} + +impl From for McCancel { + fn from(cancel_send_funds: CancelSendFundsOp) -> Self { + Self { + request_id: cancel_send_funds.request_id, + } + } +} diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 03abdad57..aecc83648 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -74,7 +74,8 @@ async fn incoming_message_request( local_public_key: &PublicKey, max_operations_in_batch: usize, router_output: &mut RouterOutput, - mut request_send_funds: RequestSendFundsOp, + currency: Currency, + mut mc_request: McRequest, ) -> Result<(), RouterError> where RC: RouterDbClient, @@ -85,8 +86,8 @@ where router_db_client, &*router_state, friend_public_key.clone(), - request_send_funds.currency.clone(), - request_send_funds.request_id.clone(), + currency.clone(), + mc_request.request_id.clone(), ) .await? { @@ -95,9 +96,9 @@ where .pending_backwards_push_back( friend_public_key.clone(), BackwardsOp::Cancel( - request_send_funds.currency, + currency.clone(), McCancel { - request_id: request_send_funds.request_id.clone(), + request_id: mc_request.request_id.clone(), }, ), ) @@ -117,17 +118,9 @@ where } // If directed to us, punt - if request_send_funds.route.is_empty() { + if mc_request.route.is_empty() { // Directed to us. Punt: - let mc_request = McRequest { - request_id: request_send_funds.request_id, - src_hashed_lock: request_send_funds.src_hashed_lock, - dest_payment: request_send_funds.dest_payment, - invoice_hash: request_send_funds.invoice_hash, - route: request_send_funds.route, - left_fees: request_send_funds.left_fees, - }; - router_output.add_incoming_request(request_send_funds.currency, mc_request); + router_output.add_incoming_request(currency.clone(), mc_request.into()); return Ok(()); } @@ -135,19 +128,19 @@ where // - If friend exists and ready, forward to next hop // - Otherwise, queue cancel // Route is not empty. We need to forward the request to a friend - let next_public_key = request_send_funds.route.remove(0); + let next_public_key = mc_request.route.remove(0); // Check if next public key corresponds to a friend that is ready let should_forward = is_credit_line_ready( router_db_client, &*router_state, next_public_key.clone(), - request_send_funds.currency.clone(), - request_send_funds.request_id.clone(), + currency.clone(), + mc_request.request_id.clone(), ) .await? && !router_db_client - .is_local_request_exists(request_send_funds.request_id.clone()) + .is_local_request_exists(mc_request.request_id.clone()) .await?; // Attempt to collect fees according to rate. If credits in fees jar are insufficient, do not @@ -155,21 +148,9 @@ where todo!(); if should_forward { - let mc_request = McRequest { - request_id: request_send_funds.request_id, - src_hashed_lock: request_send_funds.src_hashed_lock, - dest_payment: request_send_funds.dest_payment, - invoice_hash: request_send_funds.invoice_hash, - route: request_send_funds.route, - left_fees: request_send_funds.left_fees, - }; // Queue request to friend and flush destination friend router_db_client - .pending_requests_push_back( - next_public_key.clone(), - request_send_funds.currency, - mc_request, - ) + .pending_requests_push_back(next_public_key.clone(), currency, mc_request.into()) .await?; flush_friend( router_db_client, @@ -186,9 +167,9 @@ where .pending_backwards_push_back( friend_public_key.clone(), BackwardsOp::Cancel( - request_send_funds.currency, + currency, McCancel { - request_id: request_send_funds.request_id.clone(), + request_id: mc_request.request_id.clone(), }, ), ) @@ -216,7 +197,7 @@ async fn incoming_message_request_cancel( identity_client: &mut IdentityClient, router_output: &mut RouterOutput, currency: Currency, - request_send_funds: RequestSendFundsOp, + mc_request: McRequest, ) -> Result<(), RouterError> where RC: RouterDbClient, @@ -229,14 +210,17 @@ where .await? .is_consistent() { - // TODO: Something is strange here. Are we actually queueing a cancel message or something - // else? + let backwards_op = BackwardsOp::Cancel( + currency, + McCancel { + request_id: mc_request.request_id, + }, + ); // Queue cancel to friend_public_key (Request origin) router_db_client - .pending_requests_push_back(friend_public_key.clone(), currency, request_send_funds) + .pending_backwards_push_back(friend_public_key.clone(), backwards_op) .await?; - todo!(); } else { // We have just received a cancel message from this friend. // We expect that this friend is consistent @@ -281,7 +265,8 @@ where .await?; // We punt the response - router_output.add_incoming_response(incoming_response.incoming_response); + router_output + .add_incoming_response(currency.clone(), incoming_response.incoming_response); } (false, Some(request_origin)) => { // Request has originated from a friend. @@ -292,8 +277,7 @@ where router_db_client .pending_backwards_push_back( friend_public_key.clone(), - currency, - BackwardsOp::Response(incoming_response.incoming_response), + BackwardsOp::Response(currency, incoming_response.incoming_response), ) .await?; @@ -356,7 +340,7 @@ where .await?; // We punt the cancel - router_output.add_incoming_cancel(incoming_cancel.incoming_cancel); + router_output.add_incoming_cancel(currency, incoming_cancel.incoming_cancel); } (false, Some(request_origin)) => { // Request has originated from a friend. @@ -367,8 +351,7 @@ where router_db_client .pending_backwards_push_back( friend_public_key.clone(), - currency, - BackwardsOp::Cancel(incoming_cancel.incoming_cancel), + BackwardsOp::Cancel(currency, incoming_cancel.incoming_cancel), ) .await?; @@ -388,7 +371,7 @@ where // Note that this only happen during a cycle request, but a cycle always begins and // ends at the local node. // Therefore, this should never happen when processing a friend incoming cancel. - unreachable!(); + return Err(RouterError::InvalidState); } } Ok(()) @@ -440,6 +423,7 @@ where local_public_key, friend_public_key.clone(), max_operations_in_batch, + &mut output, ) .await?; @@ -474,7 +458,7 @@ where ReceiveMoveTokenOutput::Received(move_token_received) => { for (currency, incoming_message) in move_token_received.incoming_messages { match incoming_message { - IncomingMessage::Request(request_send_funds) => { + IncomingMessage::Request(mc_request) => { incoming_message_request( router_db_client, router_state, @@ -484,18 +468,18 @@ where max_operations_in_batch, &mut output, currency, - request_send_funds, + mc_request, ) .await } - IncomingMessage::RequestCancel(request_send_funds) => { + IncomingMessage::RequestCancel(mc_request) => { incoming_message_request_cancel( router_db_client, friend_public_key.clone(), identity_client, &mut output, currency, - request_send_funds, + mc_request, ) .await } @@ -541,6 +525,7 @@ where local_public_key, friend_public_key.clone(), max_operations_in_batch, + &mut output, ) .await?, ) @@ -552,6 +537,7 @@ where local_public_key, friend_public_key.clone(), max_operations_in_batch, + &mut output, ) .await? }; From 20d64bc4fb33ca17d987fc020b03c28b0132aebf Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 16:37:32 +0200 Subject: [PATCH 449/478] funder: TODO comment --- components/funder/src/router/handle_config.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 3a9eace11..5ed03d3b9 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -260,6 +260,9 @@ pub async fn close_currency( public_key: friend_public_key, currency, })); + + // TODO: Cancel all requests pending for this currency. + todo!(); } } From 34e980c5cd4c0b097bd033b9ffa99fa6d8b1cc31 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 16:41:20 +0200 Subject: [PATCH 450/478] funder: Restored handle_route submodule --- components/funder/src/router/handle_route.rs | 51 +++++++++++--------- components/funder/src/router/mod.rs | 2 +- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index 5291efa51..346359932 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -14,9 +14,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; use proto::crypto::{NodePort, PublicKey}; use proto::funder::messages::{ - CancelSendFundsOp, CurrenciesOperations, Currency, CurrencyOperations, FriendMessage, - FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, RequestSendFundsOp, ResetTerms, - ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, + RelaysUpdate, RequestSendFundsOp, ResetTerms, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -28,8 +27,10 @@ use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; use crate::router::utils::flush::flush_friend; -use crate::router::utils::index_mutation::create_update_index_mutation; use crate::router::utils::move_token::is_pending_move_token; + +use crate::mutual_credit::{McCancel, McRequest, McResponse}; + use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; @@ -38,14 +39,11 @@ pub async fn send_request( router_db_client: &mut impl RouterDbClient, router_state: &RouterState, currency: Currency, - mut request: RequestSendFundsOp, + mut request: McRequest, identity_client: &mut IdentityClient, local_public_key: &PublicKey, max_operations_in_batch: usize, ) -> Result { - // TODO: Do not forward if requests not enabled? / Friend not enabled? - todo!(); - // Make sure that the provided route is valid: if !request.route.is_valid() { return Err(RouterError::InvalidRoute); @@ -58,9 +56,12 @@ pub async fn send_request( .await? { // We already have a local request with the same id. Return back a cancel. - output.add_incoming_cancel(CancelSendFundsOp { - request_id: request.request_id, - }); + output.add_incoming_cancel( + currency, + McCancel { + request_id: request.request_id, + }, + ); return Ok(output); } @@ -82,9 +83,12 @@ pub async fn send_request( } else { // Friend is not ready to accept a request. // We cancel the request: - output.add_incoming_cancel(CancelSendFundsOp { - request_id: request.request_id.clone(), - }); + output.add_incoming_cancel( + currency, + McCancel { + request_id: request.request_id.clone(), + }, + ); return Ok(output); }; @@ -118,9 +122,12 @@ pub async fn send_request( ) .await?; } else { - output.add_incoming_cancel(CancelSendFundsOp { - request_id: request.request_id, - }); + output.add_incoming_cancel( + currency, + McCancel { + request_id: request.request_id, + }, + ); } Ok(output) @@ -128,7 +135,7 @@ pub async fn send_request( pub async fn send_response( router_db_client: &mut impl RouterDbClient, - response: ResponseSendFundsOp, + response: McResponse, identity_client: &mut IdentityClient, local_public_key: &PublicKey, max_operations_in_batch: usize, @@ -146,8 +153,7 @@ pub async fn send_response( router_db_client .pending_backwards_push_back( request_origin.friend_public_key.clone(), - request_origin.currency, - BackwardsOp::Response(response), + BackwardsOp::Response(request_origin.currency, response), ) .await?; @@ -167,7 +173,7 @@ pub async fn send_response( pub async fn send_cancel( router_db_client: &mut impl RouterDbClient, - cancel: CancelSendFundsOp, + cancel: McCancel, identity_client: &mut IdentityClient, local_public_key: &PublicKey, max_operations_in_batch: usize, @@ -185,8 +191,7 @@ pub async fn send_cancel( router_db_client .pending_backwards_push_back( request_origin.friend_public_key.clone(), - request_origin.currency, - BackwardsOp::Cancel(cancel), + BackwardsOp::Cancel(request_origin.currency, cancel), ) .await?; diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 55f0a81f0..63ee61afc 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -4,6 +4,6 @@ mod handle_config; mod handle_friend; mod handle_liveness; mod handle_relays; -// mod handle_route; +mod handle_route; mod types; From e8bc24294a20880d5b609c4e35b8f8c528b440f8 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 16:43:27 +0200 Subject: [PATCH 451/478] funder: Removed redundant code --- .../funder/src/router/utils/index_mutation.rs | 82 ------------------- 1 file changed, 82 deletions(-) diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index f1092b735..14f414a2c 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -90,85 +90,3 @@ pub fn create_index_mutation( }) }) } - -/* -/// Create a list of index mutations based on an outgoing MoveToken message. -/// Note that the outgoing MoveToken message was already applied. -pub async fn create_index_mutations_from_outgoing_move_token( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - move_token: &MoveToken, -) -> Result, RouterError> { - // Strategy: - // - For every currency in currencies diff: - // - If currency is gone, send a RemoveFriendCurrency - // - If currency exists, send UpdateFriendCurrency - // - For the currencies from currencies operations, that were not in the currencies diff: - // - If currency is gone: Impossible - // - If currency exists: send UpdateFriendCurrency - // - // This strategy is consolidated into the following simplified strategy: - // - For each mentioned currency (currencies_diff or currencies_operations): - // - If currency is gone, send a RemoveFriendCurrency - // - If currency exists, send UpdateFriendCurrency - - // Collect all mentioned currencies: - let currencies = { - let mut currencies = HashSet::new(); - for currency in &move_token.currencies_diff { - currencies.insert(currency.clone()); - } - - for (currency, _operation) in &move_token.currencies_operations { - currencies.insert(currency.clone()); - } - currencies - }; - - // TODO: Sort currencies set here, to get deterministic result. - // Possibly use a function instead of inlining here. - todo!(); - - let mut index_mutations = Vec::new(); - - // Create all index mutations: - for currency in currencies.into_iter() { - let opt_currency_info = router_db_client - .get_currency_info(friend_public_key.clone(), currency.clone()) - .await?; - if let Some(currency_info) = opt_currency_info { - // Currency exists - index_mutations.push(create_update_index_mutation( - friend_public_key.clone(), - currency.clone(), - currency_info, - )?); - } else { - // Currency does not exist anymore - index_mutations.push(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { - public_key: friend_public_key.clone(), - currency, - })); - } - } - - Ok(index_mutations) -} -*/ - -/// Create a list of index mutations based on an incoming MoveToken message. -/// Note that the incoming MoveToken message was already applied. -pub async fn create_index_mutations_from_incoming_move_token( - router_db_client: &mut impl RouterDbClient, - friend_public_key: PublicKey, - move_token: &MoveToken, -) -> Result, RouterError> { - // Strategy: - // - For every currency in currencies diff: - // - If currency is gone, send nothing (Because it was already gone before) - // - If currency exists, send UpdateFriendCurrency - // - For the currencies from currencies operations, that were not in the currencies diff: - // - If currency is gone: Impossible - // - If currency exists: send UpdateFriendCurrency - todo!(); -} From 876a1400a57a249222d822d7bb42f906bae1daa9 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 16:44:46 +0200 Subject: [PATCH 452/478] funder: Removed old comments --- .../funder/src/router/utils/move_token.rs | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 7f79afa98..6795ded38 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -261,51 +261,6 @@ async fn is_pending_currencies_operations( .await?) } -/* -// TODO: Rewrite this function to also return index mutations. -// Should be very similar to `handle_in_move_token_index_mutations`. -/// Attempt to create an outgoing move token -/// May create an empty move token. -pub async fn collect_outgoing_move_token_allow_empty( - router_db_client: &mut impl RouterDbClient, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - friend_public_key: PublicKey, - max_operations_in_batch: usize, -) -> Result { - todo!(); - let currencies_operations = collect_currencies_operations( - router_db_client, - friend_public_key.clone(), - max_operations_in_batch, - ) - .await?; - - let mut currencies_diff = router_db_client - .currencies_diff(friend_public_key.clone()) - .await?; - - // Create move token and update internal state: - let move_token = handle_out_move_token( - router_db_client - .tc_db_client(friend_public_key.clone()) - .await? - .ok_or(RouterError::InvalidDbState)?, - identity_client, - currencies_operations, - currencies_diff, - local_public_key, - &friend_public_key, - ) - .await?; - - Ok(MoveTokenRequest { - move_token, - token_wanted: is_pending_currencies_operations(router_db_client, friend_public_key).await?, - }) -} -*/ - async fn get_currencies_info( router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, From 5e599ed8f685bed5fb179fa3a7f911d12c0b50dd Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 16:50:09 +0200 Subject: [PATCH 453/478] funder: calc_capacities() is now private --- .../funder/src/router/utils/index_mutation.rs | 2 +- .../funder/src/router/utils/move_token.rs | 33 +++++++------------ 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/components/funder/src/router/utils/index_mutation.rs b/components/funder/src/router/utils/index_mutation.rs index 14f414a2c..3e75df531 100644 --- a/components/funder/src/router/utils/index_mutation.rs +++ b/components/funder/src/router/utils/index_mutation.rs @@ -28,7 +28,7 @@ use crate::token_channel::{TcDbClient, TcStatus, TokenChannelError}; /// Calculate send and receive capacity for a certain currency /// This is the number we are going to report to an index server -pub fn calc_capacities(currency_info: &CurrencyInfo) -> Result<(u128, u128), RouterError> { +fn calc_capacities(currency_info: &CurrencyInfo) -> Result<(u128, u128), RouterError> { // TODO: Should also take into account liveness? Maybe from the outside? if !currency_info.is_open { diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 6795ded38..05d7feff0 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -28,7 +28,7 @@ use crate::router::types::{ BackwardsOp, CurrencyInfo, FriendBalance, FriendBalanceDiff, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, }; -use crate::router::utils::index_mutation::calc_capacities; +use crate::router::utils::index_mutation::create_index_mutation; use crate::token_channel::{ handle_in_move_token, OutMoveToken, ReceiveMoveTokenOutput, TcDbClient, TcOp, TcStatus, TokenChannelError, @@ -281,14 +281,14 @@ async fn get_currencies_info( fn create_index_mutations( friend_public_key: PublicKey, - currencies_info: &HashMap, + currencies_info: HashMap, ) -> Result, RouterError> { let mut index_mutations = Vec::new(); // Sort currencies_info, to have deterministic results let currencies_info_vec = { - let mut currencies_info_vec: Vec<(&Currency, &CurrencyInfo)> = currencies_info - .iter() + let mut currencies_info_vec: Vec<(Currency, CurrencyInfo)> = currencies_info + .into_iter() .map(|(currency, currency_info)| (currency, currency_info)) .collect(); currencies_info_vec.sort_by(|(c_a, c_a_inf), (c_b, c_b_inf)| c_a.cmp(c_b)); @@ -297,22 +297,11 @@ fn create_index_mutations( // Create an `IndexMutation` for every currency_info: for (currency, currency_info) in currencies_info_vec { - let (send_capacity, recv_capacity) = calc_capacities(currency_info)?; - if send_capacity == 0 && recv_capacity == 0 { - index_mutations.push(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { - public_key: friend_public_key.clone(), - currency: currency.clone(), - })); - } else { - // UpdateFriendCurrency - index_mutations.push(IndexMutation::UpdateFriendCurrency(UpdateFriendCurrency { - public_key: friend_public_key.clone(), - currency: currency.clone(), - send_capacity, - recv_capacity, - rate: currency_info.rate.clone(), - })); - } + index_mutations.push(create_index_mutation( + friend_public_key.clone(), + currency, + currency_info, + )?); } Ok(index_mutations) @@ -349,7 +338,7 @@ async fn apply_out_move_token( .await?; // For each currency, create index mutations based on currency information: - let index_mutations = create_index_mutations(friend_public_key.clone(), ¤cies_info)?; + let index_mutations = create_index_mutations(friend_public_key.clone(), currencies_info)?; let move_token_request = MoveTokenRequest { move_token, @@ -481,7 +470,7 @@ where .await?; // For each currency, create index mutations based on currency information: - let index_mutations = create_index_mutations(friend_public_key.clone(), ¤cies_info)?; + let index_mutations = create_index_mutations(friend_public_key.clone(), currencies_info)?; Ok((receive_move_token_output, index_mutations)) } From dcb04e64f9a173780332928718479741839f3867 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 16:50:56 +0200 Subject: [PATCH 454/478] funder: TODO comment --- components/funder/src/router/handle_config.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 5ed03d3b9..0d325cf02 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -183,6 +183,7 @@ pub async fn set_local_max_debt( currency: Currency, remote_max_debt: u128, ) -> Result { + // TODO: Fill in todo!(); } From eeb99278554d349ef4b292dd187fce1ba71bbf75 Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 20:39:53 +0200 Subject: [PATCH 455/478] funder: impl set_local_max_debt() --- components/funder/src/router/handle_config.rs | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 0d325cf02..20684775c 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -177,14 +177,51 @@ pub async fn set_remote_max_debt( Ok(output) } + pub async fn set_local_max_debt( router_db_client: &mut impl RouterDbClient, friend_public_key: PublicKey, currency: Currency, - remote_max_debt: u128, + local_max_debt: u128, ) -> Result { - // TODO: Fill in - todo!(); + // First we make sure that the friend exists: + let mut output = RouterOutput::new(); + if router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .is_none() + { + return Ok(output); + } + + let opt_currency_info = router_db_client + .get_currency_info(friend_public_key.clone(), currency.clone()) + .await?; + if let Some(currency_info) = opt_currency_info { + // Currency exists (We don't do anything otherwise) + // Set remote max debt: + router_db_client + .set_local_max_debt(friend_public_key.clone(), currency.clone(), local_max_debt) + .await?; + + // TODO: It is possible that the capacity was already zero, and when we changed + // remote_max_debt the capacity has somehow stayed zero. In that case we will not need to + // resend an index mutation. Currently we do send. It wastes bandwidth, but it is still + // correct. Maybe in the future we can decide more elegantly when to send an index + // mutation. + + // Create an index mutation if needed: + if currency_info.is_open { + // Currency is open: + output.add_index_mutation(create_index_mutation( + friend_public_key.clone(), + currency, + currency_info, + )?); + } + } + + Ok(output) } pub async fn open_currency( From 790b39218b1a799e51236c21f64270373b46ad3e Mon Sep 17 00:00:00 2001 From: real Date: Mon, 8 Feb 2021 22:05:18 +0200 Subject: [PATCH 456/478] funder: Added TODO comments for flush_friend() --- components/funder/src/router/handle_config.rs | 25 ++++++++++++++++--- components/funder/src/router/handle_friend.rs | 17 ++++++++++++- .../funder/src/router/handle_liveness.rs | 1 - components/funder/src/router/handle_route.rs | 6 +++++ components/funder/src/router/types.rs | 11 ++++++++ 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 20684775c..fbc9d486c 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -54,6 +54,8 @@ pub async fn add_currency( .add_currency_config(friend_public_key.clone(), currency) .await?; + // TODO: Update flush_friend to a newer mechanism. + todo!(); flush_friend( router_db_client, friend_public_key, @@ -87,6 +89,8 @@ pub async fn set_remove_currency( .set_currency_remove(friend_public_key.clone(), currency) .await?; + // TODO: Update flush_friend to a newer mechanism. + todo!(); flush_friend( router_db_client, friend_public_key, @@ -120,6 +124,8 @@ pub async fn unset_remove_currency( .unset_currency_remove(friend_public_key.clone(), currency) .await?; + // TODO: Update flush_friend to a newer mechanism. + todo!(); flush_friend( router_db_client, friend_public_key, @@ -295,12 +301,25 @@ pub async fn close_currency( // Add index mutation: output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { - public_key: friend_public_key, + public_key: friend_public_key.clone(), currency, })); - // TODO: Cancel all requests pending for this currency. - todo!(); + // Cancel all user requests pending for this currency: + while let Some(mc_request) = router_db_client + .pending_user_requests_pop_front_by_currency(friend_public_key.clone()) + .await? + { + todo!(); + } + + // Cancel all requests pending for this currency: + while let Some(mc_request) = router_db_client + .pending_user_requests_pop_front_by_currency(friend_public_key.clone()) + .await? + { + todo!(); + } } } diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index aecc83648..98eb55b09 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -104,6 +104,9 @@ where ) .await?; + // TODO: flush_friend() is delicate. We might be able to aggregate some more pending + // requests before flushing this friend. Find out how to do this. + todo!(); flush_friend( router_db_client, friend_public_key, @@ -152,6 +155,9 @@ where router_db_client .pending_requests_push_back(next_public_key.clone(), currency, mc_request.into()) .await?; + // TODO: flush_friend() is delicate. We might be able to aggregate some more pending + // requests before flushing this friend. Find out how to do this. + todo!(); flush_friend( router_db_client, next_public_key, @@ -175,6 +181,9 @@ where ) .await?; + // TODO: flush_friend() is delicate. We might be able to aggregate some more pending + // requests before flushing this friend. Find out how to do this. + todo!(); flush_friend( router_db_client, friend_public_key, @@ -282,6 +291,9 @@ where .await?; // Attempt to send a move token if possible + // TODO: flush_friend() is delicate. We might be able to aggregate some more pending + // requests before flushing this friend. Find out how to do this. + todo!(); flush_friend( router_db_client, friend_public_key.clone(), @@ -297,7 +309,7 @@ where // Note that this only happen during a cycle request, but a cycle always begins and // ends at the local node. // Therefore, this should never happen when processing a friend incoming response. - unreachable!(); + return Err(RouterError::InvalidState); } } Ok(()) @@ -356,6 +368,9 @@ where .await?; // Attempt to send a move token if possible + // TODO: flush_friend() is delicate. We might be able to aggregate some more pending + // requests before flushing this friend. Find out how to do this. + todo!(); flush_friend( router_db_client, friend_public_key.clone(), diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index fad2fdd4a..602c615af 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -33,7 +33,6 @@ use crate::token_channel::{ handle_in_move_token, ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError, }; -use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_index_mutation; use crate::router::utils::move_token::{ handle_out_move_token_index_mutations_disallow_empty, is_pending_move_token, diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index 346359932..5814e8f4c 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -112,6 +112,8 @@ pub async fn send_request( // response/cancel message later. router_db_client.add_local_request(request_id).await?; + // TODO: Change flush_friend design + todo!(); flush_friend( router_db_client, friend_public_key.clone(), @@ -157,6 +159,8 @@ pub async fn send_response( ) .await?; + // TODO: Change flush_friend design + todo!(); flush_friend( router_db_client, request_origin.friend_public_key, @@ -195,6 +199,8 @@ pub async fn send_cancel( ) .await?; + // TODO: Change flush_friend design + todo!(); flush_friend( router_db_client, request_origin.friend_public_key, diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index fd7007645..e2c1eea74 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -181,6 +181,11 @@ pub trait RouterDbClient { friend_public_key: PublicKey, ) -> AsyncOpResult>; + fn pending_user_requests_pop_front_by_currency( + &mut self, + friend_public_key: PublicKey, + ) -> AsyncOpResult>; + fn pending_user_requests_push_back( &mut self, friend_public_key: PublicKey, @@ -198,6 +203,12 @@ pub trait RouterDbClient { friend_public_key: PublicKey, ) -> AsyncOpResult>; + fn pending_requests_pop_front_by_currency( + &mut self, + friend_public_key: PublicKey, + currency: Currency, + ) -> AsyncOpResult>; + /// Check if a `request_id` is already in use. /// Searches all local pending requests, and all local open transactions. fn is_local_request_exists(&mut self, request_id: Uid) -> AsyncOpResult; From 33ddbedc4b69491e3492547069d46f30ce3086f9 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 11 Feb 2021 13:29:17 +0200 Subject: [PATCH 457/478] funder: Began work on router's handler --- components/funder/src/router/handle_config.rs | 2 + components/funder/src/router/handler.rs | 25 ++++++++ components/funder/src/router/mod.rs | 2 + components/funder/src/router/types.rs | 63 +++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 components/funder/src/router/handler.rs diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index fbc9d486c..441f2b622 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -76,6 +76,8 @@ pub async fn set_remove_currency( local_public_key: &PublicKey, max_operations_in_batch: usize, ) -> Result { + // Revise implementation with respect to new design + todo!(); // First we make sure that the friend exists: let mut output = RouterOutput::new(); if router_db_client diff --git a/components/funder/src/router/handler.rs b/components/funder/src/router/handler.rs new file mode 100644 index 000000000..98d31f544 --- /dev/null +++ b/components/funder/src/router/handler.rs @@ -0,0 +1,25 @@ +use crate::router::types::{RouterControl, RouterDbClient, RouterOp}; +use crate::router::{handle_config, handle_friend, handle_liveness, handle_relays, handle_route}; + +pub async fn handle_router_op(router_control: &mut RouterControl<'_, RC>, router_op: RouterOp) +where + RC: RouterDbClient, +{ + match router_op { + RouterOp::AddCurrency(friend_public_key, currency) => todo!(), + RouterOp::RemoveCurrency(friend_public_key, currency) => todo!(), + RouterOp::SetRemoteMaxDebt(friend_public_key, currency, remote_max_debt) => todo!(), + RouterOp::SetLocalMaxDebt(friend_public_key, currency, remote_max_debt) => todo!(), + RouterOp::OpenCurrency(friend_public_key, currency) => todo!(), + RouterOp::CloseCurrency(friend_public_key, currency) => todo!(), + RouterOp::FriendMessage(friend_public_key, friend_message) => todo!(), + RouterOp::SetFriendOnline(friend_public_key) => todo!(), + RouterOp::SetFriendOffline(friend_public_key) => todo!(), + RouterOp::UpdateFriendLocalRelays(friend_public_key, friend_local_relays) => todo!(), + RouterOp::UpdateLocalRelays(local_relays) => todo!(), + RouterOp::SendRequest(currency, mc_request) => todo!(), + RouterOp::SendResponse(mc_response) => todo!(), + RouterOp::SendCancel(mc_cancel) => todo!(), + } + todo!(); +} diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 63ee61afc..48dad6a71 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -6,4 +6,6 @@ mod handle_liveness; mod handle_relays; mod handle_route; +mod handler; + mod types; diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index e2c1eea74..c91ab08ab 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -8,6 +8,8 @@ use common::u256::U256; use crate::liveness::Liveness; use crate::token_channel::TcDbClient; +use identity::IdentityClient; + use proto::app_server::messages::{NamedRelayAddress, RelayAddressPort}; use proto::crypto::{PublicKey, Uid}; use proto::funder::messages::{ @@ -15,6 +17,7 @@ use proto::funder::messages::{ ResponseSendFundsOp, }; use proto::index_server::messages::IndexMutation; +use proto::net::messages::NetAddress; use crate::mutual_credit::{McCancel, McRequest, McResponse}; use crate::token_channel::TokenChannelError; @@ -339,6 +342,15 @@ pub struct RouterOutput { pub incoming_cancels: Vec<(Currency, McCancel)>, } +#[derive(Debug)] +pub struct RouterHandle<'a, RC> { + pub router_db_client: &'a mut RC, + pub identity_client: &'a mut IdentityClient, + pub local_public_key: PublicKey, + pub max_operations_in_batch: usize, + pub output: RouterOutput, +} + impl RouterOutput { pub fn new() -> Self { RouterOutput { @@ -377,3 +389,54 @@ impl RouterOutput { self.incoming_cancels.push((currency, cancel)); } } + +pub struct RouterControl<'a, RC> { + pub router_db_client: &'a mut RC, + pub friend_public_key: PublicKey, + pub currency: Currency, + pub identity_client: &'a mut IdentityClient, + pub local_public_key: PublicKey, + pub max_operations_in_batch: usize, +} + +#[derive(Debug)] +pub enum RouterOp { + // Config + // ------ + /// (friend_public_key, currency) + AddCurrency(PublicKey, Currency), + /// (friend_public_key, currency) + RemoveCurrency(PublicKey, Currency), + /// (friend_public_key, currency, remote_max_debt) + SetRemoteMaxDebt(PublicKey, Currency, u128), + /// (friend_public_key, currency, local_max_debt) + SetLocalMaxDebt(PublicKey, Currency, u128), + /// (friend_public_key, currency) + OpenCurrency(PublicKey, Currency), + /// (friend_public_key, currency) + CloseCurrency(PublicKey, Currency), + // Friend + // ------ + /// (friend_public_key, friend_message) + FriendMessage(PublicKey, FriendMessage), + // Livenesss + // --------- + /// (friend_public_key) + SetFriendOnline(PublicKey), + /// (friend_public_key) + SetFriendOffline(PublicKey), + // Relays + // ------ + /// (friend_public_key, friend_local_relays) + UpdateFriendLocalRelays(PublicKey, HashMap), + /// (friend_public_key, local_relays) + UpdateLocalRelays(HashMap), + // Route + // ----- + /// (currency, mc_request) + SendRequest(Currency, McRequest), + /// (mc_response) + SendResponse(McResponse), + /// (mc_cancel) + SendCancel(McCancel), +} From de8d0a8a7637a52d8c98f4f74cba19defb2d340d Mon Sep 17 00:00:00 2001 From: real Date: Thu, 11 Feb 2021 13:37:09 +0200 Subject: [PATCH 458/478] funder: Updated RouterControl --- components/funder/src/router/types.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index c91ab08ab..f61af4e9a 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -390,13 +390,14 @@ impl RouterOutput { } } +#[derive(Debug)] pub struct RouterControl<'a, RC> { pub router_db_client: &'a mut RC, - pub friend_public_key: PublicKey, - pub currency: Currency, pub identity_client: &'a mut IdentityClient, pub local_public_key: PublicKey, pub max_operations_in_batch: usize, + /// Ephemeral state: + pub state: RouterState, } #[derive(Debug)] From 81eefe5fbc2a82a44146747529e96e903129df6a Mon Sep 17 00:00:00 2001 From: real Date: Thu, 11 Feb 2021 13:55:28 +0200 Subject: [PATCH 459/478] funder: Removed redundant struct --- components/funder/src/router/types.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index f61af4e9a..ea00fb51d 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -342,15 +342,6 @@ pub struct RouterOutput { pub incoming_cancels: Vec<(Currency, McCancel)>, } -#[derive(Debug)] -pub struct RouterHandle<'a, RC> { - pub router_db_client: &'a mut RC, - pub identity_client: &'a mut IdentityClient, - pub local_public_key: PublicKey, - pub max_operations_in_batch: usize, - pub output: RouterOutput, -} - impl RouterOutput { pub fn new() -> Self { RouterOutput { From b490af31344921504531db8bcd346aebfb33cf97 Mon Sep 17 00:00:00 2001 From: real Date: Thu, 11 Feb 2021 14:42:16 +0200 Subject: [PATCH 460/478] funder: router handler: connected handle_config --- components/funder/src/router/handle_config.rs | 196 ++++++++---------- components/funder/src/router/handler.rs | 42 +++- components/funder/src/router/types.rs | 16 +- 3 files changed, 138 insertions(+), 116 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 441f2b622..b0767876a 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -24,7 +24,8 @@ use crypto::rand::{CryptoRandom, RandGen}; use crate::route::Route; use crate::router::types::{ - BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, + BackwardsOp, CurrencyInfo, RouterControl, RouterDbClient, RouterError, RouterInfo, + RouterOutput, RouterState, SentRelay, }; use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_index_mutation; @@ -34,135 +35,109 @@ use crate::token_channel::{ }; pub async fn add_currency( - router_db_client: &mut impl RouterDbClient, + control: &mut RouterControl<'_, impl RouterDbClient>, + info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, -) -> Result { +) -> Result<(), RouterError> { // First we make sure that the friend exists: - let mut output = RouterOutput::new(); - if router_db_client + if control + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .is_none() { - return Ok(output); + return Ok(()); } - router_db_client + control + .router_db_client .add_currency_config(friend_public_key.clone(), currency) .await?; - // TODO: Update flush_friend to a newer mechanism. - todo!(); - flush_friend( - router_db_client, - friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, - ) - .await?; - Ok(output) + control.pending_send.insert(friend_public_key); + + Ok(()) } pub async fn set_remove_currency( - router_db_client: &mut impl RouterDbClient, + control: &mut RouterControl<'_, impl RouterDbClient>, + info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, -) -> Result { +) -> Result<(), RouterError> { // Revise implementation with respect to new design todo!(); // First we make sure that the friend exists: - let mut output = RouterOutput::new(); - if router_db_client + if control + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .is_none() { - return Ok(output); + return Ok(()); } - router_db_client + control + .router_db_client .set_currency_remove(friend_public_key.clone(), currency) .await?; - // TODO: Update flush_friend to a newer mechanism. - todo!(); - flush_friend( - router_db_client, - friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, - ) - .await?; - Ok(output) + control.pending_send.insert(friend_public_key); + Ok(()) } pub async fn unset_remove_currency( - router_db_client: &mut impl RouterDbClient, + control: &mut RouterControl<'_, impl RouterDbClient>, + info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, -) -> Result { +) -> Result<(), RouterError> { + // TODO: Update implementation according to new design + todo!(); + // First we make sure that the friend exists: - let mut output = RouterOutput::new(); - if router_db_client + if control + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .is_none() { - return Ok(output); + return Ok(()); } - router_db_client + control + .router_db_client .unset_currency_remove(friend_public_key.clone(), currency) .await?; - // TODO: Update flush_friend to a newer mechanism. - todo!(); - flush_friend( - router_db_client, - friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, - ) - .await?; - Ok(output) + control.pending_send.insert(friend_public_key); + Ok(()) } pub async fn set_remote_max_debt( - router_db_client: &mut impl RouterDbClient, + control: &mut RouterControl<'_, impl RouterDbClient>, + info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, remote_max_debt: u128, -) -> Result { +) -> Result<(), RouterError> { // First we make sure that the friend exists: - let mut output = RouterOutput::new(); - if router_db_client + if control + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .is_none() { - return Ok(output); + return Ok(()); } - let opt_currency_info = router_db_client + let opt_currency_info = control + .router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) .await?; if let Some(currency_info) = opt_currency_info { // Currency exists (We don't do anything otherwise) // Set remote max debt: - router_db_client + control + .router_db_client .set_remote_max_debt(friend_public_key.clone(), currency.clone(), remote_max_debt) .await?; @@ -175,7 +150,7 @@ pub async fn set_remote_max_debt( // Create an index mutation if needed: if currency_info.is_open { // Currency is open: - output.add_index_mutation(create_index_mutation( + control.output.add_index_mutation(create_index_mutation( friend_public_key.clone(), currency, currency_info, @@ -183,32 +158,35 @@ pub async fn set_remote_max_debt( } } - Ok(output) + Ok(()) } pub async fn set_local_max_debt( - router_db_client: &mut impl RouterDbClient, + control: &mut RouterControl<'_, impl RouterDbClient>, + info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, local_max_debt: u128, -) -> Result { +) -> Result<(), RouterError> { // First we make sure that the friend exists: - let mut output = RouterOutput::new(); - if router_db_client + if control + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .is_none() { - return Ok(output); + return Ok(()); } - let opt_currency_info = router_db_client + let opt_currency_info = control + .router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) .await?; if let Some(currency_info) = opt_currency_info { // Currency exists (We don't do anything otherwise) // Set remote max debt: - router_db_client + control + .router_db_client .set_local_max_debt(friend_public_key.clone(), currency.clone(), local_max_debt) .await?; @@ -221,7 +199,7 @@ pub async fn set_local_max_debt( // Create an index mutation if needed: if currency_info.is_open { // Currency is open: - output.add_index_mutation(create_index_mutation( + control.output.add_index_mutation(create_index_mutation( friend_public_key.clone(), currency, currency_info, @@ -229,25 +207,26 @@ pub async fn set_local_max_debt( } } - Ok(output) + Ok(()) } pub async fn open_currency( - router_db_client: &mut impl RouterDbClient, + control: &mut RouterControl<'_, impl RouterDbClient>, friend_public_key: PublicKey, currency: Currency, -) -> Result { +) -> Result<(), RouterError> { // First we make sure that the friend exists: - let mut output = RouterOutput::new(); - if router_db_client + if control + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .is_none() { - return Ok(output); + return Ok(()); } - let opt_currency_info = router_db_client + let opt_currency_info = control + .router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) .await?; @@ -257,37 +236,39 @@ pub async fn open_currency( // currency is closed: // Open currency: - router_db_client + control + .router_db_client .open_currency(friend_public_key.clone(), currency.clone()) .await?; let index_mutation = create_index_mutation(friend_public_key, currency, currency_info)?; if matches!(index_mutation, IndexMutation::UpdateFriendCurrency(..)) { // Add index mutation: - output.add_index_mutation(index_mutation); + control.output.add_index_mutation(index_mutation); } } } - Ok(output) + Ok(()) } pub async fn close_currency( - router_db_client: &mut impl RouterDbClient, + control: &mut RouterControl<'_, impl RouterDbClient>, friend_public_key: PublicKey, currency: Currency, -) -> Result { +) -> Result<(), RouterError> { // First we make sure that the friend exists: - let mut output = RouterOutput::new(); - if router_db_client + if control + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .is_none() { - return Ok(output); + return Ok(()); } - let opt_currency_info = router_db_client + let opt_currency_info = control + .router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) .await?; @@ -297,18 +278,22 @@ pub async fn close_currency( // currency is open: // Close currency: - router_db_client + control + .router_db_client .close_currency(friend_public_key.clone(), currency.clone()) .await?; // Add index mutation: - output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { - public_key: friend_public_key.clone(), - currency, - })); + control + .output + .add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { + public_key: friend_public_key.clone(), + currency, + })); // Cancel all user requests pending for this currency: - while let Some(mc_request) = router_db_client + while let Some(mc_request) = control + .router_db_client .pending_user_requests_pop_front_by_currency(friend_public_key.clone()) .await? { @@ -316,7 +301,8 @@ pub async fn close_currency( } // Cancel all requests pending for this currency: - while let Some(mc_request) = router_db_client + while let Some(mc_request) = control + .router_db_client .pending_user_requests_pop_front_by_currency(friend_public_key.clone()) .await? { @@ -325,5 +311,5 @@ pub async fn close_currency( } } - Ok(output) + Ok(()) } diff --git a/components/funder/src/router/handler.rs b/components/funder/src/router/handler.rs index 98d31f544..f4cc09b81 100644 --- a/components/funder/src/router/handler.rs +++ b/components/funder/src/router/handler.rs @@ -1,17 +1,45 @@ -use crate::router::types::{RouterControl, RouterDbClient, RouterOp}; +use crate::router::types::{RouterControl, RouterDbClient, RouterError, RouterInfo, RouterOp}; use crate::router::{handle_config, handle_friend, handle_liveness, handle_relays, handle_route}; -pub async fn handle_router_op(router_control: &mut RouterControl<'_, RC>, router_op: RouterOp) +pub async fn handle_router_op( + control: &mut RouterControl<'_, RC>, + info: &RouterInfo, + router_op: RouterOp, +) -> Result<(), RouterError> where RC: RouterDbClient, { match router_op { - RouterOp::AddCurrency(friend_public_key, currency) => todo!(), + RouterOp::AddCurrency(friend_public_key, currency) => { + handle_config::add_currency(control, info, friend_public_key, currency).await? + } RouterOp::RemoveCurrency(friend_public_key, currency) => todo!(), - RouterOp::SetRemoteMaxDebt(friend_public_key, currency, remote_max_debt) => todo!(), - RouterOp::SetLocalMaxDebt(friend_public_key, currency, remote_max_debt) => todo!(), - RouterOp::OpenCurrency(friend_public_key, currency) => todo!(), - RouterOp::CloseCurrency(friend_public_key, currency) => todo!(), + RouterOp::SetRemoteMaxDebt(friend_public_key, currency, remote_max_debt) => { + handle_config::set_remote_max_debt( + control, + info, + friend_public_key, + currency, + remote_max_debt, + ) + .await? + } + RouterOp::SetLocalMaxDebt(friend_public_key, currency, local_max_debt) => { + handle_config::set_local_max_debt( + control, + info, + friend_public_key, + currency, + local_max_debt, + ) + .await? + } + RouterOp::OpenCurrency(friend_public_key, currency) => { + handle_config::open_currency(control, friend_public_key, currency).await? + } + RouterOp::CloseCurrency(friend_public_key, currency) => { + handle_config::close_currency(control, friend_public_key, currency).await? + } RouterOp::FriendMessage(friend_public_key, friend_message) => todo!(), RouterOp::SetFriendOnline(friend_public_key) => todo!(), RouterOp::SetFriendOffline(friend_public_key) => todo!(), diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index ea00fb51d..ee77a4872 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use derive_more::From; @@ -381,14 +381,22 @@ impl RouterOutput { } } +#[derive(Debug)] +pub struct RouterInfo { + pub local_public_key: PublicKey, + pub max_operations_in_batch: usize, +} + #[derive(Debug)] pub struct RouterControl<'a, RC> { pub router_db_client: &'a mut RC, pub identity_client: &'a mut IdentityClient, - pub local_public_key: PublicKey, - pub max_operations_in_batch: usize, + /// Friends with new pending outgoing messages + pub pending_send: HashSet, /// Ephemeral state: - pub state: RouterState, + pub state: &'a mut RouterState, + /// Router's output: + pub output: RouterOutput, } #[derive(Debug)] From 64fe46c2475123977e04b6cfb30f84ee197b6bea Mon Sep 17 00:00:00 2001 From: real Date: Thu, 11 Feb 2021 15:14:07 +0200 Subject: [PATCH 461/478] funder: router handler: connected handle_friend --- components/funder/src/router/handle_friend.rs | 327 +++++++----------- components/funder/src/router/handler.rs | 23 +- 2 files changed, 142 insertions(+), 208 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 98eb55b09..bf1077e06 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -23,14 +23,15 @@ use proto::net::messages::NetAddress; use crypto::rand::{CryptoRandom, RandGen}; use crate::route::Route; -use crate::router::types::{ - BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, -}; use crate::mutual_credit::incoming::{ IncomingCancelSendFundsOp, IncomingMessage, IncomingResponseSendFundsOp, }; use crate::mutual_credit::{McCancel, McRequest}; +use crate::router::types::{ + BackwardsOp, CurrencyInfo, RouterControl, RouterDbClient, RouterError, RouterInfo, + RouterOutput, RouterState, SentRelay, +}; use crate::router::utils::flush::flush_friend; use crate::router::utils::move_token::{ handle_in_move_token_index_mutations, handle_out_move_token_index_mutations_allow_empty, @@ -41,19 +42,19 @@ use crate::token_channel::{ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenCh /// Check if credit line between this node and a friend is ready /// Works for sending requests in both directions async fn is_credit_line_ready( - router_db_client: &mut impl RouterDbClient, - router_state: &RouterState, + control: &mut RouterControl<'_, impl RouterDbClient>, friend_public_key: PublicKey, currency: Currency, request_id: Uid, ) -> Result { // Friend must be online: - if !router_state.liveness.is_online(&friend_public_key) { + if !control.state.liveness.is_online(&friend_public_key) { return Ok(false); } // Currency must exist: - let currency_info = if let Some(currency_info) = router_db_client + let currency_info = if let Some(currency_info) = control + .router_db_client .get_currency_info(friend_public_key, currency) .await? { @@ -63,17 +64,17 @@ async fn is_credit_line_ready( }; // Note: We bypass `is_open` check if the request is of local origin: - Ok(currency_info.is_open || router_db_client.is_request_local_origin(request_id).await?) + Ok(currency_info.is_open + || control + .router_db_client + .is_request_local_origin(request_id) + .await?) } async fn incoming_message_request( - mut router_db_client: &mut RC, - router_state: &mut RouterState, + control: &mut RouterControl<'_, RC>, + info: &RouterInfo, friend_public_key: PublicKey, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, - router_output: &mut RouterOutput, currency: Currency, mut mc_request: McRequest, ) -> Result<(), RouterError> @@ -83,8 +84,7 @@ where // Make sure that we are ready to receive this request operation // We might not be ready in the case of currency being closed. if !is_credit_line_ready( - router_db_client, - &*router_state, + control, friend_public_key.clone(), currency.clone(), mc_request.request_id.clone(), @@ -92,7 +92,8 @@ where .await? { // Return a cancel message and flush origin friend - router_db_client + control + .router_db_client .pending_backwards_push_back( friend_public_key.clone(), BackwardsOp::Cancel( @@ -104,18 +105,7 @@ where ) .await?; - // TODO: flush_friend() is delicate. We might be able to aggregate some more pending - // requests before flushing this friend. Find out how to do this. - todo!(); - flush_friend( - router_db_client, - friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - router_output, - ) - .await?; + control.pending_send.insert(friend_public_key); return Ok(()); } @@ -123,7 +113,9 @@ where // If directed to us, punt if mc_request.route.is_empty() { // Directed to us. Punt: - router_output.add_incoming_request(currency.clone(), mc_request.into()); + control + .output + .add_incoming_request(currency.clone(), mc_request.into()); return Ok(()); } @@ -135,14 +127,14 @@ where // Check if next public key corresponds to a friend that is ready let should_forward = is_credit_line_ready( - router_db_client, - &*router_state, + control, next_public_key.clone(), currency.clone(), mc_request.request_id.clone(), ) .await? - && !router_db_client + && !control + .router_db_client .is_local_request_exists(mc_request.request_id.clone()) .await?; @@ -152,24 +144,18 @@ where if should_forward { // Queue request to friend and flush destination friend - router_db_client + control + .router_db_client .pending_requests_push_back(next_public_key.clone(), currency, mc_request.into()) .await?; // TODO: flush_friend() is delicate. We might be able to aggregate some more pending // requests before flushing this friend. Find out how to do this. - todo!(); - flush_friend( - router_db_client, - next_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - router_output, - ) - .await?; + + control.pending_send.insert(next_public_key); } else { // Return a cancel message and flush origin friend - router_db_client + control + .router_db_client .pending_backwards_push_back( friend_public_key.clone(), BackwardsOp::Cancel( @@ -181,18 +167,7 @@ where ) .await?; - // TODO: flush_friend() is delicate. We might be able to aggregate some more pending - // requests before flushing this friend. Find out how to do this. - todo!(); - flush_friend( - router_db_client, - friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - router_output, - ) - .await?; + control.pending_send.insert(friend_public_key); } Ok(()) @@ -201,17 +176,16 @@ where /// An incoming request was received, but due to insufficient trust we can not /// forward this request. We return a cancel message to the sender friend async fn incoming_message_request_cancel( - mut router_db_client: &mut RC, + control: &mut RouterControl<'_, RC>, friend_public_key: PublicKey, - identity_client: &mut IdentityClient, - router_output: &mut RouterOutput, currency: Currency, mc_request: McRequest, ) -> Result<(), RouterError> where RC: RouterDbClient, { - if router_db_client + if control + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .ok_or(RouterError::InvalidState)? @@ -227,7 +201,8 @@ where ); // Queue cancel to friend_public_key (Request origin) - router_db_client + control + .router_db_client .pending_backwards_push_back(friend_public_key.clone(), backwards_op) .await?; } else { @@ -239,13 +214,9 @@ where } async fn incoming_message_response( - mut router_db_client: &mut RC, - router_state: &mut RouterState, + control: &mut RouterControl<'_, RC>, + info: &RouterInfo, friend_public_key: PublicKey, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, - router_output: &mut RouterOutput, currency: Currency, incoming_response: IncomingResponseSendFundsOp, ) -> Result<(), RouterError> @@ -253,10 +224,12 @@ where RC: RouterDbClient, { // Gather information about request's origin: - let opt_request_origin = router_db_client + let opt_request_origin = control + .router_db_client .get_remote_pending_request_origin(incoming_response.incoming_response.request_id.clone()) .await?; - let is_local_origin = router_db_client + let is_local_origin = control + .router_db_client .is_request_local_origin(incoming_response.incoming_response.request_id.clone()) .await?; @@ -269,12 +242,14 @@ where // Request has originated locally // Clear the request from local requests list - router_db_client + control + .router_db_client .remove_local_request(incoming_response.incoming_response.request_id.clone()) .await?; // We punt the response - router_output + control + .output .add_incoming_response(currency.clone(), incoming_response.incoming_response); } (false, Some(request_origin)) => { @@ -283,26 +258,15 @@ where // an origin. // Push response: - router_db_client + control + .router_db_client .pending_backwards_push_back( friend_public_key.clone(), BackwardsOp::Response(currency, incoming_response.incoming_response), ) .await?; - // Attempt to send a move token if possible - // TODO: flush_friend() is delicate. We might be able to aggregate some more pending - // requests before flushing this friend. Find out how to do this. - todo!(); - flush_friend( - router_db_client, - friend_public_key.clone(), - identity_client, - local_public_key, - max_operations_in_batch, - router_output, - ) - .await?; + control.pending_send.insert(friend_public_key); } (true, Some(request_origin)) => { // This means the request has both originated locally, and from a friend. @@ -315,26 +279,21 @@ where Ok(()) } -// TODO: This function seems too similar to`incoming_message_response` -async fn incoming_message_cancel( - mut router_db_client: &mut RC, - router_state: &mut RouterState, +// TODO: This function seems too similar to `incoming_message_response` +async fn incoming_message_cancel( + control: &mut RouterControl<'_, impl RouterDbClient>, + info: &RouterInfo, friend_public_key: PublicKey, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, - router_output: &mut RouterOutput, currency: Currency, incoming_cancel: IncomingCancelSendFundsOp, -) -> Result<(), RouterError> -where - RC: RouterDbClient, -{ +) -> Result<(), RouterError> { // Gather information about request's origin: - let opt_request_origin = router_db_client + let opt_request_origin = control + .router_db_client .get_remote_pending_request_origin(incoming_cancel.incoming_cancel.request_id.clone()) .await?; - let is_local_origin = router_db_client + let is_local_origin = control + .router_db_client .is_request_local_origin(incoming_cancel.incoming_cancel.request_id.clone()) .await?; @@ -347,12 +306,15 @@ where // Request has originated locally // Clear the request from local requests list - router_db_client + control + .router_db_client .remove_local_request(incoming_cancel.incoming_cancel.request_id.clone()) .await?; // We punt the cancel - router_output.add_incoming_cancel(currency, incoming_cancel.incoming_cancel); + control + .output + .add_incoming_cancel(currency, incoming_cancel.incoming_cancel); } (false, Some(request_origin)) => { // Request has originated from a friend. @@ -360,26 +322,15 @@ where // an origin. // Push cancel: - router_db_client + control + .router_db_client .pending_backwards_push_back( friend_public_key.clone(), BackwardsOp::Cancel(currency, incoming_cancel.incoming_cancel), ) .await?; - // Attempt to send a move token if possible - // TODO: flush_friend() is delicate. We might be able to aggregate some more pending - // requests before flushing this friend. Find out how to do this. - todo!(); - flush_friend( - router_db_client, - friend_public_key.clone(), - identity_client, - local_public_key, - max_operations_in_batch, - router_output, - ) - .await?; + control.pending_send.insert(friend_public_key.clone()); } (true, Some(request_origin)) => { // This means the request has both originated locally, and from a friend. @@ -393,63 +344,60 @@ where } async fn incoming_move_token_request( - mut router_db_client: &mut RC, - router_state: &mut RouterState, + control: &mut RouterControl<'_, RC>, + info: &RouterInfo, friend_public_key: PublicKey, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, in_move_token_request: MoveTokenRequest, -) -> Result +) -> Result<(), RouterError> where RC: RouterDbClient, // TODO: Maybe not necessary: RC::TcDbClient: Transaction + Send, ::McDbClient: Send, { - let mut output = RouterOutput::new(); - let (receive_move_token_output, index_mutations) = handle_in_move_token_index_mutations( - router_db_client, - identity_client, + control.router_db_client, + control.identity_client, in_move_token_request.move_token, - local_public_key, + &info.local_public_key, friend_public_key.clone(), ) .await?; // Add mutations: for index_mutation in index_mutations { - output.add_index_mutation(index_mutation); + control.output.add_index_mutation(index_mutation); } match receive_move_token_output { ReceiveMoveTokenOutput::Duplicate => { // We should have nothing else to send at this point, otherwise we would have already // sent it. - assert!(!is_pending_move_token(router_db_client, friend_public_key.clone()).await?); + assert!( + !is_pending_move_token(control.router_db_client, friend_public_key.clone()).await? + ); // Possibly send token to remote side (According to token_wanted) if in_move_token_request.token_wanted { let (out_move_token_request, index_mutations) = handle_out_move_token_index_mutations_allow_empty( - router_db_client, - identity_client, - local_public_key, + control.router_db_client, + control.identity_client, + &info.local_public_key, friend_public_key.clone(), - max_operations_in_batch, - &mut output, + info.max_operations_in_batch, + &mut control.output, ) .await?; // We just got a message from remote side. Remote side should be online: - assert!(router_state.liveness.is_online(&friend_public_key)); + assert!(control.state.liveness.is_online(&friend_public_key)); // Add index mutations: for index_mutation in index_mutations { - output.add_index_mutation(index_mutation); + control.output.add_index_mutation(index_mutation); } - output.add_friend_message( + control.output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(out_move_token_request), ); @@ -459,12 +407,15 @@ where // Retransmit outgoing move token message to friend: let move_token_request = MoveTokenRequest { move_token, - token_wanted: is_pending_move_token(router_db_client, friend_public_key.clone()) - .await?, + token_wanted: is_pending_move_token( + control.router_db_client, + friend_public_key.clone(), + ) + .await?, }; - if router_state.liveness.is_online(&friend_public_key) { - output.add_friend_message( + if control.state.liveness.is_online(&friend_public_key) { + control.output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(move_token_request), ); @@ -475,13 +426,9 @@ where match incoming_message { IncomingMessage::Request(mc_request) => { incoming_message_request( - router_db_client, - router_state, + control, + info, friend_public_key.clone(), - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, currency, mc_request, ) @@ -489,10 +436,8 @@ where } IncomingMessage::RequestCancel(mc_request) => { incoming_message_request_cancel( - router_db_client, + control, friend_public_key.clone(), - identity_client, - &mut output, currency, mc_request, ) @@ -500,13 +445,9 @@ where } IncomingMessage::Response(incoming_response) => { incoming_message_response( - router_db_client, - router_state, + control, + info, friend_public_key.clone(), - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, currency, incoming_response, ) @@ -514,13 +455,9 @@ where } IncomingMessage::Cancel(incoming_cancel) => { incoming_message_cancel( - router_db_client, - router_state, + control, + info, friend_public_key.clone(), - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, currency, incoming_cancel, ) @@ -535,37 +472,37 @@ where // to remote side, even if it is empty Some( handle_out_move_token_index_mutations_allow_empty( - router_db_client, - identity_client, - local_public_key, + control.router_db_client, + control.identity_client, + &info.local_public_key, friend_public_key.clone(), - max_operations_in_batch, - &mut output, + info.max_operations_in_batch, + &mut control.output, ) .await?, ) } else { // We only send a MoveTokenRequest to remote side if we have something to send: handle_out_move_token_index_mutations_disallow_empty( - router_db_client, - identity_client, - local_public_key, + control.router_db_client, + control.identity_client, + &info.local_public_key, friend_public_key.clone(), - max_operations_in_batch, - &mut output, + info.max_operations_in_batch, + &mut control.output, ) .await? }; if let Some((out_move_token_request, index_mutations)) = opt_res { // We just got a message from remote side. Remote side should be online: - assert!(router_state.liveness.is_online(&friend_public_key)); + assert!(control.state.liveness.is_online(&friend_public_key)); // Add index mutations: for index_mutation in index_mutations { - output.add_index_mutation(index_mutation); + control.output.add_index_mutation(index_mutation); } - output.add_friend_message( + control.output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(out_move_token_request), ); @@ -586,42 +523,39 @@ where } } - Ok(output) + Ok(()) } async fn incoming_inconsistency_error( - router_db_client: &mut impl RouterDbClient, + control: &mut RouterControl<'_, impl RouterDbClient>, friend_public_key: PublicKey, reset_terms: ResetTerms, -) -> Result { +) -> Result<(), RouterError> { todo!(); } async fn incoming_relays_update( - router_db_client: &mut impl RouterDbClient, + control: &mut RouterControl<'_, impl RouterDbClient>, friend_public_key: PublicKey, relays_update: RelaysUpdate, -) -> Result { +) -> Result<(), RouterError> { todo!(); } async fn incoming_relays_ack( - router_db_client: &mut impl RouterDbClient, + control: &mut RouterControl<'_, impl RouterDbClient>, friend_public_key: PublicKey, generation: u128, -) -> Result { +) -> Result<(), RouterError> { todo!(); } pub async fn incoming_friend_message( - router_db_client: &mut RC, - router_state: &mut RouterState, + control: &mut RouterControl<'_, RC>, + info: &RouterInfo, friend_public_key: PublicKey, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, friend_message: FriendMessage, -) -> Result +) -> Result<(), RouterError> where RC: RouterDbClient, RC::TcDbClient: Transaction + Send, @@ -629,25 +563,16 @@ where { match friend_message { FriendMessage::MoveTokenRequest(move_token_request) => { - incoming_move_token_request( - router_db_client, - router_state, - friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - move_token_request, - ) - .await + incoming_move_token_request(control, info, friend_public_key, move_token_request).await } FriendMessage::InconsistencyError(reset_terms) => { - incoming_inconsistency_error(router_db_client, friend_public_key, reset_terms).await + incoming_inconsistency_error(control, friend_public_key, reset_terms).await } FriendMessage::RelaysUpdate(relays_update) => { - incoming_relays_update(router_db_client, friend_public_key, relays_update).await + incoming_relays_update(control, friend_public_key, relays_update).await } FriendMessage::RelaysAck(generation) => { - incoming_relays_ack(router_db_client, friend_public_key, generation).await + incoming_relays_ack(control, friend_public_key, generation).await } } } diff --git a/components/funder/src/router/handler.rs b/components/funder/src/router/handler.rs index f4cc09b81..b7470c93f 100644 --- a/components/funder/src/router/handler.rs +++ b/components/funder/src/router/handler.rs @@ -1,3 +1,7 @@ +use database::transaction::Transaction; + +use crate::token_channel::TcDbClient; + use crate::router::types::{RouterControl, RouterDbClient, RouterError, RouterInfo, RouterOp}; use crate::router::{handle_config, handle_friend, handle_liveness, handle_relays, handle_route}; @@ -8,10 +12,12 @@ pub async fn handle_router_op( ) -> Result<(), RouterError> where RC: RouterDbClient, + RC::TcDbClient: Transaction + Send, + ::McDbClient: Send, { match router_op { RouterOp::AddCurrency(friend_public_key, currency) => { - handle_config::add_currency(control, info, friend_public_key, currency).await? + handle_config::add_currency(control, info, friend_public_key, currency).await } RouterOp::RemoveCurrency(friend_public_key, currency) => todo!(), RouterOp::SetRemoteMaxDebt(friend_public_key, currency, remote_max_debt) => { @@ -22,7 +28,7 @@ where currency, remote_max_debt, ) - .await? + .await } RouterOp::SetLocalMaxDebt(friend_public_key, currency, local_max_debt) => { handle_config::set_local_max_debt( @@ -32,15 +38,18 @@ where currency, local_max_debt, ) - .await? + .await } RouterOp::OpenCurrency(friend_public_key, currency) => { - handle_config::open_currency(control, friend_public_key, currency).await? + handle_config::open_currency(control, friend_public_key, currency).await } RouterOp::CloseCurrency(friend_public_key, currency) => { - handle_config::close_currency(control, friend_public_key, currency).await? + handle_config::close_currency(control, friend_public_key, currency).await + } + RouterOp::FriendMessage(friend_public_key, friend_message) => { + handle_friend::incoming_friend_message(control, info, friend_public_key, friend_message) + .await } - RouterOp::FriendMessage(friend_public_key, friend_message) => todo!(), RouterOp::SetFriendOnline(friend_public_key) => todo!(), RouterOp::SetFriendOffline(friend_public_key) => todo!(), RouterOp::UpdateFriendLocalRelays(friend_public_key, friend_local_relays) => todo!(), @@ -48,6 +57,6 @@ where RouterOp::SendRequest(currency, mc_request) => todo!(), RouterOp::SendResponse(mc_response) => todo!(), RouterOp::SendCancel(mc_cancel) => todo!(), - } + }?; todo!(); } From b4c6e774dce3e60aa658b6c06cb483052cc2ddcb Mon Sep 17 00:00:00 2001 From: real Date: Thu, 11 Feb 2021 17:33:39 +0200 Subject: [PATCH 462/478] funder: router handler: connected handle_liveness --- .../funder/src/router/handle_liveness.rs | 90 ++++++++++--------- components/funder/src/router/handler.rs | 8 +- 2 files changed, 55 insertions(+), 43 deletions(-) diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index 602c615af..05194e037 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -24,7 +24,8 @@ use crypto::rand::{CryptoRandom, RandGen}; use crate::route::Route; use crate::router::types::{ - BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, + BackwardsOp, CurrencyInfo, RouterControl, RouterDbClient, RouterError, RouterInfo, + RouterOutput, RouterState, SentRelay, }; use crate::mutual_credit::McCancel; @@ -39,37 +40,35 @@ use crate::router::utils::move_token::{ }; pub async fn set_friend_online( - router_db_client: &mut impl RouterDbClient, - router_state: &mut RouterState, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, + control: &mut RouterControl<'_, impl RouterDbClient>, + info: &RouterInfo, friend_public_key: PublicKey, - max_operations_in_batch: usize, -) -> Result { +) -> Result<(), RouterError> { // First we make sure that the friend exists: - let mut output = RouterOutput::new(); - let tc_status = if let Some(tc_db_client) = router_db_client + let tc_status = if let Some(tc_db_client) = control + .router_db_client .tc_db_client(friend_public_key.clone()) .await? { tc_db_client.get_tc_status().await? } else { - return Ok(output); + return Ok(()); }; - if router_state.liveness.is_online(&friend_public_key) { + if control.state.liveness.is_online(&friend_public_key) { // The friend is already marked as online! return Err(RouterError::FriendAlreadyOnline); } - router_state.liveness.set_online(friend_public_key.clone()); + control.state.liveness.set_online(friend_public_key.clone()); // Check if we have any relays information to send to the remote side: - if let (Some(generation), relays) = router_db_client + if let (Some(generation), relays) = control + .router_db_client .get_last_sent_relays(friend_public_key.clone()) .await? { // Add a message for sending relays: - output.add_friend_message( + control.output.add_friend_message( friend_public_key.clone(), FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), ); @@ -79,12 +78,12 @@ pub async fn set_friend_online( TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. let opt_tuple = handle_out_move_token_index_mutations_disallow_empty( - router_db_client, - identity_client, - local_public_key, + control.router_db_client, + control.identity_client, + &info.local_public_key, friend_public_key.clone(), - max_operations_in_batch, - &mut output, + info.max_operations_in_batch, + &mut control.output, ) .await?; @@ -93,7 +92,7 @@ pub async fn set_friend_online( // open currencies anyways. // We have something to send to remote side: - output.add_friend_message( + control.output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(move_token_request), ); @@ -102,12 +101,12 @@ pub async fn set_friend_online( TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { // Resend outgoing move token, // possibly asking for the token if we have something to send - output.add_friend_message( + control.output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(MoveTokenRequest { move_token: move_token_out, token_wanted: is_pending_move_token( - router_db_client, + control.router_db_client, friend_public_key.clone(), ) .await?, @@ -116,7 +115,7 @@ pub async fn set_friend_online( } TcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { // Resend reset terms - output.add_friend_message( + control.output.add_friend_message( friend_public_key.clone(), FriendMessage::InconsistencyError(local_reset_terms), ); @@ -124,7 +123,9 @@ pub async fn set_friend_online( } // Add an index mutation for all open currencies: - let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); + let mut open_currencies = control + .router_db_client + .list_open_currencies(friend_public_key.clone()); while let Some(res) = open_currencies.next().await { let (open_currency, open_currency_info) = res?; @@ -133,45 +134,47 @@ pub async fn set_friend_online( // We only add currencies with non zero send/recv capacity if matches!(IndexMutation::UpdateFriendCurrency, index_mutation) { - output.add_index_mutation(index_mutation); + control.output.add_index_mutation(index_mutation); } } - Ok(output) + Ok(()) } pub async fn set_friend_offline( - router_db_client: &mut impl RouterDbClient, - router_state: &mut RouterState, + control: &mut RouterControl<'_, impl RouterDbClient>, friend_public_key: PublicKey, -) -> Result { +) -> Result<(), RouterError> { // First we make sure that the friend exists: let mut output = RouterOutput::new(); - if router_db_client + if control + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .is_none() { - return Ok(output); + return Ok(()); } - if !router_state.liveness.is_online(&friend_public_key) { + if !control.state.liveness.is_online(&friend_public_key) { // The friend is already marked as offline! return Err(RouterError::FriendAlreadyOffline); } - router_state.liveness.set_offline(&friend_public_key); + control.state.liveness.set_offline(&friend_public_key); // Cancel all pending user requests - while let Some((currency, pending_user_request)) = router_db_client + while let Some((currency, pending_user_request)) = control + .router_db_client .pending_user_requests_pop_front(friend_public_key.clone()) .await? { // Clear the request from local requests list - router_db_client + control + .router_db_client .remove_local_request(pending_user_request.request_id.clone()) .await?; // Send outgoing cancel to user: - output.add_incoming_cancel( + control.output.add_incoming_cancel( currency, McCancel { request_id: pending_user_request.request_id, @@ -180,14 +183,16 @@ pub async fn set_friend_offline( } // Cancel all pending requests - while let Some((currency, pending_request)) = router_db_client + while let Some((currency, pending_request)) = control + .router_db_client .pending_requests_pop_front(friend_public_key.clone()) .await? { // Find from which friend this pending request has originated from. // Due to inconsistencies, it is possible that this pending request has no origin (An // orphan request) - let opt_request_origin = router_db_client + let opt_request_origin = control + .router_db_client .get_remote_pending_request_origin(pending_request.request_id.clone()) .await?; @@ -198,7 +203,8 @@ pub async fn set_friend_offline( } // Cancel request by queue-ing a cancel into the relevant friend's queue: - router_db_client + control + .router_db_client .pending_backwards_push_back( request_origin.friend_public_key, BackwardsOp::Cancel( @@ -214,7 +220,9 @@ pub async fn set_friend_offline( // Add index mutations // We send index mutations to remove all currencies that are considered open - let mut open_currencies = router_db_client.list_open_currencies(friend_public_key.clone()); + let mut open_currencies = control + .router_db_client + .list_open_currencies(friend_public_key.clone()); while let Some(res) = open_currencies.next().await { let (open_currency, _open_currency_info) = res?; output.add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { @@ -223,5 +231,5 @@ pub async fn set_friend_offline( })); } - Ok(output) + Ok(()) } diff --git a/components/funder/src/router/handler.rs b/components/funder/src/router/handler.rs index b7470c93f..1d572cdca 100644 --- a/components/funder/src/router/handler.rs +++ b/components/funder/src/router/handler.rs @@ -50,8 +50,12 @@ where handle_friend::incoming_friend_message(control, info, friend_public_key, friend_message) .await } - RouterOp::SetFriendOnline(friend_public_key) => todo!(), - RouterOp::SetFriendOffline(friend_public_key) => todo!(), + RouterOp::SetFriendOnline(friend_public_key) => { + handle_liveness::set_friend_online(control, info, friend_public_key).await + } + RouterOp::SetFriendOffline(friend_public_key) => { + handle_liveness::set_friend_offline(control, friend_public_key).await + } RouterOp::UpdateFriendLocalRelays(friend_public_key, friend_local_relays) => todo!(), RouterOp::UpdateLocalRelays(local_relays) => todo!(), RouterOp::SendRequest(currency, mc_request) => todo!(), From 45ade458d840bc13549b4ce39b6d1b3793c778ec Mon Sep 17 00:00:00 2001 From: real Date: Fri, 12 Feb 2021 12:57:16 +0200 Subject: [PATCH 463/478] funder: Changed RouterControl to be a trait --- components/funder/src/router/handle_config.rs | 75 ++++---- components/funder/src/router/handle_friend.rs | 164 ++++++++++-------- .../funder/src/router/handle_liveness.rs | 59 ++++--- components/funder/src/router/handler.rs | 15 +- components/funder/src/router/mod.rs | 4 +- components/funder/src/router/types.rs | 82 ++++++++- 6 files changed, 251 insertions(+), 148 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index b0767876a..e12692bd9 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -35,13 +35,14 @@ use crate::token_channel::{ }; pub async fn add_currency( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, ) -> Result<(), RouterError> { + let access = control.access(); // First we make sure that the friend exists: - if control + if access .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -49,26 +50,27 @@ pub async fn add_currency( { return Ok(()); } - control + access .router_db_client .add_currency_config(friend_public_key.clone(), currency) .await?; - control.pending_send.insert(friend_public_key); + access.pending_send.insert(friend_public_key); Ok(()) } pub async fn set_remove_currency( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, ) -> Result<(), RouterError> { + let access = control.access(); // Revise implementation with respect to new design todo!(); // First we make sure that the friend exists: - if control + if access .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -76,26 +78,27 @@ pub async fn set_remove_currency( { return Ok(()); } - control + access .router_db_client .set_currency_remove(friend_public_key.clone(), currency) .await?; - control.pending_send.insert(friend_public_key); + access.pending_send.insert(friend_public_key); Ok(()) } pub async fn unset_remove_currency( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, ) -> Result<(), RouterError> { + let access = control.access(); // TODO: Update implementation according to new design todo!(); // First we make sure that the friend exists: - if control + if access .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -103,24 +106,25 @@ pub async fn unset_remove_currency( { return Ok(()); } - control + access .router_db_client .unset_currency_remove(friend_public_key.clone(), currency) .await?; - control.pending_send.insert(friend_public_key); + access.pending_send.insert(friend_public_key); Ok(()) } pub async fn set_remote_max_debt( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, remote_max_debt: u128, ) -> Result<(), RouterError> { + let access = control.access(); // First we make sure that the friend exists: - if control + if access .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -129,14 +133,14 @@ pub async fn set_remote_max_debt( return Ok(()); } - let opt_currency_info = control + let opt_currency_info = access .router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) .await?; if let Some(currency_info) = opt_currency_info { // Currency exists (We don't do anything otherwise) // Set remote max debt: - control + access .router_db_client .set_remote_max_debt(friend_public_key.clone(), currency.clone(), remote_max_debt) .await?; @@ -150,7 +154,7 @@ pub async fn set_remote_max_debt( // Create an index mutation if needed: if currency_info.is_open { // Currency is open: - control.output.add_index_mutation(create_index_mutation( + access.output.add_index_mutation(create_index_mutation( friend_public_key.clone(), currency, currency_info, @@ -162,14 +166,15 @@ pub async fn set_remote_max_debt( } pub async fn set_local_max_debt( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, local_max_debt: u128, ) -> Result<(), RouterError> { + let access = control.access(); // First we make sure that the friend exists: - if control + if access .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -178,14 +183,14 @@ pub async fn set_local_max_debt( return Ok(()); } - let opt_currency_info = control + let opt_currency_info = access .router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) .await?; if let Some(currency_info) = opt_currency_info { // Currency exists (We don't do anything otherwise) // Set remote max debt: - control + access .router_db_client .set_local_max_debt(friend_public_key.clone(), currency.clone(), local_max_debt) .await?; @@ -199,7 +204,7 @@ pub async fn set_local_max_debt( // Create an index mutation if needed: if currency_info.is_open { // Currency is open: - control.output.add_index_mutation(create_index_mutation( + access.output.add_index_mutation(create_index_mutation( friend_public_key.clone(), currency, currency_info, @@ -211,12 +216,13 @@ pub async fn set_local_max_debt( } pub async fn open_currency( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, friend_public_key: PublicKey, currency: Currency, ) -> Result<(), RouterError> { + let access = control.access(); // First we make sure that the friend exists: - if control + if access .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -225,7 +231,7 @@ pub async fn open_currency( return Ok(()); } - let opt_currency_info = control + let opt_currency_info = access .router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) .await?; @@ -236,7 +242,7 @@ pub async fn open_currency( // currency is closed: // Open currency: - control + access .router_db_client .open_currency(friend_public_key.clone(), currency.clone()) .await?; @@ -244,7 +250,7 @@ pub async fn open_currency( let index_mutation = create_index_mutation(friend_public_key, currency, currency_info)?; if matches!(index_mutation, IndexMutation::UpdateFriendCurrency(..)) { // Add index mutation: - control.output.add_index_mutation(index_mutation); + access.output.add_index_mutation(index_mutation); } } } @@ -253,12 +259,13 @@ pub async fn open_currency( } pub async fn close_currency( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, friend_public_key: PublicKey, currency: Currency, ) -> Result<(), RouterError> { + let access = control.access(); // First we make sure that the friend exists: - if control + if access .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -267,7 +274,7 @@ pub async fn close_currency( return Ok(()); } - let opt_currency_info = control + let opt_currency_info = access .router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) .await?; @@ -278,13 +285,13 @@ pub async fn close_currency( // currency is open: // Close currency: - control + access .router_db_client .close_currency(friend_public_key.clone(), currency.clone()) .await?; // Add index mutation: - control + access .output .add_index_mutation(IndexMutation::RemoveFriendCurrency(RemoveFriendCurrency { public_key: friend_public_key.clone(), @@ -292,7 +299,7 @@ pub async fn close_currency( })); // Cancel all user requests pending for this currency: - while let Some(mc_request) = control + while let Some(mc_request) = access .router_db_client .pending_user_requests_pop_front_by_currency(friend_public_key.clone()) .await? @@ -301,7 +308,7 @@ pub async fn close_currency( } // Cancel all requests pending for this currency: - while let Some(mc_request) = control + while let Some(mc_request) = access .router_db_client .pending_user_requests_pop_front_by_currency(friend_public_key.clone()) .await? diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index bf1077e06..235e5b2ba 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -42,18 +42,24 @@ use crate::token_channel::{ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenCh /// Check if credit line between this node and a friend is ready /// Works for sending requests in both directions async fn is_credit_line_ready( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, friend_public_key: PublicKey, currency: Currency, request_id: Uid, ) -> Result { // Friend must be online: - if !control.state.liveness.is_online(&friend_public_key) { + if !control + .access() + .ephemeral + .liveness + .is_online(&friend_public_key) + { return Ok(false); } // Currency must exist: let currency_info = if let Some(currency_info) = control + .access() .router_db_client .get_currency_info(friend_public_key, currency) .await? @@ -66,21 +72,19 @@ async fn is_credit_line_ready( // Note: We bypass `is_open` check if the request is of local origin: Ok(currency_info.is_open || control + .access() .router_db_client .is_request_local_origin(request_id) .await?) } -async fn incoming_message_request( - control: &mut RouterControl<'_, RC>, +async fn incoming_message_request( + control: &mut impl RouterControl, info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, mut mc_request: McRequest, -) -> Result<(), RouterError> -where - RC: RouterDbClient, -{ +) -> Result<(), RouterError> { // Make sure that we are ready to receive this request operation // We might not be ready in the case of currency being closed. if !is_credit_line_ready( @@ -93,6 +97,7 @@ where { // Return a cancel message and flush origin friend control + .access() .router_db_client .pending_backwards_push_back( friend_public_key.clone(), @@ -105,7 +110,7 @@ where ) .await?; - control.pending_send.insert(friend_public_key); + control.access().pending_send.insert(friend_public_key); return Ok(()); } @@ -114,6 +119,7 @@ where if mc_request.route.is_empty() { // Directed to us. Punt: control + .access() .output .add_incoming_request(currency.clone(), mc_request.into()); return Ok(()); @@ -125,15 +131,18 @@ where // Route is not empty. We need to forward the request to a friend let next_public_key = mc_request.route.remove(0); - // Check if next public key corresponds to a friend that is ready - let should_forward = is_credit_line_ready( + let is_credit_line_ready = is_credit_line_ready( control, next_public_key.clone(), currency.clone(), mc_request.request_id.clone(), ) - .await? + .await?; + + // Check if next public key corresponds to a friend that is ready + let should_forward = is_credit_line_ready && !control + .access() .router_db_client .is_local_request_exists(mc_request.request_id.clone()) .await?; @@ -145,16 +154,18 @@ where if should_forward { // Queue request to friend and flush destination friend control + .access() .router_db_client .pending_requests_push_back(next_public_key.clone(), currency, mc_request.into()) .await?; // TODO: flush_friend() is delicate. We might be able to aggregate some more pending // requests before flushing this friend. Find out how to do this. - control.pending_send.insert(next_public_key); + control.access().pending_send.insert(next_public_key); } else { // Return a cancel message and flush origin friend control + .access() .router_db_client .pending_backwards_push_back( friend_public_key.clone(), @@ -167,7 +178,7 @@ where ) .await?; - control.pending_send.insert(friend_public_key); + control.access().pending_send.insert(friend_public_key); } Ok(()) @@ -175,16 +186,14 @@ where /// An incoming request was received, but due to insufficient trust we can not /// forward this request. We return a cancel message to the sender friend -async fn incoming_message_request_cancel( - control: &mut RouterControl<'_, RC>, +async fn incoming_message_request_cancel( + control: &mut impl RouterControl, friend_public_key: PublicKey, currency: Currency, mc_request: McRequest, -) -> Result<(), RouterError> -where - RC: RouterDbClient, -{ +) -> Result<(), RouterError> { if control + .access() .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -202,6 +211,7 @@ where // Queue cancel to friend_public_key (Request origin) control + .access() .router_db_client .pending_backwards_push_back(friend_public_key.clone(), backwards_op) .await?; @@ -213,22 +223,21 @@ where Ok(()) } -async fn incoming_message_response( - control: &mut RouterControl<'_, RC>, +async fn incoming_message_response( + control: &mut impl RouterControl, info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, incoming_response: IncomingResponseSendFundsOp, -) -> Result<(), RouterError> -where - RC: RouterDbClient, -{ +) -> Result<(), RouterError> { // Gather information about request's origin: let opt_request_origin = control + .access() .router_db_client .get_remote_pending_request_origin(incoming_response.incoming_response.request_id.clone()) .await?; let is_local_origin = control + .access() .router_db_client .is_request_local_origin(incoming_response.incoming_response.request_id.clone()) .await?; @@ -243,12 +252,14 @@ where // Clear the request from local requests list control + .access() .router_db_client .remove_local_request(incoming_response.incoming_response.request_id.clone()) .await?; // We punt the response control + .access() .output .add_incoming_response(currency.clone(), incoming_response.incoming_response); } @@ -259,6 +270,7 @@ where // Push response: control + .access() .router_db_client .pending_backwards_push_back( friend_public_key.clone(), @@ -266,7 +278,7 @@ where ) .await?; - control.pending_send.insert(friend_public_key); + control.access().pending_send.insert(friend_public_key); } (true, Some(request_origin)) => { // This means the request has both originated locally, and from a friend. @@ -281,7 +293,7 @@ where // TODO: This function seems too similar to `incoming_message_response` async fn incoming_message_cancel( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, info: &RouterInfo, friend_public_key: PublicKey, currency: Currency, @@ -289,10 +301,12 @@ async fn incoming_message_cancel( ) -> Result<(), RouterError> { // Gather information about request's origin: let opt_request_origin = control + .access() .router_db_client .get_remote_pending_request_origin(incoming_cancel.incoming_cancel.request_id.clone()) .await?; let is_local_origin = control + .access() .router_db_client .is_request_local_origin(incoming_cancel.incoming_cancel.request_id.clone()) .await?; @@ -307,12 +321,14 @@ async fn incoming_message_cancel( // Clear the request from local requests list control + .access() .router_db_client .remove_local_request(incoming_cancel.incoming_cancel.request_id.clone()) .await?; // We punt the cancel control + .access() .output .add_incoming_cancel(currency, incoming_cancel.incoming_cancel); } @@ -323,6 +339,7 @@ async fn incoming_message_cancel( // Push cancel: control + .access() .router_db_client .pending_backwards_push_back( friend_public_key.clone(), @@ -330,7 +347,10 @@ async fn incoming_message_cancel( ) .await?; - control.pending_send.insert(friend_public_key.clone()); + control + .access() + .pending_send + .insert(friend_public_key.clone()); } (true, Some(request_origin)) => { // This means the request has both originated locally, and from a friend. @@ -343,21 +363,16 @@ async fn incoming_message_cancel( Ok(()) } -async fn incoming_move_token_request( - control: &mut RouterControl<'_, RC>, +async fn incoming_move_token_request( + control: &mut impl RouterControl, info: &RouterInfo, friend_public_key: PublicKey, in_move_token_request: MoveTokenRequest, -) -> Result<(), RouterError> -where - RC: RouterDbClient, - // TODO: Maybe not necessary: - RC::TcDbClient: Transaction + Send, - ::McDbClient: Send, -{ +) -> Result<(), RouterError> { + let access = control.access(); let (receive_move_token_output, index_mutations) = handle_in_move_token_index_mutations( - control.router_db_client, - control.identity_client, + access.router_db_client, + access.identity_client, in_move_token_request.move_token, &info.local_public_key, friend_public_key.clone(), @@ -366,38 +381,39 @@ where // Add mutations: for index_mutation in index_mutations { - control.output.add_index_mutation(index_mutation); + control.access().output.add_index_mutation(index_mutation); } match receive_move_token_output { ReceiveMoveTokenOutput::Duplicate => { + let mut access = control.access(); // We should have nothing else to send at this point, otherwise we would have already // sent it. assert!( - !is_pending_move_token(control.router_db_client, friend_public_key.clone()).await? + !is_pending_move_token(access.router_db_client, friend_public_key.clone()).await? ); // Possibly send token to remote side (According to token_wanted) if in_move_token_request.token_wanted { let (out_move_token_request, index_mutations) = handle_out_move_token_index_mutations_allow_empty( - control.router_db_client, - control.identity_client, + access.router_db_client, + access.identity_client, &info.local_public_key, friend_public_key.clone(), info.max_operations_in_batch, - &mut control.output, + &mut access.output, ) .await?; // We just got a message from remote side. Remote side should be online: - assert!(control.state.liveness.is_online(&friend_public_key)); + assert!(access.ephemeral.liveness.is_online(&friend_public_key)); // Add index mutations: for index_mutation in index_mutations { - control.output.add_index_mutation(index_mutation); + access.output.add_index_mutation(index_mutation); } - control.output.add_friend_message( + access.output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(out_move_token_request), ); @@ -408,14 +424,19 @@ where let move_token_request = MoveTokenRequest { move_token, token_wanted: is_pending_move_token( - control.router_db_client, + control.access().router_db_client, friend_public_key.clone(), ) .await?, }; - if control.state.liveness.is_online(&friend_public_key) { - control.output.add_friend_message( + if control + .access() + .ephemeral + .liveness + .is_online(&friend_public_key) + { + control.access().output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(move_token_request), ); @@ -470,39 +491,45 @@ where let opt_res = if in_move_token_request.token_wanted { // Remote side wants to have the token back, so we have to send a MoveTokenRequest // to remote side, even if it is empty + let mut access = control.access(); Some( handle_out_move_token_index_mutations_allow_empty( - control.router_db_client, - control.identity_client, + access.router_db_client, + access.identity_client, &info.local_public_key, friend_public_key.clone(), info.max_operations_in_batch, - &mut control.output, + &mut access.output, ) .await?, ) } else { // We only send a MoveTokenRequest to remote side if we have something to send: + let mut access = control.access(); handle_out_move_token_index_mutations_disallow_empty( - control.router_db_client, - control.identity_client, + access.router_db_client, + access.identity_client, &info.local_public_key, friend_public_key.clone(), info.max_operations_in_batch, - &mut control.output, + &mut access.output, ) .await? }; if let Some((out_move_token_request, index_mutations)) = opt_res { // We just got a message from remote side. Remote side should be online: - assert!(control.state.liveness.is_online(&friend_public_key)); + assert!(control + .access() + .ephemeral + .liveness + .is_online(&friend_public_key)); // Add index mutations: for index_mutation in index_mutations { - control.output.add_index_mutation(index_mutation); + control.access().output.add_index_mutation(index_mutation); } - control.output.add_friend_message( + control.access().output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(out_move_token_request), ); @@ -527,7 +554,7 @@ where } async fn incoming_inconsistency_error( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, friend_public_key: PublicKey, reset_terms: ResetTerms, ) -> Result<(), RouterError> { @@ -535,7 +562,7 @@ async fn incoming_inconsistency_error( } async fn incoming_relays_update( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, friend_public_key: PublicKey, relays_update: RelaysUpdate, ) -> Result<(), RouterError> { @@ -543,24 +570,19 @@ async fn incoming_relays_update( } async fn incoming_relays_ack( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, friend_public_key: PublicKey, generation: u128, ) -> Result<(), RouterError> { todo!(); } -pub async fn incoming_friend_message( - control: &mut RouterControl<'_, RC>, +pub async fn incoming_friend_message( + control: &mut impl RouterControl, info: &RouterInfo, friend_public_key: PublicKey, friend_message: FriendMessage, -) -> Result<(), RouterError> -where - RC: RouterDbClient, - RC::TcDbClient: Transaction + Send, - ::McDbClient: Send, -{ +) -> Result<(), RouterError> { match friend_message { FriendMessage::MoveTokenRequest(move_token_request) => { incoming_move_token_request(control, info, friend_public_key, move_token_request).await diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index 05194e037..84441f61b 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -40,12 +40,14 @@ use crate::router::utils::move_token::{ }; pub async fn set_friend_online( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, info: &RouterInfo, friend_public_key: PublicKey, ) -> Result<(), RouterError> { + let mut access = control.access(); + // First we make sure that the friend exists: - let tc_status = if let Some(tc_db_client) = control + let tc_status = if let Some(tc_db_client) = access .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -55,20 +57,23 @@ pub async fn set_friend_online( return Ok(()); }; - if control.state.liveness.is_online(&friend_public_key) { + if access.ephemeral.liveness.is_online(&friend_public_key) { // The friend is already marked as online! return Err(RouterError::FriendAlreadyOnline); } - control.state.liveness.set_online(friend_public_key.clone()); + access + .ephemeral + .liveness + .set_online(friend_public_key.clone()); // Check if we have any relays information to send to the remote side: - if let (Some(generation), relays) = control + if let (Some(generation), relays) = access .router_db_client .get_last_sent_relays(friend_public_key.clone()) .await? { // Add a message for sending relays: - control.output.add_friend_message( + access.output.add_friend_message( friend_public_key.clone(), FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), ); @@ -78,12 +83,12 @@ pub async fn set_friend_online( TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. let opt_tuple = handle_out_move_token_index_mutations_disallow_empty( - control.router_db_client, - control.identity_client, + access.router_db_client, + access.identity_client, &info.local_public_key, friend_public_key.clone(), info.max_operations_in_batch, - &mut control.output, + &mut access.output, ) .await?; @@ -92,7 +97,7 @@ pub async fn set_friend_online( // open currencies anyways. // We have something to send to remote side: - control.output.add_friend_message( + access.output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(move_token_request), ); @@ -101,12 +106,12 @@ pub async fn set_friend_online( TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { // Resend outgoing move token, // possibly asking for the token if we have something to send - control.output.add_friend_message( + access.output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(MoveTokenRequest { move_token: move_token_out, token_wanted: is_pending_move_token( - control.router_db_client, + access.router_db_client, friend_public_key.clone(), ) .await?, @@ -115,7 +120,7 @@ pub async fn set_friend_online( } TcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { // Resend reset terms - control.output.add_friend_message( + access.output.add_friend_message( friend_public_key.clone(), FriendMessage::InconsistencyError(local_reset_terms), ); @@ -123,7 +128,7 @@ pub async fn set_friend_online( } // Add an index mutation for all open currencies: - let mut open_currencies = control + let mut open_currencies = access .router_db_client .list_open_currencies(friend_public_key.clone()); while let Some(res) = open_currencies.next().await { @@ -134,7 +139,7 @@ pub async fn set_friend_online( // We only add currencies with non zero send/recv capacity if matches!(IndexMutation::UpdateFriendCurrency, index_mutation) { - control.output.add_index_mutation(index_mutation); + access.output.add_index_mutation(index_mutation); } } @@ -142,12 +147,14 @@ pub async fn set_friend_online( } pub async fn set_friend_offline( - control: &mut RouterControl<'_, impl RouterDbClient>, + control: &mut impl RouterControl, friend_public_key: PublicKey, ) -> Result<(), RouterError> { + let access = control.access(); + // First we make sure that the friend exists: let mut output = RouterOutput::new(); - if control + if access .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -156,25 +163,25 @@ pub async fn set_friend_offline( return Ok(()); } - if !control.state.liveness.is_online(&friend_public_key) { + if !access.ephemeral.liveness.is_online(&friend_public_key) { // The friend is already marked as offline! return Err(RouterError::FriendAlreadyOffline); } - control.state.liveness.set_offline(&friend_public_key); + access.ephemeral.liveness.set_offline(&friend_public_key); // Cancel all pending user requests - while let Some((currency, pending_user_request)) = control + while let Some((currency, pending_user_request)) = access .router_db_client .pending_user_requests_pop_front(friend_public_key.clone()) .await? { // Clear the request from local requests list - control + access .router_db_client .remove_local_request(pending_user_request.request_id.clone()) .await?; // Send outgoing cancel to user: - control.output.add_incoming_cancel( + access.output.add_incoming_cancel( currency, McCancel { request_id: pending_user_request.request_id, @@ -183,7 +190,7 @@ pub async fn set_friend_offline( } // Cancel all pending requests - while let Some((currency, pending_request)) = control + while let Some((currency, pending_request)) = access .router_db_client .pending_requests_pop_front(friend_public_key.clone()) .await? @@ -191,7 +198,7 @@ pub async fn set_friend_offline( // Find from which friend this pending request has originated from. // Due to inconsistencies, it is possible that this pending request has no origin (An // orphan request) - let opt_request_origin = control + let opt_request_origin = access .router_db_client .get_remote_pending_request_origin(pending_request.request_id.clone()) .await?; @@ -203,7 +210,7 @@ pub async fn set_friend_offline( } // Cancel request by queue-ing a cancel into the relevant friend's queue: - control + access .router_db_client .pending_backwards_push_back( request_origin.friend_public_key, @@ -220,7 +227,7 @@ pub async fn set_friend_offline( // Add index mutations // We send index mutations to remove all currencies that are considered open - let mut open_currencies = control + let mut open_currencies = access .router_db_client .list_open_currencies(friend_public_key.clone()); while let Some(res) = open_currencies.next().await { diff --git a/components/funder/src/router/handler.rs b/components/funder/src/router/handler.rs index 1d572cdca..13382c0d2 100644 --- a/components/funder/src/router/handler.rs +++ b/components/funder/src/router/handler.rs @@ -3,18 +3,14 @@ use database::transaction::Transaction; use crate::token_channel::TcDbClient; use crate::router::types::{RouterControl, RouterDbClient, RouterError, RouterInfo, RouterOp}; -use crate::router::{handle_config, handle_friend, handle_liveness, handle_relays, handle_route}; +// use crate::router::{handle_config, handle_friend, handle_liveness, handle_relays, handle_route}; -pub async fn handle_router_op( - control: &mut RouterControl<'_, RC>, +pub async fn handle_router_op( + control: &mut impl RouterControl, info: &RouterInfo, router_op: RouterOp, -) -> Result<(), RouterError> -where - RC: RouterDbClient, - RC::TcDbClient: Transaction + Send, - ::McDbClient: Send, -{ +) -> Result<(), RouterError> { + /* match router_op { RouterOp::AddCurrency(friend_public_key, currency) => { handle_config::add_currency(control, info, friend_public_key, currency).await @@ -62,5 +58,6 @@ where RouterOp::SendResponse(mc_response) => todo!(), RouterOp::SendCancel(mc_cancel) => todo!(), }?; + */ todo!(); } diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 48dad6a71..cf4df06cb 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -3,8 +3,8 @@ mod utils; mod handle_config; mod handle_friend; mod handle_liveness; -mod handle_relays; -mod handle_route; +// mod handle_relays; +// mod handle_route; mod handler; diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index ee77a4872..ae52b105d 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -5,11 +5,11 @@ use derive_more::From; use common::async_rpc::{AsyncOpResult, AsyncOpStream, OpError}; use common::u256::U256; -use crate::liveness::Liveness; -use crate::token_channel::TcDbClient; - +use crypto::rand::CryptoRandom; use identity::IdentityClient; +use database::transaction::Transaction; + use proto::app_server::messages::{NamedRelayAddress, RelayAddressPort}; use proto::crypto::{PublicKey, Uid}; use proto::funder::messages::{ @@ -19,7 +19,9 @@ use proto::funder::messages::{ use proto::index_server::messages::IndexMutation; use proto::net::messages::NetAddress; -use crate::mutual_credit::{McCancel, McRequest, McResponse}; +use crate::liveness::Liveness; +use crate::mutual_credit::{McCancel, McDbClient, McRequest, McResponse}; +use crate::token_channel::TcDbClient; use crate::token_channel::TokenChannelError; #[derive(Debug, From)] @@ -388,17 +390,85 @@ pub struct RouterInfo { } #[derive(Debug)] -pub struct RouterControl<'a, RC> { +pub struct RouterHandle<'a, R, RC> { pub router_db_client: &'a mut RC, pub identity_client: &'a mut IdentityClient, + pub rng: &'a mut R, /// Friends with new pending outgoing messages pub pending_send: HashSet, /// Ephemeral state: - pub state: &'a mut RouterState, + pub ephemeral: &'a mut RouterState, /// Router's output: pub output: RouterOutput, } +#[derive(Debug)] +pub struct RouterAccess<'a, R, RC> { + pub router_db_client: &'a mut RC, + pub identity_client: &'a mut IdentityClient, + pub rng: &'a mut R, + /// Friends with new pending outgoing messages + pub pending_send: &'a mut HashSet, + /// Ephemeral state: + pub ephemeral: &'a mut RouterState, + /// Router's output: + pub output: &'a mut RouterOutput, +} + +pub trait RouterControl { + type Rng: CryptoRandom; + type RouterDbClient: RouterDbClient; + type TcDbClient: TcDbClient + Transaction + Send; + type McDbClient: McDbClient + Send; + + fn access(&mut self) -> RouterAccess<'_, Self::Rng, Self::RouterDbClient>; +} + +impl<'a, R, RC> RouterControl for RouterHandle<'a, R, RC> +where + RC: RouterDbClient, + ::TcDbClient: Transaction + Send, + <::TcDbClient as TcDbClient>::McDbClient: Send, + R: CryptoRandom, +{ + type Rng = R; + type RouterDbClient = RC; + type TcDbClient = ::TcDbClient; + type McDbClient = <::TcDbClient as TcDbClient>::McDbClient; + + fn access(&mut self) -> RouterAccess<'_, Self::Rng, Self::RouterDbClient> { + RouterAccess { + router_db_client: self.router_db_client, + identity_client: self.identity_client, + rng: self.rng, + pending_send: &mut self.pending_send, + ephemeral: self.ephemeral, + output: &mut self.output, + } + } + + /* + fn router_db_client(&mut self) -> &mut Self::RouterDbClient { + self.router_db_client + } + fn identity_client(&mut self) -> &mut IdentityClient { + self.identity_client + } + fn rng(&mut self) -> &mut Self::Rng { + self.rng + } + fn add_pending_send(&mut self, friend_public_key: PublicKey) -> bool { + self.pending_send.insert(friend_public_key) + } + fn ephemeral(&mut self) -> &mut RouterState { + &mut self.state + } + fn output(&mut self) -> &mut RouterOutput { + &mut self.output + } + */ +} + #[derive(Debug)] pub enum RouterOp { // Config From 63e76049369e68c16fd374c76f7f6098446be9ac Mon Sep 17 00:00:00 2001 From: real Date: Fri, 12 Feb 2021 13:15:41 +0200 Subject: [PATCH 464/478] funder: Converted router to new RouterControl trait design --- components/funder/src/router/handle_relays.rs | 44 +++--- components/funder/src/router/handle_route.rs | 138 ++++++++---------- components/funder/src/router/mod.rs | 4 +- 3 files changed, 87 insertions(+), 99 deletions(-) diff --git a/components/funder/src/router/handle_relays.rs b/components/funder/src/router/handle_relays.rs index 3eb14ffc5..7eaf0e944 100644 --- a/components/funder/src/router/handle_relays.rs +++ b/components/funder/src/router/handle_relays.rs @@ -24,7 +24,7 @@ use crypto::rand::{CryptoRandom, RandGen}; use crate::route::Route; use crate::router::types::{ - BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, + BackwardsOp, CurrencyInfo, RouterControl, RouterDbClient, RouterError, RouterState, SentRelay, }; use crate::mutual_credit::incoming::IncomingMessage; @@ -54,18 +54,21 @@ fn max_generation(sent_relays: &[SentRelay]) -> Option { /// Returns whether friend's relays were updated async fn update_friend_local_relays( - router_db_client: &mut impl RouterDbClient, + control: &mut impl RouterControl, local_relays: HashMap, friend_public_key: PublicKey, - rng: &mut impl CryptoRandom, ) -> Result)>, RouterError> { // First we make sure that the friend exists: - let _ = router_db_client + let _ = control + .access() + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .ok_or(RouterError::InvalidState)?; - let sent_relays = router_db_client + let sent_relays = control + .access() + .router_db_client .get_sent_relays(friend_public_key.clone()) .await?; @@ -106,7 +109,7 @@ async fn update_friend_local_relays( public_key: relay_public_key, address, // Randomly generate a new port: - port: NodePort::rand_gen(rng), + port: NodePort::rand_gen(control.access().rng), }; new_sent_relays.push(SentRelay { relay_address, @@ -118,7 +121,9 @@ async fn update_friend_local_relays( Ok(if sent_relays_updated { // Update sent relays: - router_db_client + control + .access() + .router_db_client .set_sent_relays(friend_public_key.clone(), new_sent_relays.clone()) .await?; Some(( @@ -134,27 +139,22 @@ async fn update_friend_local_relays( } pub async fn update_local_relays( - router_db_client: &mut impl RouterDbClient, + control: &mut impl RouterControl, router_state: &RouterState, local_relays: HashMap, - rng: &mut impl CryptoRandom, -) -> Result { - let mut output = RouterOutput::new(); - +) -> Result<(), RouterError> { let mut opt_friend_public_key = None; - while let Some(friend_public_key) = router_db_client + while let Some(friend_public_key) = control + .access() + .router_db_client .get_next_friend(opt_friend_public_key) .await? { opt_friend_public_key = Some(friend_public_key.clone()); - let opt_res = update_friend_local_relays( - router_db_client, - local_relays.clone(), - friend_public_key.clone(), - rng, - ) - .await?; + let opt_res = + update_friend_local_relays(control, local_relays.clone(), friend_public_key.clone()) + .await?; // If sent_relays was updated and the friend is ready, we need to send relays to // remote friend: @@ -162,7 +162,7 @@ pub async fn update_local_relays( // Make sure that remote friend is online: if router_state.liveness.is_online(&friend_public_key) { // Add a message for sending relays: - output.add_friend_message( + control.access().output.add_friend_message( friend_public_key.clone(), FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), ); @@ -170,5 +170,5 @@ pub async fn update_local_relays( } } - Ok(output) + Ok(()) } diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index 5814e8f4c..d729f5902 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -24,7 +24,8 @@ use crypto::rand::{CryptoRandom, RandGen}; use crate::route::Route; use crate::router::types::{ - BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, + BackwardsOp, CurrencyInfo, RouterControl, RouterDbClient, RouterError, RouterInfo, + RouterOutput, RouterState, SentRelay, }; use crate::router::utils::flush::flush_friend; use crate::router::utils::move_token::is_pending_move_token; @@ -36,45 +37,44 @@ use crate::token_channel::{ }; pub async fn send_request( - router_db_client: &mut impl RouterDbClient, - router_state: &RouterState, + control: &mut impl RouterControl, + info: &RouterInfo, currency: Currency, mut request: McRequest, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, -) -> Result { +) -> Result<(), RouterError> { // Make sure that the provided route is valid: if !request.route.is_valid() { return Err(RouterError::InvalidRoute); } - let mut output = RouterOutput::new(); - - if router_db_client + if control + .access() + .router_db_client .is_local_request_exists(request.request_id.clone()) .await? { // We already have a local request with the same id. Return back a cancel. - output.add_incoming_cancel( + control.access().output.add_incoming_cancel( currency, McCancel { request_id: request.request_id, }, ); - return Ok(output); + return Ok(()); } // We cut the first two public keys from the route: // Pop first route public key: let route_local_public_key = request.route.remove(0); - if &route_local_public_key != local_public_key { + if &route_local_public_key != &info.local_public_key { return Err(RouterError::InvalidRoute); } // Pop second route public key: let friend_public_key = request.route.remove(0); - let opt_tc_db_client = router_db_client + let opt_tc_db_client = control + .access() + .router_db_client .tc_db_client(friend_public_key.clone()) .await?; @@ -83,13 +83,13 @@ pub async fn send_request( } else { // Friend is not ready to accept a request. // We cancel the request: - output.add_incoming_cancel( + control.access().output.add_incoming_cancel( currency, McCancel { request_id: request.request_id.clone(), }, ); - return Ok(output); + return Ok(()); }; // Gather information about friend's channel and liveness: @@ -98,33 +98,36 @@ pub async fn send_request( // Check if friend is ready: if tc_db_client.get_tc_status().await?.is_consistent() - && router_state.liveness.is_online(&friend_public_key) + && control + .access() + .ephemeral + .liveness + .is_online(&friend_public_key) { // Keep request_id: let request_id = request.request_id.clone(); // Push request: - router_db_client + control + .access() + .router_db_client .pending_user_requests_push_back(friend_public_key.clone(), currency, request) .await?; // Mark request as created locally, so that we remember to punt the corresponding // response/cancel message later. - router_db_client.add_local_request(request_id).await?; - - // TODO: Change flush_friend design - todo!(); - flush_friend( - router_db_client, - friend_public_key.clone(), - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, - ) - .await?; + control + .access() + .router_db_client + .add_local_request(request_id) + .await?; + + control + .access() + .pending_send + .insert(friend_public_key.clone()); } else { - output.add_incoming_cancel( + control.access().output.add_incoming_cancel( currency, McCancel { request_id: request.request_id, @@ -132,19 +135,17 @@ pub async fn send_request( ); } - Ok(output) + Ok(()) } pub async fn send_response( - router_db_client: &mut impl RouterDbClient, + control: &mut impl RouterControl, + info: &RouterInfo, response: McResponse, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, -) -> Result { - let mut output = RouterOutput::new(); - - let opt_request_origin = router_db_client +) -> Result<(), RouterError> { + let opt_request_origin = control + .access() + .router_db_client .get_remote_pending_request_origin(response.request_id.clone()) .await?; @@ -152,39 +153,31 @@ pub async fn send_response( // so that we can forward him the response. // If we can not find the request's origin, we discard the response. if let Some(request_origin) = opt_request_origin { - router_db_client + control + .access() + .router_db_client .pending_backwards_push_back( request_origin.friend_public_key.clone(), BackwardsOp::Response(request_origin.currency, response), ) .await?; - // TODO: Change flush_friend design - todo!(); - flush_friend( - router_db_client, - request_origin.friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, - ) - .await?; + control + .access() + .pending_send + .insert(request_origin.friend_public_key); } - Ok(output) + Ok(()) } pub async fn send_cancel( - router_db_client: &mut impl RouterDbClient, + control: &mut impl RouterControl, cancel: McCancel, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, -) -> Result { - let mut output = RouterOutput::new(); - - let opt_request_origin = router_db_client +) -> Result<(), RouterError> { + let opt_request_origin = control + .access() + .router_db_client .get_remote_pending_request_origin(cancel.request_id.clone()) .await?; @@ -192,25 +185,20 @@ pub async fn send_cancel( // so that we can forward him the response. // If we can not find the request's origin, we discard the response. if let Some(request_origin) = opt_request_origin { - router_db_client + control + .access() + .router_db_client .pending_backwards_push_back( request_origin.friend_public_key.clone(), BackwardsOp::Cancel(request_origin.currency, cancel), ) .await?; - // TODO: Change flush_friend design - todo!(); - flush_friend( - router_db_client, - request_origin.friend_public_key, - identity_client, - local_public_key, - max_operations_in_batch, - &mut output, - ) - .await?; + control + .access() + .pending_send + .insert(request_origin.friend_public_key); } - Ok(output) + Ok(()) } diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index cf4df06cb..48dad6a71 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -3,8 +3,8 @@ mod utils; mod handle_config; mod handle_friend; mod handle_liveness; -// mod handle_relays; -// mod handle_route; +mod handle_relays; +mod handle_route; mod handler; From d5879ba8750689aa1821692d8c23ead8543ca0ef Mon Sep 17 00:00:00 2001 From: real Date: Fri, 12 Feb 2021 13:28:26 +0200 Subject: [PATCH 465/478] funder: router: restored handler --- components/funder/src/router/handler.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/funder/src/router/handler.rs b/components/funder/src/router/handler.rs index 13382c0d2..f4d837719 100644 --- a/components/funder/src/router/handler.rs +++ b/components/funder/src/router/handler.rs @@ -3,14 +3,13 @@ use database::transaction::Transaction; use crate::token_channel::TcDbClient; use crate::router::types::{RouterControl, RouterDbClient, RouterError, RouterInfo, RouterOp}; -// use crate::router::{handle_config, handle_friend, handle_liveness, handle_relays, handle_route}; +use crate::router::{handle_config, handle_friend, handle_liveness, handle_relays, handle_route}; pub async fn handle_router_op( control: &mut impl RouterControl, info: &RouterInfo, router_op: RouterOp, ) -> Result<(), RouterError> { - /* match router_op { RouterOp::AddCurrency(friend_public_key, currency) => { handle_config::add_currency(control, info, friend_public_key, currency).await @@ -58,6 +57,5 @@ pub async fn handle_router_op( RouterOp::SendResponse(mc_response) => todo!(), RouterOp::SendCancel(mc_cancel) => todo!(), }?; - */ todo!(); } From 5cd91825329f3d308063a6d8ed77d5cc3f93741e Mon Sep 17 00:00:00 2001 From: real Date: Fri, 12 Feb 2021 13:30:41 +0200 Subject: [PATCH 466/478] funder: router: Added Send{Request,Response,Cancel} cases --- components/funder/src/router/handler.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/funder/src/router/handler.rs b/components/funder/src/router/handler.rs index f4d837719..817dec462 100644 --- a/components/funder/src/router/handler.rs +++ b/components/funder/src/router/handler.rs @@ -53,9 +53,14 @@ pub async fn handle_router_op( } RouterOp::UpdateFriendLocalRelays(friend_public_key, friend_local_relays) => todo!(), RouterOp::UpdateLocalRelays(local_relays) => todo!(), - RouterOp::SendRequest(currency, mc_request) => todo!(), - RouterOp::SendResponse(mc_response) => todo!(), - RouterOp::SendCancel(mc_cancel) => todo!(), + RouterOp::SendRequest(currency, mc_request) => { + handle_route::send_request(control, info, currency, mc_request).await + } + RouterOp::SendResponse(mc_response) => { + handle_route::send_response(control, info, mc_response).await + } + RouterOp::SendCancel(mc_cancel) => handle_route::send_cancel(control, mc_cancel).await, + // TODO: Should also handle add/remove friend? }?; todo!(); } From 05fb9d1c1115f6cf2bff8c130b0407daa961aed4 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 12 Feb 2021 13:31:23 +0200 Subject: [PATCH 467/478] funder: TODO comment --- components/funder/src/router/handler.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/funder/src/router/handler.rs b/components/funder/src/router/handler.rs index 817dec462..e88c32b30 100644 --- a/components/funder/src/router/handler.rs +++ b/components/funder/src/router/handler.rs @@ -62,5 +62,7 @@ pub async fn handle_router_op( RouterOp::SendCancel(mc_cancel) => handle_route::send_cancel(control, mc_cancel).await, // TODO: Should also handle add/remove friend? }?; + + // TODO: flush all pending send here todo!(); } From f3be1c47963ca62d7cb7ab43b0c4899797ef4a3a Mon Sep 17 00:00:00 2001 From: real Date: Fri, 12 Feb 2021 14:02:23 +0200 Subject: [PATCH 468/478] funder: router: Refactored utils to use RouterControl trait --- components/funder/src/router/handle_friend.rs | 49 ++--- .../funder/src/router/handle_liveness.rs | 51 ++--- components/funder/src/router/utils/flush.rs | 44 ++-- .../funder/src/router/utils/move_token.rs | 205 ++++++++---------- 4 files changed, 158 insertions(+), 191 deletions(-) diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 235e5b2ba..4b0bc851e 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -369,12 +369,10 @@ async fn incoming_move_token_request( friend_public_key: PublicKey, in_move_token_request: MoveTokenRequest, ) -> Result<(), RouterError> { - let access = control.access(); let (receive_move_token_output, index_mutations) = handle_in_move_token_index_mutations( - access.router_db_client, - access.identity_client, + control, + info, in_move_token_request.move_token, - &info.local_public_key, friend_public_key.clone(), ) .await?; @@ -386,34 +384,32 @@ async fn incoming_move_token_request( match receive_move_token_output { ReceiveMoveTokenOutput::Duplicate => { - let mut access = control.access(); // We should have nothing else to send at this point, otherwise we would have already // sent it. - assert!( - !is_pending_move_token(access.router_db_client, friend_public_key.clone()).await? - ); + assert!(!is_pending_move_token(control, friend_public_key.clone()).await?); // Possibly send token to remote side (According to token_wanted) if in_move_token_request.token_wanted { let (out_move_token_request, index_mutations) = handle_out_move_token_index_mutations_allow_empty( - access.router_db_client, - access.identity_client, - &info.local_public_key, + control, + info, friend_public_key.clone(), - info.max_operations_in_batch, - &mut access.output, ) .await?; // We just got a message from remote side. Remote side should be online: - assert!(access.ephemeral.liveness.is_online(&friend_public_key)); + assert!(control + .access() + .ephemeral + .liveness + .is_online(&friend_public_key)); // Add index mutations: for index_mutation in index_mutations { - access.output.add_index_mutation(index_mutation); + control.access().output.add_index_mutation(index_mutation); } - access.output.add_friend_message( + control.access().output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(out_move_token_request), ); @@ -423,11 +419,7 @@ async fn incoming_move_token_request( // Retransmit outgoing move token message to friend: let move_token_request = MoveTokenRequest { move_token, - token_wanted: is_pending_move_token( - control.access().router_db_client, - friend_public_key.clone(), - ) - .await?, + token_wanted: is_pending_move_token(control, friend_public_key.clone()).await?, }; if control @@ -494,25 +486,18 @@ async fn incoming_move_token_request( let mut access = control.access(); Some( handle_out_move_token_index_mutations_allow_empty( - access.router_db_client, - access.identity_client, - &info.local_public_key, + control, + info, friend_public_key.clone(), - info.max_operations_in_batch, - &mut access.output, ) .await?, ) } else { // We only send a MoveTokenRequest to remote side if we have something to send: - let mut access = control.access(); handle_out_move_token_index_mutations_disallow_empty( - access.router_db_client, - access.identity_client, - &info.local_public_key, + control, + info, friend_public_key.clone(), - info.max_operations_in_batch, - &mut access.output, ) .await? }; diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index 84441f61b..5b0c38d7e 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -44,10 +44,9 @@ pub async fn set_friend_online( info: &RouterInfo, friend_public_key: PublicKey, ) -> Result<(), RouterError> { - let mut access = control.access(); - // First we make sure that the friend exists: - let tc_status = if let Some(tc_db_client) = access + let tc_status = if let Some(tc_db_client) = control + .access() .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -57,23 +56,30 @@ pub async fn set_friend_online( return Ok(()); }; - if access.ephemeral.liveness.is_online(&friend_public_key) { + if control + .access() + .ephemeral + .liveness + .is_online(&friend_public_key) + { // The friend is already marked as online! return Err(RouterError::FriendAlreadyOnline); } - access + control + .access() .ephemeral .liveness .set_online(friend_public_key.clone()); // Check if we have any relays information to send to the remote side: - if let (Some(generation), relays) = access + if let (Some(generation), relays) = control + .access() .router_db_client .get_last_sent_relays(friend_public_key.clone()) .await? { // Add a message for sending relays: - access.output.add_friend_message( + control.access().output.add_friend_message( friend_public_key.clone(), FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), ); @@ -83,12 +89,9 @@ pub async fn set_friend_online( TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. let opt_tuple = handle_out_move_token_index_mutations_disallow_empty( - access.router_db_client, - access.identity_client, - &info.local_public_key, + control, + info, friend_public_key.clone(), - info.max_operations_in_batch, - &mut access.output, ) .await?; @@ -97,7 +100,7 @@ pub async fn set_friend_online( // open currencies anyways. // We have something to send to remote side: - access.output.add_friend_message( + control.access().output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(move_token_request), ); @@ -106,21 +109,18 @@ pub async fn set_friend_online( TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { // Resend outgoing move token, // possibly asking for the token if we have something to send - access.output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(MoveTokenRequest { - move_token: move_token_out, - token_wanted: is_pending_move_token( - access.router_db_client, - friend_public_key.clone(), - ) - .await?, - }), - ); + let friend_message = FriendMessage::MoveTokenRequest(MoveTokenRequest { + move_token: move_token_out, + token_wanted: is_pending_move_token(control, friend_public_key.clone()).await?, + }); + control + .access() + .output + .add_friend_message(friend_public_key.clone(), friend_message); } TcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { // Resend reset terms - access.output.add_friend_message( + control.access().output.add_friend_message( friend_public_key.clone(), FriendMessage::InconsistencyError(local_reset_terms), ); @@ -128,6 +128,7 @@ pub async fn set_friend_online( } // Add an index mutation for all open currencies: + let access = control.access(); let mut open_currencies = access .router_db_client .list_open_currencies(friend_public_key.clone()); diff --git a/components/funder/src/router/utils/flush.rs b/components/funder/src/router/utils/flush.rs index 1dbc65ee9..17e32b636 100644 --- a/components/funder/src/router/utils/flush.rs +++ b/components/funder/src/router/utils/flush.rs @@ -24,7 +24,8 @@ use crate::token_channel::{TcDbClient, TcStatus, TokenChannelError}; use crate::route::Route; use crate::router::types::{ - BackwardsOp, CurrencyInfo, RouterDbClient, RouterError, RouterOutput, RouterState, SentRelay, + BackwardsOp, CurrencyInfo, RouterControl, RouterDbClient, RouterError, RouterInfo, + RouterOutput, RouterState, SentRelay, }; // use crate::router::utils::index_mutation::create_index_mutations_from_outgoing_move_token; use crate::router::utils::move_token::{ @@ -34,14 +35,13 @@ use crate::router::utils::move_token::{ /// Attempt to send as much as possible through a token channel to remote side /// Assumes that the token channel is in consistent state (Incoming / Outgoing). pub async fn flush_friend( - router_db_client: &mut impl RouterDbClient, + control: &mut impl RouterControl, + info: &RouterInfo, friend_public_key: PublicKey, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, - max_operations_in_batch: usize, - router_output: &mut RouterOutput, ) -> Result<(), RouterError> { - match router_db_client + match control + .access() + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .ok_or(RouterError::InvalidState)? @@ -51,12 +51,9 @@ pub async fn flush_friend( TcStatus::ConsistentIn(_) => { // Create an outgoing move token if we have something to send. let opt_tuple = handle_out_move_token_index_mutations_disallow_empty( - router_db_client, - identity_client, - local_public_key, + control, + info, friend_public_key.clone(), - max_operations_in_batch, - router_output, ) .await?; @@ -65,9 +62,9 @@ pub async fn flush_friend( // Update index mutations: for index_mutation in index_mutations { - router_output.add_index_mutation(index_mutation); + control.access().output.add_index_mutation(index_mutation); } - router_output.add_friend_message( + control.access().output.add_friend_message( friend_public_key.clone(), FriendMessage::MoveTokenRequest(move_token_request), ); @@ -76,17 +73,14 @@ pub async fn flush_friend( TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { // Resend outgoing move token, // possibly asking for the token if we have something to send - router_output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(MoveTokenRequest { - move_token: move_token_out, - token_wanted: is_pending_move_token( - router_db_client, - friend_public_key.clone(), - ) - .await?, - }), - ); + let friend_message = FriendMessage::MoveTokenRequest(MoveTokenRequest { + move_token: move_token_out, + token_wanted: is_pending_move_token(control, friend_public_key.clone()).await?, + }); + control + .access() + .output + .add_friend_message(friend_public_key.clone(), friend_message); } // This state is not possible, because we did manage to locate our request with this // friend: diff --git a/components/funder/src/router/utils/move_token.rs b/components/funder/src/router/utils/move_token.rs index 05d7feff0..c7b86511c 100644 --- a/components/funder/src/router/utils/move_token.rs +++ b/components/funder/src/router/utils/move_token.rs @@ -25,8 +25,8 @@ use database::transaction::Transaction; use crate::mutual_credit::{McCancel, McRequest, McResponse}; use crate::route::Route; use crate::router::types::{ - BackwardsOp, CurrencyInfo, FriendBalance, FriendBalanceDiff, RouterDbClient, RouterError, - RouterOutput, RouterState, SentRelay, + BackwardsOp, CurrencyInfo, FriendBalance, FriendBalanceDiff, RouterControl, RouterDbClient, + RouterError, RouterInfo, RouterOutput, RouterState, SentRelay, }; use crate::router::utils::index_mutation::create_index_mutation; use crate::token_channel::{ @@ -35,13 +35,15 @@ use crate::token_channel::{ }; async fn queue_backwards_op( - router_db_client: &mut impl RouterDbClient, + control: &mut impl RouterControl, + info: &RouterInfo, out_move_token: &mut OutMoveToken, - local_public_key: &PublicKey, friend_public_key: PublicKey, backwards_op: BackwardsOp, ) -> Result<(), RouterError> { - let tc_db_client = if let Some(tc_db_client) = router_db_client + let tc_db_client = if let Some(tc_db_client) = control + .access() + .router_db_client .tc_db_client(friend_public_key.clone()) .await? { @@ -52,7 +54,7 @@ async fn queue_backwards_op( let friend_tc_op = match backwards_op { BackwardsOp::Response(currency, mc_response) => { out_move_token - .queue_response(tc_db_client, currency, mc_response, local_public_key) + .queue_response(tc_db_client, currency, mc_response, &info.local_public_key) .await?; } BackwardsOp::Cancel(currency, mc_cancel) => { @@ -67,15 +69,16 @@ async fn queue_backwards_op( /// Queue a request to an `out_move_token`. /// Handles failure by returning a cancel message to the relevant origin. async fn queue_request( - router_db_client: &mut impl RouterDbClient, + control: &mut impl RouterControl, + info: &RouterInfo, out_move_token: &mut OutMoveToken, - local_public_key: &PublicKey, friend_public_key: PublicKey, currency: Currency, mc_request: McRequest, - router_output: &mut RouterOutput, ) -> Result<(), RouterError> { - let tc_db_client = if let Some(tc_db_client) = router_db_client + let tc_db_client = if let Some(tc_db_client) = control + .access() + .router_db_client .tc_db_client(friend_public_key.clone()) .await? { @@ -90,7 +93,9 @@ async fn queue_request( match res { Ok(mc_balance) => { - let currency_info = router_db_client + let currency_info = control + .access() + .router_db_client .get_currency_info(friend_public_key.clone(), currency.clone()) .await? // If currency does not exist, we should have already cancelled this request. @@ -103,7 +108,9 @@ async fn queue_request( && mc_balance.balance == 0 { // Remove currency: - router_db_client + control + .access() + .router_db_client .remove_currency(friend_public_key.clone(), currency.clone()) .await?; @@ -126,39 +133,48 @@ async fn queue_request( balances_diff.insert(currency.clone(), friend_balance_diff); balances_diff }; - router_db_client + control + .access() + .router_db_client .add_friend_event(friend_public_key.clone(), balances_diff) .await?; } } Err(mc_cancel) => { // We need to send a cancel message to the origin - if router_db_client + if control + .access() + .router_db_client .is_request_local_origin(mc_request.request_id.clone()) .await? { // Request is of local origin - router_output.add_incoming_cancel( + control.access().output.add_incoming_cancel( currency, McCancel { request_id: mc_request.request_id.clone(), }, ); } else { - if let Some(request_origin) = router_db_client + if let Some(request_origin) = control + .access() + .router_db_client .get_remote_pending_request_origin(mc_request.request_id.clone()) .await? { // Request is of remote origin - router_db_client.pending_backwards_push_back( - request_origin.friend_public_key.clone(), - BackwardsOp::Cancel( - request_origin.currency.clone(), - McCancel { - request_id: mc_request.request_id.clone(), - }, - ), - ); + control + .access() + .router_db_client + .pending_backwards_push_back( + request_origin.friend_public_key.clone(), + BackwardsOp::Cancel( + request_origin.currency.clone(), + McCancel { + request_id: mc_request.request_id.clone(), + }, + ), + ); } else { // Request is orphan, nothing to do here } @@ -169,75 +185,77 @@ async fn queue_request( } async fn collect_currencies_operations( - router_db_client: &mut impl RouterDbClient, - local_public_key: &PublicKey, + control: &mut impl RouterControl, + info: &RouterInfo, friend_public_key: PublicKey, - max_operations_in_batch: usize, - router_output: &mut RouterOutput, ) -> Result { // Create a structure that aggregates operations to be sent in a single MoveToken message: let mut out_move_token = OutMoveToken::new(); // Collect any pending responses and cancels: - while let Some(backwards_op) = router_db_client + while let Some(backwards_op) = control + .access() + .router_db_client .pending_backwards_pop_front(friend_public_key.clone()) .await? { queue_backwards_op( - router_db_client, + control, + info, &mut out_move_token, - local_public_key, friend_public_key.clone(), backwards_op, ) .await?; // Make sure we do not exceed maximum amount of operations: - if out_move_token.len() >= max_operations_in_batch { + if out_move_token.len() >= info.max_operations_in_batch { return Ok(out_move_token); } } // Collect any pending user requests: - while let Some((currency, mc_request)) = router_db_client + while let Some((currency, mc_request)) = control + .access() + .router_db_client .pending_user_requests_pop_front(friend_public_key.clone()) .await? { queue_request( - router_db_client, + control, + info, &mut out_move_token, - local_public_key, friend_public_key.clone(), currency, mc_request, - router_output, ) .await?; // Make sure we do not exceed maximum amount of operations: - if out_move_token.len() >= max_operations_in_batch { + if out_move_token.len() >= info.max_operations_in_batch { return Ok(out_move_token); } } // Collect any pending requests: - while let Some((currency, mc_request)) = router_db_client + while let Some((currency, mc_request)) = control + .access() + .router_db_client .pending_requests_pop_front(friend_public_key.clone()) .await? { queue_request( - router_db_client, + control, + info, &mut out_move_token, - local_public_key, friend_public_key.clone(), currency, mc_request, - router_output, ) .await?; // Make sure we do not exceed maximum amount of operations: - if out_move_token.len() >= max_operations_in_batch { + if out_move_token.len() >= info.max_operations_in_batch { return Ok(out_move_token); } } @@ -308,13 +326,14 @@ fn create_index_mutations( } async fn apply_out_move_token( - router_db_client: &mut impl RouterDbClient, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, + control: &mut impl RouterControl, + info: &RouterInfo, friend_public_key: PublicKey, out_move_token: OutMoveToken, ) -> Result<(MoveTokenRequest, Vec), RouterError> { - let tc_client = router_db_client + let access = control.access(); + let tc_client = access + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .ok_or(RouterError::InvalidState)?; @@ -323,15 +342,15 @@ async fn apply_out_move_token( let (move_token, mentioned_currencies) = out_move_token .finalize( tc_client, - identity_client, - local_public_key, + access.identity_client, + &info.local_public_key, &friend_public_key, ) .await?; // Get currency info for all mentioned currencies: let currencies_info = get_currencies_info( - router_db_client, + control.access().router_db_client, friend_public_key.clone(), &mentioned_currencies, ) @@ -342,28 +361,19 @@ async fn apply_out_move_token( let move_token_request = MoveTokenRequest { move_token, - token_wanted: is_pending_move_token(router_db_client, friend_public_key).await?, + token_wanted: is_pending_move_token(control, friend_public_key).await?, }; Ok((move_token_request, index_mutations)) } pub async fn handle_out_move_token_index_mutations_disallow_empty( - router_db_client: &mut impl RouterDbClient, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, + control: &mut impl RouterControl, + info: &RouterInfo, friend_public_key: PublicKey, - max_operations_in_batch: usize, - router_output: &mut RouterOutput, ) -> Result)>, RouterError> { - let out_move_token = collect_currencies_operations( - router_db_client, - local_public_key, - friend_public_key.clone(), - max_operations_in_batch, - router_output, - ) - .await?; + let out_move_token = + collect_currencies_operations(control, info, friend_public_key.clone()).await?; // Do nothing if we have nothing to send to remote side: if out_move_token.is_empty() { @@ -371,74 +381,51 @@ pub async fn handle_out_move_token_index_mutations_disallow_empty( } Ok(Some( - apply_out_move_token( - router_db_client, - identity_client, - local_public_key, - friend_public_key, - out_move_token, - ) - .await?, + apply_out_move_token(control, info, friend_public_key, out_move_token).await?, )) } pub async fn handle_out_move_token_index_mutations_allow_empty( - router_db_client: &mut impl RouterDbClient, - identity_client: &mut IdentityClient, - local_public_key: &PublicKey, + control: &mut impl RouterControl, + info: &RouterInfo, friend_public_key: PublicKey, - max_operations_in_batch: usize, - router_output: &mut RouterOutput, ) -> Result<(MoveTokenRequest, Vec), RouterError> { - let out_move_token = collect_currencies_operations( - router_db_client, - local_public_key, - friend_public_key.clone(), - max_operations_in_batch, - router_output, - ) - .await?; + let out_move_token = + collect_currencies_operations(control, info, friend_public_key.clone()).await?; - apply_out_move_token( - router_db_client, - identity_client, - local_public_key, - friend_public_key, - out_move_token, - ) - .await + apply_out_move_token(control, info, friend_public_key, out_move_token).await } /// Check if we have anything to send to a remove friend on a move token message, /// without performing any data mutations pub async fn is_pending_move_token( - router_db_client: &mut impl RouterDbClient, + control: &mut impl RouterControl, friend_public_key: PublicKey, ) -> Result { - Ok(is_pending_currencies_operations(router_db_client, friend_public_key.clone()).await?) + Ok(is_pending_currencies_operations( + control.access().router_db_client, + friend_public_key.clone(), + ) + .await?) } -pub async fn handle_in_move_token_index_mutations( - router_db_client: &mut RC, - identity_client: &mut IdentityClient, +pub async fn handle_in_move_token_index_mutations( + control: &mut impl RouterControl, + info: &RouterInfo, move_token: MoveToken, - local_public_key: &PublicKey, friend_public_key: PublicKey, -) -> Result<(ReceiveMoveTokenOutput, Vec), RouterError> -where - RC: RouterDbClient, - RC::TcDbClient: Transaction + Send, - ::McDbClient: Send, -{ +) -> Result<(ReceiveMoveTokenOutput, Vec), RouterError> { // Handle incoming move token: + let access = control.access(); let receive_move_token_output = handle_in_move_token( - router_db_client + access + .router_db_client .tc_db_client(friend_public_key.clone()) .await? .ok_or(RouterError::InvalidState)?, - identity_client, + access.identity_client, move_token, - local_public_key, + &info.local_public_key, &friend_public_key, ) .await?; @@ -463,7 +450,7 @@ where // Get currency info for all mentioned currencies: let currencies_info = get_currencies_info( - router_db_client, + control.access().router_db_client, friend_public_key.clone(), &mentioned_currencies, ) From 1a45c1e58604f460204dfe6ebc8e7b827fcc9eef Mon Sep 17 00:00:00 2001 From: real Date: Fri, 12 Feb 2021 17:34:32 +0200 Subject: [PATCH 469/478] funder: Updated set/unset remove currency impl --- components/funder/src/router/handle_config.rs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index e12692bd9..7905a2905 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -66,11 +66,10 @@ pub async fn set_remove_currency( friend_public_key: PublicKey, currency: Currency, ) -> Result<(), RouterError> { - let access = control.access(); // Revise implementation with respect to new design - todo!(); // First we make sure that the friend exists: - if access + if control + .access() .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -78,12 +77,13 @@ pub async fn set_remove_currency( { return Ok(()); } - access + control + .access() .router_db_client .set_currency_remove(friend_public_key.clone(), currency) .await?; - access.pending_send.insert(friend_public_key); + control.access().pending_send.insert(friend_public_key); Ok(()) } @@ -93,12 +93,9 @@ pub async fn unset_remove_currency( friend_public_key: PublicKey, currency: Currency, ) -> Result<(), RouterError> { - let access = control.access(); - // TODO: Update implementation according to new design - todo!(); - // First we make sure that the friend exists: - if access + if control + .access() .router_db_client .tc_db_client(friend_public_key.clone()) .await? @@ -106,12 +103,13 @@ pub async fn unset_remove_currency( { return Ok(()); } - access + control + .access() .router_db_client .unset_currency_remove(friend_public_key.clone(), currency) .await?; - access.pending_send.insert(friend_public_key); + control.access().pending_send.insert(friend_public_key); Ok(()) } From efd59be06f578fd0ff09b5da5c9980843b918895 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 12 Feb 2021 17:39:48 +0200 Subject: [PATCH 470/478] funder: Added SetRemoveCurrency, UnsetRemoveCurrency --- components/funder/src/router/handler.rs | 7 ++++++- components/funder/src/router/types.rs | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/components/funder/src/router/handler.rs b/components/funder/src/router/handler.rs index e88c32b30..53c2da274 100644 --- a/components/funder/src/router/handler.rs +++ b/components/funder/src/router/handler.rs @@ -14,7 +14,12 @@ pub async fn handle_router_op( RouterOp::AddCurrency(friend_public_key, currency) => { handle_config::add_currency(control, info, friend_public_key, currency).await } - RouterOp::RemoveCurrency(friend_public_key, currency) => todo!(), + RouterOp::SetRemoveCurrency(friend_public_key, currency) => { + handle_config::set_remove_currency(control, info, friend_public_key, currency).await + } + RouterOp::UnsetRemoveCurrency(friend_public_key, currency) => { + handle_config::unset_remove_currency(control, info, friend_public_key, currency).await + } RouterOp::SetRemoteMaxDebt(friend_public_key, currency, remote_max_debt) => { handle_config::set_remote_max_debt( control, diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index ae52b105d..6981cefa4 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -476,7 +476,9 @@ pub enum RouterOp { /// (friend_public_key, currency) AddCurrency(PublicKey, Currency), /// (friend_public_key, currency) - RemoveCurrency(PublicKey, Currency), + SetRemoveCurrency(PublicKey, Currency), + /// (friend_public_key, currency) + UnsetRemoveCurrency(PublicKey, Currency), /// (friend_public_key, currency, remote_max_debt) SetRemoteMaxDebt(PublicKey, Currency, u128), /// (friend_public_key, currency, local_max_debt) From 1134c990d0245d0f23de59f4e78114d561aa5d31 Mon Sep 17 00:00:00 2001 From: real Date: Fri, 12 Feb 2021 17:51:11 +0200 Subject: [PATCH 471/478] funder: Added flush_friends() stub --- components/funder/src/router/handler.rs | 7 ++++--- components/funder/src/router/mod.rs | 2 ++ components/funder/src/router/send.rs | 9 +++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 components/funder/src/router/send.rs diff --git a/components/funder/src/router/handler.rs b/components/funder/src/router/handler.rs index 53c2da274..5a5a787ad 100644 --- a/components/funder/src/router/handler.rs +++ b/components/funder/src/router/handler.rs @@ -3,7 +3,9 @@ use database::transaction::Transaction; use crate::token_channel::TcDbClient; use crate::router::types::{RouterControl, RouterDbClient, RouterError, RouterInfo, RouterOp}; -use crate::router::{handle_config, handle_friend, handle_liveness, handle_relays, handle_route}; +use crate::router::{ + handle_config, handle_friend, handle_liveness, handle_relays, handle_route, send, +}; pub async fn handle_router_op( control: &mut impl RouterControl, @@ -68,6 +70,5 @@ pub async fn handle_router_op( // TODO: Should also handle add/remove friend? }?; - // TODO: flush all pending send here - todo!(); + send::flush_friends(control, info).await } diff --git a/components/funder/src/router/mod.rs b/components/funder/src/router/mod.rs index 48dad6a71..ac47a0262 100644 --- a/components/funder/src/router/mod.rs +++ b/components/funder/src/router/mod.rs @@ -6,6 +6,8 @@ mod handle_liveness; mod handle_relays; mod handle_route; +mod send; + mod handler; mod types; diff --git a/components/funder/src/router/send.rs b/components/funder/src/router/send.rs new file mode 100644 index 000000000..3c4cb4c6b --- /dev/null +++ b/components/funder/src/router/send.rs @@ -0,0 +1,9 @@ +use crate::router::types::{RouterControl, RouterError, RouterInfo}; + +/// Send all pending MoveToken messages +pub async fn flush_friends( + control: &mut impl RouterControl, + info: &RouterInfo, +) -> Result<(), RouterError> { + todo!(); +} From 9504819bec96893356f39e558659a82d1e375092 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 13 Feb 2021 10:56:52 +0200 Subject: [PATCH 472/478] funder: Added SendCommands --- components/funder/src/router/handle_config.rs | 6 ++-- components/funder/src/router/handle_friend.rs | 10 +++--- components/funder/src/router/handle_route.rs | 6 ++-- components/funder/src/router/types.rs | 31 +++++++++++++++++-- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 7905a2905..c09b7f49d 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -55,7 +55,7 @@ pub async fn add_currency( .add_currency_config(friend_public_key.clone(), currency) .await?; - access.pending_send.insert(friend_public_key); + access.send_commands.insert(friend_public_key); Ok(()) } @@ -83,7 +83,7 @@ pub async fn set_remove_currency( .set_currency_remove(friend_public_key.clone(), currency) .await?; - control.access().pending_send.insert(friend_public_key); + control.access().send_commands.insert(friend_public_key); Ok(()) } @@ -109,7 +109,7 @@ pub async fn unset_remove_currency( .unset_currency_remove(friend_public_key.clone(), currency) .await?; - control.access().pending_send.insert(friend_public_key); + control.access().send_commands.insert(friend_public_key); Ok(()) } diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 4b0bc851e..95c025537 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -110,7 +110,7 @@ async fn incoming_message_request( ) .await?; - control.access().pending_send.insert(friend_public_key); + control.access().send_commands.insert(friend_public_key); return Ok(()); } @@ -161,7 +161,7 @@ async fn incoming_message_request( // TODO: flush_friend() is delicate. We might be able to aggregate some more pending // requests before flushing this friend. Find out how to do this. - control.access().pending_send.insert(next_public_key); + control.access().send_commands.insert(next_public_key); } else { // Return a cancel message and flush origin friend control @@ -178,7 +178,7 @@ async fn incoming_message_request( ) .await?; - control.access().pending_send.insert(friend_public_key); + control.access().send_commands.insert(friend_public_key); } Ok(()) @@ -278,7 +278,7 @@ async fn incoming_message_response( ) .await?; - control.access().pending_send.insert(friend_public_key); + control.access().send_commands.insert(friend_public_key); } (true, Some(request_origin)) => { // This means the request has both originated locally, and from a friend. @@ -349,7 +349,7 @@ async fn incoming_message_cancel( control .access() - .pending_send + .send_commands .insert(friend_public_key.clone()); } (true, Some(request_origin)) => { diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index d729f5902..a3c444d45 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -124,7 +124,7 @@ pub async fn send_request( control .access() - .pending_send + .send_commands .insert(friend_public_key.clone()); } else { control.access().output.add_incoming_cancel( @@ -164,7 +164,7 @@ pub async fn send_response( control .access() - .pending_send + .send_commands .insert(request_origin.friend_public_key); } @@ -196,7 +196,7 @@ pub async fn send_cancel( control .access() - .pending_send + .send_commands .insert(request_origin.friend_public_key); } diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 6981cefa4..d3d73bb85 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -389,13 +389,38 @@ pub struct RouterInfo { pub max_operations_in_batch: usize, } +#[derive(Debug)] +pub struct SendCommands { + /// friend_public_key -> allow_empty + send_commands: HashMap, +} + +impl SendCommands { + pub fn new() -> Self { + Self { + send_commands: HashMap::new(), + } + } + + /// Schedule send for a friend. + pub fn insert(&mut self, friend_public_key: PublicKey) { + // Note: If we already set allow_empty = true, we will leave it equals to true. + let _ = self.send_commands.entry(friend_public_key).or_insert(false); + } + + /// Schedule a send for a friend. Send will happen even if there is nothing to send. + pub fn insert_allow_empty(&mut self, friend_public_key: PublicKey) { + let _ = self.send_commands.insert(friend_public_key, true); + } +} + #[derive(Debug)] pub struct RouterHandle<'a, R, RC> { pub router_db_client: &'a mut RC, pub identity_client: &'a mut IdentityClient, pub rng: &'a mut R, /// Friends with new pending outgoing messages - pub pending_send: HashSet, + pub send_commands: SendCommands, /// Ephemeral state: pub ephemeral: &'a mut RouterState, /// Router's output: @@ -408,7 +433,7 @@ pub struct RouterAccess<'a, R, RC> { pub identity_client: &'a mut IdentityClient, pub rng: &'a mut R, /// Friends with new pending outgoing messages - pub pending_send: &'a mut HashSet, + pub send_commands: &'a mut SendCommands, /// Ephemeral state: pub ephemeral: &'a mut RouterState, /// Router's output: @@ -441,7 +466,7 @@ where router_db_client: self.router_db_client, identity_client: self.identity_client, rng: self.rng, - pending_send: &mut self.pending_send, + send_commands: &mut self.send_commands, ephemeral: self.ephemeral, output: &mut self.output, } From 370390a081707a5efe614db05c837764671e18e1 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 13 Feb 2021 14:42:12 +0200 Subject: [PATCH 473/478] funder: Updated SendCommands --- components/funder/src/router/handle_config.rs | 6 +- components/funder/src/router/handle_friend.rs | 108 ++++-------------- .../funder/src/router/handle_liveness.rs | 39 ++----- components/funder/src/router/handle_route.rs | 10 +- components/funder/src/router/send.rs | 1 + components/funder/src/router/types.rs | 20 +++- 6 files changed, 57 insertions(+), 127 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index c09b7f49d..21399ec4f 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -55,7 +55,7 @@ pub async fn add_currency( .add_currency_config(friend_public_key.clone(), currency) .await?; - access.send_commands.insert(friend_public_key); + access.send_commands.move_token(friend_public_key); Ok(()) } @@ -83,7 +83,7 @@ pub async fn set_remove_currency( .set_currency_remove(friend_public_key.clone(), currency) .await?; - control.access().send_commands.insert(friend_public_key); + control.access().send_commands.move_token(friend_public_key); Ok(()) } @@ -109,7 +109,7 @@ pub async fn unset_remove_currency( .unset_currency_remove(friend_public_key.clone(), currency) .await?; - control.access().send_commands.insert(friend_public_key); + control.access().send_commands.move_token(friend_public_key); Ok(()) } diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 95c025537..68b6a9eb8 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -33,10 +33,7 @@ use crate::router::types::{ RouterOutput, RouterState, SentRelay, }; use crate::router::utils::flush::flush_friend; -use crate::router::utils::move_token::{ - handle_in_move_token_index_mutations, handle_out_move_token_index_mutations_allow_empty, - handle_out_move_token_index_mutations_disallow_empty, is_pending_move_token, -}; +use crate::router::utils::move_token::handle_in_move_token_index_mutations; use crate::token_channel::{ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError}; /// Check if credit line between this node and a friend is ready @@ -110,7 +107,7 @@ async fn incoming_message_request( ) .await?; - control.access().send_commands.insert(friend_public_key); + control.access().send_commands.move_token(friend_public_key); return Ok(()); } @@ -161,7 +158,7 @@ async fn incoming_message_request( // TODO: flush_friend() is delicate. We might be able to aggregate some more pending // requests before flushing this friend. Find out how to do this. - control.access().send_commands.insert(next_public_key); + control.access().send_commands.move_token(next_public_key); } else { // Return a cancel message and flush origin friend control @@ -178,7 +175,7 @@ async fn incoming_message_request( ) .await?; - control.access().send_commands.insert(friend_public_key); + control.access().send_commands.move_token(friend_public_key); } Ok(()) @@ -278,7 +275,7 @@ async fn incoming_message_response( ) .await?; - control.access().send_commands.insert(friend_public_key); + control.access().send_commands.move_token(friend_public_key); } (true, Some(request_origin)) => { // This means the request has both originated locally, and from a friend. @@ -350,7 +347,7 @@ async fn incoming_message_cancel( control .access() .send_commands - .insert(friend_public_key.clone()); + .move_token(friend_public_key.clone()); } (true, Some(request_origin)) => { // This means the request has both originated locally, and from a friend. @@ -386,53 +383,17 @@ async fn incoming_move_token_request( ReceiveMoveTokenOutput::Duplicate => { // We should have nothing else to send at this point, otherwise we would have already // sent it. - assert!(!is_pending_move_token(control, friend_public_key.clone()).await?); - - // Possibly send token to remote side (According to token_wanted) - if in_move_token_request.token_wanted { - let (out_move_token_request, index_mutations) = - handle_out_move_token_index_mutations_allow_empty( - control, - info, - friend_public_key.clone(), - ) - .await?; - - // We just got a message from remote side. Remote side should be online: - assert!(control - .access() - .ephemeral - .liveness - .is_online(&friend_public_key)); - - // Add index mutations: - for index_mutation in index_mutations { - control.access().output.add_index_mutation(index_mutation); - } - control.access().output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(out_move_token_request), - ); - } + control + .access() + .send_commands + .move_token_allow_empty(friend_public_key.clone()); } ReceiveMoveTokenOutput::RetransmitOutgoing(move_token) => { // Retransmit outgoing move token message to friend: - let move_token_request = MoveTokenRequest { - move_token, - token_wanted: is_pending_move_token(control, friend_public_key.clone()).await?, - }; - - if control + control .access() - .ephemeral - .liveness - .is_online(&friend_public_key) - { - control.access().output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(move_token_request), - ); - } + .send_commands + .move_token_allow_empty(friend_public_key.clone()); } ReceiveMoveTokenOutput::Received(move_token_received) => { for (currency, incoming_message) in move_token_received.incoming_messages { @@ -480,45 +441,20 @@ async fn incoming_move_token_request( } // Possibly send RequestMoveToken back to friend in one of the following cases: - let opt_res = if in_move_token_request.token_wanted { + if in_move_token_request.token_wanted { // Remote side wants to have the token back, so we have to send a MoveTokenRequest // to remote side, even if it is empty - let mut access = control.access(); - Some( - handle_out_move_token_index_mutations_allow_empty( - control, - info, - friend_public_key.clone(), - ) - .await?, - ) + control + .access() + .send_commands + .move_token_allow_empty(friend_public_key.clone()); } else { // We only send a MoveTokenRequest to remote side if we have something to send: - handle_out_move_token_index_mutations_disallow_empty( - control, - info, - friend_public_key.clone(), - ) - .await? - }; - - if let Some((out_move_token_request, index_mutations)) = opt_res { - // We just got a message from remote side. Remote side should be online: - assert!(control + control .access() - .ephemeral - .liveness - .is_online(&friend_public_key)); - - // Add index mutations: - for index_mutation in index_mutations { - control.access().output.add_index_mutation(index_mutation); - } - control.access().output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(out_move_token_request), - ); - } + .send_commands + .move_token(friend_public_key.clone()); + }; } ReceiveMoveTokenOutput::ChainInconsistent(reset_terms) => { // TODO: diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index 5b0c38d7e..ee6e57bab 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -35,9 +35,7 @@ use crate::token_channel::{ }; use crate::router::utils::index_mutation::create_index_mutation; -use crate::router::utils::move_token::{ - handle_out_move_token_index_mutations_disallow_empty, is_pending_move_token, -}; +use crate::router::utils::move_token::is_pending_move_token; pub async fn set_friend_online( control: &mut impl RouterControl, @@ -87,38 +85,25 @@ pub async fn set_friend_online( match tc_status { TcStatus::ConsistentIn(_) => { - // Create an outgoing move token if we have something to send. - let opt_tuple = handle_out_move_token_index_mutations_disallow_empty( - control, - info, - friend_public_key.clone(), - ) - .await?; - - if let Some((move_token_request, _index_mutations)) = opt_tuple { - // We discard index_mutations calculation here, because we are going to add all - // open currencies anyways. - - // We have something to send to remote side: - control.access().output.add_friend_message( - friend_public_key.clone(), - FriendMessage::MoveTokenRequest(move_token_request), - ); - } + // Send an outgoing move token if we have something to send. + control + .access() + .send_commands + .move_token(friend_public_key.clone()); } TcStatus::ConsistentOut(move_token_out, _opt_move_token_hashed_in) => { // Resend outgoing move token, // possibly asking for the token if we have something to send - let friend_message = FriendMessage::MoveTokenRequest(MoveTokenRequest { - move_token: move_token_out, - token_wanted: is_pending_move_token(control, friend_public_key.clone()).await?, - }); + // Send an outgoing move token if we have something to send. control .access() - .output - .add_friend_message(friend_public_key.clone(), friend_message); + .send_commands + .move_token_allow_empty(friend_public_key.clone()); } TcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { + todo!(); + // TODO: Should we signal using send_commands instead? + // Resend reset terms control.access().output.add_friend_message( friend_public_key.clone(), diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index a3c444d45..4512d9a28 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -14,8 +14,8 @@ use identity::IdentityClient; use proto::app_server::messages::RelayAddressPort; use proto::crypto::{NodePort, PublicKey}; use proto::funder::messages::{ - CancelSendFundsOp, Currency, FriendMessage, FriendTcOp, MoveToken, MoveTokenRequest, - RelaysUpdate, RequestSendFundsOp, ResetTerms, ResponseSendFundsOp, + CancelSendFundsOp, Currency, FriendTcOp, MoveToken, MoveTokenRequest, RelaysUpdate, + RequestSendFundsOp, ResetTerms, ResponseSendFundsOp, }; use proto::index_server::messages::{IndexMutation, RemoveFriendCurrency, UpdateFriendCurrency}; use proto::net::messages::NetAddress; @@ -125,7 +125,7 @@ pub async fn send_request( control .access() .send_commands - .insert(friend_public_key.clone()); + .move_token(friend_public_key.clone()); } else { control.access().output.add_incoming_cancel( currency, @@ -165,7 +165,7 @@ pub async fn send_response( control .access() .send_commands - .insert(request_origin.friend_public_key); + .move_token(request_origin.friend_public_key); } Ok(()) @@ -197,7 +197,7 @@ pub async fn send_cancel( control .access() .send_commands - .insert(request_origin.friend_public_key); + .move_token(request_origin.friend_public_key); } Ok(()) diff --git a/components/funder/src/router/send.rs b/components/funder/src/router/send.rs index 3c4cb4c6b..df51938ff 100644 --- a/components/funder/src/router/send.rs +++ b/components/funder/src/router/send.rs @@ -5,5 +5,6 @@ pub async fn flush_friends( control: &mut impl RouterControl, info: &RouterInfo, ) -> Result<(), RouterError> { + // TODO: Remember to deal with index mutations here too todo!(); } diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index d3d73bb85..4a8448dd6 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -392,25 +392,33 @@ pub struct RouterInfo { #[derive(Debug)] pub struct SendCommands { /// friend_public_key -> allow_empty - send_commands: HashMap, + move_token: HashMap, + /// Should we send relays update to remote side? + relays_update: HashSet, } impl SendCommands { pub fn new() -> Self { Self { - send_commands: HashMap::new(), + move_token: HashMap::new(), + relays_update: HashSet::new(), } } /// Schedule send for a friend. - pub fn insert(&mut self, friend_public_key: PublicKey) { + pub fn move_token(&mut self, friend_public_key: PublicKey) { // Note: If we already set allow_empty = true, we will leave it equals to true. - let _ = self.send_commands.entry(friend_public_key).or_insert(false); + let _ = self.move_token.entry(friend_public_key).or_insert(false); } /// Schedule a send for a friend. Send will happen even if there is nothing to send. - pub fn insert_allow_empty(&mut self, friend_public_key: PublicKey) { - let _ = self.send_commands.insert(friend_public_key, true); + pub fn move_token_allow_empty(&mut self, friend_public_key: PublicKey) { + let _ = self.move_token.insert(friend_public_key, true); + } + + /// Schedule relays update message + pub fn relays_update(&mut self, friend_public_key: PublicKey) { + self.relays_update.insert(friend_public_key); } } From 84a4f7c2c5c448a1604141ccf106f9f9d0c9723f Mon Sep 17 00:00:00 2001 From: real Date: Sat, 13 Feb 2021 14:56:39 +0200 Subject: [PATCH 474/478] funder: Only send module may send friend message --- components/funder/src/router/handle_config.rs | 1 - components/funder/src/router/handle_friend.rs | 1 - .../funder/src/router/handle_liveness.rs | 20 ++++++++----------- components/funder/src/router/handle_relays.rs | 12 ++++------- components/funder/src/router/handle_route.rs | 1 - components/funder/src/router/types.rs | 14 ++----------- components/funder/src/router/utils/mod.rs | 2 +- 7 files changed, 15 insertions(+), 36 deletions(-) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 21399ec4f..19e3601c9 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -27,7 +27,6 @@ use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterControl, RouterDbClient, RouterError, RouterInfo, RouterOutput, RouterState, SentRelay, }; -use crate::router::utils::flush::flush_friend; use crate::router::utils::index_mutation::create_index_mutation; use crate::router::utils::move_token::is_pending_move_token; use crate::token_channel::{ diff --git a/components/funder/src/router/handle_friend.rs b/components/funder/src/router/handle_friend.rs index 68b6a9eb8..99d286961 100644 --- a/components/funder/src/router/handle_friend.rs +++ b/components/funder/src/router/handle_friend.rs @@ -32,7 +32,6 @@ use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterControl, RouterDbClient, RouterError, RouterInfo, RouterOutput, RouterState, SentRelay, }; -use crate::router::utils::flush::flush_friend; use crate::router::utils::move_token::handle_in_move_token_index_mutations; use crate::token_channel::{ReceiveMoveTokenOutput, TcDbClient, TcStatus, TokenChannelError}; diff --git a/components/funder/src/router/handle_liveness.rs b/components/funder/src/router/handle_liveness.rs index ee6e57bab..6c377fba5 100644 --- a/components/funder/src/router/handle_liveness.rs +++ b/components/funder/src/router/handle_liveness.rs @@ -76,11 +76,10 @@ pub async fn set_friend_online( .get_last_sent_relays(friend_public_key.clone()) .await? { - // Add a message for sending relays: - control.access().output.add_friend_message( - friend_public_key.clone(), - FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), - ); + control + .access() + .send_commands + .relays_update(friend_public_key.clone()); } match tc_status { @@ -101,14 +100,11 @@ pub async fn set_friend_online( .move_token_allow_empty(friend_public_key.clone()); } TcStatus::Inconsistent(local_reset_terms, _opt_remote_reset_terms) => { - todo!(); - // TODO: Should we signal using send_commands instead? - // Resend reset terms - control.access().output.add_friend_message( - friend_public_key.clone(), - FriendMessage::InconsistencyError(local_reset_terms), - ); + control + .access() + .send_commands + .move_token_allow_empty(friend_public_key.clone()); } } diff --git a/components/funder/src/router/handle_relays.rs b/components/funder/src/router/handle_relays.rs index 7eaf0e944..ca9ce0161 100644 --- a/components/funder/src/router/handle_relays.rs +++ b/components/funder/src/router/handle_relays.rs @@ -159,14 +159,10 @@ pub async fn update_local_relays( // If sent_relays was updated and the friend is ready, we need to send relays to // remote friend: if let Some((generation, relays)) = opt_res { - // Make sure that remote friend is online: - if router_state.liveness.is_online(&friend_public_key) { - // Add a message for sending relays: - control.access().output.add_friend_message( - friend_public_key.clone(), - FriendMessage::RelaysUpdate(RelaysUpdate { generation, relays }), - ); - } + control + .access() + .send_commands + .relays_update(friend_public_key.clone()); } } diff --git a/components/funder/src/router/handle_route.rs b/components/funder/src/router/handle_route.rs index 4512d9a28..9d33e1532 100644 --- a/components/funder/src/router/handle_route.rs +++ b/components/funder/src/router/handle_route.rs @@ -27,7 +27,6 @@ use crate::router::types::{ BackwardsOp, CurrencyInfo, RouterControl, RouterDbClient, RouterError, RouterInfo, RouterOutput, RouterState, SentRelay, }; -use crate::router::utils::flush::flush_friend; use crate::router::utils::move_token::is_pending_move_token; use crate::mutual_credit::{McCancel, McRequest, McResponse}; diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 4a8448dd6..31d8c904a 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -336,9 +336,8 @@ pub trait RouterDbClient { #[derive(Debug)] pub struct RouterOutput { - pub friends_messages: HashMap>, pub index_mutations: Vec, - pub updated_remote_relays: Vec, + // pub updated_remote_relays: Vec, pub incoming_requests: Vec<(Currency, McRequest)>, pub incoming_responses: Vec<(Currency, McResponse)>, pub incoming_cancels: Vec<(Currency, McCancel)>, @@ -347,23 +346,14 @@ pub struct RouterOutput { impl RouterOutput { pub fn new() -> Self { RouterOutput { - friends_messages: HashMap::new(), index_mutations: Vec::new(), - updated_remote_relays: Vec::new(), + // updated_remote_relays: Vec::new(), incoming_requests: Vec::new(), incoming_responses: Vec::new(), incoming_cancels: Vec::new(), } } - pub fn add_friend_message(&mut self, public_key: PublicKey, friend_message: FriendMessage) { - let entry = self - .friends_messages - .entry(public_key) - .or_insert(Vec::new()); - (*entry).push(friend_message); - } - pub fn add_index_mutation(&mut self, index_mutation: IndexMutation) { self.index_mutations.push(index_mutation); } diff --git a/components/funder/src/router/utils/mod.rs b/components/funder/src/router/utils/mod.rs index 5bb7b7705..ff8b8e871 100644 --- a/components/funder/src/router/utils/mod.rs +++ b/components/funder/src/router/utils/mod.rs @@ -1,3 +1,3 @@ -pub mod flush; +// pub mod flush; pub mod index_mutation; pub mod move_token; From d6b1e664cad36c0790840bb145addeecd4f140e9 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 13 Feb 2021 15:56:27 +0200 Subject: [PATCH 475/478] database: Fixed event type character --- components/database/src/create.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index 81469c528..d66340b4a 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -791,8 +791,8 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { "CREATE TABLE events( counter BLOB NOT NULL PRIMARY KEY, time INTEGER NOT NULL, - event_type TEXT CHECK (event_type IN ('P', 'I', 'R')) NOT NULL, - -- Event type: P: Payment, I: Invoice, R: Friend Removal + event_type TEXT CHECK (event_type IN ('P', 'I', 'F')) NOT NULL, + -- Event type: P: Payment, I: Invoice, F: Friend -- Information about the application that trigerred this event: app_public_key BLOB NOT NULL, app_name TEXT NOT NULL From e311b8308073079e03236b3113a173f0c6f964d4 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 13 Feb 2021 16:28:15 +0200 Subject: [PATCH 476/478] funder: Initial work on add/remove friend --- components/funder/src/router/handle_config.rs | 68 +++++++++++++++++++ components/funder/src/router/handler.rs | 6 ++ components/funder/src/router/types.rs | 14 ++++ 3 files changed, 88 insertions(+) diff --git a/components/funder/src/router/handle_config.rs b/components/funder/src/router/handle_config.rs index 19e3601c9..f98dcd6c7 100644 --- a/components/funder/src/router/handle_config.rs +++ b/components/funder/src/router/handle_config.rs @@ -317,3 +317,71 @@ pub async fn close_currency( Ok(()) } + +pub async fn add_friend( + control: &mut impl RouterControl, + friend_public_key: PublicKey, + friend_name: String, +) -> Result<(), RouterError> { + // First we make sure that the friend does not exist: + if control + .access() + .router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + .is_some() + { + return Ok(()); + } + + control + .access() + .router_db_client + .add_friend(friend_name, friend_public_key) + .await?; + Ok(()) +} + +pub async fn remove_friend( + control: &mut impl RouterControl, + friend_public_key: PublicKey, +) -> Result<(), RouterError> { + // TODO: A sudden change of balance is possible + // How to document this change correctly (As a friend event)? + + let tc_db_client = if let Some(tc_db_client) = control + .access() + .router_db_client + .tc_db_client(friend_public_key.clone()) + .await? + { + tc_db_client + } else { + // No such friend exists + return Ok(()); + }; + + // TODO: Somehow report balance changes: + if tc_db_client.get_tc_status().await?.is_consistent() { + todo!(); + // tc_db_client.list_balances(&mut self) -> AsyncOpStream<(Currency, McBalance)>; + } else { + todo!(); + } + + /* + fn add_friend_event( + &mut self, + friend_public_key: PublicKey, + balances_diff: HashMap, + ) -> AsyncOpResult<()>; + */ + + control + .access() + .router_db_client + .remove_friend(friend_public_key) + .await?; + + Ok(()) +} diff --git a/components/funder/src/router/handler.rs b/components/funder/src/router/handler.rs index 5a5a787ad..b5f82d393 100644 --- a/components/funder/src/router/handler.rs +++ b/components/funder/src/router/handler.rs @@ -48,6 +48,12 @@ pub async fn handle_router_op( RouterOp::CloseCurrency(friend_public_key, currency) => { handle_config::close_currency(control, friend_public_key, currency).await } + RouterOp::AddFriend(friend_public_key, friend_name) => { + handle_config::add_friend(control, friend_public_key, friend_name).await + } + RouterOp::RemoveFriend(friend_public_key) => { + handle_config::remove_friend(control, friend_public_key).await + } RouterOp::FriendMessage(friend_public_key, friend_message) => { handle_friend::incoming_friend_message(control, info, friend_public_key, friend_message) .await diff --git a/components/funder/src/router/types.rs b/components/funder/src/router/types.rs index 31d8c904a..015f11922 100644 --- a/components/funder/src/router/types.rs +++ b/components/funder/src/router/types.rs @@ -119,6 +119,16 @@ pub trait RouterDbClient { fn get_local_relays(&mut self) -> AsyncOpResult>; */ + /// Add a new friend + fn add_friend( + &mut self, + friend_name: String, + friend_public_key: PublicKey, + ) -> AsyncOpResult<()>; + + /// Remove friend + fn remove_friend(&mut self, friend_public_key: PublicKey) -> AsyncOpResult<()>; + /// A util to iterate over friends and mutating them. /// A None input will return the first friend. /// A None output means that there are no more friends. @@ -510,6 +520,10 @@ pub enum RouterOp { OpenCurrency(PublicKey, Currency), /// (friend_public_key, currency) CloseCurrency(PublicKey, Currency), + /// (friend_public_key, friend_name) + AddFriend(PublicKey, String), + /// (friend_public_key) + RemoveFriend(PublicKey), // Friend // ------ /// (friend_public_key, friend_message) From b669f49b93cac1662df1bcb8511fcdfda9143cc4 Mon Sep 17 00:00:00 2001 From: real Date: Sat, 13 Feb 2021 19:37:30 +0200 Subject: [PATCH 477/478] funder: set_inconsistent() should calculate reset terms --- .../funder/src/token_channel/token_channel.rs | 26 +++++++++++++++++-- components/funder/src/token_channel/types.rs | 11 +++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/components/funder/src/token_channel/token_channel.rs b/components/funder/src/token_channel/token_channel.rs index 2cd307391..5941487df 100644 --- a/components/funder/src/token_channel/token_channel.rs +++ b/components/funder/src/token_channel/token_channel.rs @@ -334,7 +334,6 @@ async fn create_reset_token( } /// Set token channel to be inconsistent -/// Local reset terms are automatically calculated async fn set_inconsistent( tc_client: &mut impl TcDbClient, identity_client: &mut IdentityClient, @@ -360,13 +359,36 @@ async fn set_inconsistent( ) .await?; + let balances = { + let mut balances = HashMap::::new(); + let mut balances_stream = tc_client.list_balances(); + while let Some(res) = balances_stream.next().await { + let (currency, mc_balance) = res?; + balances.insert(currency, mc_balance); + } + balances + }; + tc_client - .set_inconsistent( + .set_inconsistent_local_terms( local_reset_token.clone(), local_reset_move_token_counter.clone(), ) .await?; + for (currency, mc_balance) in balances { + let reset_balance = ResetBalance { + balance: todo!(), + // TODO: How to calculate in_fees/out_fees? We need to take into account current + // pending requests. + in_fees: todo!(), + out_fees: todo!(), + }; + tc_client + .add_local_reset_balance(currency, reset_balance) + .await?; + } + Ok((local_reset_token, local_reset_move_token_counter)) } diff --git a/components/funder/src/token_channel/types.rs b/components/funder/src/token_channel/types.rs index 1107d97a9..22fe17b28 100644 --- a/components/funder/src/token_channel/types.rs +++ b/components/funder/src/token_channel/types.rs @@ -72,12 +72,21 @@ pub trait TcDbClient { move_token: MoveToken, move_token_counter: u128, ) -> AsyncOpResult<()>; - fn set_inconsistent( + + fn set_inconsistent_local_terms( &mut self, local_reset_token: Signature, local_reset_move_token_counter: u128, ) -> AsyncOpResult<()>; + /// Add a new local reset balance to the remote reset terms list + /// Can only be called if we already called `set_inconsistent_local_terms()`. + fn add_local_reset_balance( + &mut self, + currency: Currency, + reset_balance: ResetBalance, + ) -> AsyncOpResult<()>; + /// Set remote terms for reset. Can only be called if we are in inconsistent state. fn set_inconsistent_remote_terms( &mut self, From 4b538d4e802fe2377f008b253339a49fe57177cf Mon Sep 17 00:00:00 2001 From: real Date: Sat, 13 Feb 2021 21:31:03 +0200 Subject: [PATCH 478/478] funder: Commented out pending debt columns --- components/database/src/create.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/database/src/create.rs b/components/database/src/create.rs index d66340b4a..d109acb57 100644 --- a/components/database/src/create.rs +++ b/components/database/src/create.rs @@ -238,8 +238,9 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { currency TEXT NOT NULL, balance BLOB NOT NULL, - local_pending_debt BLOB NOT NULL, - remote_pending_debt BLOB NOT NULL, + -- TODO: Pending credits be calculated automatically from the pending requests: + -- local_pending_debt BLOB NOT NULL, + -- remote_pending_debt BLOB NOT NULL, in_fees BLOB NOT NULL, out_fees BLOB NOT NULL, @@ -344,8 +345,9 @@ fn create_database(conn: &mut Connection) -> rusqlite::Result<()> { friend_public_key BLOB NOT NULL, currency TEXT NOT NULL, balance BLOB NOT NULL, - local_pending_debt BLOB NOT NULL, - remote_pending_debt BLOB NOT NULL, + -- TODO: Pending credits be calculated automatically from the pending requests: + -- local_pending_debt BLOB NOT NULL, + -- remote_pending_debt BLOB NOT NULL, in_fees BLOB NOT NULL, out_fees BLOB NOT NULL, PRIMARY KEY(friend_public_key, currency),