Skip to content

Commit

Permalink
test(solver): add ephemeral load gen (#2676)
Browse files Browse the repository at this point in the history
Adds simple periodic devapp deposit load generation to solver on
ephemeral networks.

issue: #2666
  • Loading branch information
corverroos authored Dec 12, 2024
1 parent 30c9c93 commit a4c6758
Show file tree
Hide file tree
Showing 20 changed files with 256 additions and 44 deletions.
4 changes: 2 additions & 2 deletions contracts/allocs/scripts/genallocs_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ func TestBridgeBalance(t *testing.T) {
mp = add(mp, th.TargetBalance())
}

mp = add(mp, ether(100)) // 100 OMNI: genesis validator 1
mp = add(mp, ether(100)) // 100 OMNI: genesis validator 2
mp = add(mp, ether(1000)) // 1000 OMNI: genesis validator 1
mp = add(mp, ether(1000)) // 1000 OMNI: genesis validator 2

tests := []struct {
name string
Expand Down
29 changes: 22 additions & 7 deletions e2e/app/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,8 +504,9 @@ func writeSolverConfig(ctx context.Context, def Definition, logCfg log.Config) e
confRoot := filepath.Join(def.Testnet.Dir, "solver")

const (
privKeyFile = "privatekey"
configFile = "solver.toml"
privKeyFile = "privatekey"
loadGenKeyFile = "loadgenkey"
configFile = "solver.toml"
)

if err := os.MkdirAll(confRoot, 0o755); err != nil {
Expand All @@ -518,24 +519,38 @@ func writeSolverConfig(ctx context.Context, def Definition, logCfg log.Config) e
endpoints = ExternalEndpoints(def)
}

// Save private key (use random keys for non-ephemeral)
// Save solver private key (use random keys for non-ephemeral)
// TODO(corver): Switch to proper keys once ready.
privKey, err := ethcrypto.GenerateKey()
solverPrivKey, err := ethcrypto.GenerateKey()
if err != nil {
return errors.Wrap(err, "generate private key")
} else if def.Testnet.Network.IsEphemeral() {
privKey, err = eoa.PrivateKey(ctx, def.Testnet.Network, eoa.RoleSolver)
solverPrivKey, err = eoa.PrivateKey(ctx, def.Testnet.Network, eoa.RoleSolver)
if err != nil {
return errors.Wrap(err, "get solver key")
}
}
if err := ethcrypto.SaveECDSA(filepath.Join(confRoot, privKeyFile), solverPrivKey); err != nil {
return errors.Wrap(err, "write private key")
}

if err := ethcrypto.SaveECDSA(filepath.Join(confRoot, privKeyFile), privKey); err != nil {
// Save loadgen private key (use random keys for non-ephemeral)
loadGenPrivKey, err := ethcrypto.GenerateKey()
if err != nil {
return errors.Wrap(err, "generate loadgen private key")
} else if def.Testnet.Network.IsEphemeral() {
loadGenPrivKey, err = eoa.PrivateKey(ctx, def.Testnet.Network, eoa.RoleXCaller)
if err != nil {
return errors.Wrap(err, "get loadgen key")
}
}
if err := ethcrypto.SaveECDSA(filepath.Join(confRoot, loadGenKeyFile), loadGenPrivKey); err != nil {
return errors.Wrap(err, "write private key")
}

solverCfg := solverapp.DefaultConfig()
solverCfg.PrivateKey = privKeyFile
solverCfg.SolverPrivKey = privKeyFile
solverCfg.LoadGenPrivKey = loadGenKeyFile
solverCfg.Network = def.Testnet.Network
solverCfg.RPCEndpoints = endpoints

Expand Down
35 changes: 21 additions & 14 deletions e2e/solve/devapp/deposits.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)

type DepositReq struct {
Expand Down Expand Up @@ -53,7 +54,7 @@ func TestFlow(ctx context.Context, network netconf.Network, endpoints xchain.RPC
}

for deposit := range toCheck {
ok, err := isDeposited(ctx, backends, deposit)
ok, err := IsDeposited(ctx, backends, deposit)
if err != nil {
return err
} else if ok {
Expand Down Expand Up @@ -117,8 +118,11 @@ func makeTestDeposits(ctx context.Context, backends ethbackend.Backends) ([]Depo
return nil, errors.Wrap(err, "make depositors")
}

depositAmount := big.NewInt(1e18)
fundAmount := new(big.Int).Add(depositAmount, big.NewInt(params.GWei)) // Add gas

// fund for gas
if err := anvil.FundAccounts(ctx, backend, big.NewInt(1e18), depositors...); err != nil {
if err := anvil.FundAccounts(ctx, backend, fundAmount, depositors...); err != nil {
return nil, errors.Wrap(err, "fund accounts")
}

Expand All @@ -127,15 +131,23 @@ func makeTestDeposits(ctx context.Context, backends ethbackend.Backends) ([]Depo
return nil, errors.Wrap(err, "get addresses")
}

reqs, err := requestDeposits(ctx, backend, addrs.SolveInbox, depositors)
var deposits []DepositArgs
for _, depositor := range depositors {
deposits = append(deposits, DepositArgs{
OnBehalfOf: depositor,
Amount: depositAmount,
})
}

reqs, err := RequestDeposits(ctx, backend, addrs.SolveInbox, deposits...)
if err != nil {
return nil, errors.Wrap(err, "request deposits")
}

return reqs, nil
}

func isDeposited(ctx context.Context, backends ethbackend.Backends, req DepositReq) (bool, error) {
func IsDeposited(ctx context.Context, backends ethbackend.Backends, req DepositReq) (bool, error) {
app := MustGetApp(netconf.Devnet)

backend, err := backends.Backend(app.L1.ChainID)
Expand Down Expand Up @@ -209,14 +221,9 @@ func addRandomDepositors(n int, backend *ethbackend.Backend) ([]common.Address,
return depositors, nil
}

func requestDeposits(ctx context.Context, backend *ethbackend.Backend, inbox common.Address, depositors []common.Address) ([]DepositReq, error) {
var reqs []DepositReq
for _, depositor := range depositors {
deposit := DepositArgs{
OnBehalfOf: depositor,
Amount: big.NewInt(1e18),
}

func RequestDeposits(ctx context.Context, backend *ethbackend.Backend, inbox common.Address, deposits ...DepositArgs) ([]DepositReq, error) {
var resp []DepositReq
for _, deposit := range deposits {
if err := mintAndApprove(ctx, backend, inbox, deposit); err != nil {
return nil, errors.Wrap(err, "mint and approve")
}
Expand All @@ -226,10 +233,10 @@ func requestDeposits(ctx context.Context, backend *ethbackend.Backend, inbox com
return nil, errors.Wrap(err, "request at inbox")
}

reqs = append(reqs, req)
resp = append(resp, req)
}

return reqs, nil
return resp, nil
}

func requestAtInbox(ctx context.Context, backend *ethbackend.Backend, addr common.Address, deposit DepositArgs) (DepositReq, error) {
Expand Down
4 changes: 4 additions & 0 deletions e2e/solve/devapp/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ type DepositArgs struct {
Amount *big.Int
}

func (App) Name() string {
return "devapp"
}

func (App) ChainID() uint64 {
return evmchain.IDMockL1
}
Expand Down
4 changes: 4 additions & 0 deletions e2e/solve/symbiotic/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ type DepositArgs struct {
Amount *big.Int
}

func (App) Name() string {
return "symbiotic"
}

func (t App) ChainID() uint64 {
return t.L1.ChainID
}
Expand Down
4 changes: 2 additions & 2 deletions halo/genutil/genutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ import (
// since Omni block period (+-1s) is very fast, roughly 10x normal period of 10s.
const slashingBlocksWindow = 1000

// ValidatorPower is the default power assigned to genesis validators.
const ValidatorPower = 100
// ValidatorPower is the default power assigned to ephemeral genesis validators.
const ValidatorPower = 1000

func MakeGenesis(
network netconf.ID,
Expand Down
10 changes: 5 additions & 5 deletions halo/genutil/testdata/TestMakeGenesis.golden
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"coins": [
{
"denom": "stake",
"amount": "100000000000000000000"
"amount": "1000000000000000000000"
}
]
},
Expand All @@ -51,15 +51,15 @@
"coins": [
{
"denom": "stake",
"amount": "100000000000000000000"
"amount": "1000000000000000000000"
}
]
}
],
"supply": [
{
"denom": "stake",
"amount": "200000000000000000000"
"amount": "2000000000000000000000"
}
],
"denom_metadata": [],
Expand Down Expand Up @@ -118,7 +118,7 @@
},
"value": {
"denom": "stake",
"amount": "100000000000000000000"
"amount": "1000000000000000000000"
}
}
],
Expand Down Expand Up @@ -165,7 +165,7 @@
},
"value": {
"denom": "stake",
"amount": "100000000000000000000"
"amount": "1000000000000000000000"
}
}
],
Expand Down
15 changes: 15 additions & 0 deletions lib/ethclient/ethbackend/backends.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,21 @@ func (b Backends) All() map[uint64]*Backend {
return b.backends
}

// AddAccount adds a in-memory private key account to all backends.
// Note this can be called even if other accounts are fireblocks based.
func (b Backends) AddAccount(privkey *ecdsa.PrivateKey) (common.Address, error) {
var addr common.Address
for _, backend := range b.backends {
var err error
addr, err = backend.AddAccount(privkey)
if err != nil {
return common.Address{}, err
}
}

return addr, nil
}

func (b Backends) Clients() map[uint64]ethclient.Client {
clients := make(map[uint64]ethclient.Client)
for chainID, backend := range b.backends {
Expand Down
23 changes: 20 additions & 3 deletions solver/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ import (
)

// confLevel of solver streamers.
const confLevel = xchain.ConfLatest
const (
confLevel = xchain.ConfLatest
unknown = "unknown"
)

func chainVerFromID(id uint64) xchain.ChainVersion {
return xchain.ChainVersion{ID: id, ConfLevel: confLevel}
Expand All @@ -52,10 +55,10 @@ func Run(ctx context.Context, cfg Config) error {
return err
}

if cfg.PrivateKey == "" {
if cfg.SolverPrivKey == "" {
return errors.New("private key not set")
}
privKey, err := ethcrypto.LoadECDSA(cfg.PrivateKey)
privKey, err := ethcrypto.LoadECDSA(cfg.SolverPrivKey)
if err != nil {
return errors.Wrap(err, "load private key")
}
Expand All @@ -67,6 +70,10 @@ func Run(ctx context.Context, cfg Config) error {
return err
}

if err := maybeStartLoadGen(ctx, cfg, network, backends); err != nil {
return err
}

xprov := xprovider.New(network, backends.Clients(), nil)

db, err := newSolverDB(cfg.DBDir)
Expand Down Expand Up @@ -223,6 +230,15 @@ func startEventStreams(
return cursors.Set(ctx, chainVerFromID(chainID), height)
}

targetNamer := func(req bindings.SolveRequest) string {
target, err := getTarget(network.ID, req.Call)
if err != nil {
return unknown
}

return target.Name()
}

deps := procDeps{
ParseID: newIDParser(inboxContracts),
GetRequest: newRequestGetter(inboxContracts),
Expand All @@ -233,6 +249,7 @@ func startEventStreams(
Claim: newClaimer(inboxContracts, backends, solverAddr),
SetCursor: cursorSetter,
ChainName: network.ChainName,
TargetName: targetNamer,
}

for _, chain := range inboxChains {
Expand Down
2 changes: 1 addition & 1 deletion solver/app/bindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func statusString(status uint8) string {
case statusClaimed:
return "claimed"
default:
return "unknown"
return unknown
}
}

Expand Down
5 changes: 3 additions & 2 deletions solver/app/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ type Config struct {
RPCEndpoints xchain.RPCEndpoints
Network netconf.ID
MonitoringAddr string
PrivateKey string
SolverPrivKey string
LoadGenPrivKey string
DBDir string
}

func DefaultConfig() Config {
return Config{
PrivateKey: "solver.key",
SolverPrivKey: "solver.key",
MonitoringAddr: ":26660",
DBDir: "./db",
}
Expand Down
7 changes: 5 additions & 2 deletions solver/app/config.toml.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ network = "{{ .Network }}"
### Solver Options ###
#######################################################################

# Path to the ethereum private key used to sign avs omni sync transactions.
private-key = "{{ .PrivateKey }}"
# Path to the ethereum private key used to for inbox and outbox request state transitions.
private-key = "{{ .SolverPrivKey }}"

# Path to the ethereum private key used to generate deposit load on ephemeral networks only.
loadgen-key = "{{ .LoadGenPrivKey }}"

# The address that the solver listens for metric scrape requests.
monitoring-addr = "{{ .MonitoringAddr }}"
Expand Down
1 change: 1 addition & 0 deletions solver/app/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func TestDefaultConfigReference(t *testing.T) {
tempDir := t.TempDir()

cfg := solver.DefaultConfig()
cfg.LoadGenPrivKey = "loadgen.key"

path := filepath.Join(tempDir, "solver.toml")

Expand Down
Loading

0 comments on commit a4c6758

Please sign in to comment.