Skip to content

Commit f30437d

Browse files
StephenButtolphcam-schultz
authored andcommitted
Add ACP-176 e2e tests (#3749)
1 parent 8caf037 commit f30437d

File tree

12 files changed

+246
-102
lines changed

12 files changed

+246
-102
lines changed

.github/workflows/ci.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,25 @@ jobs:
6565
prometheus_password: ${{ secrets.PROMETHEUS_PASSWORD || '' }}
6666
loki_username: ${{ secrets.LOKI_ID || '' }}
6767
loki_password: ${{ secrets.LOKI_PASSWORD || '' }}
68+
e2e_post_fortuna:
69+
runs-on: ubuntu-latest
70+
steps:
71+
- uses: actions/checkout@v4
72+
- uses: ./.github/actions/setup-go-for-project
73+
- name: Build AvalancheGo Binary
74+
shell: bash
75+
run: ./scripts/build.sh -r
76+
- name: Run e2e tests
77+
uses: ./.github/actions/run-monitored-tmpnet-cmd
78+
with:
79+
run: ./scripts/tests.e2e.sh --activate-fortuna
80+
run_env: E2E_SERIAL=1
81+
artifact_prefix: e2e-post-fortuna
82+
filter_by_owner: avalanchego-e2e
83+
prometheus_username: ${{ secrets.PROMETHEUS_ID || '' }}
84+
prometheus_password: ${{ secrets.PROMETHEUS_PASSWORD || '' }}
85+
loki_username: ${{ secrets.LOKI_ID || '' }}
86+
loki_password: ${{ secrets.LOKI_PASSWORD || '' }}
6887
e2e_existing_network:
6988
runs-on: ubuntu-latest
7089
steps:

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ require (
1313
github.com/DataDog/zstd v1.5.2
1414
github.com/NYTimes/gziphandler v1.1.1
1515
github.com/antithesishq/antithesis-sdk-go v0.3.8
16-
github.com/ava-labs/coreth v0.14.1-rc.1.0.20250219185827-6a9db205a450
16+
github.com/ava-labs/coreth v0.14.1-acp-176.1
1717
github.com/ava-labs/ledger-avalanche/go v0.0.0-20241009183145-e6f90a8a1a60
1818
github.com/btcsuite/btcd/btcutil v1.1.3
1919
github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ github.com/antithesishq/antithesis-sdk-go v0.3.8/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl
6464
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
6565
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
6666
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
67-
github.com/ava-labs/coreth v0.14.1-rc.1.0.20250219185827-6a9db205a450 h1:xSoL6plkPrb2w21v4JRnQg3BIJSg2svBHXyil09RMAg=
68-
github.com/ava-labs/coreth v0.14.1-rc.1.0.20250219185827-6a9db205a450/go.mod h1:AEQcF8MWrKH0sS114wEZlkSfeGF5F66xTbQYqqimNLI=
67+
github.com/ava-labs/coreth v0.14.1-acp-176.1 h1:44iXYYeLR4LzTM+5DB7ohGqysDiTFPIvxiuFY9vZJAI=
68+
github.com/ava-labs/coreth v0.14.1-acp-176.1/go.mod h1:AEQcF8MWrKH0sS114wEZlkSfeGF5F66xTbQYqqimNLI=
6969
github.com/ava-labs/ledger-avalanche/go v0.0.0-20241009183145-e6f90a8a1a60 h1:EL66gtXOAwR/4KYBjOV03LTWgkEXvLePribLlJNu4g0=
7070
github.com/ava-labs/ledger-avalanche/go v0.0.0-20241009183145-e6f90a8a1a60/go.mod h1:/7qKobTfbzBu7eSTVaXMTr56yTYk4j2Px6/8G+idxHo=
7171
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=

tests/e2e/c/consume_gas.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package c
5+
6+
const (
7+
// consumeGasCompiledContract is the compiled bytecode of the contract
8+
// defined in consume_gas.sol.
9+
consumeGasCompiledContract = "6080604052348015600f57600080fd5b5060788061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b5b6001156040576036565b56fea264697066735822122070cfeeb0992270b4ff725a1264654534853d25ea6bb28c85d986beccfdbc997164736f6c63430008060033"
10+
// consumeGasABIJson is the ABI of the contract defined in consume_gas.sol.
11+
consumeGasABIJson = `[{"inputs":[],"name":"run","outputs":[],"stateMutability":"nonpayable","type":"function"}]`
12+
// consumeGasFunction is the name of the function to call to consume gas.
13+
consumeGasFunction = "run"
14+
)

tests/e2e/c/consume_gas.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity = 0.8.6;
4+
5+
contract ConsumeGas {
6+
function run() public {
7+
while (true){}
8+
}
9+
}

tests/e2e/c/dynamic_fees.go

Lines changed: 147 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,66 @@ package c
66
import (
77
"math/big"
88
"strings"
9+
"time"
910

1011
"github.com/ava-labs/coreth/core/types"
1112
"github.com/ava-labs/coreth/params"
13+
"github.com/ava-labs/coreth/plugin/evm/upgrade/acp176"
14+
"github.com/ava-labs/coreth/plugin/evm/upgrade/cortina"
1215
"github.com/ethereum/go-ethereum/accounts/abi"
1316
"github.com/ethereum/go-ethereum/common"
1417
"github.com/onsi/ginkgo/v2"
1518
"github.com/stretchr/testify/require"
1619
"go.uber.org/zap"
1720

21+
"github.com/ava-labs/avalanchego/api/info"
1822
"github.com/ava-labs/avalanchego/tests/fixture/e2e"
1923
"github.com/ava-labs/avalanchego/tests/fixture/tmpnet"
2024
)
2125

22-
// This test uses the compiled bin for `hashing.sol` as
23-
// well as its ABI contained in `hashing_contract.go`.
26+
// This test uses the compiled bytecode for `consume_gas.sol` as well as its ABI
27+
// contained in `consume_gas.go`.
2428

2529
var _ = e2e.DescribeCChain("[Dynamic Fees]", func() {
2630
tc := e2e.NewTestContext()
2731
require := require.New(tc)
2832

29-
// Need a gas limit much larger than the standard 21_000 to enable
30-
// the contract to induce a gas price increase
31-
const largeGasLimit = uint64(8_000_000)
33+
const (
34+
// maxFeePerGas is the maximum fee that transactions issued by this test
35+
// will be willing to pay. The actual value doesn't really matter, it
36+
// just needs to be higher than the `targetGasPrice` calculated below.
37+
maxFeePerGas = 1000 * params.GWei
38+
// minFeePerGas is the minimum fee that transactions issued by this test
39+
// will pay. The mempool enforces that this value is non-zero.
40+
minFeePerGas = 1 * params.Wei
3241

33-
// TODO(marun) What is the significance of this value?
34-
gasTip := big.NewInt(1000 * params.GWei)
42+
// expectedGasPriceIncreaseNumerator/expectedGasPriceIncreaseDenominator
43+
// is the multiplier that the gas price is attempted to reach. So if the
44+
// initial gas price is 5 GWei, the test will attempt to increase the
45+
// gas price to 6 GWei.
46+
expectedGasPriceIncreaseNumerator = 6
47+
expectedGasPriceIncreaseDenominator = 5
48+
)
49+
var (
50+
bigExpectedGasPriceIncreaseNumerator = big.NewInt(expectedGasPriceIncreaseNumerator)
51+
bigExpectedGasPriceIncreaseDenominator = big.NewInt(expectedGasPriceIncreaseDenominator)
52+
bigExpectedGasPriceIncreaseDenominatorMinus1 = big.NewInt(expectedGasPriceIncreaseDenominator - 1)
53+
54+
gasFeeCap = big.NewInt(maxFeePerGas)
55+
gasTipCap = big.NewInt(minFeePerGas)
56+
)
3557

3658
ginkgo.It("should ensure that the gas price is affected by load", func() {
3759
tc.By("creating a new private network to ensure isolation from other tests")
60+
env := e2e.GetEnv(tc)
61+
publicNetwork := env.GetNetwork()
62+
3863
privateNetwork := tmpnet.NewDefaultNetwork("avalanchego-e2e-dynamic-fees")
39-
e2e.GetEnv(tc).StartPrivateNetwork(privateNetwork)
64+
// Copy over the defaults from the normal test suite to include settings
65+
// like the upgrade config.
66+
privateNetwork.DefaultFlags = tmpnet.FlagsMap{}
67+
privateNetwork.DefaultFlags.SetDefaults(publicNetwork.DefaultFlags)
68+
env.StartPrivateNetwork(privateNetwork)
4069

4170
// Avoid emitting a spec-scoped metrics link for the shared
4271
// network since the link emitted by the start of the private
@@ -60,116 +89,167 @@ var _ = e2e.DescribeCChain("[Dynamic Fees]", func() {
6089
tc.By("initializing a transaction signer")
6190
cChainID, err := ethClient.ChainID(tc.DefaultContext())
6291
require.NoError(err)
63-
signer := types.NewEIP155Signer(cChainID)
92+
signer := types.NewLondonSigner(cChainID)
6493
ecdsaKey := key.ToECDSA()
6594
sign := func(tx *types.Transaction) *types.Transaction {
6695
signedTx, err := types.SignTx(tx, signer, ecdsaKey)
6796
require.NoError(err)
6897
return signedTx
6998
}
7099

100+
// gasLimit is the maximum amount of gas that can be used in a block.
101+
var gasLimit uint64
102+
tc.By("checking if Fortuna is activated", func() {
103+
infoClient := info.NewClient(nodeURI.URI)
104+
upgrades, err := infoClient.Upgrades(tc.DefaultContext())
105+
require.NoError(err)
106+
107+
now := time.Now()
108+
if upgrades.IsFUpgradeActivated(now) {
109+
gasLimit = acp176.MinMaxCapacity
110+
} else {
111+
gasLimit = cortina.GasLimit
112+
}
113+
})
114+
tc.Log().Info("set gas limit",
115+
zap.Uint64("gasLimit", gasLimit),
116+
)
117+
71118
var contractAddress common.Address
72119
tc.By("deploying an expensive contract", func() {
73120
// Create transaction
74121
nonce, err := ethClient.AcceptedNonceAt(tc.DefaultContext(), ethAddress)
75122
require.NoError(err)
76-
compiledContract := common.Hex2Bytes(hashingCompiledContract)
77-
tx := types.NewTx(&types.LegacyTx{
78-
Nonce: nonce,
79-
GasPrice: gasTip,
80-
Gas: largeGasLimit,
81-
Value: common.Big0,
82-
Data: compiledContract,
123+
compiledContract := common.Hex2Bytes(consumeGasCompiledContract)
124+
tx := types.NewTx(&types.DynamicFeeTx{
125+
ChainID: cChainID,
126+
Nonce: nonce,
127+
GasTipCap: gasTipCap,
128+
GasFeeCap: gasFeeCap,
129+
Gas: gasLimit,
130+
To: nil, // contract creation
131+
Data: compiledContract,
83132
})
84133

85134
// Send the transaction and wait for acceptance
86135
signedTx := sign(tx)
87136
receipt := e2e.SendEthTransaction(tc, ethClient, signedTx)
137+
require.Equal(types.ReceiptStatusSuccessful, receipt.Status)
88138

89139
contractAddress = receipt.ContractAddress
90140
})
91141

92-
var gasPrice *big.Int
93-
tc.By("calling the expensive contract repeatedly until a gas price increase is detected", func() {
142+
latest, err := ethClient.HeaderByNumber(tc.DefaultContext(), nil)
143+
require.NoError(err)
144+
145+
initialGasPrice := latest.BaseFee
146+
targetGasPrice := new(big.Int).Set(initialGasPrice)
147+
targetGasPrice.Mul(targetGasPrice, bigExpectedGasPriceIncreaseNumerator)
148+
targetGasPrice.Add(targetGasPrice, bigExpectedGasPriceIncreaseDenominatorMinus1)
149+
targetGasPrice.Div(targetGasPrice, bigExpectedGasPriceIncreaseDenominator)
150+
151+
tc.Log().Info("initializing gas prices",
152+
zap.Stringer("initialPrice", initialGasPrice),
153+
zap.Stringer("targetPrice", targetGasPrice),
154+
)
155+
156+
tc.By("calling the contract repeatedly until a sufficient gas price increase is detected", func() {
94157
// Evaluate the bytes representation of the contract
95-
hashingABI, err := abi.JSON(strings.NewReader(hashingABIJson))
158+
hashingABI, err := abi.JSON(strings.NewReader(consumeGasABIJson))
96159
require.NoError(err)
97-
contractData, err := hashingABI.Pack("hashIt")
160+
contractData, err := hashingABI.Pack(consumeGasFunction)
98161
require.NoError(err)
99162

100-
var initialGasPrice *big.Int
101163
tc.Eventually(func() bool {
102164
// Check the gas price
103-
var err error
104-
gasPrice, err = ethClient.SuggestGasPrice(tc.DefaultContext())
165+
latest, err := ethClient.HeaderByNumber(tc.DefaultContext(), nil)
105166
require.NoError(err)
106-
if initialGasPrice == nil {
107-
initialGasPrice = gasPrice
108-
tc.Log().Info("initial gas price",
109-
zap.Uint64("price", initialGasPrice.Uint64()),
110-
)
111-
} else if gasPrice.Cmp(initialGasPrice) > 0 {
167+
168+
// If the gas price has increased, stop the loop.
169+
if latest.BaseFee.Cmp(targetGasPrice) >= 0 {
112170
tc.Log().Info("gas price has increased",
113-
zap.Uint64("price", gasPrice.Uint64()),
171+
zap.Stringer("initialPrice", initialGasPrice),
172+
zap.Stringer("targetPrice", targetGasPrice),
173+
zap.Stringer("newPrice", latest.BaseFee),
114174
)
115175
return true
116176
}
117177

178+
tc.Log().Info("gas price hasn't sufficiently increased",
179+
zap.Stringer("initialPrice", initialGasPrice),
180+
zap.Stringer("newPrice", latest.BaseFee),
181+
zap.Stringer("targetPrice", targetGasPrice),
182+
)
183+
118184
// Create the transaction
119185
nonce, err := ethClient.AcceptedNonceAt(tc.DefaultContext(), ethAddress)
120186
require.NoError(err)
121-
tx := types.NewTx(&types.LegacyTx{
122-
Nonce: nonce,
123-
GasPrice: gasTip,
124-
Gas: largeGasLimit,
125-
To: &contractAddress,
126-
Value: common.Big0,
127-
Data: contractData,
187+
tx := types.NewTx(&types.DynamicFeeTx{
188+
ChainID: cChainID,
189+
Nonce: nonce,
190+
GasTipCap: gasTipCap,
191+
GasFeeCap: gasFeeCap,
192+
Gas: gasLimit,
193+
To: &contractAddress,
194+
Data: contractData,
128195
})
129196

130197
// Send the transaction and wait for acceptance
131198
signedTx := sign(tx)
132-
_ = e2e.SendEthTransaction(tc, ethClient, signedTx)
199+
receipt := e2e.SendEthTransaction(tc, ethClient, signedTx)
200+
// The transaction should have run out of gas
201+
require.Equal(types.ReceiptStatusFailed, receipt.Status)
133202

134203
// The gas price will be checked at the start of the next iteration
135204
return false
136205
}, e2e.DefaultTimeout, e2e.DefaultPollingInterval, "failed to see gas price increase before timeout")
137206
})
138207

139-
tc.By("waiting for the gas price to decrease...", func() {
140-
initialGasPrice := gasPrice
208+
// Create a recipient address
209+
var (
210+
recipientKey = e2e.NewPrivateKey(tc)
211+
recipientEthAddress = recipientKey.EthAddress()
212+
)
213+
tc.By("sending small transactions until a sufficient gas price decrease is detected", func() {
141214
tc.Eventually(func() bool {
142-
var err error
143-
gasPrice, err = ethClient.SuggestGasPrice(tc.DefaultContext())
215+
// Check the gas price
216+
latest, err := ethClient.HeaderByNumber(tc.DefaultContext(), nil)
144217
require.NoError(err)
145-
return initialGasPrice.Cmp(gasPrice) > 0
146-
}, e2e.DefaultTimeout, e2e.DefaultPollingInterval, "failed to see gas price decrease before timeout")
147-
tc.Log().Info("gas price has decreased",
148-
zap.Uint64("price", gasPrice.Uint64()),
149-
)
150-
})
151218

152-
tc.By("sending funds at the current gas price", func() {
153-
// Create a recipient address
154-
var (
155-
recipientKey = e2e.NewPrivateKey(tc)
156-
recipientEthAddress = recipientKey.EthAddress()
157-
)
219+
// If the gas price has decreased, stop the loop.
220+
if latest.BaseFee.Cmp(initialGasPrice) <= 0 {
221+
tc.Log().Info("gas price has decreased",
222+
zap.Stringer("initialPrice", initialGasPrice),
223+
zap.Stringer("newPrice", latest.BaseFee),
224+
)
225+
return true
226+
}
227+
228+
tc.Log().Info("gas price hasn't sufficiently decreased",
229+
zap.Stringer("initialPrice", initialGasPrice),
230+
zap.Stringer("newPrice", latest.BaseFee),
231+
)
158232

159-
// Create transaction
160-
nonce, err := ethClient.AcceptedNonceAt(tc.DefaultContext(), ethAddress)
161-
require.NoError(err)
162-
tx := types.NewTx(&types.LegacyTx{
163-
Nonce: nonce,
164-
GasPrice: gasPrice,
165-
Gas: e2e.DefaultGasLimit,
166-
To: &recipientEthAddress,
167-
Value: common.Big0,
168-
})
233+
// Create the transaction
234+
nonce, err := ethClient.AcceptedNonceAt(tc.DefaultContext(), ethAddress)
235+
require.NoError(err)
236+
tx := types.NewTx(&types.DynamicFeeTx{
237+
ChainID: cChainID,
238+
Nonce: nonce,
239+
GasTipCap: gasTipCap,
240+
GasFeeCap: gasFeeCap,
241+
Gas: e2e.DefaultGasLimit,
242+
To: &recipientEthAddress,
243+
})
169244

170-
// Send the transaction and wait for acceptance
171-
signedTx := sign(tx)
172-
_ = e2e.SendEthTransaction(tc, ethClient, signedTx)
245+
// Send the transaction and wait for acceptance
246+
signedTx := sign(tx)
247+
receipt := e2e.SendEthTransaction(tc, ethClient, signedTx)
248+
require.Equal(types.ReceiptStatusSuccessful, receipt.Status)
249+
250+
// The gas price will be checked at the start of the next iteration
251+
return false
252+
}, e2e.DefaultTimeout, e2e.DefaultPollingInterval, "failed to see gas price decrease before timeout")
173253
})
174254

175255
_ = e2e.CheckBootstrapIsPossible(tc, privateNetwork)

tests/e2e/c/hashing.sol

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)