github.com/ethereum-optimism/optimism/l2geth@v0.0.0-20230612200230-50b04ade19e3/rollup/fees/bindings/gaspriceoracle_test.go (about)

     1  package bindings
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/ecdsa"
     7  	"errors"
     8  	"math/big"
     9  	"testing"
    10  
    11  	"github.com/ethereum-optimism/optimism/l2geth/accounts/abi/bind"
    12  	"github.com/ethereum-optimism/optimism/l2geth/accounts/abi/bind/backends"
    13  	"github.com/ethereum-optimism/optimism/l2geth/common"
    14  	"github.com/ethereum-optimism/optimism/l2geth/core"
    15  	"github.com/ethereum-optimism/optimism/l2geth/core/rawdb"
    16  	"github.com/ethereum-optimism/optimism/l2geth/core/types"
    17  	"github.com/ethereum-optimism/optimism/l2geth/crypto"
    18  	"github.com/ethereum-optimism/optimism/l2geth/eth/gasprice"
    19  	"github.com/ethereum-optimism/optimism/l2geth/ethdb"
    20  	"github.com/ethereum-optimism/optimism/l2geth/rollup/fees"
    21  )
    22  
    23  // Test that the fee calculation is the same in both go and solidity
    24  func TestCalculateFee(t *testing.T) {
    25  	key, _ := crypto.GenerateKey()
    26  	sim, _ := newSimulatedBackend(key)
    27  	chain := sim.Blockchain()
    28  
    29  	opts, _ := NewKeyedTransactor(key)
    30  	addr, _, gpo, err := DeployGasPriceOracle(opts, sim, opts.From)
    31  	if err != nil {
    32  		t.Fatal(err)
    33  	}
    34  	sim.Commit()
    35  	callopts := bind.CallOpts{}
    36  
    37  	signer := types.NewEIP155Signer(big.NewInt(1337))
    38  	gasOracle := gasprice.NewRollupOracle()
    39  
    40  	// Set the L1 base fee
    41  	if _, err := gpo.SetL1BaseFee(opts, big.NewInt(1)); err != nil {
    42  		t.Fatal("cannot set 1l base fee")
    43  	}
    44  	sim.Commit()
    45  
    46  	tests := map[string]struct {
    47  		tx *types.Transaction
    48  	}{
    49  		"simple": {
    50  			types.NewTransaction(0, common.Address{}, big.NewInt(0), 0, big.NewInt(0), []byte{}),
    51  		},
    52  		"high-nonce": {
    53  			types.NewTransaction(12345678, common.Address{}, big.NewInt(0), 0, big.NewInt(0), []byte{}),
    54  		},
    55  		"full-tx": {
    56  			types.NewTransaction(20, common.HexToAddress("0x"), big.NewInt(1234), 215000, big.NewInt(769109341), common.FromHex(GasPriceOracleBin)),
    57  		},
    58  	}
    59  
    60  	for name, tt := range tests {
    61  		t.Run(name, func(t *testing.T) {
    62  			tx := tt.tx
    63  			raw := new(bytes.Buffer)
    64  			if err := tx.EncodeRLP(raw); err != nil {
    65  				t.Fatal("cannot rlp encode tx")
    66  			}
    67  
    68  			l1BaseFee, err := gpo.L1BaseFee(&callopts)
    69  			if err != nil {
    70  				t.Fatal("cannot get l1 base fee")
    71  			}
    72  			overhead, err := gpo.Overhead(&callopts)
    73  			if err != nil {
    74  				t.Fatal("cannot get overhead")
    75  			}
    76  			scalar, err := gpo.Scalar(&callopts)
    77  			if err != nil {
    78  				t.Fatal("cannot get scalar")
    79  			}
    80  			decimals, err := gpo.Decimals(&callopts)
    81  			if err != nil {
    82  				t.Fatal("cannot get decimals")
    83  			}
    84  			l2GasPrice, err := gpo.GasPrice(&callopts)
    85  			if err != nil {
    86  				t.Fatal("cannot get l2 gas price")
    87  			}
    88  
    89  			gasOracle.SetL1GasPrice(l1BaseFee)
    90  			gasOracle.SetL2GasPrice(l2GasPrice)
    91  			gasOracle.SetOverhead(overhead)
    92  			gasOracle.SetScalar(scalar, decimals)
    93  
    94  			l1Fee, err := gpo.GetL1Fee(&callopts, raw.Bytes())
    95  			if err != nil {
    96  				t.Fatal("cannot get l1 fee")
    97  			}
    98  
    99  			scaled := fees.ScaleDecimals(scalar, decimals)
   100  			expectL1Fee := fees.CalculateL1Fee(raw.Bytes(), overhead, l1BaseFee, scaled)
   101  			if expectL1Fee.Cmp(l1Fee) != 0 {
   102  				t.Fatal("solidity does not match go")
   103  			}
   104  
   105  			state, err := chain.State()
   106  			if err != nil {
   107  				t.Fatal("cannot get state")
   108  			}
   109  
   110  			// Ignore the error here because the tx isn't signed
   111  			msg, _ := tx.AsMessage(signer)
   112  
   113  			l1MsgFee, err := fees.CalculateL1MsgFee(msg, state, &addr)
   114  			if err != nil {
   115  				t.Fatal(err)
   116  			}
   117  			if l1MsgFee.Cmp(expectL1Fee) != 0 {
   118  				t.Fatal("l1 msg fee not computed correctly")
   119  			}
   120  
   121  			msgFee, err := fees.CalculateTotalMsgFee(msg, state, new(big.Int).SetUint64(msg.Gas()), &addr)
   122  			if err != nil {
   123  				t.Fatal("cannot calculate total msg fee")
   124  			}
   125  			txFee, err := fees.CalculateTotalFee(tx, gasOracle)
   126  			if err != nil {
   127  				t.Fatal("cannot calculate total tx fee")
   128  			}
   129  			if msgFee.Cmp(txFee) != 0 {
   130  				t.Fatal("msg fee and tx fee mismatch")
   131  			}
   132  		})
   133  	}
   134  }
   135  
   136  func newSimulatedBackend(key *ecdsa.PrivateKey) (*backends.SimulatedBackend, ethdb.Database) {
   137  	var gasLimit uint64 = 9_000_000
   138  	auth, _ := NewKeyedTransactor(key)
   139  	genAlloc := make(core.GenesisAlloc)
   140  	genAlloc[auth.From] = core.GenesisAccount{Balance: big.NewInt(9223372036854775807)}
   141  	db := rawdb.NewMemoryDatabase()
   142  	sim := backends.NewSimulatedBackendWithDatabase(db, genAlloc, gasLimit)
   143  	return sim, db
   144  }
   145  
   146  // NewKeyedTransactor is a utility method to easily create a transaction signer
   147  // from a single private key. This was copied and modified from upstream geth
   148  func NewKeyedTransactor(key *ecdsa.PrivateKey) (*bind.TransactOpts, error) {
   149  	keyAddr := crypto.PubkeyToAddress(key.PublicKey)
   150  	return &bind.TransactOpts{
   151  		From: keyAddr,
   152  		Signer: func(signer types.Signer, address common.Address, tx *types.Transaction) (*types.Transaction, error) {
   153  			if address != keyAddr {
   154  				return nil, errors.New("unauthorized")
   155  			}
   156  			signature, err := crypto.Sign(signer.Hash(tx).Bytes(), key)
   157  			if err != nil {
   158  				return nil, err
   159  			}
   160  			return tx.WithSignature(signer, signature)
   161  		},
   162  		Context: context.Background(),
   163  	}, nil
   164  }