Skip to content

Commit 670f30c

Browse files
committed
Merge branch 'master' into fulu-support
2 parents 70ce50a + e47284f commit 670f30c

File tree

13 files changed

+1733
-32
lines changed

13 files changed

+1733
-32
lines changed

Dockerfile-local

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ RUN apt-get update && apt-get -y upgrade && apt-get install -y --no-install-reco
2323
&& update-ca-certificates
2424
ARG userid=10001
2525
ARG groupid=10001
26-
RUN groupadd -g ${groupid} assertoor && useradd -m -u ${userid} -g assertoor assertoor
26+
RUN (getent group ${groupid} || groupadd -g ${groupid} assertoor) && \
27+
useradd -m -u ${userid} -g ${groupid} assertoor
2728
RUN echo "assertoor ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/assertoor
2829
WORKDIR /app
2930
COPY --from=builder /src/bin/* /app/
30-
RUN chown -R assertoor:assertoor /app
31+
RUN chown -R assertoor:${groupid} /app
3132
RUN mkdir /workspace
3233
USER assertoor
3334
WORKDIR /workspace

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ devnet:
2626
.hack/devnet/run.sh
2727

2828
devnet-run: devnet
29-
go run main.go --config .hack/devnet/generated-assertoor-config.yaml
29+
go run main.go --config .hack/devnet/generated-assertoor-config.yaml --verbose
3030

3131
devnet-run-docker: devnet
3232
docker build --file ./Dockerfile-local -t assertoor:devnet-run --build-arg userid=$(CURRENT_UID) --build-arg groupid=$(CURRENT_GID) .

pkg/coordinator/clients/consensus/rpc/beaconapi.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,3 +496,30 @@ func (bc *BeaconClient) SubmitProposerSlashing(ctx context.Context, slashing *ph
496496

497497
return nil
498498
}
499+
500+
type NodeIdentity struct {
501+
PeerID string `json:"peer_id"`
502+
ENR string `json:"enr"`
503+
P2PAddresses []string `json:"p2p_addresses"`
504+
DiscoveryAddresses []string `json:"discovery_addresses"`
505+
Metadata struct {
506+
SeqNumber uint64 `json:"seq_number,string"`
507+
Attnets string `json:"attnets"`
508+
Syncnets string `json:"syncnets"`
509+
} `json:"metadata"`
510+
}
511+
512+
type apiNodeIdentity struct {
513+
Data *NodeIdentity `json:"data"`
514+
}
515+
516+
func (bc *BeaconClient) GetNodeIdentity(ctx context.Context) (*NodeIdentity, error) {
517+
var nodeIdentity apiNodeIdentity
518+
519+
err := bc.getJSON(ctx, fmt.Sprintf("%s/eth/v1/node/identity", bc.endpoint), &nodeIdentity)
520+
if err != nil {
521+
return nil, fmt.Errorf("error retrieving node identity: %v", err)
522+
}
523+
524+
return nodeIdentity.Data, nil
525+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# `check_consensus_identity` Task
2+
3+
This task checks consensus client node identity information by querying the `/eth/v1/node/identity` API endpoint. It can verify various aspects of the node identity including CGC (Custody Group Count) extracted from ENR (Ethereum Node Record).
4+
5+
## Configuration
6+
7+
### Required Parameters
8+
- **`clientPattern`** *(string)*: Pattern to match client names (e.g., `"lodestar-*"`, `"*"` for all)
9+
10+
### Optional Parameters
11+
- **`pollInterval`** *(duration)*: Interval between checks (default: `10s`)
12+
- **`minClientCount`** *(int)*: Minimum number of clients that must pass checks (default: `1`)
13+
- **`maxFailCount`** *(int)*: Maximum number of clients that can fail (-1 for no limit, default: `-1`)
14+
- **`failOnCheckMiss`** *(bool)*: Whether to fail the task when checks don't pass (default: `false`)
15+
16+
### CGC (Custody Group Count) Checks
17+
- **`expectCgc`** *(int)*: Expect exact CGC value
18+
- **`minCgc`** *(int)*: Minimum CGC value required
19+
- **`maxCgc`** *(int)*: Maximum CGC value allowed
20+
21+
### ENR Checks
22+
- **`expectEnrField`** *(map[string]interface{})*: Expected ENR field values
23+
24+
### PeerID Checks
25+
- **`expectPeerIdPattern`** *(string)*: Regex pattern that PeerID must match
26+
27+
### P2P Address Checks
28+
- **`expectP2pAddressCount`** *(int)*: Expected number of P2P addresses
29+
- **`expectP2pAddressMatch`** *(string)*: Regex pattern that at least one P2P address must match
30+
31+
### Metadata Checks
32+
- **`expectSeqNumber`** *(uint64)*: Expected sequence number
33+
- **`minSeqNumber`** *(uint64)*: Minimum sequence number required
34+
35+
## Outputs
36+
37+
The task exports the following data via `ctx.Outputs`:
38+
39+
- **`matchingClients`**: Array of clients that passed all checks
40+
- **`failedClients`**: Array of clients that failed checks
41+
- **`totalCount`**: Total number of clients checked
42+
- **`matchingCount`**: Number of clients that passed checks
43+
- **`failedCount`**: Number of clients that failed checks
44+
45+
Each client result includes:
46+
- `clientName`: Name of the consensus client
47+
- `peerId`: Peer ID from node identity
48+
- `enr`: ENR string
49+
- `p2pAddresses`: Array of P2P addresses
50+
- `discoveryAddresses`: Array of discovery addresses
51+
- `seqNumber`: Metadata sequence number
52+
- `attnets`: Attestation subnets
53+
- `syncnets`: Sync subnets
54+
- `cgc`: Extracted Custody Group Count
55+
- `enrFields`: Parsed ENR fields
56+
- `checksPassed`: Whether all configured checks passed
57+
- `failureReasons`: Array of reasons why checks failed (if any)
58+
59+
## Example Configurations
60+
61+
### Basic Identity Check
62+
```yaml
63+
- name: check_node_identity
64+
task: check_consensus_identity
65+
config:
66+
clientPattern: "lodestar-*"
67+
minClientCount: 1
68+
```
69+
70+
### CGC Validation
71+
```yaml
72+
- name: validate_cgc
73+
task: check_consensus_identity
74+
config:
75+
clientPattern: "*"
76+
expectCgc: 8
77+
failOnCheckMiss: true
78+
```
79+
80+
### Comprehensive Identity Check
81+
```yaml
82+
- name: full_identity_check
83+
task: check_consensus_identity
84+
config:
85+
clientPattern: "prysm-*"
86+
minCgc: 4
87+
maxCgc: 16
88+
expectP2pAddressCount: 2
89+
expectPeerIdPattern: "^16Uiu2HA.*"
90+
minSeqNumber: 1
91+
pollInterval: 30s
92+
failOnCheckMiss: true
93+
```
94+
95+
### Using Outputs in Subsequent Tasks
96+
```yaml
97+
- name: check_identity
98+
task: check_consensus_identity
99+
config:
100+
clientPattern: "*"
101+
expectCgc: 8
102+
103+
- name: verify_results
104+
task: run_shell
105+
config:
106+
command: |
107+
echo "Found ${check_identity.matchingCount} matching clients"
108+
echo "Total CGC sum: $(echo '${check_identity.matchingClients}' | jq '[.[] | .cgc] | add')"
109+
```
110+
111+
## Use Cases
112+
113+
1. **PeerDAS Validation**: Verify nodes have correct custody assignments
114+
2. **Network Health**: Check node identity consistency across clients
115+
3. **Configuration Validation**: Ensure nodes are properly configured for specific network requirements
116+
4. **Testing**: Validate node behavior changes after deposits or configuration updates
117+
5. **Monitoring**: Track node identity changes over time
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package checkconsensusidentity
2+
3+
import (
4+
"fmt"
5+
"time"
6+
7+
"github.com/ethpandaops/assertoor/pkg/coordinator/helper"
8+
)
9+
10+
type Config struct {
11+
ClientPattern string `yaml:"clientPattern" json:"clientPattern"`
12+
PollInterval helper.Duration `yaml:"pollInterval" json:"pollInterval"`
13+
MinClientCount int `yaml:"minClientCount" json:"minClientCount"`
14+
MaxFailCount int `yaml:"maxFailCount" json:"maxFailCount"`
15+
FailOnCheckMiss bool `yaml:"failOnCheckMiss" json:"failOnCheckMiss"`
16+
17+
// CGC (Custody Group Count) checks
18+
ExpectCGC *uint64 `yaml:"expectCgc" json:"expectCgc"`
19+
MinCGC *uint64 `yaml:"minCgc" json:"minCgc"`
20+
MaxCGC *uint64 `yaml:"maxCgc" json:"maxCgc"`
21+
22+
// ENR checks
23+
ExpectENRField map[string]interface{} `yaml:"expectEnrField" json:"expectEnrField"`
24+
25+
// PeerID checks
26+
ExpectPeerIDPattern string `yaml:"expectPeerIdPattern" json:"expectPeerIdPattern"`
27+
28+
// P2P address checks
29+
ExpectP2PAddressCount *int `yaml:"expectP2pAddressCount" json:"expectP2pAddressCount"`
30+
ExpectP2PAddressMatch string `yaml:"expectP2pAddressMatch" json:"expectP2pAddressMatch"`
31+
32+
// Metadata checks
33+
ExpectSeqNumber *uint64 `yaml:"expectSeqNumber" json:"expectSeqNumber"`
34+
MinSeqNumber *uint64 `yaml:"minSeqNumber" json:"minSeqNumber"`
35+
}
36+
37+
func DefaultConfig() Config {
38+
return Config{
39+
PollInterval: helper.Duration{Duration: 10 * time.Second},
40+
MaxFailCount: -1,
41+
MinClientCount: 1,
42+
}
43+
}
44+
45+
func (c *Config) Validate() error {
46+
if c.ClientPattern == "" {
47+
return fmt.Errorf("clientPattern is required")
48+
}
49+
50+
if c.MinCGC != nil && c.MaxCGC != nil && *c.MinCGC > *c.MaxCGC {
51+
return fmt.Errorf("minCgc must be <= maxCgc")
52+
}
53+
54+
if c.ExpectP2PAddressCount != nil && *c.ExpectP2PAddressCount < 0 {
55+
return fmt.Errorf("expectP2pAddressCount must be >= 0")
56+
}
57+
58+
return nil
59+
}

0 commit comments

Comments
 (0)