Skip to content

Commit

Permalink
feat(api): Make ILDCP and RouteControlRequest when adding a parent
Browse files Browse the repository at this point in the history
When a parent account is added, we must update our ILP Address in the store, so that the addresses of children accounts we add are calculated properly in the future. This is done via an ILDCP Request to the parent.

We also need the parent's routes which we may care about, hence we send a RouteControlRequest as well.
  • Loading branch information
gakonst committed Sep 24, 2019
1 parent af7311a commit d95be4c
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 8 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/interledger-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interledger-service-util = { path = "../interledger-service-util", version = "^0
interledger-settlement = { path = "../interledger-settlement", version = "^0.1.1-alpha.1"}
interledger-spsp = { path = "../interledger-spsp", version = "^0.2.2-alpha.1"}
interledger-stream = { path = "../interledger-stream", version = "^0.2.2-alpha.1" }
interledger-ccp = { path = "../interledger-ccp", version = "^0.1.1-alpha.1"}
log = "0.4.6"
serde = "1.0.99"
serde_json = "1.0.39"
Expand Down
21 changes: 17 additions & 4 deletions crates/interledger-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use futures::Future;
use interledger_http::{HttpAccount, HttpServer as IlpOverHttpServer, HttpStore};
use interledger_packet::Address;
use interledger_router::RouterStore;
use interledger_service::{Account, AddressStore, IncomingService, Username};
use interledger_service::{Account, AddressStore, IncomingService, OutgoingService, Username};
use interledger_service_util::{BalanceStore, ExchangeRateStore};
use interledger_settlement::{SettlementAccount, SettlementStore};
use interledger_stream::StreamNotificationsStore;
Expand All @@ -15,6 +15,7 @@ use std::{
};
use warp::{self, Filter};
mod routes;
use interledger_ccp::{CcpRoutingAccount, RoutingRelation};

pub(crate) mod http_retry;

Expand Down Expand Up @@ -124,15 +125,16 @@ impl Display for ApiError {

impl StdError for ApiError {}

pub struct NodeApi<S, I> {
pub struct NodeApi<S, I, O> {
store: S,
admin_api_token: String,
default_spsp_account: Option<Username>,
incoming_handler: I,
outgoing_handler: O,
server_secret: Bytes,
}

impl<S, I, A> NodeApi<S, I>
impl<S, I, O, A> NodeApi<S, I, O>
where
S: NodeStore<Account = A>
+ HttpStore<Account = A>
Expand All @@ -142,19 +144,29 @@ where
+ RouterStore
+ ExchangeRateStore,
I: IncomingService<A> + Clone + Send + Sync + 'static,
A: Account + HttpAccount + SettlementAccount + Serialize + Send + Sync + 'static,
O: OutgoingService<A> + Clone + Send + Sync + 'static,
A: CcpRoutingAccount
+ Account
+ HttpAccount
+ SettlementAccount
+ Serialize
+ Send
+ Sync
+ 'static,
{
pub fn new(
server_secret: Bytes,
admin_api_token: String,
store: S,
incoming_handler: I,
outgoing_handler: O,
) -> Self {
NodeApi {
store,
admin_api_token,
default_spsp_account: None,
incoming_handler,
outgoing_handler,
server_secret,
}
}
Expand All @@ -176,6 +188,7 @@ where
self.admin_api_token.clone(),
self.default_spsp_account,
self.incoming_handler,
self.outgoing_handler,
self.store.clone(),
))
.or(routes::node_settings_api(self.admin_api_token, self.store))
Expand Down
85 changes: 81 additions & 4 deletions crates/interledger-api/src/routes/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@ use futures::{
future::{err, ok, result, Either},
Future, Stream,
};
use interledger_ccp::{CcpRoutingAccount, Mode, RouteControlRequest, RoutingRelation};
use interledger_http::{HttpAccount, HttpStore};
use interledger_ildcp::IldcpRequest;
use interledger_ildcp::IldcpResponse;
use interledger_router::RouterStore;
use interledger_service::{Account, AuthToken, IncomingService, Username};
use interledger_service::{
Account, AddressStore, AuthToken, IncomingService, OutgoingRequest, OutgoingService, Username,
};
use interledger_service_util::{BalanceStore, ExchangeRateStore};
use interledger_spsp::{pay, SpspResponder};
use interledger_stream::{PaymentNotification, StreamNotificationsStore};
use log::{debug, error, trace};
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::convert::TryFrom;
use std::time::Duration;
use url::Url;
use warp::{self, Filter};
Expand All @@ -26,22 +32,24 @@ struct SpspPayRequest {
source_amount: u64,
}

pub fn accounts_api<I, S, A>(
pub fn accounts_api<I, O, S, A>(
server_secret: Bytes,
admin_api_token: String,
default_spsp_account: Option<Username>,
incoming_handler: I,
outgoing_handler: O,
store: S,
) -> warp::filters::BoxedFilter<(impl warp::Reply,)>
where
I: IncomingService<A> + Clone + Send + Sync + 'static,
O: OutgoingService<A> + Clone + Send + Sync + 'static,
S: NodeStore<Account = A>
+ HttpStore<Account = A>
+ BalanceStore<Account = A>
+ StreamNotificationsStore<Account = A>
+ ExchangeRateStore
+ RouterStore,
A: Account + HttpAccount + Serialize + 'static,
A: CcpRoutingAccount + Account + HttpAccount + Serialize + Send + Sync + 'static,
{
// TODO can we make any of the Filters const or put them in lazy_static?

Expand Down Expand Up @@ -121,16 +129,29 @@ where
.and(warp::body::json())
.and(with_store.clone())
.and_then(move |account_details: AccountDetails, store: S| {
let store_clone = store.clone();
let handler = outgoing_handler.clone();
let settlement_engine_url = account_details.settlement_engine_url.clone();
let http_client = http_client.clone();
store.insert_account(account_details)
.map_err(|_| {
warp::reject::custom(ApiError::InternalServerError)
})
.and_then(move |account: A| {
let fut = if account.routing_relation() == RoutingRelation::Parent {
Either::A(
get_address_from_parent_and_update_routes(handler, account.clone(), store_clone)
.map_err(|_| {
warp::reject::custom(ApiError::InternalServerError)
})
)
} else {
Either::B(ok(()))
};
let http_client = http_client.clone();
// Register the account with the settlement engine
// if a settlement_engine_url was configured on the account
fut.and_then(move |_|
if let Some(se_url) = settlement_engine_url {
let id = account.id();
Either::A(result(Url::parse(&se_url))
Expand Down Expand Up @@ -163,7 +184,7 @@ where
}))
} else {
Either::B(ok(account))
}
})
})
.and_then(|account: A| {
Ok(warp::reply::json(&account))
Expand Down Expand Up @@ -408,3 +429,59 @@ where
.or(post_payments)
.boxed()
}

fn get_address_from_parent_and_update_routes<S, A, T>(
mut service: S,
parent: A,
store: T,
) -> impl Future<Item = (), Error = ()>
where
S: OutgoingService<A> + Clone + Send + Sync + 'static,
A: CcpRoutingAccount + Clone + Send + Sync + 'static,
T: AddressStore + Clone + Send + Sync + 'static,
{
let prepare = IldcpRequest {}.to_prepare();
service
.send_request(OutgoingRequest {
from: parent.clone(), // Does not matter what we put here, they will get the account from the HTTP/BTP credentials
to: parent.clone(),
prepare,
original_amount: 0,
})
.map_err(|err| error!("Error getting ILDCP info: {:?}", err))
.and_then(|fulfill| {
let response = IldcpResponse::try_from(fulfill.into_data().freeze()).map_err(|err| {
error!(
"Unable to parse ILDCP response from fulfill packet: {:?}",
err
);
});
debug!("Got ILDCP response: {:?}", response);
let ilp_address = match response {
Ok(info) => info.ilp_address(),
Err(_) => return err(()),
};
ok(ilp_address)
})
.and_then(move |ilp_address| store.set_ilp_address(ilp_address))
.and_then(move |_| {
// Get the parent's routes for us
let prepare = RouteControlRequest {
mode: Mode::Sync,
last_known_epoch: 0,
last_known_routing_table_id: [0; 16],
features: Vec::new(),
}
.to_prepare();
debug!("Asking for routes from {:?}", parent.clone());
service
.send_request(OutgoingRequest {
from: parent.clone(),
to: parent.clone(),
original_amount: prepare.amount(),
prepare: prepare.clone(),
})
.map_err(move |err| error!("Got error when trying to update routes {:?}", err))
})
.and_then(move |_| Ok(()))
}

0 comments on commit d95be4c

Please sign in to comment.