diff --git a/api/api.go b/api/api.go index a74aa43c..fd842924 100644 --- a/api/api.go +++ b/api/api.go @@ -503,30 +503,37 @@ func (b *BlockChainAPI) EstimateGas( data = *args.Input } - eoa := newEOATestAccount(b.config.COAKey.String()[2:]) - // Provide a high enough gas for the tx to be able to execute - gas := uint64(15_000_000) + // provide a high enough gas for the tx to be able to execute + defaultGasLimit := uint64(15_000_000) if args.Gas != nil { - gas = uint64(*args.Gas) + defaultGasLimit = uint64(*args.Gas) } - txData := eoa.PrepareSignAndEncodeTx( + txData, err := signGasEstimationTx( args.To, data, (*big.Int)(args.Value), - gas, + defaultGasLimit, (*big.Int)(args.GasPrice), ) + if err != nil { + b.logger.Error().Err(err).Msg("failed to sign transaction for gas estimate") + return hexutil.Uint64(defaultGasLimit), nil // return default gas limit + } - gas, err := b.evm.EstimateGas(ctx, txData) + estimatedGas, err := b.evm.EstimateGas(ctx, txData) if err != nil { b.logger.Error().Err(err).Msg("failed to estimate gas") return hexutil.Uint64(0), err } - return hexutil.Uint64(gas), nil + return hexutil.Uint64(estimatedGas), nil } +// handleError takes in an error and in case the error is of type ErrNotFound +// it returns nil instead of an error since that is according to the API spec, +// if the error is not of type ErrNotFound it will return the error and the generic +// empty type. func handleError[T any](log zerolog.Logger, err error) (T, error) { var zero T if errors.Is(err, storageErrs.ErrNotFound) { diff --git a/api/eoa_test_account.go b/api/eoa_test_account.go deleted file mode 100644 index 9cf7bc64..00000000 --- a/api/eoa_test_account.go +++ /dev/null @@ -1,75 +0,0 @@ -package api - -import ( - "bytes" - "crypto/ecdsa" - "io" - "math/big" - - gethCommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - gethCrypto "github.com/ethereum/go-ethereum/crypto" - "github.com/onflow/flow-go/fvm/evm/emulator" -) - -type eoaTestAccount struct { - address gethCommon.Address - key *ecdsa.PrivateKey - signer types.Signer -} - -func (a *eoaTestAccount) PrepareSignAndEncodeTx( - to *gethCommon.Address, - data []byte, - amount *big.Int, - gasLimit uint64, - gasPrice *big.Int, -) []byte { - tx := a.prepareAndSignTx(to, data, amount, gasLimit, gasPrice) - - var b bytes.Buffer - writer := io.Writer(&b) - err := tx.EncodeRLP(writer) - if err != nil { - panic(err) - } - - return b.Bytes() -} - -func (a *eoaTestAccount) prepareAndSignTx( - to *gethCommon.Address, - data []byte, - amount *big.Int, - gasLimit uint64, - gasPrice *big.Int, -) *types.Transaction { - tx := types.NewTx( - &types.LegacyTx{ - Nonce: 0, - To: to, - Value: amount, - Gas: gasLimit, - GasPrice: gasPrice, - Data: data, - }, - ) - tx, err := types.SignTx(tx, a.signer, a.key) - if err != nil { - panic(err) - } - - return tx -} - -func newEOATestAccount(keyHex string) *eoaTestAccount { - key, _ := gethCrypto.HexToECDSA(keyHex) - address := gethCrypto.PubkeyToAddress(key.PublicKey) - signer := emulator.GetDefaultSigner() - - return &eoaTestAccount{ - address: address, - key: key, - signer: signer, - } -} diff --git a/api/gas_estimation.go b/api/gas_estimation.go new file mode 100644 index 00000000..120b3fed --- /dev/null +++ b/api/gas_estimation.go @@ -0,0 +1,42 @@ +package api + +import ( + "fmt" + "math/big" + + gethCommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + gethCrypto "github.com/ethereum/go-ethereum/crypto" + "github.com/onflow/flow-go/fvm/evm/emulator" +) + +var key, _ = gethCrypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") +var signer = emulator.GetDefaultSigner() + +// signGasEstimationTx will create a transaction and sign it with a test account +// used only for gas estimation, since gas estimation is run inside a script +// and does not change the state this account is not important it just has to be valid. +func signGasEstimationTx( + to *gethCommon.Address, + data []byte, + amount *big.Int, + gasLimit uint64, + gasPrice *big.Int, +) ([]byte, error) { + tx := types.NewTx( + &types.LegacyTx{ + Nonce: 0, + To: to, + Value: amount, + Gas: gasLimit, + GasPrice: gasPrice, + Data: data, + }, + ) + tx, err := types.SignTx(tx, signer, key) + if err != nil { + return nil, fmt.Errorf("failed to sign tx for gas estimation: %w", err) + } + + return tx.MarshalBinary() +}