|
| 1 | +# Tangle Network - Chopsticks Testing Suite |
| 2 | + |
| 3 | +This directory contains configuration files and tests for validating Tangle runtime upgrades using [Chopsticks](https://github.com/AcalaNetwork/chopsticks), a powerful tool for forking and testing Substrate-based blockchains. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +Chopsticks enables safe, local testing of runtime migrations by creating a fork of the live Tangle network. This allows us to: |
| 8 | + |
| 9 | +- Test runtime upgrades against real mainnet state |
| 10 | +- Validate storage migrations without risk |
| 11 | +- Debug issues before deploying to production |
| 12 | +- Simulate complex scenarios (governance, XCM, etc.) |
| 13 | + |
| 14 | +## Prerequisites |
| 15 | + |
| 16 | +- **Node.js** >= 18.0.0 |
| 17 | +- **Rust** toolchain with wasm32 target |
| 18 | +- **Tangle node** built with `try-runtime` feature |
| 19 | + |
| 20 | +## Quick Start |
| 21 | + |
| 22 | +### 1. Install Dependencies |
| 23 | + |
| 24 | +```bash |
| 25 | +cd chopsticks |
| 26 | +npm install |
| 27 | +``` |
| 28 | + |
| 29 | +### 2. Build Runtime with Try-Runtime |
| 30 | + |
| 31 | +```bash |
| 32 | +# From repository root |
| 33 | +cargo build --release -p tangle-mainnet-runtime --features=try-runtime |
| 34 | +cargo build --release -p tangle-testnet-runtime --features=try-runtime |
| 35 | +``` |
| 36 | + |
| 37 | +### 3. Fork Tangle Network |
| 38 | + |
| 39 | +```bash |
| 40 | +# Fork mainnet |
| 41 | +npm run fork:mainnet |
| 42 | + |
| 43 | +# Or fork testnet |
| 44 | +npm run fork:testnet |
| 45 | +``` |
| 46 | + |
| 47 | +The forked chain will be available at `ws://localhost:8000`. |
| 48 | + |
| 49 | +### 4. Connect with Polkadot.js Apps |
| 50 | + |
| 51 | +1. Open https://polkadot.js.org/apps |
| 52 | +2. Connect to `ws://localhost:8000` |
| 53 | +3. Interact with forked chain as if it were live |
| 54 | + |
| 55 | +### 5. Run Automated Tests |
| 56 | + |
| 57 | +```bash |
| 58 | +npm test |
| 59 | +``` |
| 60 | + |
| 61 | +## Directory Structure |
| 62 | + |
| 63 | +``` |
| 64 | +chopsticks/ |
| 65 | +├── configs/ |
| 66 | +│ ├── tangle-mainnet.yml # Mainnet fork configuration |
| 67 | +│ └── tangle-testnet.yml # Testnet fork configuration |
| 68 | +├── tests/ |
| 69 | +│ ├── migration.test.ts # Migration testing suite |
| 70 | +│ └── integration.test.ts # Integration tests |
| 71 | +├── db/ |
| 72 | +│ └── *.sqlite # Cached chain state (gitignored) |
| 73 | +├── output/ |
| 74 | +│ └── *.json # Test outputs (gitignored) |
| 75 | +├── package.json |
| 76 | +├── tsconfig.json |
| 77 | +├── vitest.config.ts |
| 78 | +└── README.md |
| 79 | +``` |
| 80 | + |
| 81 | +## Configuration Files |
| 82 | + |
| 83 | +### Mainnet Configuration (`configs/tangle-mainnet.yml`) |
| 84 | + |
| 85 | +Connects to Tangle mainnet RPC and forks the chain with the new runtime. |
| 86 | + |
| 87 | +**Key settings:** |
| 88 | +- `endpoint`: Live RPC endpoints |
| 89 | +- `wasm-override`: Path to new runtime WASM |
| 90 | +- `import-storage`: Custom storage for testing (Alice/Bob accounts) |
| 91 | +- `mock-signature-host`: Enables testing without real signatures |
| 92 | + |
| 93 | +### Testnet Configuration (`configs/tangle-testnet.yml`) |
| 94 | + |
| 95 | +Similar to mainnet but connects to Tangle testnet. |
| 96 | + |
| 97 | +## Usage Examples |
| 98 | + |
| 99 | +### Basic Forking |
| 100 | + |
| 101 | +```bash |
| 102 | +# Fork at latest block |
| 103 | +npx @acala-network/chopsticks --config=./configs/tangle-mainnet.yml |
| 104 | + |
| 105 | +# Fork at specific block |
| 106 | +npx @acala-network/chopsticks \ |
| 107 | + --config=./configs/tangle-mainnet.yml \ |
| 108 | + --block=1000000 |
| 109 | +``` |
| 110 | + |
| 111 | +### With Runtime Override |
| 112 | + |
| 113 | +```bash |
| 114 | +# Test new runtime against mainnet state |
| 115 | +npx @acala-network/chopsticks \ |
| 116 | + --config=./configs/tangle-mainnet.yml \ |
| 117 | + --wasm-override=../target/release/wbuild/tangle-mainnet-runtime/tangle_mainnet_runtime.compact.compressed.wasm |
| 118 | +``` |
| 119 | + |
| 120 | +### Block Replay |
| 121 | + |
| 122 | +```bash |
| 123 | +# Analyze specific block |
| 124 | +npx @acala-network/chopsticks run-block \ |
| 125 | + --config=./configs/tangle-mainnet.yml \ |
| 126 | + --block=1000000 \ |
| 127 | + --output-path=./output/block-1000000.json \ |
| 128 | + --html \ |
| 129 | + --open |
| 130 | +``` |
| 131 | + |
| 132 | +### Dry-Run Extrinsics |
| 133 | + |
| 134 | +```bash |
| 135 | +# Test extrinsic without committing |
| 136 | +npx @acala-network/chopsticks dry-run \ |
| 137 | + --config=./configs/tangle-mainnet.yml \ |
| 138 | + --extrinsic=0x... \ |
| 139 | + --html \ |
| 140 | + --open |
| 141 | +``` |
| 142 | + |
| 143 | +## Testing Runtime Migrations |
| 144 | + |
| 145 | +### 1. Manual Testing via Polkadot.js |
| 146 | + |
| 147 | +```javascript |
| 148 | +// Connect to forked chain |
| 149 | +const api = await ApiPromise.create({ |
| 150 | + provider: new WsProvider('ws://localhost:8000') |
| 151 | +}); |
| 152 | + |
| 153 | +// Check runtime version |
| 154 | +const version = await api.rpc.state.getRuntimeVersion(); |
| 155 | +console.log('Runtime:', version.toHuman()); |
| 156 | + |
| 157 | +// Simulate runtime upgrade |
| 158 | +const blockNumber = (await api.rpc.chain.getHeader()).number.toNumber(); |
| 159 | +await api.rpc('dev_setStorage', { |
| 160 | + Scheduler: { |
| 161 | + Agenda: [[ |
| 162 | + [blockNumber + 1], |
| 163 | + [{ |
| 164 | + call: { Inline: api.tx.system.setCode('0x...').toHex() }, |
| 165 | + origin: { system: 'Root' } |
| 166 | + }] |
| 167 | + ]] |
| 168 | + } |
| 169 | +}); |
| 170 | + |
| 171 | +// Execute upgrade |
| 172 | +await api.rpc('dev_newBlock', { count: 1 }); |
| 173 | + |
| 174 | +// Verify success |
| 175 | +const events = await api.query.system.events(); |
| 176 | +events.forEach(({ event }) => { |
| 177 | + console.log(`${event.section}.${event.method}`); |
| 178 | +}); |
| 179 | +``` |
| 180 | + |
| 181 | +### 2. Automated Testing |
| 182 | + |
| 183 | +```bash |
| 184 | +# Run all tests |
| 185 | +npm test |
| 186 | + |
| 187 | +# Run specific test file |
| 188 | +npx vitest run tests/migration.test.ts |
| 189 | + |
| 190 | +# Watch mode for development |
| 191 | +npm run test:watch |
| 192 | + |
| 193 | +# Generate coverage report |
| 194 | +npm run test:coverage |
| 195 | +``` |
| 196 | + |
| 197 | +### 3. Try-Runtime CLI Integration |
| 198 | + |
| 199 | +```bash |
| 200 | +# Test migrations with try-runtime |
| 201 | +try-runtime \ |
| 202 | + --runtime ../target/release/wbuild/tangle-mainnet-runtime/tangle_mainnet_runtime.compact.compressed.wasm \ |
| 203 | + on-runtime-upgrade \ |
| 204 | + --checks=all \ |
| 205 | + live \ |
| 206 | + --uri ws://localhost:8000 |
| 207 | +``` |
| 208 | + |
| 209 | +## Best Practices |
| 210 | + |
| 211 | +### ✅ DO |
| 212 | + |
| 213 | +- Build runtime with `--features=try-runtime` for testing |
| 214 | +- Implement `pre_upgrade` and `post_upgrade` hooks |
| 215 | +- Test against both mainnet and testnet forks |
| 216 | +- Verify storage migrations are idempotent |
| 217 | +- Check weight consumption doesn't exceed limits |
| 218 | +- Test critical user flows after migration |
| 219 | +- Use try-runtime-cli for additional validation |
| 220 | + |
| 221 | +### ❌ DON'T |
| 222 | + |
| 223 | +- Deploy migrations without testing on fork |
| 224 | +- Iterate over unbounded storage |
| 225 | +- Forget to increment RuntimeVersion |
| 226 | +- Skip try-runtime checks |
| 227 | +- Test only happy paths |
| 228 | + |
| 229 | +## Troubleshooting |
| 230 | + |
| 231 | +### "Connection refused" error |
| 232 | + |
| 233 | +**Cause**: RPC endpoint unavailable or network issues |
| 234 | + |
| 235 | +**Solution**: |
| 236 | +- Check endpoint in config file |
| 237 | +- Try alternative RPC from `endpoint` list |
| 238 | +- Verify network connectivity |
| 239 | + |
| 240 | +### "WASM override not found" error |
| 241 | + |
| 242 | +**Cause**: Runtime WASM not built or wrong path |
| 243 | + |
| 244 | +**Solution**: |
| 245 | +```bash |
| 246 | +cargo build --release -p tangle-mainnet-runtime --features=try-runtime |
| 247 | +ls -lh ../target/release/wbuild/tangle-mainnet-runtime/*.wasm |
| 248 | +``` |
| 249 | + |
| 250 | +### "Weight limit exceeded" error |
| 251 | + |
| 252 | +**Cause**: Migration consumes too much weight |
| 253 | + |
| 254 | +**Solution**: Implement multi-block migration or optimize code |
| 255 | + |
| 256 | +### Database corruption |
| 257 | + |
| 258 | +**Cause**: Interrupted fork or version mismatch |
| 259 | + |
| 260 | +**Solution**: Delete and recreate database |
| 261 | +```bash |
| 262 | +rm -rf db/*.sqlite |
| 263 | +``` |
| 264 | + |
| 265 | +## Additional Resources |
| 266 | + |
| 267 | +- [Chopsticks Documentation](https://github.com/AcalaNetwork/chopsticks) |
| 268 | +- [Chopsticks Recipe Book](https://hackmd.io/@seadanda/Sk3qcRlM0) |
| 269 | +- [Polkadot SDK Runtime Migrations Guide](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_runtime_upgrades_and_migrations/index.html) |
| 270 | +- [Try-Runtime CLI](https://github.com/paritytech/try-runtime-cli) |
| 271 | +- [Substrate Stack Exchange](https://substrate.stackexchange.com/) |
| 272 | + |
| 273 | +## Support |
| 274 | + |
| 275 | +For issues with Chopsticks: |
| 276 | +- [GitHub Issues](https://github.com/AcalaNetwork/chopsticks/issues) |
| 277 | +- [Polkadot Forum](https://forum.polkadot.network/) |
| 278 | + |
| 279 | +For Tangle-specific questions: |
| 280 | +- [Tangle Discord](https://discord.gg/tangle) |
| 281 | +- [Tangle GitHub](https://github.com/tangle-network/tangle) |
| 282 | + |
| 283 | +## License |
| 284 | + |
| 285 | +This testing suite is part of the Tangle Network project and follows the same license terms. |
0 commit comments