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

Flutter前端无法连接Election智能合约,遇RPCError执行回滚求助

选举DApp Flutter连接智能合约执行回滚问题解决

问题描述

开发的小型选举DApp在Remix IDE中部署测试完全正常,但通过Flutter应用连接智能合约时无法正常工作。已尝试重新部署合约并同步更新ABI与合约地址,问题仍存在,仅Remix内测试可正常运行,触发的错误为执行回滚。

错误信息

call function has error ::::: RPCError: got code -32000 with msg "execution reverted".

相关代码

智能合约代码

//SPDX-License-Identifier:UNLICENSED
pragma solidity ^0.8.0;

contract Election{

    struct Candidate{
        string name;
        uint numvotes;
    }

    struct Voter{
        string name;
        bool authorised;
        uint whom;
        bool voted;
    }

    modifier ownerOnly(){
        require(msg.sender == owner);
        _;
    }

    address public owner;
    string public ElectionName;

    mapping(address => Voter) public Voters;
    Candidate[] public candidates;
    uint public totalvotes=0;

    function startElection(string memory _ElectionName)public{
        owner = msg.sender;
        ElectionName = _ElectionName;
    }

    function addCandidate(string memory _candidatename) ownerOnly public{
        candidates.push(Candidate(_candidatename,0));
    }

    function authoriseVoter(address _voteradress)ownerOnly public{
        require(!Voters[msg.sender].voted);
        Voters[_voteradress].authorised = true;
    }

    function getNumcandidates()public view returns(uint){
            return candidates.length;
    }

    function Vote(uint CandidateIndex)public {
        require(!Voters[msg.sender].voted);
        require(Voters[msg.sender].authorised = true);
        Voters[msg.sender].whom = CandidateIndex;
        Voters[msg.sender].voted = true;

        candidates[CandidateIndex].numvotes++;
        totalvotes++;

    }

    function candidateInfo(uint index) public view returns(Candidate memory){ 
        return candidates[index];
    }

    function getTotalVotes()public view returns(uint) {
        return totalvotes;
    } 
    
}

前端函数代码

Future<DeployedContract> loadContract() async {
  try{
    String abi = await rootBundle.loadString('assets/abi.json');
    String contractAddress = contractAdressConst;
    final contract = DeployedContract(ContractAbi.fromJson(abi, 'Election'),
        EthereumAddress.fromHex(contractAddress));
    return contract;
  }catch(e){
    print('load contract failed ::::: $e');
    print('{{{{{{{{{{{{{{{[[{{{{{');
    String abi = await rootBundle.loadString('assets/abi.json');
    String contractAddress = contractAdressConst;
    final contract = DeployedContract(ContractAbi.fromJson(abi, 'Election'),
        EthereumAddress.fromHex(contractAddress));
    return contract;
  }
}

Future<String> callFunction(String funcname, List<dynamic> args,
    Web3Client ethClient, String privateKey) async {
  try{
    EthPrivateKey credentials = EthPrivateKey.fromHex(privateKey);
    DeployedContract contract = await loadContract();
    final ethFunction = contract.function(funcname);
    final result = await ethClient.sendTransaction(
        credentials,
        Transaction.callContract(
          contract: contract,
          function: ethFunction,
          parameters: args,
        ),
        chainId: null,
        fetchChainIdFromNetworkId: true);
    return result;
  }catch(e){
    print('call function has error ::::: $e');
    return e.toString();
  }
}

Future<String> startElection(String name, Web3Client ethClient) async {
  try{
    var response =
    await callFunction('startElection', [name], ethClient, owner_private_key);
    print('Election started successfully');
    return response;
  }catch(e){
    print("election not started : : : $e");
    return e.toString();
  }
}

Future<String> addCandidate(String name, Web3Client ethClient) async {
  try{
    var response =
    await callFunction('addCandidate', [name], ethClient, owner_private_key);
    print('Candidate added successfully');
    return response;
  }catch(e){
    print(" candidate not added : : :$e");
    return e.toString();
  }
}

home.dart代码

import 'package:election/utils/Constants.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:web3dart/web3dart.dart';

import '../services/functions.dart';
import 'Electioninfo.dart';

class Home extends StatefulWidget {
  const Home({Key? key}) : super(key: key);

  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  Client? httpClient;
  Web3Client? ethClient;
  TextEditingController controller = TextEditingController();

  @override
  void initState() {
    httpClient = Client();
    ethClient = Web3Client(infura_url, httpClient!);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Start Election'),
      ),
      body: Container(
        padding: EdgeInsets.all(14),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(
              controller: controller,
              decoration: InputDecoration(
                  filled: true, hintText: 'Enter election name'),
            ),
            SizedBox(
              height: 10,
            ),
            Container(
                width: double.infinity,
                height: 45,
                child: ElevatedButton(
                    onPressed: () async {
                      if (controller.text.length > 0) {
                        await startElection(controller.text, ethClient!);
                        Navigator.push(
                            context,
                            MaterialPageRoute(
                                builder: (context) => ElectionInfo(
                                    ethClient: ethClient!,
                                    electionName: controller.text)));
                      }
                    },
                    child: Text('Start Election')))
          ],
        ),
      ),
    );
  }
}

解决方案

1. 修复智能合约语法错误

在Vote函数中存在致命的赋值错误,将判断条件误写为赋值操作,会导致逻辑异常:

// 错误写法
require(Voters[msg.sender].authorised = true);
// 正确写法(二选一)
require(Voters[msg.sender].authorised == true);
require(Voters[msg.sender].authorised);

2. 明确指定交易Chain ID

Flutter代码中sendTransaction依赖自动获取Chain ID可能出现偏差,需手动指定对应网络的Chain ID(如Sepolia为11155111,Goerli为5):

final result = await ethClient.sendTransaction(
    credentials,
    Transaction.callContract(
      contract: contract,
      function: ethFunction,
      parameters: args,
    ),
    chainId: 11155111, // 替换为你使用的网络Chain ID
    fetchChainIdFromNetworkId: false);

3. 验证调用者与合约Owner一致性

  • 确认owner_private_key对应的地址,是调用startElection时设置的合约Owner地址;若多次调用startElection,Owner会被更新,后续addCandidate需使用最新Owner的私钥。
  • 调用addCandidate前,通过合约owner()方法查询当前Owner,确保与Flutter使用的私钥地址匹配。

4. 确保ABI文件正确性

重新编译合约并导出最新ABI,替换assets/abi.json,避免手动编辑导致的签名或参数类型不匹配问题。

5. 增强错误日志信息

在Flutter错误捕获中添加上下文信息,帮助定位问题:

catch(e){
    print('call function has error ::::: $e');
    print('Function: $funcname, Args: $args, Sender: ${credentials.address}');
    return e.toString();
}

内容的提问来源于stack exchange,提问作者Abhiram

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 06:40:25