Skip to content

Commit c85e070

Browse files
authored
refactor: restructure loadtest into library with mode packages (#828)
* refactor: restructure loadtest into library with mode packages - Move loadtest logic from cmd/loadtest/ to loadtest/ library - Create loadtest/mode/ for shared infrastructure (interface, registry, dependencies, util) - Create loadtest/modes/ for mode implementations - Create loadtest/config/ for configuration types - Refactor UniswapV3Mode to use dependencies directly instead of callback - Fix strings.HasPrefix() argument order in recall.go for ERC20/ERC721 detection - Fix index mismatch in rpc.go using wrong array length after deduplication - Replace println() with fmt.Println() in util.go for proper stdout output - Simplify deduplicate() using maps.Keys and slices.Collect - Rename Initialize to Init in mode interface - Move AccountPoolConfig to loadtest/account.go * fix: resolve variable shadowing errors in loadtest/runner.go * fix: lint * fix: remove ineffectual assignment to gasPrice in account.go * fix: initialize RandSource in mode dependencies * fix: regressions * fix: more regressions * fix: more regressions * fix: even more regressions * fix: regressions * fix: regressions * fix: improve shutdown handling and initialization order * fix: lint * fix: more regressions * fix: lint * fix: uniswapv3 subcommand * fix: regression * fix: rename var
1 parent 8abc054 commit c85e070

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+4264
-3184
lines changed

CLAUDE.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,20 @@ The project follows a command-based architecture using Cobra framework:
1212

1313
- **Main Entry**: `main.go` simply calls `cmd.Execute()`
1414
- **Command Structure**: Each command is organized in its own package under `cmd/` (e.g., `cmd/loadtest/`, `cmd/monitor/`)
15+
- **Subcommand Structure**: Subcommands should also be in their own package (e.g., `cmd/loadtest/uniswapv3/` for `polycli loadtest uniswapv3`)
1516
- **Bindings**: Go bindings for smart contracts are in `bindings/` (generated from Solidity contracts in `contracts/`)
1617
- **Utilities**: Common utilities are in `util/` package
1718

1819
Key architectural patterns:
20+
1921
- Commands are self-contained with their own usage documentation (`.md` files)
2022
- Heavy use of code generation for documentation, protobuf, contract bindings, and RPC types
2123
- Docker-based generation workflows to ensure consistency
2224

2325
## Common Development Commands
2426

2527
### Building and Installation
28+
2629
```bash
2730
# Build the binary
2831
make build
@@ -36,6 +39,7 @@ make simplecross # Without CGO
3639
```
3740

3841
### Testing
42+
3943
```bash
4044
# Run all tests with coverage
4145
make test
@@ -49,6 +53,7 @@ make geth-loadtest # Fund account and run load test
4953
```
5054

5155
### Code Quality
56+
5257
```bash
5358
# Run all linters (includes tidy, vet, golangci-lint)
5459
make lint
@@ -61,6 +66,7 @@ make golangci-lint # Run golangci-lint
6166
```
6267

6368
### Code Generation
69+
6470
```bash
6571
# Generate everything (docs, proto, bindings, etc.)
6672
make gen
@@ -74,6 +80,7 @@ make gen-json-rpc-types # Generate JSON RPC types
7480
```
7581

7682
### Contract Development
83+
7784
```bash
7885
# Work with smart contracts
7986
cd contracts/
@@ -84,6 +91,7 @@ make gen-go-bindings # Generate Go bindings
8491
## Adding New Features
8592

8693
When adding a new command:
94+
8795
1. Create a new package under `cmd/your-command/`
8896
2. Add the command to `cmd/root.go` in the `NewPolycliCommand()` function
8997
3. Create a usage documentation file (e.g., `yourCommandUsage.md`)
@@ -93,6 +101,7 @@ When adding a new command:
93101
## CI/CD Considerations
94102

95103
The CI pipeline (`/.github/workflows/ci.yml`) runs:
104+
96105
- Linting (golangci-lint, shadow)
97106
- Tests
98107
- Generation checks (ensures all generated files are up-to-date)
@@ -110,6 +119,7 @@ Always run `make gen` before committing if you've changed anything that affects
110119
## Environment Configuration
111120

112121
The tool supports configuration via:
122+
113123
- CLI flags (highest priority)
114124
- Environment variables
115125
- Config file (`~/.polygon-cli.yaml`)
@@ -120,16 +130,19 @@ The tool supports configuration via:
120130
- Use zerolog for structured, performant logging throughout the project
121131

122132
## Development Guidelines
133+
123134
- Use conventional commit messages
124135

125136
## Development Memories
137+
126138
- Use `make build` to build polycli
127139

128140
## Code Quality Checklist
129141

130142
**CRITICAL**: Before writing any code, systematically check these categories to avoid rework:
131143

132144
### 0. Critical Thinking & Code Analysis (Meta-Level)
145+
133146
**MOST IMPORTANT**: Think critically before implementing any suggestion or requirement.
134147

135148
- **Analyze Existing Code First**: Before adding validation, checks, or features, thoroughly examine what already exists
@@ -143,12 +156,14 @@ The tool supports configuration via:
143156
- **Evaluate Necessity**: Just because something CAN be added doesn't mean it SHOULD be. Ask: "Does this add value or just clutter?"
144157

145158
**Questions to ask before writing ANY code:**
159+
146160
1. "What validation/checks already exist in this call chain?"
147161
2. "Is this truly adding safety, or is it redundant?"
148162
3. "What value does this code provide?"
149163
4. "Am I implementing this because it was suggested, or because it's actually needed?"
150164

151165
**Example of what NOT to do:**
166+
152167
```go
153168
// Earlier in function (line 211)
154169
if report.EndBlock == math.MaxUint64 {
@@ -163,29 +178,34 @@ if report.EndBlock == math.MaxUint64 {
163178
}
164179
totalBlocks := report.EndBlock - report.StartBlock + 1
165180
```
181+
166182
This is pure redundancy - if the value can't be MaxUint64 (validated at line 211), checking again at line 231 adds zero value.
167183

168184
### 1. Security
185+
169186
- **HTML/Template Injection**: Always use `html.EscapeString()` for any data interpolated into HTML, even if currently from trusted sources
170187
- **Input Validation**: Validate all user inputs at boundaries (flags, API inputs)
171188
- **SQL Injection**: Use parameterized queries, never string concatenation
172189
- **Command Injection**: Never pass user input directly to shell commands
173190
- **Question to ask**: "What data is untrusted? Where does it flow? Is it escaped/validated at every output point?"
174191

175192
### 2. Resource Management & Performance
193+
176194
- **Goroutine Lifecycle**: Every goroutine must have a clear termination condition via context cancellation
177195
- **Timer Cleanup**: Use `time.NewTimer()` + `defer timer.Stop()`, never `time.After()` in select statements (causes goroutine leaks)
178196
- **Channel Buffers**: Use small fixed buffers (e.g., `concurrency*2`), never proportional to total dataset size
179197
- **Memory Allocation**: Consider behavior with 10x, 100x, 1000x expected input
180198
- **Question to ask**: "How does every goroutine, timer, and channel clean up on cancellation? What's the memory footprint at scale?"
181199

182200
### 3. Context Propagation
201+
183202
- **Never create root contexts**: Always thread `context.Context` through call chains; never use `context.Background()` in the middle of operations
184203
- **Cancellation Flow**: Context should flow through every I/O operation, long-running task, and goroutine
185204
- **Timeout Management**: Create child contexts with `context.WithTimeout(parentCtx, duration)`, not `context.WithTimeout(context.Background(), duration)`
186205
- **Question to ask**: "Does context flow through all long-running operations? Will Ctrl+C immediately stop everything?"
187206

188207
### 4. Data Integrity & Determinism
208+
189209
- **Completeness**: Data collection operations must fetch ALL requested data or fail entirely - never produce partial results
190210
- **Retry Logic**: Failed operations should retry (with backoff) before failing
191211
- **Idempotency**: Same input parameters should produce identical output every time
@@ -194,6 +214,7 @@ This is pure redundancy - if the value can't be MaxUint64 (validated at line 211
194214
- **Question to ask**: "If I run this twice with the same parameters, will I get identical results? What makes this non-deterministic? Am I reading from the authoritative data source?"
195215

196216
### 5. Error Handling & Logging
217+
197218
- **Error Wrapping**: Use `fmt.Errorf("context: %w", err)` to wrap errors with context
198219
- **Single-line Messages**: Put context before `%w` in single line: `fmt.Errorf("failed after %d attempts: %w", n, err)`
199220
- **Failure Modes**: Consider and handle all failure paths explicitly
@@ -202,6 +223,7 @@ This is pure redundancy - if the value can't be MaxUint64 (validated at line 211
202223
- **Question to ask**: "What can fail? How is each failure mode handled? Are errors properly wrapped? Is progress logging accurate during retries/failures?"
203224

204225
### 6. Concurrency Patterns
226+
205227
- **Channel Closing**: Close channels in the correct goroutine (usually the sender); use atomic counters to coordinate
206228
- **Channel Draining**: When using select with multiple channels and one closes, drain remaining channels to avoid missing messages
207229
- **Worker Pools**: Use `sync.WaitGroup` to wait for workers; protect shared state with mutexes or channels
@@ -210,6 +232,7 @@ This is pure redundancy - if the value can't be MaxUint64 (validated at line 211
210232
- **Question to ask**: "Who closes each channel? Can any goroutine block forever? Does this have race conditions? Are all channel messages guaranteed to be read?"
211233

212234
### 7. Testing & Validation
235+
213236
- **Test Coverage**: Write tests for edge cases, not just happy paths
214237
- **Error Injection**: Test retry logic, failure modes, and error paths
215238
- **Resource Limits**: Test with large inputs to verify scalability
@@ -297,6 +320,7 @@ go func() {
297320
## Code Style
298321

299322
### Cobra Flags
323+
300324
- Flag names: lowercase with hyphens (kebab-case), e.g., `--output-file`
301325
- Usage strings: lowercase, no ending punctuation, e.g., `"path to output file"`
302326
- Remove unnecessary leading articles and filler words (e.g., "the", "a", "an") from usage strings
@@ -317,9 +341,11 @@ go func() {
317341
```
318342

319343
### Cobra Command Arguments
344+
320345
- Prefer to use Cobra built-in validators (`cobra.NoArgs`, `cobra.ExactArgs(n)`, `cobra.MinimumNArgs(n)`, `cobra.MaximumNArgs(n)`, `cobra.ArbitraryArgs`) instead of custom `Args: func(cmd *cobra.Command, args []string) error` functions, and move argument parsing/validation logic to `PreRunE` hook
321346

322347
### Cobra Commands
348+
323349
- Command `Short` descriptions: sentence case with ending period, e.g., `"Generate a node list to seed a node."`
324350
- Command `Long` descriptions: consider using embedded usage.md file via `//go:embed usage.md` pattern; when using inline strings, use sentence case with ending period for complete sentences
325351
- Command `Short` should be brief (~50 characters or less), appears in help menus and command lists

0 commit comments

Comments
 (0)