Skip to content

feat: library canhttp#364

Merged
gregorydemay merged 39 commits intomainfrom
gdemay/XC-287-canjsonrpc
Feb 13, 2025
Merged

feat: library canhttp#364
gregorydemay merged 39 commits intomainfrom
gdemay/XC-287-canjsonrpc

Conversation

@gregorydemay
Copy link
Contributor

@gregorydemay gregorydemay commented Feb 3, 2025

Starts extracting the logic to handle HTTPs outcalls into a separate library, named canhttp, that temporarily lives in the same repository. The main idea is to start from a low-level client implementing the tower::Service trait that can be extended by additional middlewares. This PR focusses on this low-level client and a first middleware handling cycles accounting.

Left for future PRs:

  1. Add a mapping layer so that requests are of type http::Request<> and responses are of type http::Response<>. This will allow to be able to use the Request builder from the http crate as well as various HTTP-specific middlewares such as the ones from the tower-http crate. In particular, the TraceLayer will allow to react on requests/responses to add the appropriates metrics and logs.
  2. Add an additional mapping layer for JSON-RPC applications so that requests are of type http::Request<JsonRpcRequest<>> and responses are of type http::Response<JsonRpcResponse<>> to easily make JSON-RPC requests.

@gregorydemay gregorydemay changed the title feat: library canjsonrpc feat: library canhttp Feb 10, 2025
Copy link
Contributor Author

@gregorydemay gregorydemay left a comment

Choose a reason for hiding this comment

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

Thanks @lpahlavi for the review and the interesting questions!

gregorydemay and others added 2 commits February 12, 2025 08:48
Co-authored-by: Louis Pahlavi <louis.pahlavi@gmail.com>
Co-authored-by: Louis Pahlavi <louis.pahlavi@gmail.com>
lpahlavi
lpahlavi previously approved these changes Feb 12, 2025
Copy link
Contributor

@lpahlavi lpahlavi left a comment

Choose a reason for hiding this comment

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

@gregorydemay thanks a lot for the detailed explanation!

I was a little bit confused at cycles_to_attach and cycles_to_charge but actually it makes complete sense now. I think ultimately a little explanation in the README for example could make sense, but I would take care of this kind of documentation only once the library is close to being done.

Overall the code LGTM! Thanks again for the PR!

Copy link
Contributor

@lpahlavi lpahlavi left a comment

Choose a reason for hiding this comment

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

@gregorydemay I think it looks very good now, especially with the changes suggested by @ninegua! LGTM 🚀

@gregorydemay gregorydemay merged commit f2b62c4 into main Feb 13, 2025
7 checks passed
@gregorydemay gregorydemay deleted the gdemay/XC-287-canjsonrpc branch February 13, 2025 15:51
gregorydemay added a commit that referenced this pull request Feb 25, 2025
Follow-up on #364 to add a new observability layer to take care of
logging and metrics. Unfortunately,
[`tower_http::trace`](https://docs.rs/tower-http/latest/tower_http/trace/index.html)
cannot be used in a canister environment because it measures call
latency with `Instant::now`. The proposed layer, while inspired by
[`tower_http::trace`](https://docs.rs/tower-http/latest/tower_http/trace/index.html),
is also simpler because it does not have to deal with streaming
responses.

---------

Co-authored-by: Louis Pahlavi <louis.pahlavi@gmail.com>
gregorydemay added a commit that referenced this pull request Feb 28, 2025
Follow-up on #370 and #364 to add a conversion layer between request and
responses so that the caller only has to deal with types from the Rust
[`http`](https://crates.io/crates/http) crate. This has several
advantages from the caller's point of view:

1. Can re-use existing types like `Request::builder` or `StatusCode`.
2. Requests are automatically sanitized and canonicalized (e.g. header
names are validated and lower cased).
3. Can re-use existing middlewares, like from the
`[tower-http`](https://crates.io/crates/tower-http) crate, since many of
them require a client that uses the
[`http`](https://crates.io/crates/http) crate.
gregorydemay added a commit that referenced this pull request Mar 7, 2025
Follow-up on #370, #364, and #374 to add a conversion layer between
request and responses to handle [JSON
RPC](https://www.jsonrpc.org/specification) over HTTP.

Concretely:
1. Refactor existing infrastructure to handle errors explicitly, instead
of having to downcast `BoxError`. This is beneficial since errors may
happen at different layers and they all need to be handled by the above
observability layer, e.g., add the corresponding metric in case the
response has a non successful status.
2. Refactor existing infrastructure to transform request and response to
use a single `Convert` trait to convert one type into another with some
potential error.
3. Add a layer for `http::Request` and `http::Response` to transform
their body into a JSON RPC type. This uses the above `Convert` trait.
This conversion layer is behind a feature flag (`json`) since it
requires `serde_json` to handle the serialization/deserialization
4. Add a new layer to filter out non-successful HTTP responses.
@gregorydemay gregorydemay mentioned this pull request Mar 7, 2025
gregorydemay added a commit that referenced this pull request Mar 11, 2025
Follow-up on #370, #364, #374, and #375 to automatically retry requests
by doubling its `max_response_bytes` when the response was too big.
gregorydemay added a commit to dfinity/canhttp that referenced this pull request Jul 9, 2025
Starts extracting the logic to handle HTTPs outcalls into a separate
library, named `canhttp`, that temporarily lives in the same repository.
The main idea is to start from a low-level client implementing the
[`tower::Service`](https://docs.rs/tower/latest/tower/trait.Service.html)
trait that can be extended by additional middlewares. This PR focusses
on this low-level client and a first middleware handling cycles
accounting.

Left for future PRs:
1. Add a mapping layer so that requests are of type `http::Request<>`
and responses are of type `http::Response<>`. This will allow to be able
to use the `Request` builder from the
[`http`](https://crates.io/crates/http) crate as well as various
HTTP-specific middlewares such as the ones from the
[`tower-http`](https://crates.io/crates/tower-http) crate. In
particular, the
[`TraceLayer`](https://docs.rs/tower-http/latest/tower_http/trace/index.html)
will allow to react on requests/responses to add the appropriates
metrics and logs.
2. Add an additional mapping layer for JSON-RPC applications so that
requests are of type `http::Request<JsonRpcRequest<>>` and responses are
of type `http::Response<JsonRpcResponse<>>` to easily make JSON-RPC
requests.

---------

Co-authored-by: Louis Pahlavi <louis.pahlavi@gmail.com>
gregorydemay added a commit to dfinity/canhttp that referenced this pull request Jul 9, 2025
Follow-up on dfinity/evm-rpc-canister#364 to add a new observability layer to take care of
logging and metrics. Unfortunately,
[`tower_http::trace`](https://docs.rs/tower-http/latest/tower_http/trace/index.html)
cannot be used in a canister environment because it measures call
latency with `Instant::now`. The proposed layer, while inspired by
[`tower_http::trace`](https://docs.rs/tower-http/latest/tower_http/trace/index.html),
is also simpler because it does not have to deal with streaming
responses.

---------

Co-authored-by: Louis Pahlavi <louis.pahlavi@gmail.com>
gregorydemay added a commit to dfinity/canhttp that referenced this pull request Jul 9, 2025
Follow-up on dfinity/evm-rpc-canister#370 and dfinity/evm-rpc-canister#364 to add a conversion layer between request and
responses so that the caller only has to deal with types from the Rust
[`http`](https://crates.io/crates/http) crate. This has several
advantages from the caller's point of view:

1. Can re-use existing types like `Request::builder` or `StatusCode`.
2. Requests are automatically sanitized and canonicalized (e.g. header
names are validated and lower cased).
3. Can re-use existing middlewares, like from the
`[tower-http`](https://crates.io/crates/tower-http) crate, since many of
them require a client that uses the
[`http`](https://crates.io/crates/http) crate.
gregorydemay added a commit to dfinity/canhttp that referenced this pull request Jul 9, 2025
Follow-up on dfinity/evm-rpc-canister#370, dfinity/evm-rpc-canister#364, and dfinity/evm-rpc-canister#374 to add a conversion layer between
request and responses to handle [JSON
RPC](https://www.jsonrpc.org/specification) over HTTP.

Concretely:
1. Refactor existing infrastructure to handle errors explicitly, instead
of having to downcast `BoxError`. This is beneficial since errors may
happen at different layers and they all need to be handled by the above
observability layer, e.g., add the corresponding metric in case the
response has a non successful status.
2. Refactor existing infrastructure to transform request and response to
use a single `Convert` trait to convert one type into another with some
potential error.
3. Add a layer for `http::Request` and `http::Response` to transform
their body into a JSON RPC type. This uses the above `Convert` trait.
This conversion layer is behind a feature flag (`json`) since it
requires `serde_json` to handle the serialization/deserialization
4. Add a new layer to filter out non-successful HTTP responses.
gregorydemay added a commit to dfinity/canhttp that referenced this pull request Jul 9, 2025
Follow-up on dfinity/evm-rpc-canister#370, dfinity/evm-rpc-canister#364, dfinity/evm-rpc-canister#374, and dfinity/evm-rpc-canister#375 to automatically retry requests
by doubling its `max_response_bytes` when the response was too big.
gregorydemay added a commit to dfinity/canhttp that referenced this pull request Jul 9, 2025
The library `canhttp` that was initially in the EVM RPC canister
[repository](https://github.com/dfinity/evm-rpc-canister) was moved **as
is** from commit
[3995dbd](https://github.com/dfinity/evm-rpc-canister/tree/3995dbd3eb3b03a781aaf35453d6757fa6edac47/canhttp)
to this repository as commit
[d41568a](d41568a)
while preserving the Git history (using `git filter-repo
--subdirectory-filter canhttp` as described
[here](https://gist.github.com/trongthanh/2779392)). Additionally, the
Git history was rewritten to preserve the links to the original PRs with
```
git filter-repo --message-callback 'return re.sub(br"#(\d{3})", br"dfinity/evm-rpc-canister#\1", message)'
```
so that commit messages like this
[one](d41568a)
that were pointed to PRs such as `#364` are now pointing to
`dfinity/evm-rpc-canister#364`.

This broke various things that this PR addresses:

1. Symlinks for license and notice that were pointing to files outside
the moved crate.
2. Re-create a Cargo workspace.
3. Add Github CI pipeline.
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.

3 participants