@@ -7,7 +7,9 @@ package e2e
7
7
import (
8
8
"context"
9
9
"encoding/json"
10
+ "errors"
10
11
"fmt"
12
+ "math/big"
11
13
"math/rand"
12
14
"strings"
13
15
"time"
@@ -16,8 +18,11 @@ import (
16
18
17
19
"github.com/stretchr/testify/require"
18
20
21
+ "github.com/ava-labs/coreth/core/types"
19
22
"github.com/ava-labs/coreth/ethclient"
23
+ "github.com/ava-labs/coreth/interfaces"
20
24
25
+ "github.com/ava-labs/avalanchego/ids"
21
26
"github.com/ava-labs/avalanchego/tests"
22
27
"github.com/ava-labs/avalanchego/tests/fixture"
23
28
"github.com/ava-labs/avalanchego/tests/fixture/testnet"
@@ -58,7 +63,7 @@ type TestEnvironment struct {
58
63
// The directory where the test network configuration is stored
59
64
NetworkDir string
60
65
// URIs used to access the API endpoints of nodes of the network
61
- URIs []string
66
+ URIs []testnet. NodeURI
62
67
// The URI used to access the http server that allocates test data
63
68
TestDataServerURI string
64
69
@@ -76,9 +81,11 @@ func InitTestEnvironment(envBytes []byte) {
76
81
77
82
// Retrieve a random URI to naively attempt to spread API load across
78
83
// nodes.
79
- func (te * TestEnvironment ) GetRandomNodeURI () string {
84
+ func (te * TestEnvironment ) GetRandomNodeURI () testnet. NodeURI {
80
85
r := rand .New (rand .NewSource (time .Now ().Unix ())) //#nosec G404
81
- return te .URIs [r .Intn (len (te .URIs ))]
86
+ nodeURI := te .URIs [r .Intn (len (te .URIs ))]
87
+ tests .Outf ("{{blue}} targeting node %s with URI: %s{{/}}\n " , nodeURI .NodeID , nodeURI .URI )
88
+ return nodeURI
82
89
}
83
90
84
91
// Retrieve the network to target for testing.
@@ -92,6 +99,7 @@ func (te *TestEnvironment) GetNetwork() testnet.Network {
92
99
func (te * TestEnvironment ) AllocateFundedKeys (count int ) []* secp256k1.PrivateKey {
93
100
keys , err := fixture .AllocateFundedKeys (te .TestDataServerURI , count )
94
101
te .require .NoError (err )
102
+ tests .Outf ("{{blue}} allocated funded key(s): %+v{{/}}\n " , keys )
95
103
return keys
96
104
}
97
105
@@ -102,36 +110,33 @@ func (te *TestEnvironment) AllocateFundedKey() *secp256k1.PrivateKey {
102
110
103
111
// Create a new keychain with the specified number of test keys.
104
112
func (te * TestEnvironment ) NewKeychain (count int ) * secp256k1fx.Keychain {
105
- tests .Outf ("{{blue}} initializing keychain with %d keys {{/}}\n " , count )
106
113
keys := te .AllocateFundedKeys (count )
107
114
return secp256k1fx .NewKeychain (keys ... )
108
115
}
109
116
110
- // Create a new wallet for the provided keychain against a random node URI.
111
- func (te * TestEnvironment ) NewWallet (keychain * secp256k1fx.Keychain ) primary.Wallet {
112
- return te .NewWalletForURI (keychain , te .GetRandomNodeURI ())
113
- }
114
-
115
117
// Create a new wallet for the provided keychain against the specified node URI.
116
- func (te * TestEnvironment ) NewWalletForURI (keychain * secp256k1fx.Keychain , uri string ) primary.Wallet {
117
- tests .Outf ("{{blue}} initializing a new wallet {{/}}\n " )
118
- wallet , err := primary .MakeWallet (DefaultContext (), & primary.WalletConfig {
119
- URI : uri ,
118
+ func (te * TestEnvironment ) NewWallet (keychain * secp256k1fx.Keychain , nodeURI testnet. NodeURI ) primary.Wallet {
119
+ tests .Outf ("{{blue}} initializing a new wallet for node %s with URI: %s {{/}}\n " , nodeURI . NodeID , nodeURI . URI )
120
+ baseWallet , err := primary .MakeWallet (DefaultContext (), & primary.WalletConfig {
121
+ URI : nodeURI . URI ,
120
122
AVAXKeychain : keychain ,
121
123
EthKeychain : keychain ,
122
124
})
123
125
te .require .NoError (err )
124
- return wallet
125
- }
126
-
127
- // Create a new eth client targeting a random node.
128
- func (te * TestEnvironment ) NewEthClient () ethclient.Client {
129
- return te .NewEthClientForURI (te .GetRandomNodeURI ())
126
+ return primary .NewWalletWithOptions (
127
+ baseWallet ,
128
+ common .WithPostIssuanceFunc (
129
+ func (id ids.ID ) {
130
+ tests .Outf (" issued transaction with ID: %s\n " , id )
131
+ },
132
+ ),
133
+ )
130
134
}
131
135
132
136
// Create a new eth client targeting the specified node URI.
133
- func (te * TestEnvironment ) NewEthClientForURI (nodeURI string ) ethclient.Client {
134
- nodeAddress := strings .Split (nodeURI , "//" )[1 ]
137
+ func (te * TestEnvironment ) NewEthClient (nodeURI testnet.NodeURI ) ethclient.Client {
138
+ tests .Outf ("{{blue}} initializing a new eth client for node %s with URI: %s {{/}}\n " , nodeURI .NodeID , nodeURI .URI )
139
+ nodeAddress := strings .Split (nodeURI .URI , "//" )[1 ]
135
140
uri := fmt .Sprintf ("ws://%s/ext/bc/C/ws" , nodeAddress )
136
141
client , err := ethclient .Dial (uri )
137
142
te .require .NoError (err )
@@ -198,3 +203,47 @@ func WaitForHealthy(node testnet.Node) {
198
203
defer cancel ()
199
204
require .NoError (ginkgo .GinkgoT (), testnet .WaitForHealthy (ctx , node ))
200
205
}
206
+
207
+ // Sends an eth transaction, waits for the transaction receipt to be issued
208
+ // and checks that the receipt indicates success.
209
+ func SendEthTransaction (ethClient ethclient.Client , signedTx * types.Transaction ) * types.Receipt {
210
+ require := require .New (ginkgo .GinkgoT ())
211
+
212
+ txID := signedTx .Hash ()
213
+ tests .Outf (" sending eth transaction with ID: %s\n " , txID )
214
+
215
+ require .NoError (ethClient .SendTransaction (DefaultContext (), signedTx ))
216
+
217
+ // Wait for the receipt
218
+ var receipt * types.Receipt
219
+ Eventually (func () bool {
220
+ var err error
221
+ receipt , err = ethClient .TransactionReceipt (DefaultContext (), txID )
222
+ if errors .Is (err , interfaces .NotFound ) {
223
+ return false // Transaction is still pending
224
+ }
225
+ require .NoError (err )
226
+ return true
227
+ }, DefaultTimeout , DefaultPollingInterval , "failed to see transaction acceptance before timeout" )
228
+
229
+ require .Equal (receipt .Status , types .ReceiptStatusSuccessful )
230
+ return receipt
231
+ }
232
+
233
+ // Determines the suggested gas price for the configured client that will
234
+ // maximize the chances of transaction acceptance.
235
+ func SuggestGasPrice (ethClient ethclient.Client ) * big.Int {
236
+ gasPrice , err := ethClient .SuggestGasPrice (DefaultContext ())
237
+ require .NoError (ginkgo .GinkgoT (), err )
238
+ // Double the suggested gas price to maximize the chances of
239
+ // acceptance. Maybe this can be revisited pending resolution of
240
+ // https://github.com/ava-labs/coreth/issues/314.
241
+ gasPrice .Add (gasPrice , gasPrice )
242
+ return gasPrice
243
+ }
244
+
245
+ // Helper simplifying use via an option of a gas price appropriate for testing.
246
+ func WithSuggestedGasPrice (ethClient ethclient.Client ) common.Option {
247
+ baseFee := SuggestGasPrice (ethClient )
248
+ return common .WithBaseFee (baseFee )
249
+ }
0 commit comments