Skip to content

Commit

Permalink
Merge branch 'master' into f_two_convienence_methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Tofel committed May 15, 2024
2 parents 42d128c + a09841a commit 030c2d6
Show file tree
Hide file tree
Showing 7 changed files with 679 additions and 43 deletions.
47 changes: 47 additions & 0 deletions examples_wasp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
## Running multi-key load test with Seth and WASP
To effectively simulate transaction workloads from multiple keys, you can utilize a "rotating wallet." Refer to the [example](client_wasp_test.go) code provided for guidance.

There are 2 modes: Ephemeral and a static keyfile mode

### Ephemeral mode
We generate 60 ephemeral keys and run the test, set `ephemeral_addresses_number` in `seth.toml`

This mode **should never be used on testnets or mainnets** in order not to lose funds. Please use it to test with simulated networks, like private `Geth` or `Anvil`

```toml
ephemeral_addresses_number = 60
```
Then start the Geth and run the test

```
nix develop
make GethSync
// another terminal, from examples_wasp dir
export SETH_LOG_LEVEL=debug
export SETH_CONFIG_PATH=seth.toml
export NETWORK=Geth
export ROOT_PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
export LOKI_TENANT_ID=promtail
export LOKI_URL=...
go test -v -run TestWithWasp
```
See both [generator](client_wasp_test.go) and [test](client_wasp_test.go) implementation example

Check your results [here](https://grafana.ops.prod.cldev.sh/d/WaspDebug/waspdebug?orgId=1&from=now-5m&to=now)

If you see `key sync timeout`, just increase `ephemeral_addresses_number` to have more load

You can also change default `key_sync` values
```toml
[nonce_manager]
# 20 req/s limit for key syncing
key_sync_rate_limit_per_sec = 20
# key synchronization timeout, if it's more than N sec you'll see an error, raise amount of keys or increase the timeout
key_sync_timeout = "30s"
# key sync retry delay, each N seconds we'll updage each key nonce
key_sync_retry_delay = "1s"
# total number of retries until we throw an error
key_sync_retries = 30
```
129 changes: 129 additions & 0 deletions examples_wasp/client_main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package examples_wasp

import (
"os"
"testing"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"github.com/smartcontractkit/seth"
network_debug_contract "github.com/smartcontractkit/seth/contracts/bind/debug"
link_token "github.com/smartcontractkit/seth/contracts/bind/link"
network_sub_contract "github.com/smartcontractkit/seth/contracts/bind/sub"
)

func init() {
_ = os.Setenv("SETH_CONFIG_PATH", "seth.toml")
}

var (
TestEnv TestEnvironment
)

type TestEnvironment struct {
Client *seth.Client
DebugContract *network_debug_contract.NetworkDebugContract
DebugSubContract *network_sub_contract.NetworkDebugSubContract
LinkTokenContract *link_token.LinkToken
DebugContractAddress common.Address
DebugSubContractAddress common.Address
DebugContractRaw *bind.BoundContract
ContractMap seth.ContractMap
}

func NewDebugContractSetup() (
*seth.Client,
*network_debug_contract.NetworkDebugContract,
common.Address,
common.Address,
*bind.BoundContract,
error,
) {
cfg, err := seth.ReadConfig()
if err != nil {
return nil, nil, common.Address{}, common.Address{}, nil, err
}
cs, err := seth.NewContractStore(cfg.ABIDir, cfg.BINDir)
if err != nil {
return nil, nil, common.Address{}, common.Address{}, nil, err
}
addrs, pkeys, err := cfg.ParseKeys()
if err != nil {
return nil, nil, common.Address{}, common.Address{}, nil, err
}
contractMap := seth.NewEmptyContractMap()

abiFinder := seth.NewABIFinder(contractMap, cs)
tracer, err := seth.NewTracer(cfg.Network.URLs[0], cs, &abiFinder, cfg, contractMap, addrs)
if err != nil {
return nil, nil, common.Address{}, common.Address{}, nil, err
}

nm, err := seth.NewNonceManager(cfg, addrs, pkeys)
if err != nil {
return nil, nil, common.Address{}, common.Address{}, nil, errors.Wrap(err, seth.ErrCreateNonceManager)
}

c, err := seth.NewClientRaw(cfg, addrs, pkeys, seth.WithContractStore(cs), seth.WithTracer(tracer), seth.WithNonceManager(nm))
if err != nil {
return nil, nil, common.Address{}, common.Address{}, nil, err
}
subData, err := c.DeployContractFromContractStore(c.NewTXOpts(), "NetworkDebugSubContract.abi")
if err != nil {
return nil, nil, common.Address{}, common.Address{}, nil, err
}
data, err := c.DeployContractFromContractStore(c.NewTXOpts(), "NetworkDebugContract.abi", subData.Address)
if err != nil {
return nil, nil, common.Address{}, common.Address{}, nil, err
}
contract, err := network_debug_contract.NewNetworkDebugContract(data.Address, c.Client)
if err != nil {
return nil, nil, common.Address{}, common.Address{}, nil, err
}
return c, contract, data.Address, subData.Address, data.BoundContract, nil
}

func TestMain(m *testing.M) {
var err error
client, debugContract, debugContractAddress, debugSubContractAddress, debugContractRaw, err := NewDebugContractSetup()
if err != nil {
panic(err)
}

linkTokenAbi, err := link_token.LinkTokenMetaData.GetAbi()
if err != nil {
panic(err)
}
linkDeploymentData, err := client.DeployContract(client.NewTXOpts(), "LinkToken", *linkTokenAbi, common.FromHex(link_token.LinkTokenMetaData.Bin))
if err != nil {
panic(err)
}
linkToken, err := link_token.NewLinkToken(linkDeploymentData.Address, client.Client)
if err != nil {
panic(err)
}
linkAbi, err := link_token.LinkTokenMetaData.GetAbi()
if err != nil {
panic(err)
}
client.ContractStore.AddABI("LinkToken", *linkAbi)

contractMap := seth.NewEmptyContractMap()
for k, v := range client.ContractAddressToNameMap.GetContractMap() {
contractMap.AddContract(k, v)
}

TestEnv = TestEnvironment{
Client: client,
DebugContract: debugContract,
LinkTokenContract: linkToken,
DebugContractAddress: debugContractAddress,
DebugSubContractAddress: debugSubContractAddress,
DebugContractRaw: debugContractRaw,
ContractMap: contractMap,
}

exitVal := m.Run()
os.Exit(exitVal)
}
62 changes: 62 additions & 0 deletions examples_wasp/client_wasp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package examples_wasp

import (
"errors"
"github.com/smartcontractkit/seth"
"github.com/smartcontractkit/wasp"
"github.com/stretchr/testify/require"
"math/big"
"testing"
"time"
)

type ExampleGun struct {
client *seth.Client
Data []string
}

func NewExampleHTTPGun(client *seth.Client) *ExampleGun {
return &ExampleGun{
client: client,
Data: make([]string, 0),
}
}

func (m *ExampleGun) Call(l *wasp.Generator) *wasp.Response {
_, err := m.client.Decode(
TestEnv.DebugContract.AddCounter(m.client.NewTXKeyOpts(m.client.AnySyncedKey()), big.NewInt(0), big.NewInt(1)),
)
if err != nil {
return &wasp.Response{Error: errors.Join(err).Error()}
}
return &wasp.Response{}
}

func TestWithWasp(t *testing.T) {
t.Setenv("ROOT_PRIVATE_KEY", "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")
t.Setenv("SETH_CONFIG_PATH", "seth.toml")
cfg, err := seth.ReadConfig()
require.NoError(t, err, "failed to read config")
c, err := seth.NewClientWithConfig(cfg)
require.NoError(t, err, "failed to initalise seth")
labels := map[string]string{
"go_test_name": "TestWithWasp",
"gen_name": "TestWithWasp",
"branch": "TestWithWasp",
"commit": "TestWithWasp",
}
gen, err := wasp.NewGenerator(&wasp.Config{
LoadType: wasp.RPS,
Schedule: wasp.CombineAndRepeat(
2,
wasp.Plain(2, 30*time.Second),
wasp.Plain(10, 30*time.Second),
wasp.Plain(2, 30*time.Second),
),
Gun: NewExampleHTTPGun(c),
Labels: labels,
LokiConfig: wasp.NewEnvLokiConfig(),
})
require.NoError(t, err)
gen.Run(true)
}

0 comments on commit 030c2d6

Please sign in to comment.