ci: mdbook (#2003)
* Applied same book structure as Reth * ci: [WIP] added book workflow * fix warning mdbook version different from template plugin version * ci: added deploy step * Http provider docs * IPC provider docs * RetryClient docs * WebSocket provider docs Co-authored-by: Andrea Simeoni <>
This commit is contained in:
parent
4fd742f8ce
commit
da0363918b
|
@ -0,0 +1,61 @@
|
||||||
|
name: book
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
paths:
|
||||||
|
- 'book/**'
|
||||||
|
- 'book.toml'
|
||||||
|
pull_request:
|
||||||
|
branches: [master]
|
||||||
|
paths:
|
||||||
|
- 'book/**'
|
||||||
|
- 'book.toml'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install mdbook
|
||||||
|
run: |
|
||||||
|
mkdir mdbook
|
||||||
|
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.21/mdbook-v0.4.21-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook
|
||||||
|
echo `pwd`/mdbook >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: Install mdbook-template
|
||||||
|
run: |
|
||||||
|
mkdir mdbook-template
|
||||||
|
curl -sSL https://github.com/sgoudham/mdbook-template/releases/latest/download/mdbook-template-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook-template
|
||||||
|
echo `pwd`/mdbook-template >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: mdbook build
|
||||||
|
|
||||||
|
- name: Save pages artifact
|
||||||
|
uses: actions/upload-pages-artifact@v1
|
||||||
|
with:
|
||||||
|
path: target/book
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
# Only deploy if a push to master
|
||||||
|
if: github.ref_name == 'master' && github.event_name == 'push'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [build]
|
||||||
|
|
||||||
|
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
|
||||||
|
permissions:
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# reference: https://github.com/actions/deploy-pages
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v1
|
|
@ -1684,6 +1684,7 @@ version = "1.0.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethers",
|
"ethers",
|
||||||
"eyre",
|
"eyre",
|
||||||
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
[book]
|
||||||
|
authors = ["The ethers-rs contributors"]
|
||||||
|
language = "en"
|
||||||
|
multilingual = false
|
||||||
|
src = "book"
|
||||||
|
title = "Ethers.rs: The Ethereum Library for Rust"
|
||||||
|
description = "A book on all things ethers-rs"
|
||||||
|
|
||||||
|
[output.html]
|
||||||
|
git-repository-url = "https://github.com/gakonst/ethers-rs"
|
||||||
|
default-theme = "ayu"
|
||||||
|
no-section-label = true
|
||||||
|
|
||||||
|
[output.html.fold]
|
||||||
|
enable = true
|
||||||
|
level = 1
|
||||||
|
|
||||||
|
[build]
|
||||||
|
build-dir = "target/book"
|
||||||
|
|
||||||
|
[preprocessor.template]
|
||||||
|
before = [ "links" ]
|
||||||
|
|
||||||
|
[preprocessor.index]
|
||||||
|
|
||||||
|
[preprocessor.links]
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
# Reference guide
|
# Reference guide
|
||||||
- [Providers]()
|
- [Providers]()
|
||||||
- [Http]()
|
- [Http](./providers/http.md)
|
||||||
- [IPC]()
|
- [IPC](./providers/ipc.md)
|
||||||
- [Mock]()
|
- [Mock]()
|
||||||
- [Quorum]()
|
- [Quorum]()
|
||||||
- [Retry]()
|
- [Retry](./providers/retry.md)
|
||||||
- [RW]()
|
- [RW]()
|
||||||
- [WS]()
|
- [WebSocket](./providers/ws.md)
|
||||||
- [Middleware]()
|
- [Middleware]()
|
||||||
- [Builder]()
|
- [Builder]()
|
||||||
- [Create custom middleware]()
|
- [Create custom middleware]()
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
# Comparison and equivalence
|
||||||
|
|
||||||
|
```rust
|
||||||
|
{{#include ../../examples/big-numbers/examples/comparison_equivalence.rs}}
|
||||||
|
```
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Conversion
|
||||||
|
|
||||||
|
```rust
|
||||||
|
{{#include ../../examples/big-numbers/examples/conversion.rs}}
|
||||||
|
```
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Creating instances
|
||||||
|
|
||||||
|
```rust
|
||||||
|
{{#include ../../examples/big-numbers/examples/create_instances.rs}}
|
||||||
|
```
|
|
@ -0,0 +1 @@
|
||||||
|
{{#include ../../examples/big-numbers/README.md}}
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Math operations
|
||||||
|
|
||||||
|
```rust
|
||||||
|
{{#include ../../examples/big-numbers/examples/math_operations.rs}}
|
||||||
|
```
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Utilities
|
||||||
|
|
||||||
|
```rust
|
||||||
|
{{#include ../../examples/big-numbers/examples/utilities.rs}}
|
||||||
|
```
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Http provider
|
||||||
|
|
||||||
|
```rust
|
||||||
|
{{#include ../../examples/providers/examples/http.rs}}
|
||||||
|
```
|
|
@ -0,0 +1,5 @@
|
||||||
|
# IPC provider
|
||||||
|
|
||||||
|
```rust
|
||||||
|
{{#include ../../examples/providers/examples/ipc.rs}}
|
||||||
|
```
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Retry client
|
||||||
|
|
||||||
|
```rust
|
||||||
|
{{#include ../../examples/providers/examples/retry.rs}}
|
||||||
|
```
|
|
@ -0,0 +1,5 @@
|
||||||
|
# WebSocket provider
|
||||||
|
|
||||||
|
```rust
|
||||||
|
{{#include ../../examples/providers/examples/ws.rs}}
|
||||||
|
```
|
|
@ -1 +0,0 @@
|
||||||
book
|
|
|
@ -1,6 +0,0 @@
|
||||||
[book]
|
|
||||||
authors = ["The ethers-rs contributors"]
|
|
||||||
language = "en"
|
|
||||||
multilingual = false
|
|
||||||
src = "src"
|
|
||||||
title = "Ethers.rs: The Ethereum Library for Rust"
|
|
|
@ -1,6 +0,0 @@
|
||||||
|
|
||||||
# Comparison and equivalence
|
|
||||||
|
|
||||||
```rust
|
|
||||||
{{#include ../../../../examples/big-numbers/examples/comparison_equivalence.rs}}
|
|
||||||
```
|
|
|
@ -1,5 +0,0 @@
|
||||||
# Conversion
|
|
||||||
|
|
||||||
```rust
|
|
||||||
{{#include ../../../../examples/big-numbers/examples/conversion.rs}}
|
|
||||||
```
|
|
|
@ -1,5 +0,0 @@
|
||||||
# Creating instances
|
|
||||||
|
|
||||||
```rust
|
|
||||||
{{#include ../../../../examples/big-numbers/examples/create_instances.rs}}
|
|
||||||
```
|
|
|
@ -1 +0,0 @@
|
||||||
{{#include ../../../../examples/big-numbers/README.md}}
|
|
|
@ -1,5 +0,0 @@
|
||||||
# Math operations
|
|
||||||
|
|
||||||
```rust
|
|
||||||
{{#include ../../../../examples/big-numbers/examples/math_operations.rs}}
|
|
||||||
```
|
|
|
@ -1,5 +0,0 @@
|
||||||
# Utilities
|
|
||||||
|
|
||||||
```rust
|
|
||||||
{{#include ../../../../examples/big-numbers/examples/utilities.rs}}
|
|
||||||
```
|
|
|
@ -35,13 +35,13 @@
|
||||||
- [ ] Time lag
|
- [ ] Time lag
|
||||||
- [ ] Transformer
|
- [ ] Transformer
|
||||||
- [ ] Providers
|
- [ ] Providers
|
||||||
- [ ] Http
|
- [x] Http
|
||||||
- [x] IPC
|
- [x] IPC
|
||||||
- [ ] Mock
|
- [ ] Mock
|
||||||
- [x] Quorum
|
- [x] Quorum
|
||||||
- [ ] Retry
|
- [x] Retry
|
||||||
- [x] RW
|
- [x] RW
|
||||||
- [ ] WS
|
- [x] WS
|
||||||
- [ ] Queries
|
- [ ] Queries
|
||||||
- [ ] Blocks
|
- [ ] Blocks
|
||||||
- [x] Contracts
|
- [x] Contracts
|
||||||
|
|
|
@ -12,6 +12,7 @@ ipc = []
|
||||||
ethers = { path = "../..", version = "1.0.0", features = ["abigen", "ipc", "rustls", "ws"] }
|
ethers = { path = "../..", version = "1.0.0", features = ["abigen", "ipc", "rustls", "ws"] }
|
||||||
|
|
||||||
eyre = "0.6"
|
eyre = "0.6"
|
||||||
|
reqwest = { version = "0.11.13", default-features = false }
|
||||||
serde = { version = "1.0.144", features = ["derive"] }
|
serde = { version = "1.0.144", features = ["derive"] }
|
||||||
serde_json = "1.0.64"
|
serde_json = "1.0.64"
|
||||||
tokio = { version = "1.18", features = ["macros"] }
|
tokio = { version = "1.18", features = ["macros"] }
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
use ethers::prelude::*;
|
||||||
|
use reqwest::header::{HeaderMap, HeaderValue};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
const RPC_URL: &str = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27";
|
||||||
|
|
||||||
|
/// The Http transport is used to send JSON-RPC requests over Http to an
|
||||||
|
/// Ethereum node. It allows you to perform various actions on the Ethereum blockchain, such as
|
||||||
|
/// reading and writing data, sending transactions, and more. To use the Http transport, you will
|
||||||
|
/// need to create a new `Provider` instance as described in this example.
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> eyre::Result<()> {
|
||||||
|
create_instance().await?;
|
||||||
|
share_providers_across_tasks().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_instance() -> eyre::Result<()> {
|
||||||
|
// An Http provider can be created from an http(s) URI.
|
||||||
|
// In case of https you must add the "rustls" or "openssl" feature
|
||||||
|
// to the ethers library dependency in `Cargo.toml`.
|
||||||
|
let _provider = Provider::<Http>::try_from(RPC_URL)?;
|
||||||
|
|
||||||
|
// Instantiate with auth to append basic authorization headers across requests
|
||||||
|
let url = reqwest::Url::parse(RPC_URL)?;
|
||||||
|
let auth = Authorization::basic("username", "password");
|
||||||
|
let _provider = Http::new_with_auth(url, auth)?;
|
||||||
|
|
||||||
|
// Instantiate from custom Http Client if you need
|
||||||
|
// finer control over the Http client configuration
|
||||||
|
// (TLS, Proxy, Cookies, Headers, etc.)
|
||||||
|
let url = reqwest::Url::parse(RPC_URL)?;
|
||||||
|
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert("Authorization", HeaderValue::from_static("Bearer my token"));
|
||||||
|
headers.insert("X-MY-HEADERS", HeaderValue::from_static("Some value"));
|
||||||
|
|
||||||
|
let http_client = reqwest::Client::builder()
|
||||||
|
.default_headers(headers)
|
||||||
|
.proxy(reqwest::Proxy::all("http://proxy.example.com:8080")?)
|
||||||
|
.build()?;
|
||||||
|
|
||||||
|
let _provider = Http::new_with_client(url, http_client);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Providers can be easily shared across tasks using `Arc` smart pointers
|
||||||
|
async fn share_providers_across_tasks() -> eyre::Result<()> {
|
||||||
|
let provider: Provider<Http> = Provider::<Http>::try_from(RPC_URL)?;
|
||||||
|
|
||||||
|
let client_1 = Arc::new(provider);
|
||||||
|
let client_2 = Arc::clone(&client_1);
|
||||||
|
|
||||||
|
let handle1 =
|
||||||
|
tokio::spawn(async move { client_1.get_block(BlockNumber::Latest).await.unwrap_or(None) });
|
||||||
|
|
||||||
|
let handle2 =
|
||||||
|
tokio::spawn(async move { client_2.get_block(BlockNumber::Latest).await.unwrap_or(None) });
|
||||||
|
|
||||||
|
let block1: Option<Block<H256>> = handle1.await?;
|
||||||
|
let block2: Option<Block<H256>> = handle2.await?;
|
||||||
|
|
||||||
|
println!("{block1:?} {block2:?}");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,11 +1,23 @@
|
||||||
|
/// The IPC (Inter-Process Communication) transport is a way for a process to communicate with a
|
||||||
|
/// running Ethereum client over a local Unix domain socket. Using the IPC transport allows the
|
||||||
|
/// ethers library to send JSON-RPC requests to the Ethereum client and receive responses, without
|
||||||
|
/// the need for a network connection or HTTP server. This can be useful for interacting with a
|
||||||
|
/// local Ethereum node that is running on the same machine.
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[cfg(feature = "ipc")]
|
#[cfg(feature = "ipc")]
|
||||||
async fn main() -> eyre::Result<()> {
|
async fn main() -> eyre::Result<()> {
|
||||||
use ethers::prelude::*;
|
use ethers::prelude::*;
|
||||||
|
|
||||||
|
// We instantiate the provider using the path of a local Unix domain socket
|
||||||
|
// --------------------------------------------------------------------------------
|
||||||
|
// NOTE: The IPC transport supports push notifications, but we still need to specify a polling
|
||||||
|
// interval because only subscribe RPC calls (e.g., transactions, blocks, events) support push
|
||||||
|
// notifications in Ethereum's RPC API. For other calls we must use repeated polling for many
|
||||||
|
// operations even with the IPC transport.
|
||||||
let provider = Provider::connect_ipc("~/.ethereum/geth.ipc")
|
let provider = Provider::connect_ipc("~/.ethereum/geth.ipc")
|
||||||
.await?
|
.await?
|
||||||
.interval(std::time::Duration::from_millis(2000));
|
.interval(std::time::Duration::from_millis(2000));
|
||||||
|
|
||||||
let block = provider.get_block_number().await?;
|
let block = provider.get_block_number().await?;
|
||||||
println!("Current block: {block}");
|
println!("Current block: {block}");
|
||||||
let mut stream = provider.watch_blocks().await?.stream();
|
let mut stream = provider.watch_blocks().await?.stream();
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
use ethers::prelude::*;
|
||||||
|
use reqwest::Url;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
const RPC_URL: &str = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27";
|
||||||
|
|
||||||
|
/// The RetryClient is a type that wraps around a JsonRpcClient and automatically retries failed
|
||||||
|
/// requests using an exponential backoff and filtering based on a RetryPolicy. It presents as a
|
||||||
|
/// JsonRpcClient, but with additional functionality for retrying requests.
|
||||||
|
///
|
||||||
|
/// The RetryPolicy can be customized for specific applications and endpoints, mainly to handle
|
||||||
|
/// rate-limiting errors. In addition to the RetryPolicy, errors caused by connectivity issues such
|
||||||
|
/// as timed out connections or responses in the 5xx range can also be retried separately.
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> eyre::Result<()> {
|
||||||
|
let provider = Http::new(Url::parse(RPC_URL)?);
|
||||||
|
|
||||||
|
let client = RetryClientBuilder::default()
|
||||||
|
.rate_limit_retries(10)
|
||||||
|
.timeout_retries(3)
|
||||||
|
.initial_backoff(Duration::from_millis(500))
|
||||||
|
.build(provider, Box::new(HttpRateLimitRetryPolicy::default()));
|
||||||
|
|
||||||
|
// Send a JSON-RPC request for the latest block
|
||||||
|
let block_num = "latest".to_string();
|
||||||
|
let txn_details = false;
|
||||||
|
let params = (block_num, txn_details);
|
||||||
|
|
||||||
|
let block: Block<H256> =
|
||||||
|
JsonRpcClient::request(&client, "eth_getBlockByNumber", params).await?;
|
||||||
|
|
||||||
|
println!("{block:?}");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use ethers::prelude::*;
|
||||||
|
|
||||||
|
const WSS_URL: &str = "wss://mainnet.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27";
|
||||||
|
|
||||||
|
type BoxErr = Box<dyn std::error::Error>;
|
||||||
|
|
||||||
|
/// The Ws transport allows you to send JSON-RPC requests and receive responses over WebSocket
|
||||||
|
/// connections. It is useful for connecting to Ethereum nodes that support WebSockets.
|
||||||
|
/// This allows to interact with the Ethereum network in real-time without the need for HTTP
|
||||||
|
/// polling.
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), BoxErr> {
|
||||||
|
create_instance().await?;
|
||||||
|
watch_blocks().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_instance() -> Result<(), BoxErr> {
|
||||||
|
// An Ws provider can be created from an ws(s) URI.
|
||||||
|
// In case of wss you must add the "rustls" or "openssl" feature
|
||||||
|
// to the ethers library dependency in `Cargo.toml`.
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
// NOTE: The Ws transport supports push notifications, but we still need to specify a polling
|
||||||
|
// interval because only subscribe RPC calls (e.g., transactions, blocks, events) support push
|
||||||
|
// notifications in Ethereum's RPC API. For other calls we must use repeated polling for many
|
||||||
|
// operations even with the Ws transport.
|
||||||
|
let _provider = Provider::<Ws>::connect(WSS_URL).await?.interval(Duration::from_millis(500));
|
||||||
|
|
||||||
|
// Instantiate with auth to send basic authorization headers on connection.
|
||||||
|
let url = reqwest::Url::parse(WSS_URL)?;
|
||||||
|
let auth = Authorization::basic("username", "password");
|
||||||
|
if let Ok(_provider) = Provider::<Ws>::connect_with_auth(url, auth).await {
|
||||||
|
println!("Create Ws provider with auth");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Let's show how the Ws connection enables listening for blocks using a persistent TCP connection
|
||||||
|
async fn watch_blocks() -> Result<(), BoxErr> {
|
||||||
|
let provider = Provider::<Ws>::connect(WSS_URL).await?;
|
||||||
|
let mut stream = provider.watch_blocks().await?.take(1);
|
||||||
|
|
||||||
|
while let Some(block_hash) = stream.next().await {
|
||||||
|
println!("{block_hash:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue