web3-proxy/README.md

197 lines
7.5 KiB
Markdown
Raw Normal View History

2022-08-06 08:46:33 +03:00
# web3_proxy
2022-03-05 06:58:00 +03:00
2022-08-06 08:46:33 +03:00
Web3_proxy is a fast caching and load balancing proxy for web3 (Ethereum or similar) JsonRPC servers.
2022-05-12 08:54:27 +03:00
2022-10-22 09:02:32 +03:00
**Under construction!** This code is under active development. If you want to run this proxy youself, send me a message on [Twitter](https://twitter.com/StittsHappening) and I can explain things that aren't documented yet. Most RPC methods are supported, but filters are coming soon. And of course, more tests are always needed.
2022-06-18 23:51:14 +03:00
2022-05-12 08:54:27 +03:00
Signed transactions (eth_sendRawTransaction) are sent in parallel to the configured private RPCs (eden, ethermine, flashbots, etc.).
All other requests are sent to an RPC server on the latest block (llamanodes, alchemy, moralis, rivet, your own node, or one of many other providers). If multiple servers are in sync, they are prioritized by `active_requests` and request latency. Note that this means that the fastest server is most likely to serve requests and slow servers are unlikely to ever get any requests.
2022-05-12 08:54:27 +03:00
2022-05-16 19:15:19 +03:00
Each server has different limits to configure. The `soft_limit` is the number of parallel active requests where a server starts to slow down. The `hard_limit` is where a server starts giving rate limits or other errors.
2022-03-05 07:59:11 +03:00
2022-11-13 21:39:49 +03:00
## Quick development
2023-03-04 02:25:44 +03:00
1. `brew install librdkafka` or `sudo apt-get install librdkafka-dev`
2. Run `docker-compose up -d` to start the database and caches. See `docker-compose.yml` for details.
3. Copy `./config/example.toml` to `./config/development.toml` and change settings to match your setup.
4. Run `cargo` commands:
2022-11-13 21:39:49 +03:00
2022-03-05 07:59:11 +03:00
```
2022-07-26 01:36:02 +03:00
$ cargo run --release -- --help
2022-03-05 07:59:11 +03:00
```
2022-03-05 06:58:00 +03:00
```
2022-08-06 08:46:33 +03:00
Compiling web3_proxy v0.1.0 (/home/bryan/src/web3_proxy/web3_proxy)
2022-05-20 05:50:22 +03:00
Finished release [optimized + debuginfo] target(s) in 17.69s
2022-08-06 08:46:33 +03:00
Running `target/release/web3_proxy --help`
Usage: web3_proxy [--port <port>] [--workers <workers>] [--config <config>]
2022-03-05 06:58:00 +03:00
2022-08-06 08:46:33 +03:00
web3_proxy is a fast caching and load balancing proxy for web3 (Ethereum or similar) JsonRPC servers.
2022-03-05 06:58:00 +03:00
Options:
2022-05-20 05:50:22 +03:00
--port what port the proxy should listen on
--workers number of worker threads
--config path to a toml of rpc servers
2022-03-05 06:58:00 +03:00
--help display usage information
2022-03-05 07:59:11 +03:00
```
2022-03-05 06:58:00 +03:00
2022-11-13 21:39:49 +03:00
Start the server with the defaults (listen on `http://localhost:8544` and use `./config/development.toml` which uses the database and cache running under docker and proxies to a bunch of public nodes:
2022-05-12 08:54:27 +03:00
2022-03-05 06:58:00 +03:00
```
2023-02-07 21:11:34 +03:00
cargo run --release -- proxyd
2022-03-05 07:59:11 +03:00
```
2023-06-25 07:16:26 +03:00
Quickly run tests:
```
RUST_LOG=web3_proxy=trace,info cargo nextest run
```
Run more tests:
```
RUST_LOG=web3_proxy=trace,info cargo nextest run --features tests-needing-docker
```
2022-07-19 09:41:04 +03:00
## Common commands
2022-09-22 02:50:55 +03:00
Create a user:
```
2023-01-18 08:26:10 +03:00
cargo run -- --db-url "$YOUR_DB_URL" create_user --address "$USER_ADDRESS_0x"
2022-09-22 02:50:55 +03:00
```
2022-05-12 08:54:27 +03:00
Check that the proxy is working:
2022-03-05 07:59:11 +03:00
```
2022-05-20 05:50:22 +03:00
curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"web3_clientVersion","id":1}' 127.0.0.1:8544
2022-03-05 07:59:11 +03:00
```
2023-05-17 02:04:17 +03:00
```
2023-06-20 04:55:31 +03:00
curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber", "params": ["latest", false],"id":1}' 127.0.0.1:8544
```
```
2023-05-17 02:04:17 +03:00
curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBalance", "params": ["0x0000000000000000000000000000000000000000", "latest"],"id":1}' 127.0.0.1:8544
```
2022-03-05 07:59:11 +03:00
2022-07-19 09:41:04 +03:00
Check that the websocket is working:
```
$ websocat ws://127.0.0.1:8544
{"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["newHeads"]}
2022-07-19 09:41:04 +03:00
{"jsonrpc": "2.0", "id": 2, "method": "eth_subscribe", "params": ["newPendingTransactions"]}
2022-07-19 09:41:04 +03:00
{"jsonrpc": "2.0", "id": 3, "method": "eth_subscribe", "params": ["newPendingFullTransactions"]}
2022-07-19 09:41:04 +03:00
{"jsonrpc": "2.0", "id": 4, "method": "eth_subscribe", "params": ["newPendingRawTransactions"]}
2022-07-19 09:41:04 +03:00
```
You can copy `config/example.toml` to `config/production-$CHAINNAME.toml` and then run `docker-compose up --build -d` start proxies for many chains.
2022-05-12 08:54:27 +03:00
2022-11-28 10:06:47 +03:00
Compare 3 RPCs:
```
web3_proxy_cli health_compass https://eth.llamarpc.com https://eth-ski.llamarpc.com https://rpc.ankr.com/eth
```
### Run migrations
Generally it is simplest to just run the app to run migrations. It runs migrations on start.
But if you want to run them manually (generally only useful in development):
2022-11-01 21:54:39 +03:00
```
cd migration
cargo run up
```
### Create a user:
```
2023-01-09 21:09:36 +03:00
web3_proxy_cli --config ... create_user --address 0x0000000000000000000000000000000000000000 --email infra@llamanodes.com --description "..."
```
### Give a user unlimited requests per second:
Copy the ULID key (or UUID key) out of the above command, and put it into the following command.
```
2023-01-09 21:09:36 +03:00
web3_proxy_cli --config ... change_user_tier_by_key "$RPC_ULID_KEY_FROM_PREV_COMMAND" "Unlimited"
```
### Health compass
Health check 3 servers and error if the first one doesn't match the others.
```
web3_proxy_cli health_compass https://eth.llamarpc.com/ https://rpc.ankr.com/eth https://cloudflare-eth.com
```
2022-12-16 09:21:19 +03:00
## Adding new database tables
2022-08-04 02:17:02 +03:00
2022-10-22 05:57:45 +03:00
```
cargo install sea-orm-cli
```
2022-08-04 02:17:02 +03:00
2022-12-16 09:21:19 +03:00
1. (optional) drop the current dev db
2. `sea-orm-cli migrate`
3. `sea-orm-cli generate entity -u mysql://root:dev_web3_proxy@127.0.0.1:13306/dev_web3_proxy -o entities/src --with-serde both`
- Be careful when adding the `--tables THE,MODIFIED,TABLES` flag. It will delete relationships if they aren't listed
4. After running the above, you will need to manually fix some things
- Add any derives that got removed (like `Default`)
- `Vec<u8>` -> `sea_orm::prelude::Uuid` (Related: <https://github.com/SeaQL/sea-query/issues/375>)
- `i8` -> `bool` (Related: <https://github.com/SeaQL/sea-orm/issues/924>)
- add all the tables back into `mod.rs`
2022-04-28 22:30:22 +03:00
## Flame Graphs
2022-08-17 00:10:03 +03:00
Flame graphs make a developer's join of finding slow code painless:
2022-05-12 08:54:27 +03:00
2022-04-28 22:30:22 +03:00
$ cat /proc/sys/kernel/kptr_restrict
1
2022-05-20 05:48:08 +03:00
$ echo 0 | sudo tee /proc/sys/kernel/kptr_restrict
2022-04-28 22:30:22 +03:00
0
$ cat /proc/sys/kernel/perf_event_paranoid
4
$ echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
2022-11-12 09:11:58 +03:00
-1
2023-05-12 03:04:33 +03:00
$ CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph --bin web3_proxy_cli --no-inline -- proxyd
2022-04-28 22:30:22 +03:00
2022-11-12 11:24:32 +03:00
Be sure to use `--no-inline` or perf will be VERY slow
2022-04-28 22:30:22 +03:00
2022-05-17 07:24:13 +03:00
## GDB
2022-08-17 00:10:03 +03:00
Developers can run the proxy under gdb for advanced debugging:
2022-05-17 07:24:13 +03:00
2023-04-19 06:50:35 +03:00
cargo build --release && RUST_LOG=info,web3_proxy=debug,ethers_providers::rpc=off rust-gdb --args target/debug/web3_proxy --listen-port 7503 --rpc-config-path ./config/production-eth.toml
2022-05-17 07:24:13 +03:00
2022-07-26 01:36:02 +03:00
TODO: also enable debug symbols in the release build by modifying the root Cargo.toml
2022-05-17 07:24:13 +03:00
## Load Testing
Test the proxy:
wrk -t12 -c400 -d30s --latency http://127.0.0.1:8544/health
wrk -t12 -c400 -d30s --latency http://127.0.0.1:8544/status
2022-09-07 06:54:16 +03:00
wrk -s ./wrk/getBlockNumber.lua -t12 -c400 -d30s --latency http://127.0.0.1:8544/u/$API_KEY
wrk -s ./wrk/getLatestBlockByNumber.lua -t12 -c400 -d30s --latency http://127.0.0.1:8544/u/$API_KEY
2022-07-19 09:41:04 +03:00
Test geth (assuming it is on 8545):
2022-09-07 06:54:16 +03:00
wrk -s ./wrk/getBlockNumber.lua -t12 -c400 -d30s --latency http://127.0.0.1:8545
wrk -s ./wrk/getLatestBlockByNumber.lua -t12 -c400 -d30s --latency http://127.0.0.1:8545
2022-07-19 09:41:04 +03:00
Test erigon (assuming it is on 8945):
2022-09-07 06:54:16 +03:00
wrk -s ./wrk/getBlockNumber.lua -t12 -c400 -d30s --latency http://127.0.0.1:8945
wrk -s ./wrk/getLatestBlockByNumber.lua -t12 -c400 -d30s --latency http://127.0.0.1:8945
2022-05-12 08:54:27 +03:00
Note: Testing with `getLatestBlockByNumber.lua` is not great because the latest block changes and so one run is likely to be very different than another.
2022-07-19 09:41:04 +03:00
2022-08-12 22:07:14 +03:00
Run [ethspam](https://github.com/INFURA/versus) and [versus](https://github.com/shazow/ethspam) for a more realistic load test:
2022-07-19 09:41:04 +03:00
2023-06-08 03:26:38 +03:00
ethspam --rpc http://127.0.0.1:8544 | versus --concurrency=10 --stop-after=1000 http://127.0.0.1:8544
2022-12-17 07:05:01 +03:00
2022-09-07 06:54:16 +03:00
ethspam --rpc http://127.0.0.1:8544/u/$API_KEY | versus --concurrency=100 --stop-after=10000 http://127.0.0.1:8544/u/$API_KEY