新手求助:eth.estimateGas传入合约地址作为to参数执行失败
Hey there, let's break down why you're hitting this error and how to fix it quickly!
Why This Happens
When you call eth.estimateGas({from:'firstAccount', to:'contractAddr'}) without extra parameters, you're essentially sending an empty transaction to the contract. Most contracts either:
- Don’t have a fallback/receive function at all, so the transaction immediately fails
- Have a fallback function that’s not
payable, but you didn’t include avalue(if required) - Have a fallback function that intentionally reverts under certain conditions
The node recognizes this transaction as guaranteed to fail, so it throws that slightly misleading "gas required exceeds allowance" error—it really means the transaction can’t succeed no matter how much gas you allocate.
How to Fix It
You need to tell the contract which method you want to call by including the encoded data field in your estimateGas request. Here are two straightforward ways to do this with go-ethereum:
1. Use the bind Package (Recommended)
The bind package you mentioned handles ABI encoding and gas estimation automatically, so you don’t have to mess with raw data fields. Here’s a step-by-step example:
- First, have your contract’s ABI (usually a JSON string from Solidity compilation) ready.
- Create a bound contract instance, then use its
EstimateGasmethod to calculate gas for specific method calls.
package main import ( "context" "log" "strings" "math/big" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" ) func main() { // Connect to your Ethereum node ethClient, err := ethclient.Dial("http://localhost:8545") if err != nil { log.Fatal(err) } // Replace with your contract's ABI JSON string contractABI := `[{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]` // Parse the ABI parsedABI, err := abi.JSON(strings.NewReader(contractABI)) if err != nil { log.Fatal(err) } // Replace with your contract address and sender address contractAddr := common.HexToAddress("0xYourContractAddress") firstAccount := common.HexToAddress("0xYourFirstAccount") recipient := common.HexToAddress("0xRecipientAddress") // Create a bound contract instance boundContract, err := bind.NewBoundContract(contractAddr, parsedABI, ethClient, ethClient, ethClient) if err != nil { log.Fatal(err) } // Estimate gas for calling the "transfer" method with parameters gasLimit, err := boundContract.EstimateGas(context.Background(), "transfer", firstAccount, recipient, big.NewInt(100)) if err != nil { log.Fatal(err) } log.Printf("Estimated gas: %d", gasLimit) }
2. Manually Encode the data Field
If you want to use the raw eth.estimateGas method, you need to encode the method signature and parameters into the data field using the contract’s ABI:
package main import ( "context" "log" "math/big" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" ) func main() { ethClient, err := ethclient.Dial("http://localhost:8545") if err != nil { log.Fatal(err) } // Parse your contract's ABI contractABI := `[{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]` parsedABI, err := abi.JSON(strings.NewReader(contractABI)) if err != nil { log.Fatal(err) } // Encode the "transfer" method call into data data, err := parsedABI.Pack("transfer", common.HexToAddress("0xRecipientAddress"), big.NewInt(100)) if err != nil { log.Fatal(err) } // Prepare the call message with data callMsg := ethclient.CallMsg{ From: common.HexToAddress("0xYourFirstAccount"), To: &common.HexToAddress("0xYourContractAddress"), Data: data, } // Estimate gas gasLimit, err := ethClient.EstimateGas(context.Background(), callMsg) if err != nil { log.Fatal(err) } log.Printf("Estimated gas: %d", gasLimit) }
Edge Case: Calling the Fallback/Receive Function
If you actually want to trigger the contract’s fallback or receive function (e.g., sending ETH to the contract), make sure:
- The fallback/receive function is marked
payable - Include the
Valuefield in your call message if sending ETH:
callMsg := ethclient.CallMsg{ From: common.HexToAddress("0xYourFirstAccount"), To: &common.HexToAddress("0xYourContractAddress"), Value: big.NewInt(1000000000000000000), // 1 ETH } gasLimit, err := ethClient.EstimateGas(context.Background(), callMsg)
内容的提问来源于stack exchange,提问作者Vadim Filin

