docs: Add README and logging to match python package
- The readme is useful for us during development. This should be eventually removed and replaced with gitbook docs.
This commit is contained in:
663
protocol-testing/Cargo.lock
generated
663
protocol-testing/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -8,8 +8,8 @@ miette = "7.6.0"
|
|||||||
# Logging & Tracing
|
# Logging & Tracing
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
# Tycho dependencies
|
# Tycho dependencies
|
||||||
tycho-common = "0.83.0"
|
tycho-common = "0.82.0"
|
||||||
tycho-client = "0.83.0"
|
tycho-client = "0.82.0"
|
||||||
tycho-simulation = { path = "../../tycho-simulation", features = ["evm"] }
|
tycho-simulation = { path = "../../tycho-simulation", features = ["evm"] }
|
||||||
# EVM dependencies
|
# EVM dependencies
|
||||||
alloy = { version = "1.0.27", features = ["arbitrary", "json", "dyn-abi", "sol-types", "contract", "provider-http"] }
|
alloy = { version = "1.0.27", features = ["arbitrary", "json", "dyn-abi", "sol-types", "contract", "provider-http"] }
|
||||||
|
|||||||
144
protocol-testing/README.md
Normal file
144
protocol-testing/README.md
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
# Protocol Testing
|
||||||
|
|
||||||
|
Rust-based integration testing framework for Tycho protocol implementations.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. **PostgreSQL Database**: Start the required PostgreSQL instance using Docker:
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Environment Variables**: Source the environment variables:
|
||||||
|
```bash
|
||||||
|
source .env
|
||||||
|
```
|
||||||
|
Or set them manually:
|
||||||
|
- `DATABASE_URL`: PostgreSQL connection string (default: `postgres://postgres:mypassword@localhost:5431/tycho_indexer_0`)
|
||||||
|
- `RPC_URL`: Ethereum RPC endpoint
|
||||||
|
- `SUBSTREAMS_API_TOKEN`: Authentication token for Substreams API
|
||||||
|
- `AUTH_API_KEY`: API key for authentication
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
```bash
|
||||||
|
cargo run -- --package <PACKAGE_NAME>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command Line Options
|
||||||
|
|
||||||
|
- `--package <NAME>` (required): Name of the package to test
|
||||||
|
- `--tycho-logs <BOOL>`: Enable tycho logs (default: true)
|
||||||
|
- `--db-url <URL>`: Postgres database URL (default: postgres://postgres:mypassword@localhost:5431/tycho_indexer_0)
|
||||||
|
- `--vm-traces <BOOL>`: Enable tracing during VM simulations (default: false)
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
Run tests with default settings:
|
||||||
|
```bash
|
||||||
|
cargo run -- --package uniswap-v2
|
||||||
|
```
|
||||||
|
|
||||||
|
Run tests with VM tracing enabled:
|
||||||
|
```bash
|
||||||
|
cargo run -- --package uniswap-v2 --vm-traces true
|
||||||
|
```
|
||||||
|
|
||||||
|
Run tests with custom database URL:
|
||||||
|
```bash
|
||||||
|
cargo run -- --package uniswap-v2 --db-url postgres://user:pass@localhost:5432/custom_db
|
||||||
|
```
|
||||||
|
|
||||||
|
Run tests in silent mode (disable tycho logs):
|
||||||
|
```bash
|
||||||
|
cargo run -- --package uniswap-v2 --tycho-logs false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logging Configuration
|
||||||
|
|
||||||
|
The application uses `tracing` for structured logging. Control log levels using the `RUST_LOG` environment variable:
|
||||||
|
|
||||||
|
### Log Levels
|
||||||
|
```bash
|
||||||
|
# Show test results and progress (recommended)
|
||||||
|
export RUST_LOG=info
|
||||||
|
|
||||||
|
# Show all detailed logs including debug information
|
||||||
|
export RUST_LOG=debug
|
||||||
|
|
||||||
|
# Show only errors (silent mode)
|
||||||
|
export RUST_LOG=error
|
||||||
|
|
||||||
|
# Hide all logs (completely silent)
|
||||||
|
export RUST_LOG=warn
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Output Formatting
|
||||||
|
|
||||||
|
The test runner outputs results similar to:
|
||||||
|
|
||||||
|
```
|
||||||
|
Running 2 tests ...
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
TEST 1: balancer_weighted_pool_test
|
||||||
|
|
||||||
|
✅ Protocol component validation passed.
|
||||||
|
|
||||||
|
✅ Token balance validation passed.
|
||||||
|
|
||||||
|
Amount out for 0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014: calculating for tokens "BAL"/"WETH"
|
||||||
|
Spot price "BAL"/"WETH": 0.123456
|
||||||
|
|
||||||
|
✅ Simulation validation passed.
|
||||||
|
|
||||||
|
✅ balancer_weighted_pool_test passed.
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Tests finished!
|
||||||
|
RESULTS: 2/2 passed.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Module-specific Logging
|
||||||
|
```bash
|
||||||
|
# Enable debug logs for specific modules
|
||||||
|
export RUST_LOG=protocol_testing=debug,tycho_client=info
|
||||||
|
|
||||||
|
# Disable logs for noisy modules
|
||||||
|
export RUST_LOG=info,hyper=warn,reqwest=warn
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running with Different Log Levels
|
||||||
|
```bash
|
||||||
|
# Standard test run with progress output
|
||||||
|
RUST_LOG=info cargo run -- --package uniswap-v2
|
||||||
|
|
||||||
|
# Detailed debug output
|
||||||
|
RUST_LOG=debug cargo run -- --package uniswap-v2
|
||||||
|
|
||||||
|
# Minimal output (errors only)
|
||||||
|
RUST_LOG=error cargo run -- --package uniswap-v2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test Configuration
|
||||||
|
|
||||||
|
Tests are configured via YAML files located in the substreams package directory:
|
||||||
|
- Test configuration: `../substreams/<package>/integration_test.tycho.yaml`
|
||||||
|
- Substreams configuration: `../substreams/<package>/substreams.yaml`
|
||||||
|
|
||||||
|
## What the Tests Do
|
||||||
|
|
||||||
|
1. **Component Validation**: Verifies that all expected protocol components are present in Tycho after indexing
|
||||||
|
2. **State Validation**: Compares indexed component states against expected values
|
||||||
|
3. **Balance Verification**: Validates token balances by querying the blockchain directly (can be skipped)
|
||||||
|
4. **Simulation Testing**: Runs Tycho simulation engine to verify protocol functionality
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- **Database Connection Issues**: Ensure PostgreSQL is running via `docker-compose up -d`
|
||||||
|
- **RPC Errors**: Verify `RPC_URL` is set and accessible
|
||||||
|
- **Missing Substreams**: Check that the package directory exists in `../substreams/<package>/`
|
||||||
|
- **Build Failures**: Ensure all dependencies are installed and environment variables are set
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
mod config;
|
mod config;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
mod test_runner;
|
mod test_runner;
|
||||||
|
mod tycho_rpc;
|
||||||
mod tycho_runner;
|
mod tycho_runner;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod tycho_rpc;
|
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|||||||
@@ -50,28 +50,53 @@ impl TestRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_tests(&self) -> miette::Result<()> {
|
pub fn run_tests(&self) -> miette::Result<()> {
|
||||||
info!("Running tests...");
|
|
||||||
let config_yaml_path = self
|
let config_yaml_path = self
|
||||||
.substreams_path
|
.substreams_path
|
||||||
.join("integration_test.tycho.yaml");
|
.join("integration_test.tycho.yaml");
|
||||||
|
|
||||||
info!("Config YAML: {}", config_yaml_path.display());
|
|
||||||
let figment = Figment::new().merge(Yaml::file(&config_yaml_path));
|
let figment = Figment::new().merge(Yaml::file(&config_yaml_path));
|
||||||
|
|
||||||
let config = figment
|
let config = figment
|
||||||
.extract::<IntegrationTestsConfig>()
|
.extract::<IntegrationTestsConfig>()
|
||||||
.into_diagnostic()
|
.into_diagnostic()
|
||||||
.wrap_err("Failed to load test configuration:")?;
|
.wrap_err("Failed to load test configuration:")?;
|
||||||
info!("Loaded test configuration:");
|
|
||||||
info!("Protocol types: {:?}", config.protocol_type_names);
|
info!("Running {} tests ...\n", config.tests.len());
|
||||||
info!("Found {} tests to run", config.tests.len());
|
info!("--------------------------------\n");
|
||||||
|
|
||||||
|
let mut failed_tests: Vec<String> = Vec::new();
|
||||||
|
let mut count = 1;
|
||||||
|
|
||||||
for test in &config.tests {
|
for test in &config.tests {
|
||||||
if let Err(e) = self.run_test(test, &config, config.skip_balance_check) {
|
info!("TEST {}: {}", count, test.name);
|
||||||
eprintln!("Test '{}' failed: {e}", test.name);
|
|
||||||
|
match self.run_test(test, &config, config.skip_balance_check) {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("\n✅ {} passed.\n", test.name);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
failed_tests.push(test.name.clone());
|
||||||
|
info!("\n❗️ {} failed: {}\n", test.name, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info!("--------------------------------\n");
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"\nTests finished! \nRESULTS: {}/{} passed.\n",
|
||||||
|
config.tests.len() - failed_tests.len(),
|
||||||
|
config.tests.len()
|
||||||
|
);
|
||||||
|
if !failed_tests.is_empty() {
|
||||||
|
info!("Failed tests:");
|
||||||
|
for failed_test in &failed_tests {
|
||||||
|
info!("- {}", failed_test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!("\n");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +106,6 @@ impl TestRunner {
|
|||||||
config: &IntegrationTestsConfig,
|
config: &IntegrationTestsConfig,
|
||||||
skip_balance_check: bool,
|
skip_balance_check: bool,
|
||||||
) -> miette::Result<()> {
|
) -> miette::Result<()> {
|
||||||
info!("Running test: {}", test.name);
|
|
||||||
self.empty_database()
|
self.empty_database()
|
||||||
.into_diagnostic()
|
.into_diagnostic()
|
||||||
.wrap_err("Failed to empty the database")?;
|
.wrap_err("Failed to empty the database")?;
|
||||||
@@ -89,7 +113,6 @@ impl TestRunner {
|
|||||||
let substreams_yaml_path = self
|
let substreams_yaml_path = self
|
||||||
.substreams_path
|
.substreams_path
|
||||||
.join(&config.substreams_yaml_path);
|
.join(&config.substreams_yaml_path);
|
||||||
debug!("Building SPKG on {:?}", substreams_yaml_path);
|
|
||||||
|
|
||||||
let mut initialized_accounts = config
|
let mut initialized_accounts = config
|
||||||
.initialized_accounts
|
.initialized_accounts
|
||||||
@@ -128,8 +151,6 @@ impl TestRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn empty_database(&self) -> Result<(), Error> {
|
fn empty_database(&self) -> Result<(), Error> {
|
||||||
debug!("Emptying the database");
|
|
||||||
|
|
||||||
// Remove db name from URL. This is required because we cannot drop a database that we are
|
// Remove db name from URL. This is required because we cannot drop a database that we are
|
||||||
// currently connected to.
|
// currently connected to.
|
||||||
let base_url = match self.db_url.rfind('/') {
|
let base_url = match self.db_url.rfind('/') {
|
||||||
@@ -357,11 +378,11 @@ fn validate_state(
|
|||||||
for (id, state) in block_msg.states.iter() {
|
for (id, state) in block_msg.states.iter() {
|
||||||
if let Some(tokens) = pairs.get(id) {
|
if let Some(tokens) = pairs.get(id) {
|
||||||
let formatted_token_str = format!("{:}/{:}", &tokens[0].symbol, &tokens[1].symbol);
|
let formatted_token_str = format!("{:}/{:}", &tokens[0].symbol, &tokens[1].symbol);
|
||||||
println!("Calculations for pool {:?} with tokens {:?}", id, formatted_token_str);
|
info!("Amount out for {}: calculating for tokens {:?}", id, formatted_token_str);
|
||||||
state
|
state
|
||||||
.spot_price(&tokens[0], &tokens[1])
|
.spot_price(&tokens[0], &tokens[1])
|
||||||
.map(|price| println!("Spot price {:?}: {:?}", formatted_token_str, price))
|
.map(|price| info!("Spot price {:?}: {:?}", formatted_token_str, price))
|
||||||
.map_err(|e| eprintln!("Error calculating spot price for Pool {:?}: {:?}", id, e))
|
.map_err(|e| info!("Error calculating spot price for Pool {:?}: {:?}", id, e))
|
||||||
.ok();
|
.ok();
|
||||||
// let amount_in =
|
// let amount_in =
|
||||||
// BigUint::from(1u32) * BigUint::from(10u32).pow(tokens[0].decimals as u32);
|
// BigUint::from(1u32) * BigUint::from(10u32).pow(tokens[0].decimals as u32);
|
||||||
@@ -377,5 +398,7 @@ fn validate_state(
|
|||||||
// e)) .ok();
|
// e)) .ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info!("\n✅ Simulation validation passed.\n");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
use tycho_client::rpc::RPCClient;
|
|
||||||
use std::{collections::HashMap, error::Error as StdError, fmt};
|
use std::{collections::HashMap, error::Error as StdError, fmt};
|
||||||
|
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use tycho_client::{HttpRPCClient};
|
use tycho_client::{rpc::RPCClient, HttpRPCClient};
|
||||||
use tycho_common::{
|
use tycho_common::{
|
||||||
dto::{
|
dto::{
|
||||||
Chain, PaginationParams, ProtocolComponent, ProtocolComponentsRequestBody, ResponseAccount,
|
Chain, PaginationParams, ProtocolComponent, ProtocolComponentsRequestBody, ResponseAccount,
|
||||||
ResponseProtocolState, StateRequestBody, VersionParam,
|
ResponseProtocolState, ResponseToken, StateRequestBody, VersionParam,
|
||||||
},
|
},
|
||||||
|
models::token::Token,
|
||||||
Bytes,
|
Bytes,
|
||||||
};
|
};
|
||||||
use tycho_common::dto::ResponseToken;
|
|
||||||
use tycho_common::models::token::Token;
|
|
||||||
|
|
||||||
/// Custom error type for RPC operations
|
/// Custom error type for RPC operations
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -146,7 +144,9 @@ impl TychoClient {
|
|||||||
}
|
}
|
||||||
(
|
(
|
||||||
token_clone.address.clone(),
|
token_clone.address.clone(),
|
||||||
token_clone.try_into().expect("Failed to convert token"),
|
token_clone
|
||||||
|
.try_into()
|
||||||
|
.expect("Failed to convert token"),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<HashMap<_, Token>>();
|
.collect::<HashMap<_, Token>>();
|
||||||
|
|||||||
Reference in New Issue
Block a user