Skip to content

Commit

Permalink
Merge pull request #83 from nyonson/proxy-v1-retry
Browse files Browse the repository at this point in the history
Add V1 fallback mode to the proxy
  • Loading branch information
rustaceanrob authored Oct 23, 2024
2 parents 96521ee + 49a4d98 commit fc94b9a
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 100 deletions.
2 changes: 2 additions & 0 deletions proxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ A proxy sidecar process which allows V1-only clients to communicate over the V2

`cargo run --bin proxy`

The `--v1-fallback=true` flag can be used to fallback to the V1 protocol if the remote client does not support V2.

## Testing with Nakamoto

[Nakamoto](https://github.com/cloudhead/nakamoto) is a BIP-157/BIP-158 Light Client that communicates over the Bitcoin P2P network. With a single change, Nakamoto may be modified to use the proxy. This patch hardcodes Nakamoto to connect to the localhost on port 1324 where the proxy should be running.
Expand Down
6 changes: 6 additions & 0 deletions proxy/config_spec.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,9 @@ name = "network"
type = "String"
default = "\"bitcoin\".into()"
doc = "The bitcoin network to operate on"

[[param]]
name = "v1_fallback"
type = "bool"
default = "false"
doc = "Fallback to the V1 protocol if V2 fails"
78 changes: 67 additions & 11 deletions proxy/src/bin/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::str::FromStr;

use bip324::{
serde::{deserialize, serialize},
AsyncProtocol, PacketType, Role,
AsyncProtocol, PacketType, ProtocolFailureSuggestion, Role,
};
use bip324_proxy::{V1ProtocolReader, V1ProtocolWriter};
use bitcoin::Network;
Expand All @@ -17,8 +17,51 @@ use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};

configure_me::include_config!();

/// Validate and bootstrap proxy connection.
async fn proxy_conn(client: TcpStream, network: Network) -> Result<(), bip324_proxy::Error> {
/// A v1 to v1 proxy for use as a fallback.
async fn v1_proxy(client: TcpStream, network: Network) -> Result<(), bip324_proxy::Error> {
let remote_ip = bip324_proxy::peek_addr(&client, network).await?;

info!("Initialing remote connection {}.", remote_ip);
let remote = TcpStream::connect(remote_ip).await?;

let (client_reader, client_writer) = client.into_split();
let (remote_reader, remote_writer) = remote.into_split();

let mut v1_client_reader = V1ProtocolReader::new(client_reader);
let mut v1_client_writer = V1ProtocolWriter::new(network, client_writer);
let mut v1_remote_reader = V1ProtocolReader::new(remote_reader);
let mut v1_remote_writer = V1ProtocolWriter::new(network, remote_writer);

info!("Setting up V1 proxy.");

loop {
select! {
result = v1_client_reader.read() => {
let msg = result?;
debug!(
"Read {} message from client, writing to remote.",
msg.command()
);
v1_remote_writer.write(msg).await?;
},
result = v1_remote_reader.read() => {
let msg = result?;
debug!(
"Read {} message from remote, writing to client.",
msg.command()
);
v1_client_writer.write(msg).await?;
},
}
}
}

/// Validate and bootstrap a v1 to v2 proxy connection.
async fn v2_proxy(
client: TcpStream,
network: Network,
v1_fallback: bool,
) -> Result<(), bip324_proxy::Error> {
let remote_ip = bip324_proxy::peek_addr(&client, network)
.await
.expect("peek address");
Expand All @@ -34,7 +77,7 @@ async fn proxy_conn(client: TcpStream, network: Network) -> Result<(), bip324_pr
let remote_reader = remote_reader.compat();
let remote_writer = remote_writer.compat_write();

let protocol = AsyncProtocol::new(
let protocol = match AsyncProtocol::new(
network,
Role::Initiator,
None,
Expand All @@ -43,15 +86,22 @@ async fn proxy_conn(client: TcpStream, network: Network) -> Result<(), bip324_pr
remote_writer,
)
.await
.expect("protocol establishment");
{
Ok(p) => p,
Err(bip324::ProtocolError::Io(_, ProtocolFailureSuggestion::RetryV1)) if v1_fallback => {
info!("V2 protocol failed, falling back to V1...");
return v1_proxy(client, network).await;
}
Err(e) => return Err(e.into()),
};

let (client_reader, client_writer) = client.into_split();
let mut v1_client_reader = V1ProtocolReader::new(client_reader);
let mut v1_client_writer = V1ProtocolWriter::new(network, client_writer);

let (mut remote_reader, mut remote_writer) = protocol.into_split();

info!("Setting up proxy.");
info!("Setting up V2 proxy.");

loop {
select! {
Expand Down Expand Up @@ -92,21 +142,27 @@ async fn main() {
let (config, _) = Config::including_optional_config_files::<&[&str]>(&[]).unwrap_or_exit();
let network = Network::from_str(&config.network).expect("parse-able network");

let proxy = TcpListener::bind((&*config.bind_host, config.bind_port))
let local = TcpListener::bind((&*config.bind_host, config.bind_port))
.await
.expect("Failed to bind to proxy port.");
info!(
"Listening for connections on {}:{}",
config.bind_host, config.bind_port,
"Listening for connections on {}:{} with V1 fallback {}.",
config.bind_host,
config.bind_port,
if config.v1_fallback {
"enabled"
} else {
"disabled"
},
);
loop {
let (stream, _) = proxy
let (stream, _) = local
.accept()
.await
.expect("Failed to accept inbound connection.");
// Spawn a new task per connection.
tokio::spawn(async move {
match proxy_conn(stream, network).await {
match v2_proxy(stream, network, config.v1_fallback).await {
Ok(_) => {
info!("Proxy establilshed.");
}
Expand Down
86 changes: 0 additions & 86 deletions proxy/src/bin/v1.rs

This file was deleted.

6 changes: 3 additions & 3 deletions proxy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub enum Error {
WrongCommand,
Serde,
Io(std::io::Error),
Protocol(bip324::Error),
Protocol(bip324::ProtocolError),
}

impl fmt::Display for Error {
Expand All @@ -51,8 +51,8 @@ impl fmt::Display for Error {

impl std::error::Error for Error {}

impl From<bip324::Error> for Error {
fn from(e: bip324::Error) -> Self {
impl From<bip324::ProtocolError> for Error {
fn from(e: bip324::ProtocolError) -> Self {
Error::Protocol(e)
}
}
Expand Down

0 comments on commit fc94b9a

Please sign in to comment.