You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 11:08:24