Skip to content

Commit 39129f0

Browse files
authored
Merge branch 'master' into simplex-tracker
Signed-off-by: Sam Liokumovich <65994425+samliok@users.noreply.github.com>
2 parents f623fa9 + 66a9447 commit 39129f0

File tree

7 files changed

+471
-0
lines changed

7 files changed

+471
-0
lines changed

.github/workflows/ci.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,32 @@ jobs:
253253
prometheus_password: ${{ secrets.PROMETHEUS_PASSWORD || '' }}
254254
loki_username: ${{ secrets.LOKI_ID || '' }}
255255
loki_password: ${{ secrets.LOKI_PASSWORD || '' }}
256+
load_kube:
257+
name: Run load test on kube
258+
runs-on: ubuntu-latest
259+
steps:
260+
- uses: actions/checkout@v4
261+
- uses: ./.github/actions/setup-go-for-project
262+
- uses: ./.github/actions/run-monitored-tmpnet-cmd
263+
with:
264+
run: ./scripts/run_task.sh test-load-kube
265+
artifact_prefix: load-kube
266+
prometheus_username: ${{ secrets.PROMETHEUS_ID || '' }}
267+
prometheus_password: ${{ secrets.PROMETHEUS_PASSWORD || '' }}
268+
loki_username: ${{ secrets.LOKI_ID || '' }}
269+
loki_password: ${{ secrets.LOKI_PASSWORD || '' }}
270+
load2:
271+
name: Run load2 test
272+
runs-on: ubuntu-latest
273+
steps:
274+
- uses: actions/checkout@v4
275+
- uses: ./.github/actions/setup-go-for-project
276+
- uses: ./.github/actions/run-monitored-tmpnet-cmd
277+
with:
278+
run: ./scripts/run_task.sh test-load2 -- --load-timeout=30s
279+
artifact_prefix: load2
280+
prometheus_username: ${{ secrets.PROMETHEUS_ID || '' }}
281+
prometheus_password: ${{ secrets.PROMETHEUS_PASSWORD || '' }}
282+
loki_username: ${{ secrets.LOKI_ID || '' }}
283+
loki_password: ${{ secrets.LOKI_PASSWORD || '' }}
284+

Taskfile.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,12 @@ tasks:
239239
- task: generate-load-contract-bindings
240240
- cmd: bash -x ./scripts/tests.load.kube.sh {{.CLI_ARGS}}
241241

242+
test-load2:
243+
desc: Runs second iteration of load tests
244+
cmds:
245+
- task: build
246+
- cmd: go run ./tests/load2/main --avalanchego-path=./build/avalanchego {{.CLI_ARGS}}
247+
242248
test-load-exclusive:
243249
desc: Runs load tests against kube with exclusive scheduling
244250
cmds:

tests/load2/generator.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package load2
5+
6+
import (
7+
"context"
8+
"crypto/ecdsa"
9+
"math/big"
10+
"time"
11+
12+
"github.com/ava-labs/libevm/ethclient"
13+
"github.com/prometheus/client_golang/prometheus"
14+
"golang.org/x/sync/errgroup"
15+
16+
"github.com/ava-labs/avalanchego/tests"
17+
)
18+
19+
type Test interface {
20+
Run(tc tests.TestContext, ctx context.Context, wallet *Wallet)
21+
}
22+
23+
type Worker struct {
24+
PrivKey *ecdsa.PrivateKey
25+
Nonce uint64
26+
Client *ethclient.Client
27+
}
28+
29+
type LoadGenerator struct {
30+
wallets []*Wallet
31+
test Test
32+
}
33+
34+
func NewLoadGenerator(
35+
workers []Worker,
36+
chainID *big.Int,
37+
metricsNamespace string,
38+
registry *prometheus.Registry,
39+
test Test,
40+
) (LoadGenerator, error) {
41+
metrics, err := newMetrics(metricsNamespace, registry)
42+
if err != nil {
43+
return LoadGenerator{}, err
44+
}
45+
46+
wallets := make([]*Wallet, len(workers))
47+
for i := range wallets {
48+
wallets[i] = newWallet(
49+
workers[i].PrivKey,
50+
workers[i].Nonce,
51+
chainID,
52+
workers[i].Client,
53+
metrics,
54+
)
55+
}
56+
57+
return LoadGenerator{
58+
wallets: wallets,
59+
test: test,
60+
}, nil
61+
}
62+
63+
func (l LoadGenerator) Run(
64+
tc tests.TestContext,
65+
ctx context.Context,
66+
loadTimeout time.Duration,
67+
testTimeout time.Duration,
68+
) {
69+
eg := &errgroup.Group{}
70+
71+
childCtx := ctx
72+
if loadTimeout != 0 {
73+
ctx, cancel := context.WithTimeout(ctx, loadTimeout)
74+
childCtx = ctx
75+
defer cancel()
76+
}
77+
78+
for i := range l.wallets {
79+
eg.Go(func() error {
80+
for {
81+
select {
82+
case <-childCtx.Done():
83+
return nil
84+
default:
85+
}
86+
87+
ctx, cancel := context.WithTimeout(ctx, testTimeout)
88+
defer cancel()
89+
90+
l.test.Run(tc, ctx, l.wallets[i])
91+
}
92+
})
93+
}
94+
95+
_ = eg.Wait()
96+
}

tests/load2/main/main.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package main
5+
6+
import (
7+
"flag"
8+
"os"
9+
"time"
10+
11+
"github.com/ava-labs/libevm/ethclient"
12+
"github.com/prometheus/client_golang/prometheus"
13+
"github.com/stretchr/testify/require"
14+
15+
"github.com/ava-labs/avalanchego/tests"
16+
"github.com/ava-labs/avalanchego/tests/fixture/e2e"
17+
"github.com/ava-labs/avalanchego/tests/fixture/tmpnet"
18+
"github.com/ava-labs/avalanchego/tests/load"
19+
"github.com/ava-labs/avalanchego/tests/load2"
20+
)
21+
22+
const (
23+
blockchainID = "C"
24+
metricsNamespace = "load"
25+
pollFrequency = time.Millisecond
26+
testTimeout = time.Minute
27+
)
28+
29+
var (
30+
flagVars *e2e.FlagVars
31+
32+
loadTimeout time.Duration
33+
)
34+
35+
func init() {
36+
flagVars = e2e.RegisterFlags()
37+
38+
flag.DurationVar(
39+
&loadTimeout,
40+
"load-timeout",
41+
0,
42+
"the duration that the load test should run for",
43+
)
44+
45+
flag.Parse()
46+
}
47+
48+
func main() {
49+
log := tests.NewDefaultLogger("")
50+
tc := tests.NewTestContext(log)
51+
defer tc.Cleanup()
52+
53+
require := require.New(tc)
54+
55+
numNodes, err := flagVars.NodeCount()
56+
require.NoError(err, "failed to get node count")
57+
58+
nodes := tmpnet.NewNodesOrPanic(numNodes)
59+
60+
keys, err := tmpnet.NewPrivateKeys(numNodes)
61+
require.NoError(err)
62+
network := &tmpnet.Network{
63+
Nodes: nodes,
64+
PreFundedKeys: keys,
65+
}
66+
67+
e2e.NewTestEnvironment(tc, flagVars, network)
68+
69+
ctx := tests.DefaultNotifyContext(0, tc.DeferCleanup)
70+
wsURIs, err := tmpnet.GetNodeWebsocketURIs(ctx, network.Nodes, blockchainID, tc.DeferCleanup)
71+
require.NoError(err)
72+
73+
registry := prometheus.NewRegistry()
74+
metricsServer := load.NewPrometheusServer("127.0.0.1:0", registry)
75+
metricsErrChan, err := metricsServer.Start()
76+
require.NoError(err)
77+
78+
tc.DeferCleanup(func() {
79+
select {
80+
case err := <-metricsErrChan:
81+
require.NoError(err)
82+
default:
83+
}
84+
85+
require.NoError(metricsServer.Stop(), "failed to stop metrics server")
86+
})
87+
88+
monitoringConfigFilePath, err := metricsServer.GenerateMonitoringConfig(
89+
log,
90+
network.GetMonitoringLabels(),
91+
)
92+
require.NoError(err)
93+
94+
tc.DeferCleanup(func() {
95+
require.NoError(os.Remove(monitoringConfigFilePath))
96+
})
97+
98+
workers := make([]load2.Worker, len(keys))
99+
for i := range len(keys) {
100+
wsURI := wsURIs[i%len(wsURIs)]
101+
client, err := ethclient.Dial(wsURI)
102+
require.NoError(err)
103+
104+
workers[i] = load2.Worker{
105+
PrivKey: keys[i].ToECDSA(),
106+
Client: client,
107+
}
108+
}
109+
110+
chainID, err := workers[0].Client.ChainID(ctx)
111+
require.NoError(err)
112+
113+
generator, err := load2.NewLoadGenerator(
114+
workers,
115+
chainID,
116+
metricsNamespace,
117+
registry,
118+
load2.ZeroTransferTest{PollFrequency: pollFrequency},
119+
)
120+
require.NoError(err)
121+
122+
generator.Run(tc, ctx, loadTimeout, testTimeout)
123+
}

tests/load2/metrics.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package load2
5+
6+
import (
7+
"errors"
8+
"time"
9+
10+
"github.com/prometheus/client_golang/prometheus"
11+
)
12+
13+
type metrics struct {
14+
txsIssuedCounter prometheus.Counter
15+
txIssuanceLatency prometheus.Histogram
16+
txConfirmationLatency prometheus.Histogram
17+
txTotalLatency prometheus.Histogram
18+
}
19+
20+
func newMetrics(namespace string, registry *prometheus.Registry) (metrics, error) {
21+
m := metrics{
22+
txsIssuedCounter: prometheus.NewCounter(prometheus.CounterOpts{
23+
Namespace: namespace,
24+
Name: "txs_issued",
25+
Help: "Number of transactions issued",
26+
}),
27+
txIssuanceLatency: prometheus.NewHistogram(prometheus.HistogramOpts{
28+
Namespace: namespace,
29+
Name: "tx_issuance_latency",
30+
Help: "Issuance latency of transactions",
31+
}),
32+
txConfirmationLatency: prometheus.NewHistogram(prometheus.HistogramOpts{
33+
Namespace: namespace,
34+
Name: "tx_confirmation_latency",
35+
Help: "Confirmation latency of transactions",
36+
}),
37+
txTotalLatency: prometheus.NewHistogram(prometheus.HistogramOpts{
38+
Namespace: namespace,
39+
Name: "tx_total_latency",
40+
Help: "Total latency of transactions",
41+
}),
42+
}
43+
44+
if err := errors.Join(
45+
registry.Register(m.txsIssuedCounter),
46+
registry.Register(m.txIssuanceLatency),
47+
registry.Register(m.txConfirmationLatency),
48+
registry.Register(m.txTotalLatency),
49+
); err != nil {
50+
return metrics{}, err
51+
}
52+
53+
return m, nil
54+
}
55+
56+
func (m metrics) issue(d time.Duration) {
57+
m.txsIssuedCounter.Inc()
58+
m.txIssuanceLatency.Observe(float64(d.Milliseconds()))
59+
}
60+
61+
func (m metrics) accept(confirmationDuration time.Duration, totalDuration time.Duration) {
62+
m.txConfirmationLatency.Observe(float64(confirmationDuration.Milliseconds()))
63+
m.txTotalLatency.Observe(float64(totalDuration.Milliseconds()))
64+
}

tests/load2/tests.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package load2
5+
6+
import (
7+
"context"
8+
"math/big"
9+
"time"
10+
11+
"github.com/ava-labs/libevm/common"
12+
"github.com/ava-labs/libevm/core/types"
13+
"github.com/ava-labs/libevm/crypto"
14+
"github.com/ava-labs/libevm/params"
15+
"github.com/stretchr/testify/require"
16+
17+
"github.com/ava-labs/avalanchego/tests"
18+
)
19+
20+
var _ Test = (*ZeroTransferTest)(nil)
21+
22+
type ZeroTransferTest struct {
23+
PollFrequency time.Duration
24+
}
25+
26+
func (z ZeroTransferTest) Run(
27+
tc tests.TestContext,
28+
ctx context.Context,
29+
wallet *Wallet,
30+
) {
31+
require := require.New(tc)
32+
33+
maxValue := int64(100 * 1_000_000_000 / params.TxGas)
34+
maxFeeCap := big.NewInt(maxValue)
35+
bigGwei := big.NewInt(params.GWei)
36+
gasTipCap := new(big.Int).Mul(bigGwei, big.NewInt(1))
37+
gasFeeCap := new(big.Int).Mul(bigGwei, maxFeeCap)
38+
senderAddress := crypto.PubkeyToAddress(wallet.privKey.PublicKey)
39+
tx, err := types.SignNewTx(wallet.privKey, wallet.signer, &types.DynamicFeeTx{
40+
ChainID: wallet.chainID,
41+
Nonce: wallet.nonce,
42+
GasTipCap: gasTipCap,
43+
GasFeeCap: gasFeeCap,
44+
Gas: params.TxGas,
45+
To: &senderAddress,
46+
Data: nil,
47+
Value: common.Big0,
48+
})
49+
require.NoError(err)
50+
51+
require.NoError(wallet.SendTx(ctx, tx, z.PollFrequency))
52+
}

0 commit comments

Comments
 (0)