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 http server to subspace-gateway. #3286

Merged
merged 6 commits into from
Dec 9, 2024
Merged

Conversation

shamil-gadelshin
Copy link
Member

This PR adds an HTTP endpoint to subspace-gateway as an update to AutoDrive Gateway project. It reuses the object fetcher and keeps the existing RPC-server. The new API serves files reconstructed from DSN by object fetcher using object mappings received from the object mapping indexer.

Changes

  • Refactor run command to rpc command and move shared code
  • Add http command to serve requests on http://<IP>:<PORT>/data/{object_hash} using actix-web framework.

Code contributor checklist:

clostao
clostao previously approved these changes Dec 4, 2024
Copy link
Contributor

@teor2345 teor2345 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good start, but it is missing remote input validation, which could introduce a security vulnerability. It’s also missing object data hash validation, but I don’t think that’s a security issue.

I also have a few suggestions to avoid code duplication, and a bunch of comment updates. Feel free to ignore the comment stuff for now.

Let me know if you’d like me to help with any of these changes.

crates/subspace-gateway/Cargo.toml Outdated Show resolved Hide resolved
crates/subspace-gateway/src/commands/http.rs Outdated Show resolved Hide resolved
crates/subspace-gateway/src/commands/rpc.rs Outdated Show resolved Hide resolved
crates/subspace-gateway/src/commands/rpc.rs Outdated Show resolved Hide resolved
crates/subspace-gateway/src/commands/http.rs Outdated Show resolved Hide resolved
crates/subspace-gateway/src/commands/http/server.rs Outdated Show resolved Hide resolved
Copy link
Member Author

@shamil-gadelshin shamil-gadelshin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review!

crates/subspace-gateway/Cargo.toml Outdated Show resolved Hide resolved
crates/subspace-gateway/src/main.rs Show resolved Hide resolved
crates/subspace-gateway/src/commands/http.rs Outdated Show resolved Hide resolved
#[serde(rename = "pieceIndex")]
piece_index: u64,
#[serde(rename = "pieceOffset")]
piece_offset: u32,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like spreading the dependency across contexts. I would prefer changing types.

@shamil-gadelshin shamil-gadelshin marked this pull request as draft December 5, 2024 16:58
@shamil-gadelshin shamil-gadelshin marked this pull request as ready for review December 5, 2024 17:50
Copy link
Contributor

@teor2345 teor2345 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Once we’ve got the dependencies and the hash type cleaned up, we should be ready to go.

#[serde(rename = "pieceIndex")]
piece_index: u64,
#[serde(rename = "pieceOffset")]
piece_offset: u32,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing to Blake3Hash here might simplify some of the code below.

@teor2345 teor2345 dismissed their stale review December 6, 2024 04:12

Changes mostly applied


async fn request_object_mappings(endpoint: String, key: String) -> anyhow::Result<ObjectMapping> {
let client = reqwest::Client::new();
let object_mappings_url = format!("http://{}/objects/{}", endpoint, key,);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoding the HTTP protocol would avoid the usage of indexers with HTTPS endpoints? For example, using the currenthttps://indexer.taurus.autonomys.xyz.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using this indexer could be useful for debugging and testing purposes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d suggest making the protocol part of the endpoint URL, like we do for RPC clients:

#[arg(long, value_hint = ValueHint::Url, default_value = "ws://127.0.0.1:9944")]
node_rpc_url: String,


Note: using HTTP isn’t a security issue here, because:

  • the raw object data is already public on the chain
  • we check the hash of the returned data, so it can’t be modified in transit

HTTP might be a minor privacy issue, because the hash and timing of each object fetch is unencrypted. It’s up to Carlos if that’s a significant issue in our use case though.

Allowing HTTPS in this PR would make that a deployment decision, not a developer coding decision.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this suggestion. I'll create and test a separate PR.

Copy link
Contributor

@teor2345 teor2345 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, I made PR #3293 to simplify the code further.


async fn request_object_mappings(endpoint: String, key: String) -> anyhow::Result<ObjectMapping> {
let client = reqwest::Client::new();
let object_mappings_url = format!("http://{}/objects/{}", endpoint, key,);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d suggest making the protocol part of the endpoint URL, like we do for RPC clients:

#[arg(long, value_hint = ValueHint::Url, default_value = "ws://127.0.0.1:9944")]
node_rpc_url: String,


Note: using HTTP isn’t a security issue here, because:

  • the raw object data is already public on the chain
  • we check the hash of the returned data, so it can’t be modified in transit

HTTP might be a minor privacy issue, because the hash and timing of each object fetch is unencrypted. It’s up to Carlos if that’s a significant issue in our use case though.

Allowing HTTPS in this PR would make that a deployment decision, not a developer coding decision.

#[serde(rename = "pieceIndex")]
piece_index: u64,
#[serde(rename = "pieceOffset")]
piece_offset: u32,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but I wanted to go a bit further, see 02c0ca4 (#3293) in #3293.

@shamil-gadelshin shamil-gadelshin added this pull request to the merge queue Dec 9, 2024
Merged via the queue into main with commit ac3d5e5 Dec 9, 2024
10 checks passed
@shamil-gadelshin shamil-gadelshin deleted the gateway-http-server branch December 9, 2024 11:41
Comment on lines +27 to +28
#[serde(deserialize_with = "string_to_u32")]
block_number: BlockNumber,
Copy link
Member

@nazar-pc nazar-pc Dec 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a bug to me. Why would you want to receive a number as a string in JSON instead of an actual number? This should be a number, just like all the others in this very struct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I thought that was a bit weird! The block number provided by the node in the mapping subscription is a number:

pub struct ObjectMappingResponse {
/// The block number that the object mapping is from.
pub block_number: BlockNumber,
/// The object mappings.
#[serde(flatten)]
pub objects: GlobalObjectMapping,
}

(Specifically a u32.)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be a problem on my end. I expected it to be a u64/BigInt so postgres automatically parsed to string.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants