Skip to content
Permalink
Browse files

Settlement Engine Framework and Ethereum Ledger Settlement Engine (#125)

* feat(eth-se): Add Settlement Engine trait and Redis implementation of store

* improvement(settlement): minor refactor in handling of idempotency

* fix(crate): Remove ilp_address from SettlementEngineDetails

Fixes #144

* feat(settlement-engine): Add RFC536 API implementation

* feat(settlement-engine): Add Ethereum Ledger settlement engine

* feat(api) register account in SE when registering on the connector

if it fails, retry until it succeeds

* crate: add settlement engine to workspace

* Add examples and e2e test from a user's perspective
  • Loading branch information...
gakonst committed Jul 28, 2019
1 parent b5f47e6 commit 6b6dec026a15d65fe05cd155a594b9cb52b22859
Showing with 3,961 additions and 490 deletions.
  1. +10 −1 .circleci/config.yml
  2. +4 −0 Cargo.toml
  3. +3 −0 crates/interledger-api/Cargo.toml
  4. +0 −1 crates/interledger-api/src/lib.rs
  5. +52 −3 crates/interledger-api/src/routes/accounts.rs
  6. +1 −0 crates/interledger-service/Cargo.toml
  7. +3 −1 crates/interledger-service/src/lib.rs
  8. +45 −0 crates/interledger-settlement-engines/Cargo.toml
  9. +5 −0 crates/interledger-settlement-engines/README.md
  10. +401 −0 crates/interledger-settlement-engines/src/api.rs
  11. +943 −0 crates/interledger-settlement-engines/src/engines/ethereum_ledger/eth_engine.rs
  12. +19 −0 crates/interledger-settlement-engines/src/engines/ethereum_ledger/fixtures.rs
  13. +15 −0 crates/interledger-settlement-engines/src/engines/ethereum_ledger/mod.rs
  14. +309 −0 crates/interledger-settlement-engines/src/engines/ethereum_ledger/test_helpers.rs
  15. +128 −0 crates/interledger-settlement-engines/src/engines/ethereum_ledger/types.rs
  16. +174 −0 crates/interledger-settlement-engines/src/engines/ethereum_ledger/utils.rs
  17. +1 −0 crates/interledger-settlement-engines/src/engines/mod.rs
  18. +51 −0 crates/interledger-settlement-engines/src/lib.rs
  19. +189 −0 crates/interledger-settlement-engines/src/main.rs
  20. +31 −0 crates/interledger-settlement-engines/src/stores/mod.rs
  21. +2 −0 crates/interledger-settlement-engines/src/stores/redis_ethereum_ledger/mod.rs
  22. +385 −0 crates/interledger-settlement-engines/src/stores/redis_ethereum_ledger/store.rs
  23. +156 −0 crates/interledger-settlement-engines/src/stores/redis_store_common.rs
  24. +2 −0 crates/interledger-settlement-engines/src/stores/test_helpers/mod.rs
  25. +188 −0 crates/interledger-settlement-engines/src/stores/test_helpers/redis_helpers.rs
  26. +39 −0 crates/interledger-settlement-engines/src/stores/test_helpers/store_helpers.rs
  27. +2 −1 crates/interledger-settlement/Cargo.toml
  28. +284 −334 crates/interledger-settlement/src/api.rs
  29. +2 −3 crates/interledger-settlement/src/client.rs
  30. +1 −1 crates/interledger-settlement/src/fixtures.rs
  31. +11 −6 crates/interledger-settlement/src/lib.rs
  32. +25 −34 crates/interledger-settlement/src/message_service.rs
  33. +11 −10 crates/interledger-settlement/src/test_helpers.rs
  34. +5 −37 crates/interledger-store-redis/src/account.rs
  35. +40 −35 crates/interledger-store-redis/src/store.rs
  36. +0 −3 crates/interledger-store-redis/tests/common/fixtures.rs
  37. +0 −1 crates/interledger-store-redis/tests/routing_test.rs
  38. +4 −8 crates/interledger-store-redis/tests/settlement_test.rs
  39. +0 −2 crates/interledger/src/main.rs
  40. +1 −1 crates/interledger/src/node.rs
  41. +0 −2 crates/interledger/tests/btp_end_to_end.rs
  42. +0 −6 crates/interledger/tests/three_nodes.rs
  43. +238 −0 examples/README.md
  44. +8 −0 examples/alice.yaml
  45. +8 −0 examples/bob.yaml
  46. +14 −0 examples/init.sh
  47. +38 −0 examples/pay_dump.sh
  48. +113 −0 examples/settlements_test.sh
@@ -27,12 +27,21 @@ jobs:
sudo apt-get update
sudo apt-get -t stretch-backports install redis-server
redis-server --version
- run:
name: Install node and ganache
command: |
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
source ~/.nvm/nvm.sh
nvm install node
npm install -g ganache-cli
- run:
name: Build
command: cargo build --all-features --all-targets
- run:
name: Test
command: cargo test --all --all-features
command: |
source ~/.nvm/nvm.sh # load node paths for ganache-cli
cargo test --all --all-features
environment:
RUST_BACKTRACE: "1"
- run:
@@ -16,4 +16,8 @@ members = [
"./crates/interledger-store-memory",
"./crates/interledger-store-redis",
"./crates/interledger-stream",
"./crates/interledger-settlement-engines",
]

[profile.dev]
codegen-units = 1

This comment has been minimized.

Copy link
@bstrie

bstrie Sep 18, 2019

Collaborator

@gakonst Do you remember the rationale behind this addition? Was just poking around and wondering whether we couldn't eke out some build time improvements by using multiple codegen-units.

@@ -24,6 +24,9 @@ log = "0.4.6"
serde = "1.0.89"
serde_json = "1.0.39"
tower-web = "0.3.7"
reqwest = "0.9.18"
url = "1.7.2"
tokio-retry = "0.2.0"

[badges]
circle-ci = { repository = "emschwartz/interledger-rs" }
@@ -72,7 +72,6 @@ pub struct AccountDetails {
pub packets_per_minute_limit: Option<u32>,
pub settlement_engine_url: Option<String>,
pub settlement_engine_asset_scale: Option<u8>,
pub settlement_engine_ilp_address: Option<Address>,
}

pub struct NodeApi<S, I> {
@@ -7,11 +7,14 @@ use hyper::Response;
use interledger_http::{HttpAccount, HttpStore};
use interledger_service::Account;
use interledger_service_util::BalanceStore;
use log::{debug, error};
use log::{debug, error, trace};
use reqwest::r#async::Client;
use serde::Serialize;
use serde_json::{json, Value};
use std::str::FromStr;
use tokio_retry::{strategy::FixedInterval, Retry};
use tower_web::{impl_web, Response};
use url::Url;

#[derive(Serialize, Response, Debug)]
#[web(status = "200")]
@@ -34,6 +37,8 @@ pub struct AccountsApi<T> {
admin_api_token: String,
}

const MAX_RETRIES: usize = 10;

impl_web! {
impl<T, A> AccountsApi<T>
where T: NodeStore<Account = A> + HttpStore<Account = A> + BalanceStore<Account = A>,
@@ -65,10 +70,54 @@ impl_web! {
fn post_accounts(&self, body: AccountDetails, authorization: String) -> impl Future<Item = Value, Error = Response<()>> {
// TODO don't allow accounts to be overwritten
// TODO try connecting to that account's websocket server if it has a btp_uri
let se_url = body.settlement_engine_url.clone();
self.validate_admin(authorization)
.and_then(move |store| store.insert_account(body)
.and_then(|account| Ok(json!(account)))
.map_err(|_| Response::builder().status(500).body(()).unwrap()))
.map_err(|_| Response::builder().status(500).body(()).unwrap())
.and_then(|account| {
// if the account had a SE associated with it, then register
// the account in the SE.
if let Some(se_url) = se_url {
let id = account.id();
Either::A(result(Url::parse(&se_url))
.map_err(|_| Response::builder().status(500).body(()).unwrap())
.and_then(move |mut se_url| {
se_url
.path_segments_mut()
.expect("Invalid settlement engine URL")
.push("accounts")
.push(&id.to_string());
trace!(
"Sending account {} creation request to settlement engine: {:?}",
id,
se_url.clone()
);
let action = move || {
Client::new().post(se_url.clone())
.send()
.map_err(move |err| {
error!("Error sending account creation command to the settlement engine: {:?}", err)
})
.and_then(move |response| {
if response.status().is_success() {
trace!("Account {} created on the SE", id);
Ok(())
} else {
error!("Error creating account. Settlement engine responded with HTTP code: {}", response.status());
Err(())
}
})
};
Retry::spawn(FixedInterval::from_millis(2000).take(MAX_RETRIES), action)
.map_err(|_| Response::builder().status(500).body(()).unwrap())
.and_then(move |_| {
Ok(json!(account))
})
}))
} else {
Either::B(ok(json!(account)))
}
}))
}

#[get("/accounts")]
@@ -10,3 +10,4 @@ repository = "https://github.com/emschwartz/interledger-rs"
[dependencies]
futures = "0.1.25"
interledger-packet = { path = "../interledger-packet", version = "0.2.1" }
serde = "1.0.94"
@@ -36,14 +36,16 @@ use std::{
str::FromStr,
};

use serde::Serialize;

/// The base trait that Account types from other Services extend.
/// This trait only assumes that the account has an ID that can be compared with others.
///
/// Each service can extend the Account type to include additional details they require.
/// Store implementations will implement these Account traits for a concrete type that
/// they will load from the database.
pub trait Account: Clone + Send + Sized + Debug {
type AccountId: Eq + Hash + Debug + Display + Default + FromStr + Send + Sync + Copy;
type AccountId: Eq + Hash + Debug + Display + Default + FromStr + Send + Sync + Copy + Serialize;

fn id(&self) -> Self::AccountId;
}
@@ -0,0 +1,45 @@
[package]
name = "interledger-settlement-engines"
version = "0.1.0"
authors = ["Georgios Konstantopoulos <me@gakonst.com>"]
edition = "2018"

[dependencies]
tower-web = "0.3.7"
hex = "0.3.2"
ethereum-tx-sign = { git = "https://github.com/gakonst/ethereum-tx-sign", branch = "exported-web3" }
log = "0.4.6"
tokio = "0.1.21"
hyper = "0.12.31"
futures = "0.1.25"
interledger-service = { path = "../interledger-service", version = "0.2.1" }
interledger-settlement = { path = "../interledger-settlement", version = "0.1.0" }
interledger-service-util = { path = "../interledger-service-util", version = "0.2.1" }
interledger-store-redis = { path = "../interledger-store-redis", version = "0.2.1" }
interledger-ildcp = { path = "../interledger-ildcp", version = "0.2.1" }
ethabi = "6.1.0"
serde = "1.0.91"
serde_json = "1.0.40"
json = "0.11.14"
bytes = "0.4.12"
ring = "0.14.6"
tokio-executor = "0.1.8"
url = "1.7.2"
reqwest = "0.9.18"
env_logger = "0.6.2"
uuid = { version = "0.7.4", features = ["serde", "v4"] }
tokio-retry = "0.2.0"
redis = { version = "0.10.0", features = [ "with-unix-sockets" ] }
hashbrown = "0.5.0"
http = "0.1.17"
clap = "2.32.0"
clarity = { git = "https://github.com/gakonst/clarity" }
sha3 = "0.8.2"

[dev-dependencies]
lazy_static = "1.3"
mockito = "0.18.0"
parking_lot = "0.9.0"
net2 = "0.2.33"
os_type = "2.2.0"
rand = "0.7.0"
@@ -0,0 +1,5 @@
# Settlement Engines Crate

## Implemented Engines

- Ethereum

0 comments on commit 6b6dec0

Please sign in to comment.
You can’t perform that action at this time.