使用Rust ethers.rs调用Goerli合约时遇invalid sender错误求助
解决ethers.rs调用Goerli合约出现"invalid sender"错误的线索
针对你遇到的问题,结合Node.js可正常调用的情况,以下是具体排查和解决方向:
1. 绑定正确的链ID到签名者
Goerli测试网的链ID是5,ethers.rs的LocalWallet默认不会自动关联链ID,而Node.js的ethers.js会自动从Provider获取链ID并用于签名,这是签名不匹配导致错误的常见原因。
修改签名者初始化代码:
use ethers::types::ChainId; // 绑定Goerli链ID到签名者 let signer = OWNER_PRIVATE_KEY.parse::<LocalWallet>()?.with_chain_id(ChainId::Goerli);
2. 手动指定交易Nonce
如果节点的nonce缓存异常,自动获取的nonce可能不正确,导致签名验证失败。可以手动获取并指定nonce:
// 获取当前地址的nonce let nonce = client.get_transaction_count(signer.address(), None).await?; // 创建合约调用时指定nonce let contract_call = contract.execute(params).nonce(nonce);
3. 确认签名者地址与Node.js完全一致
确保OWNER_PRIVATE_KEY和Node.js使用的私钥完全相同,直接打印地址验证(避免hex编码可能带来的错误):
info!("Call from address: {}", signer.address());
对比该地址与Node.js中使用的发送地址,确保完全一致(以太坊地址大小写不敏感,但建议完全匹配)。
4. 检查交易的Gas参数
自动估算的Gas参数可能存在异常,手动指定合理的Gas限制和价格:
use ethers::utils::parse_units; let gas_price = parse_units("10", "gwei")?; let contract_call = contract.execute(params) .gas_limit(300000) .gas_price(gas_price);
5. 验证SignerMiddleware的发送地址
打印客户端的默认发送地址,确认是否正确关联了签名者:
info!("Default sender: {:?}", client.default_sender());
修改后的示例代码片段
#[tokio::main] async fn main() -> anyhow::Result<()> { set_up_logs(); let execute_param = "SOMERAWDATA"; let rpc_url = "https://eth-goerli.g.alchemy.com/v2/{APIKEY}"; let contract_addr = "0x1577875Dd69f5276AEEabE3540b1F7c64690b3F8"; // 绑定Goerli链ID到签名者 let signer = OWNER_PRIVATE_KEY.parse::<LocalWallet>()?.with_chain_id(ChainId::Goerli); info!("Call from address: {}", signer.address()); let signer_middleware = Provider::<Http>::try_from(rpc_url)?.with_signer(signer.clone()); let client = Arc::new(signer_middleware); info!("Default sender: {:?}", client.default_sender()); let address: Address = contract_addr.parse()?; let contract = ScalarGateway::new(address.clone(), client.clone()); let params = Bytes::from_hex(execute_param)?; // 获取并指定nonce let nonce = client.get_transaction_count(signer.address(), None).await?; let contract_call = contract.execute(params).nonce(nonce); let res = contract_call.send().await?.await; info!("Call result {:?}", &res); Ok(()) }
内容的提问来源于stack exchange,提问作者viettai
相关产品推荐
相关产品推荐

