Skip to content

Commit c15bc4f

Browse files
committed
add check_execution_conversion_state task (checks verkle conversion state)
1 parent 4016768 commit c15bc4f

File tree

6 files changed

+231
-0
lines changed

6 files changed

+231
-0
lines changed

pkg/coordinator/clients/execution/rpc/executionapi.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,10 @@ func (ec *ExecutionClient) GetTransactionReceipt(ctx context.Context, txHash com
126126
func (ec *ExecutionClient) SendTransaction(ctx context.Context, tx *types.Transaction) error {
127127
return ec.ethClient.SendTransaction(ctx, tx)
128128
}
129+
130+
func (ec *ExecutionClient) GetVerkleConversionState(ctx context.Context) (*VerkleConversionState, error) {
131+
var result VerkleConversionState
132+
err := ec.rpcClient.CallContext(ctx, &result, "debug_conversionStatus", "latest")
133+
134+
return &result, err
135+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package rpc
2+
3+
type VerkleConversionState struct {
4+
Started bool `json:"started"`
5+
Ended bool `json:"ended"`
6+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
## `check_execution_conversion_state` Task
2+
3+
### Description
4+
The `check_execution_conversion_state` task is designed to monitor the status of execution clients regarding their conversion to the Verkle tree structure, a significant upgrade in the Ethereum network. This task assesses whether the execution clients have started, are in the process of, or have completed the conversion to Verkle trees, ensuring that the network's upgrade transitions are proceeding as expected.
5+
6+
### Configuration Parameters
7+
8+
- **`clientPattern`**:
9+
A regex pattern for selecting specific execution client endpoints to check. This allows for targeted monitoring of clients based on identifiers or characteristics defined in their endpoint URLs.
10+
11+
- **`pollInterval`**:
12+
The time interval, in seconds, at which the task will poll the clients to check their Verkle conversion status. A shorter interval results in more frequent checks, allowing for timely detection of state changes.
13+
14+
- **`expectStarted`**:
15+
If set to `true`, this option indicates the expectation that the Verkle conversion process has started on the targeted execution clients. The task checks for evidence that the conversion process is underway.
16+
17+
- **`expectFinished`**:
18+
When `true`, the task expects that the Verkle conversion process has been completed on the targeted execution clients. It verifies that the clients are fully upgraded to the new tree structure.
19+
20+
- **`failOnUnexpected`**:
21+
If set to `true`, the task will fail if the actual conversion status of the clients does not match the expected states (`expectStarted`, `expectFinished`). This is useful for scenarios where strict compliance with the conversion timeline is critical.
22+
23+
### Defaults
24+
25+
Default settings for the `check_execution_conversion_state` task:
26+
27+
```yaml
28+
- name: check_execution_conversion_state
29+
config:
30+
clientPattern: ""
31+
pollInterval: 5s
32+
expectStarted: false
33+
expectFinished: false
34+
failOnUnexpected: false
35+
```
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package checkexecutionconversionstate
2+
3+
import (
4+
"time"
5+
6+
"github.com/ethpandaops/assertoor/pkg/coordinator/human-duration"
7+
)
8+
9+
type Config struct {
10+
ClientPattern string `yaml:"clientPattern" json:"clientPattern"`
11+
PollInterval human.Duration `yaml:"pollInterval" json:"pollInterval"`
12+
ExpectStarted bool `yaml:"expectStarted" json:"expectStarted"`
13+
ExpectFinished bool `yaml:"expectFinished" json:"expectFinished"`
14+
FailOnUnexpected bool `yaml:"failOnUnexpected" json:"failOnUnexpected"`
15+
}
16+
17+
func DefaultConfig() Config {
18+
return Config{
19+
PollInterval: human.Duration{Duration: 5 * time.Second},
20+
}
21+
}
22+
23+
func (c *Config) Validate() error {
24+
return nil
25+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package checkexecutionconversionstate
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/ethpandaops/assertoor/pkg/coordinator/clients/execution/rpc"
9+
"github.com/ethpandaops/assertoor/pkg/coordinator/types"
10+
"github.com/sirupsen/logrus"
11+
)
12+
13+
var (
14+
TaskName = "check_execution_conversion_state"
15+
TaskDescriptor = &types.TaskDescriptor{
16+
Name: TaskName,
17+
Description: "Checks execution clients for their verkle conversion status.",
18+
Config: DefaultConfig(),
19+
NewTask: NewTask,
20+
}
21+
)
22+
23+
type Task struct {
24+
ctx *types.TaskContext
25+
options *types.TaskOptions
26+
config Config
27+
logger logrus.FieldLogger
28+
firstHeight map[uint16]uint64
29+
}
30+
31+
func NewTask(ctx *types.TaskContext, options *types.TaskOptions) (types.Task, error) {
32+
return &Task{
33+
ctx: ctx,
34+
options: options,
35+
logger: ctx.Logger.GetLogger(),
36+
firstHeight: map[uint16]uint64{},
37+
}, nil
38+
}
39+
40+
func (t *Task) Name() string {
41+
return TaskName
42+
}
43+
44+
func (t *Task) Description() string {
45+
return TaskDescriptor.Description
46+
}
47+
48+
func (t *Task) Title() string {
49+
return t.ctx.Vars.ResolvePlaceholders(t.options.Title)
50+
}
51+
52+
func (t *Task) Config() interface{} {
53+
return t.config
54+
}
55+
56+
func (t *Task) Logger() logrus.FieldLogger {
57+
return t.logger
58+
}
59+
60+
func (t *Task) Timeout() time.Duration {
61+
return t.options.Timeout.Duration
62+
}
63+
64+
func (t *Task) LoadConfig() error {
65+
config := DefaultConfig()
66+
67+
// parse static config
68+
if t.options.Config != nil {
69+
if err := t.options.Config.Unmarshal(&config); err != nil {
70+
return fmt.Errorf("error parsing task config for %v: %w", TaskName, err)
71+
}
72+
}
73+
74+
// load dynamic vars
75+
err := t.ctx.Vars.ConsumeVars(&config, t.options.ConfigVars)
76+
if err != nil {
77+
return err
78+
}
79+
80+
// validate config
81+
if err := config.Validate(); err != nil {
82+
return err
83+
}
84+
85+
t.config = config
86+
87+
return nil
88+
}
89+
90+
func (t *Task) Execute(ctx context.Context) error {
91+
t.processCheck(ctx)
92+
93+
for {
94+
select {
95+
case <-time.After(t.config.PollInterval.Duration):
96+
t.processCheck(ctx)
97+
case <-ctx.Done():
98+
return nil
99+
}
100+
}
101+
}
102+
103+
func (t *Task) processCheck(ctx context.Context) {
104+
allResultsPass := true
105+
failedClients := []string{}
106+
107+
for _, client := range t.ctx.Scheduler.GetServices().ClientPool().GetClientsByNamePatterns(t.config.ClientPattern, "") {
108+
var checkResult bool
109+
110+
checkLogger := t.logger.WithField("client", client.Config.Name)
111+
conversionStatus, err := client.ExecutionClient.GetRPCClient().GetVerkleConversionState(ctx)
112+
113+
if ctx.Err() != nil {
114+
return
115+
}
116+
117+
if err != nil {
118+
checkLogger.Warnf("error fetching verkle conversion status: %v", err)
119+
120+
checkResult = false
121+
} else {
122+
checkResult = t.processClientCheck(conversionStatus, checkLogger)
123+
}
124+
125+
if !checkResult {
126+
allResultsPass = false
127+
128+
failedClients = append(failedClients, client.Config.Name)
129+
}
130+
}
131+
132+
t.logger.Infof("Check result: %v, Failed Clients: %v", allResultsPass, failedClients)
133+
134+
switch {
135+
case allResultsPass:
136+
t.ctx.SetResult(types.TaskResultSuccess)
137+
case t.config.FailOnUnexpected:
138+
t.ctx.SetResult(types.TaskResultFailure)
139+
default:
140+
t.ctx.SetResult(types.TaskResultNone)
141+
}
142+
}
143+
144+
func (t *Task) processClientCheck(conversionStatus *rpc.VerkleConversionState, checkLogger logrus.FieldLogger) bool {
145+
if conversionStatus.Started != t.config.ExpectStarted {
146+
checkLogger.Debugf("check failed. check: ExpectStarted, expected: %v, got: %v", t.config.ExpectStarted, conversionStatus.Started)
147+
return false
148+
}
149+
150+
if conversionStatus.Ended != t.config.ExpectFinished {
151+
checkLogger.Debugf("check failed. check: ExpectFinished, expected: %v, got: %v", t.config.ExpectFinished, conversionStatus.Ended)
152+
return false
153+
}
154+
155+
return true
156+
}

pkg/coordinator/tasks/tasks.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
checkconsensusslotrange "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/check_consensus_slot_range"
1414
checkconsensussyncstatus "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/check_consensus_sync_status"
1515
checkconsensusvalidatorstatus "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/check_consensus_validator_status"
16+
checkexecutionconversionstate "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/check_execution_conversion_state"
1617
checkexecutionsyncstatus "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/check_execution_sync_status"
1718
generateblobtransactions "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/generate_blob_transactions"
1819
generateblschanges "github.com/ethpandaops/assertoor/pkg/coordinator/tasks/generate_bls_changes"
@@ -44,6 +45,7 @@ var AvailableTaskDescriptors = []*types.TaskDescriptor{
4445
checkconsensusslotrange.TaskDescriptor,
4546
checkconsensussyncstatus.TaskDescriptor,
4647
checkconsensusvalidatorstatus.TaskDescriptor,
48+
checkexecutionconversionstate.TaskDescriptor,
4749
checkexecutionsyncstatus.TaskDescriptor,
4850
generateblobtransactions.TaskDescriptor,
4951
generateblschanges.TaskDescriptor,

0 commit comments

Comments
 (0)