github.com/MetalBlockchain/metalgo@v1.11.9/tests/e2e/c/dynamic_fees.go (about)

     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  import (
     7  	"math/big"
     8  	"strings"
     9  
    10  	"github.com/MetalBlockchain/coreth/core/types"
    11  	"github.com/MetalBlockchain/coreth/params"
    12  	"github.com/MetalBlockchain/coreth/plugin/evm"
    13  	"github.com/ethereum/go-ethereum/accounts/abi"
    14  	"github.com/ethereum/go-ethereum/common"
    15  	"github.com/stretchr/testify/require"
    16  
    17  	"github.com/MetalBlockchain/metalgo/tests"
    18  	"github.com/MetalBlockchain/metalgo/tests/fixture/e2e"
    19  	"github.com/MetalBlockchain/metalgo/tests/fixture/tmpnet"
    20  	"github.com/MetalBlockchain/metalgo/utils/crypto/secp256k1"
    21  
    22  	ginkgo "github.com/onsi/ginkgo/v2"
    23  )
    24  
    25  // This test uses the compiled bin for `hashing.sol` as
    26  // well as its ABI contained in `hashing_contract.go`.
    27  
    28  var _ = e2e.DescribeCChain("[Dynamic Fees]", func() {
    29  	require := require.New(ginkgo.GinkgoT())
    30  
    31  	// Need a gas limit much larger than the standard 21_000 to enable
    32  	// the contract to induce a gas price increase
    33  	const largeGasLimit = uint64(8_000_000)
    34  
    35  	// TODO(marun) What is the significance of this value?
    36  	gasTip := big.NewInt(1000 * params.GWei)
    37  
    38  	ginkgo.It("should ensure that the gas price is affected by load", func() {
    39  		ginkgo.By("creating a new private network to ensure isolation from other tests")
    40  		privateNetwork := tmpnet.NewDefaultNetwork("avalanchego-e2e-dynamic-fees")
    41  		e2e.Env.StartPrivateNetwork(privateNetwork)
    42  
    43  		ginkgo.By("allocating a pre-funded key")
    44  		key := privateNetwork.PreFundedKeys[0]
    45  		ethAddress := evm.GetEthAddress(key)
    46  
    47  		ginkgo.By("initializing a coreth client")
    48  		node := privateNetwork.Nodes[0]
    49  		nodeURI := tmpnet.NodeURI{
    50  			NodeID: node.NodeID,
    51  			URI:    node.URI,
    52  		}
    53  		ethClient := e2e.NewEthClient(nodeURI)
    54  
    55  		ginkgo.By("initializing a transaction signer")
    56  		cChainID, err := ethClient.ChainID(e2e.DefaultContext())
    57  		require.NoError(err)
    58  		signer := types.NewEIP155Signer(cChainID)
    59  		ecdsaKey := key.ToECDSA()
    60  		sign := func(tx *types.Transaction) *types.Transaction {
    61  			signedTx, err := types.SignTx(tx, signer, ecdsaKey)
    62  			require.NoError(err)
    63  			return signedTx
    64  		}
    65  
    66  		var contractAddress common.Address
    67  		ginkgo.By("deploying an expensive contract", func() {
    68  			// Create transaction
    69  			nonce, err := ethClient.AcceptedNonceAt(e2e.DefaultContext(), ethAddress)
    70  			require.NoError(err)
    71  			compiledContract := common.Hex2Bytes(hashingCompiledContract)
    72  			tx := types.NewTx(&types.LegacyTx{
    73  				Nonce:    nonce,
    74  				GasPrice: gasTip,
    75  				Gas:      largeGasLimit,
    76  				Value:    common.Big0,
    77  				Data:     compiledContract,
    78  			})
    79  
    80  			// Send the transaction and wait for acceptance
    81  			signedTx := sign(tx)
    82  			receipt := e2e.SendEthTransaction(ethClient, signedTx)
    83  
    84  			contractAddress = receipt.ContractAddress
    85  		})
    86  
    87  		var gasPrice *big.Int
    88  		ginkgo.By("calling the expensive contract repeatedly until a gas price increase is detected", func() {
    89  			// Evaluate the bytes representation of the contract
    90  			hashingABI, err := abi.JSON(strings.NewReader(hashingABIJson))
    91  			require.NoError(err)
    92  			contractData, err := hashingABI.Pack("hashIt")
    93  			require.NoError(err)
    94  
    95  			var initialGasPrice *big.Int
    96  			e2e.Eventually(func() bool {
    97  				// Check the gas price
    98  				var err error
    99  				gasPrice, err = ethClient.SuggestGasPrice(e2e.DefaultContext())
   100  				require.NoError(err)
   101  				if initialGasPrice == nil {
   102  					initialGasPrice = gasPrice
   103  					tests.Outf("{{blue}}initial gas price is %v{{/}}\n", initialGasPrice)
   104  				} else if gasPrice.Cmp(initialGasPrice) > 0 {
   105  					// Gas price has increased
   106  					tests.Outf("{{blue}}gas price has increased to %v{{/}}\n", gasPrice)
   107  					return true
   108  				}
   109  
   110  				// Create the transaction
   111  				nonce, err := ethClient.AcceptedNonceAt(e2e.DefaultContext(), ethAddress)
   112  				require.NoError(err)
   113  				tx := types.NewTx(&types.LegacyTx{
   114  					Nonce:    nonce,
   115  					GasPrice: gasTip,
   116  					Gas:      largeGasLimit,
   117  					To:       &contractAddress,
   118  					Value:    common.Big0,
   119  					Data:     contractData,
   120  				})
   121  
   122  				// Send the transaction and wait for acceptance
   123  				signedTx := sign(tx)
   124  				_ = e2e.SendEthTransaction(ethClient, signedTx)
   125  
   126  				// The gas price will be checked at the start of the next iteration
   127  				return false
   128  			}, e2e.DefaultTimeout, e2e.DefaultPollingInterval, "failed to see gas price increase before timeout")
   129  		})
   130  
   131  		ginkgo.By("waiting for the gas price to decrease...", func() {
   132  			initialGasPrice := gasPrice
   133  			e2e.Eventually(func() bool {
   134  				var err error
   135  				gasPrice, err = ethClient.SuggestGasPrice(e2e.DefaultContext())
   136  				require.NoError(err)
   137  				tests.Outf("{{blue}}.{{/}}")
   138  				return initialGasPrice.Cmp(gasPrice) > 0
   139  			}, e2e.DefaultTimeout, e2e.DefaultPollingInterval, "failed to see gas price decrease before timeout")
   140  			tests.Outf("\n{{blue}}gas price has decreased to %v{{/}}\n", gasPrice)
   141  		})
   142  
   143  		ginkgo.By("sending funds at the current gas price", func() {
   144  			// Create a recipient address
   145  			recipientKey, err := secp256k1.NewPrivateKey()
   146  			require.NoError(err)
   147  			recipientEthAddress := evm.GetEthAddress(recipientKey)
   148  
   149  			// Create transaction
   150  			nonce, err := ethClient.AcceptedNonceAt(e2e.DefaultContext(), ethAddress)
   151  			require.NoError(err)
   152  			tx := types.NewTx(&types.LegacyTx{
   153  				Nonce:    nonce,
   154  				GasPrice: gasPrice,
   155  				Gas:      e2e.DefaultGasLimit,
   156  				To:       &recipientEthAddress,
   157  				Value:    common.Big0,
   158  			})
   159  
   160  			// Send the transaction and wait for acceptance
   161  			signedTx := sign(tx)
   162  			_ = e2e.SendEthTransaction(ethClient, signedTx)
   163  		})
   164  
   165  		e2e.CheckBootstrapIsPossible(privateNetwork)
   166  	})
   167  })