Skip to content

Commit 342ff7a

Browse files
committed
autoimpersonate API, move rpc client
1 parent 42be0a9 commit 342ff7a

File tree

7 files changed

+782
-0
lines changed

7 files changed

+782
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[blockchain_a]
2+
chain_id = "31337"
3+
image = "f4hrenh9it/foundry:latest"
4+
port = "8545"
5+
type = "anvil"
6+
docker_cmd_params = ["--fork-url", "wss://avalanche-fuji-c-chain-rpc.publicnode.com"]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package examples
2+
3+
import (
4+
"github.com/smartcontractkit/chainlink-testing-framework/framework"
5+
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain"
6+
"github.com/smartcontractkit/chainlink-testing-framework/framework/rpc"
7+
"github.com/stretchr/testify/require"
8+
"testing"
9+
)
10+
11+
type CfgFork struct {
12+
BlockchainA *blockchain.Input `toml:"blockchain_a" validate:"required"`
13+
}
14+
15+
func TestFork(t *testing.T) {
16+
in, err := framework.Load[CfgFork](t)
17+
require.NoError(t, err)
18+
19+
bc, err := blockchain.NewBlockchainNetwork(in.BlockchainA)
20+
require.NoError(t, err)
21+
22+
t.Run("test some contracts with fork", func(t *testing.T) {
23+
ac := rpc.New(bc.Nodes[0].HostHTTPUrl, nil)
24+
err = ac.AnvilAutoImpersonate(true)
25+
require.NoError(t, err)
26+
})
27+
}

framework/rpc/miner.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package rpc
2+
3+
import (
4+
"net/http"
5+
"strconv"
6+
"time"
7+
8+
"github.com/rs/zerolog/log"
9+
)
10+
11+
// RemoteAnvilMiner is a remote miner for Anvil node
12+
// Allows to control blocks emission more precisely to mimic real networks workload
13+
type RemoteAnvilMiner struct {
14+
Client *RPCClient
15+
interval time.Duration
16+
batchSendInterval time.Duration
17+
batchCapacity int64
18+
stop chan struct{}
19+
}
20+
21+
// NewRemoteAnvilMiner creates a new remote miner client
22+
func NewRemoteAnvilMiner(url string, headers http.Header) *RemoteAnvilMiner {
23+
return &RemoteAnvilMiner{
24+
Client: New(url, headers),
25+
stop: make(chan struct{}),
26+
}
27+
}
28+
29+
// MinePeriodically mines blocks with a specified interval
30+
// should be used when Anvil mining is off
31+
func (m *RemoteAnvilMiner) MinePeriodically(interval time.Duration) {
32+
m.interval = interval
33+
go func() {
34+
for {
35+
select {
36+
case <-m.stop:
37+
log.Info().Msg("anvil miner exiting")
38+
return
39+
default:
40+
if err := m.Client.AnvilMine(nil); err != nil {
41+
log.Err(err).Send()
42+
}
43+
}
44+
time.Sleep(m.interval)
45+
}
46+
}()
47+
}
48+
49+
// Stop stops the miner
50+
func (m *RemoteAnvilMiner) Stop() {
51+
m.stop <- struct{}{}
52+
}
53+
54+
// MineBatch checks the pending transactions in the pool, if threshold is reached mines the block and repeat the process
55+
func (m *RemoteAnvilMiner) MineBatch(capacity int64, checkInterval time.Duration, sendInterval time.Duration) {
56+
m.interval = checkInterval
57+
m.batchCapacity = capacity
58+
m.batchSendInterval = sendInterval
59+
ticker := time.NewTicker(m.batchSendInterval)
60+
go func() {
61+
for {
62+
resp, err := m.Client.AnvilTxPoolStatus(nil)
63+
if err != nil {
64+
log.Err(err).Send()
65+
return
66+
}
67+
if len(resp.Result.Pending) == 0 {
68+
log.Error().Msg("no pending transactions found")
69+
return
70+
}
71+
pendingTx, err := strconv.ParseInt(resp.Result.Pending[2:], 16, 64)
72+
if err != nil {
73+
log.Err(err).Msg("failed to convert pending tx from hex to dec")
74+
}
75+
log.Info().Int64("Pending", pendingTx).Msg("Batch has pending transactions")
76+
if pendingTx >= m.batchCapacity {
77+
if err := m.Client.AnvilMine(nil); err != nil {
78+
log.Err(err).Send()
79+
}
80+
log.Info().Int64("Transactions", pendingTx).Msg("Block mined")
81+
}
82+
select {
83+
case <-m.stop:
84+
log.Info().Msg("anvil miner exiting")
85+
ticker.Stop()
86+
return
87+
case <-ticker.C:
88+
if err := m.Client.AnvilMine(nil); err != nil {
89+
log.Err(err).Send()
90+
}
91+
log.Info().Int64("Transactions", pendingTx).Msg("Block mined by timeout")
92+
default:
93+
}
94+
time.Sleep(m.interval)
95+
}
96+
}()
97+
}

0 commit comments

Comments
 (0)