Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add V1 fallback mode to the proxy #83

Merged
merged 1 commit into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading