How to make transactions using web3.py from any account?

Viewed 603

I am using Flask at the backend and ganache for my blockchain project. I am also using Metamask. My smart contract is on the remix website. And here is my contract:

pragma solidity ^0.4.21;

contract Election{

    struct Candidate {
        uint voteCount;
        string name;
    }

    struct voter {
        bool authorized;
        bool voted;
        uint vote;
    }

    address public owner;
    string public electionName;

    mapping(address => voter) public voters;
    Candidate[] public candidates;
    uint public totalVotes;

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

    constructor(string _name) public {
        owner = msg.sender;
        electionName = _name;
    }

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

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

    function authorize(address _person) ownerOnly public {
        voters[_person].authorized = true;
    }

    function vote(uint _voteIndex) public {
        require(!voters[msg.sender].voted);
        require(voters[msg.sender].authorized);

        voters[msg.sender].vote = _voteIndex;
        voters[msg.sender].voted = true;

        candidates[_voteIndex].voteCount += 1;
        totalVotes += 1;
    }

    function end() ownerOnly public {
        selfdestruct(owner);
    }

}

I am facing a problem with Vote function. When I run this whole contract after deploying on the remix website it is working fine. But when I am making transaction from my flask based app there is revert error even after having the voter in Voters list. So using metamask I want to make my transaction for voting. I deploy the contract with a default account.

w3 = Web3(HTTPProvider('http://127.0.0.1:7545'))
w3.eth.defaultAccount = w3.eth.accounts[0]
contract = w3.eth.contract(address=address, abi=data["abi"])
tx_hash = contract.functions.vote(candidate_index).transact()
w3.eth.wait_for_transaction_receipt(tx_hash)

Now I want to make transactions from the account which I choose in Metamask. Because the above method is not working. Is there any way or any example to do it? I also visited metamask documentation where the use of ethereum.request() is suggested. But I was unable to implement it in web3py.

1 Answers

Your code is correct. There are 2 require statements in vote. I think that is why you are getting the error. You can add custom message to require functions so you can see which one is causing the error:

    require(!voters[msg.sender].voted,"You already voted");
    require(voters[msg.sender].authorized,"You are not authorized");

I believe since you already call vote with your default account, you are not passing the first require statement.

Related