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

Sbtc Changes #8

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .github/workflows/bitcoin-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ jobs:
- tests::neon_integrations::test_problematic_microblocks_are_not_mined
- tests::neon_integrations::test_problematic_microblocks_are_not_relayed_or_stored
- tests::neon_integrations::push_boot_receipts
- tests::neon_integrations::test_submit_and_observe_sbtc_ops
- tests::epoch_205::test_dynamic_db_method_costs
- tests::epoch_205::transition_empty_blocks
- tests::epoch_205::test_cost_limit_switch_version205
Expand Down
4 changes: 4 additions & 0 deletions Cargo.lock

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

7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ path = "src/clarity_cli_main.rs"
name = "blockstack-cli"
path = "src/blockstack_cli.rs"

[[bin]]
name = "relay-server"
path = "contrib/tools/relay-server/src/main.rs"

[dependencies]
rand = "0.7.3"
rand_chacha = "=0.2.2"
Expand Down Expand Up @@ -131,4 +135,5 @@ members = [
".",
"clarity",
"stx-genesis",
"testnet/stacks-node"]
"testnet/stacks-node",
"contrib/tools/relay-server"]
9 changes: 9 additions & 0 deletions clarity/src/vm/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1425,6 +1425,15 @@ impl From<StandardPrincipalData> for StacksAddress {
}
}

impl From<PrincipalData> for StacksAddress {
fn from(principal: PrincipalData) -> Self {
match principal {
PrincipalData::Standard(standard_principal) => standard_principal.into(),
PrincipalData::Contract(contract_principal) => contract_principal.issuer.into(),
}
}
}

impl From<StandardPrincipalData> for Value {
fn from(principal: StandardPrincipalData) -> Self {
Value::Principal(PrincipalData::from(principal))
Expand Down
8 changes: 8 additions & 0 deletions contrib/tools/relay-server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "relay-server"
version = "0.0.1"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
22 changes: 22 additions & 0 deletions contrib/tools/relay-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# A Relay Server

The `relay` server is an HTTP service that has two functions:

- Accepting messages and storing all of them. `POST` method.
For example, `curl 'http://127.0.0.1:9776' -X POST -d 'message'`.
- Returning the messages in the same order as received for each client.
For example, `curl 'http://127.0.0.1:9776/?id=alice'`.

## Start the `relay-server` server

```sh
cargo run --bin relay-server
```

The default address is `http://127.0.0.1:9776`.

## Integration Test

1. Start the server `cargo run --bit relay-server`
2. Run `./test.sh` in another terminal.
3. Close the server using `Ctrl+C`.
150 changes: 150 additions & 0 deletions contrib/tools/relay-server/src/http.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
use std::{
collections::HashMap,
io::{Error, Read},
};

use crate::to_io_result::ToIoResult;

#[derive(Debug)]
pub struct Request {
pub method: String,
pub url: String,
pub protocol: String,
pub headers: HashMap<String, String>,
pub content: Vec<u8>,
}

pub trait RequestEx: Read {
fn read_http_request(&mut self) -> Result<Request, Error> {
let mut read_byte = || -> Result<u8, Error> {
let mut buf = [0; 1];
self.read_exact(&mut buf)?;
Ok(buf[0])
};

let mut read_line = || -> Result<String, Error> {
let mut result = String::default();
loop {
let b = read_byte()?;
if b == 13 {
break;
};
result.push(b as char);
}
assert_eq!(read_byte()?, 10);
Ok(result)
};

// read and parse the request line
let request_line = read_line()?;
let mut split = request_line.split(' ');
let mut next = || {
split
.next()
.to_io_result("invalid HTTP request line")
.map(|x| x.to_string())
};
let method = next()?;
let url = next()?;
let protocol = next()?;

// read and parse headers
let mut headers = HashMap::default();
loop {
let line = read_line()?;
if line.is_empty() {
break;
}
let (name, value) = line.split_once(':').to_io_result("")?;
headers.insert(name.to_lowercase(), value.trim().to_string());
}

// read content
let content_length = headers.get("content-length").map_or(Ok(0), |v| {
v.parse::<usize>().to_io_result("invalid content-length")
})?;
let mut content = vec![0; content_length];
self.read_exact(content.as_mut_slice())?;

// return the message
Ok(Request {
method,
url,
protocol,
headers,
content,
})
}
}

impl<T: Read> RequestEx for T {}

#[cfg(test)]
mod tests {
use std::{io::Cursor, str::from_utf8};

use crate::http::RequestEx;

#[test]
fn test() {
const REQUEST: &str = "\
POST / HTTP/1.1\r\n\
Content-Length: 6\r\n\
\r\n\
Hello!";
let mut read = Cursor::new(REQUEST);
let rm = read.read_http_request().unwrap();
assert_eq!(rm.method, "POST");
assert_eq!(rm.url, "/");
assert_eq!(rm.protocol, "HTTP/1.1");
assert_eq!(rm.headers.len(), 1);
assert_eq!(rm.headers["content-length"], "6");
assert_eq!(from_utf8(&rm.content), Ok("Hello!"));
assert_eq!(read.position(), REQUEST.len() as u64);
}

#[test]
fn incomplete_message_test() {
const REQUEST: &str = "\
POST / HTTP/1.1\r\n\
Content-Leng";
let mut read = Cursor::new(REQUEST);
let _ = read.read_http_request().unwrap_err();
}

#[test]
fn incomplete_content_test() {
const REQUEST: &str = "\
POST / HTTP/1.1\r\n\
Content-Length: 6\r\n\
\r\n";
let mut read = Cursor::new(REQUEST);
let _ = read.read_http_request().unwrap_err();
}

#[test]
fn invalid_message_test() {
const REQUEST: &str = "\
POST / HTTP/1.1\r\n\
Content-Length 6\r\n\
\r\n\
Hello!";
let mut read = Cursor::new(REQUEST);
let _ = read.read_http_request().unwrap_err();
}

#[test]
fn no_content_test() {
const REQUEST: &str = "\
GET /images/logo.png HTTP/1.1\r\n\
\r\n";
let mut read = Cursor::new(REQUEST);
let rm = read.read_http_request().unwrap();
assert_eq!(rm.method, "GET");
assert_eq!(rm.url, "/images/logo.png");
assert_eq!(rm.protocol, "HTTP/1.1");
assert!(rm.headers.is_empty());
assert!(rm.content.is_empty());
assert_eq!(read.position(), REQUEST.len() as u64);
}
}
22 changes: 22 additions & 0 deletions contrib/tools/relay-server/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use std::net::TcpListener;

use server::ServerEx;

use crate::state::State;

mod http;
mod server;
mod state;
mod to_io_result;
mod url;

fn main() {
let mut state = State::default();
let listner = TcpListener::bind("127.0.0.1:9776").unwrap();
for stream_or_error in listner.incoming() {
let f = || stream_or_error?.update_state(&mut state);
if let Err(e) = f() {
eprintln!("IO error: {e}");
}
}
}
Loading