Here's a comprehensive guide to running concurrency tests for a bridging aggregator:
1. Test Types for Bridging Aggregators
Load Testing

# Using tools like Artillery or k6npm install -g artillery artillery run --config load-test.yml bridge-aggregator.yml
Stress Testing
# Push beyond normal limitsartillery run --config stress-test.yml bridge-aggregator.yml
Concurrency Testing
# Test concurrent bridge operationsnode concurrency-test.js
2. Key Test Scenarios
// Example test scenariosconst scenarios = {
// Concurrent bridge requests
concurrentBridges: async () => {
const requests = [
bridgeETHtoPolygon(1, "0x..."),
bridgeETHtoArbitrum(0.5, "0x..."),
bridgeETHtoOptimism(2, "0x...")
];
await Promise.all(requests);
},
// Same bridge, multiple users
multipleUsersSameBridge: async () => {
const users = [user1, user2, user3];
const bridges = users.map(user =>
bridgeETHtoPolygon(1, user.address)
);
await Promise.all(bridges);
},
// Rapid sequential requests
rapidSequential: async () => {
for (let i = 0; i < 100; i++) {
await bridgeETHtoPolygon(0.01, "0x...");
}
}};
3. Tools & Frameworks
Popular Options:
-
k6 (recommended for API load testing)
-
Artillery
-
Locust (Python-based)
-
JMeter
-
Custom scripts with ethers.js/hardhat
k6 Example:
// bridge-load-test.jsimport http from 'k6/http';import { check, sleep } from 'k6';export const options = {
stages: [
{ duration: '30s', target: 50 }, // Ramp up
{ duration: '1m', target: 100 }, // Stay at peak
{ duration: '30s', target: 0 }, // Ramp down
],};export default function () {
const payload = JSON.stringify({
fromChain: 'ethereum',
toChain: 'polygon',
amount: '1000000000000000000',
userAddress: '0x...'
});
const params = {
headers: {
'Content-Type': 'application/json',
},
};
const res = http.post('http://localhost:3000/bridge', payload, params);
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 2s': (r) => r.timings.duration < 2000,
});
sleep(1);}
4. Hardhat/Foundry Tests
// Foundry concurrent test examplepragma solidity ^0.8.0;import "forge-std/Test.sol";contract BridgeAggregatorConcurrencyTest is Test {
function testConcurrentBridges() public {
// Create multiple users
address[] memory users = new address[](10);
for (uint i = 0; i < 10; i++) {
users[i] = address(uint160(i + 1));
vm.deal(users[i], 10 ether);
}
// Execute concurrent bridge requests
for (uint i = 0; i < users.length; i++) {
vm.prank(users[i]);
// Call bridge function concurrently
bridgeAggregator.bridge{value: 1 ether}(
"ethereum",
"polygon",
1 ether,
users[i]
);
}
}}
5. Critical Metrics to Monitor
# Monitoring metricsmetrics:
- response_time:
p95: < 5s p99: < 10s - error_rate: < 1% - throughput: > 100 req/sec - blockchain_specific:
- gas_spikes - nonce_conflicts - rpc_rate_limits
6. Common Test Execution Flow
# Step-by-step execution1. # Start local testnetnpx hardhat node --fork https://eth-mainnet.alchemyapi.io/v2/YOUR_KEY2. # Deploy contractsnpx hardhat run scripts/deploy.js --network localhost3. # Run single-threaded testsnpx hardhat test test/BridgeAggregator.test.js4. # Run concurrency testsnpm run test:concurrency5. # Run load testsk6 run load-tests/bridge-concurrent.js6. # Monitor with Grafana/Prometheusdocker-compose up -d grafana prometheus
7. Best Practices
Before Tests:
# 1. Isolate test environmentexport NETWORK=testnetexport RPC_URL=your_testnet_rpc# 2. Fund test accountsnpm run fund-test-accounts# 3. Clear previous statenpm run clean-state
During Tests:
// Implement proper error handlingtry {
await executeConcurrentBridges();} catch (error) {
// Log specific concurrency errors
if (error.message.includes('nonce too low')) {
console.error('Nonce conflict detected');
}
if (error.message.includes('insufficient funds')) {
console.error('Gas estimation failed');
}}
After Tests:
# Generate reportsnpm run generate-report# Compare with baselinenpm run compare-baseline# Clean upnpm run cleanup-test-accounts
8. Sample Package.json Scripts
{
"scripts": {
"test:concurrency": "hardhat test test/concurrency/ --network localhost",
"test:load": "k6 run load-tests/bridge.js",
"test:stress": "artillery run stress-tests/bridge.yml",
"test:all": "npm run test:concurrency && npm run test:load"
}}
9. Troubleshooting Common Issues
| Issue | Solution |
|---|---|
| Nonce conflicts | Implement nonce management queue |
| RPC rate limiting | Use multiple RPC providers |
| Gas price spikes | Implement gas estimation with buffers |
| Chain reorgs | Add confirmation blocks wait |
10. Reporting & Analysis
# Generate visual reports# Using artilleryartillery run --output report.json test.yml artillery report report.json# Using k6k6 run --out json=test_result.json script.js k6 dashboard replay test_result.json
Start with small concurrency (10-50 users) and gradually increase. Always test on testnets before mainnet, and monitor gas usage, nonce management, and error rates closely.
