Ethereum smart contract no function return value - ethereum

I'm new to smart contracts and I've deployed this test contract
contract test {
function callme(address dest, uint num, bytes data, uint nonce)
public
returns (bytes32 myhash)
{
myhash = sha3(dest, num, data, nonce);
return (myhash);
}
}
I then call test.callme(eth.accounts[0], 10, 0xaaaaa, 1234) expecting it to return the sha3 hash of the passed parameters but there's no return value.
> test.callme(eth.accounts[0], 10, 0xaaaaa, 1234)
INFO [12-24|19:35:40] Submitted transaction fullhash=0x694e0e38d0cf8744e62113750339a65f1d5a35cdc634eeb02b93581a926fea1a recipient=0xed712462999f8f68BbF618C3845F4333eDC31cD5
"0x694e0e38d0cf8744e62113750339a65f1d5a35cdc634eeb02b93581a926fea1a"
Any help is appreciated

Your syntax is a little off - you don't need to name your return value myhash. Something like this should do the trick:
contract test {
function callme(address dest, uint num, bytes data, uint nonce)
public
constant
returns (bytes32)
{
bytes32 myhash = sha3(dest, num, data, nonce);
return myhash;
}
}
I also threw in a constant keyword since the function isn't planning on changing anything in your contract's storage. It's a small change, but necessary for what you're trying to do.
Including the constant enables you to get a 'return' value, so to speak, because it says that you won't need to be modifying the blockchain - in essence, you're 'reading' the chain, not 'writing' to it.
Imagine a contract that did something like this:
contract test {
uint example;
function callme()
public
returns (uint)
{
example = example + 1;
return example;
}
}
The transaction we send to callme actually has to be executed before we return the value (since we're modifying the blockchain). Therefore, we can't really return the final value instantly (and we instead return information about the transaction), since we have to wait for the blockchain to be updated first.

Related

Is it necessary to write a return statement in Solidity?

pragma solidity ^0.8.0;
contract Counter {
uint public number;
string public name;
constructor(string memory input_name, uint input_number){
name = input_name;
number = input_number;
}
function add () public {
number ++;
}
function subtract() public {
number --;
}
function update_name(string memory update) public {
name = update;
}
I wrote a very basic contract here and I'm wondering why I should write a return statement for each of my functions as it is already returns a value.
Could someone explain my error or the point of the return statement here?
Solidity have the "implicit return" feature, so as you noticed, you may skip the "return" statement in some cases. However, it's discourages, since you're not explicit enough and may cause a lot of confusion and issues.
For details please check the following links:
https://medium.com/#pareshmasani/ethereum-smart-contract-implicit-return-can-go-wrong-33b41c93dbba
https://github.com/ethereum/solidity/issues/3134
https://blog.openzeppelin.com/instadapp-audit/

How do you read a value returned by a method in smartcontract using web3j?

I'm using web3j in Android studio to interact with smartcontracts.
In my SmartContract i've 2 functions getName() and getAge() and i'm setting age and name in constructor as below:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
contract Identify {
string name;
uint age;
constructor() public {
name = "Shoaib Khalid";
age = 22;
}
function getName() view public returns(string memory){
return name;
}
function getAge() view public returns(uint){
return age;
}
}
But I'm not able to read the value returned by both functions. After deploying the smartcontract correctly, following is the method I'm trying to read the value returned by getName() function.
val identityContract = Identity_sol_Identify.load(
deployedContractAddress,
web3j,
getCredentialsFromPrivateKey(),
DefaultGasProvider.GAS_PRICE,
DefaultGasProvider.GAS_LIMIT
)
Log.d(TAG, "counter Result: ${identityContract.name.sendAsync().get()}")
Instead of getting the value Shoaib Khalid which I set in the constructor I'm getting a TranscriptReciept object the output screenshoot is attached below.
So I want to know can you read the exact value returned by the function getName() in smartcontract using web3j?
Please refer to the Web3j documentation:
Transactional calls do not return any values, regardless of the return type specified on the method. Hence, for all transactional
methods the Transaction Receipt associated with the transaction is
returned [1]
...
The transaction receipt is useful for two reasons:
It provides details of the mined block that the transaction resides in Solidity events that are called will be logged as part of
the transaction, which can then be extracted.
You are getting the transaction receipt. In order to query the values from your state variables you should refer to the section Querying the state of a smart contract and do something like this:
Function function = new Function<>(
"getName", // This is the name of the solidity function in your smart contract
Collections.emptyList(), // Solidity Types in smart contract functions, no input in the function so we set this to empty
Arrays.asList(new TypeReference<Utf8String>() {})); // result will be a string
String encodedFunction = FunctionEncoder.encode(function);
org.web3j.protocol.core.methods.response.EthCall response = web3j.ethCall(
Transaction.createEthCallTransaction(contractAddress, encodedFunction),
DefaultBlockParameterName.LATEST)
.sendAsync().get();
Iterator<Type> it = someType.iterator();
Type result = someType.get(0);
String a = result.toString();
Log.d("Name: ", a);

Return value from a deployed smart contract, via a smart contract, to a smart contract

I am trying to return a value using a function of a deployed smart contract on the blockchain.
pragma solidity 0.6.2;
contract Caller {
address cont;
function changeAdd(address _change) public {
cont = _change;
}
function caller (bytes memory test) public returns(bool, bytes memory) {
bytes memory payload = abi.encodeWithSignature("callMe(bytes)", test);
(bool success, bytes memory result)= address(cont).call(payload);
return (success, (result));
}
function viewCont() public view returns(address) {
return cont;
}
}
And the deployed test contract is this:
pragma solidity 0.6.2;
contract Store {
uint counter;
function callMe(bytes calldata test) external returns(bytes memory) {
counter++;
return abi.encode(test);
}
function viewCounter () public view returns(uint256) {
return(counter);
}
function clearCounter() public {
counter = 0 ;
}
}
In this example, I am deploying contract "Store" on the blockchain where it is assigned a random address, which can be pointed at via the Caller.changeAdd function in order to use Caller.caller function. Thus, I am trying to send data in the form of bytes to the Store contract, which is supposed to send back the same data to the Caller contract. I am trying to isolate -only- the data that is originally sent, so I can use it to test interaction between smart contracts on the blockchain. I tried in the beginning to send an integer, but I couldn't find a way to do it. So I used bytes and it worked, but still the data I receive isn't the same that I send in the first place(e.g. I send 0x0 and I receive a big bytes number, which isn't the same as 0x0).
I could appreciate any help on how to receive and handle data between two different, unlinked smart contracts, thank you in advance.
Do you try to use abi.decode function of Solidity.
In the below example, contract B calls setName of contract A, then decodes the result by using abi.decode function.
contract A {
string public name;
constructor(string memory tokenName) public {
name = tokenName;
}
function setName(string memory newName) public returns ( string memory){
name = newName;
return newName;
}
}
contract B {
event Log(string msg);
string public myName;
function call(address addr, string memory newName) public {
bytes memory payload = abi.encodeWithSignature("setName(string)", newName);
(bool success, bytes memory result)= addr.call(payload);
// Decode data
string memory name = abi.decode(result, (string));
myName = name;
emit Log(name);
}
}

Solidity - Truffle: Error: VM Exception while processing transaction: invalid opcode NOT because of revert

I am working on a smart contract, and I am testing it by deploying it on truffle. While it compiles fine, when I call the train() function, I get the following error:
Error: VM Exception while processing transaction: invalid opcode
After reading a bit on this, I understood it is usually caused after a revert has occurred, so I tried commenting out the 2 require functions I had just to see if it would behave differently, and it did not.
Checking out this question did not help me, or I did not see how it could.
Here is the train() function, as well as the mapping and struct type I am using in it. I should note that upon creation of a Developer, their wallet is set to 300 so I do not see how the first call of the train function by the owner could revert.
struct Developer {
address owner;
string name;
bytes32 namehash;
bytes32[] skills;
uint256[] skill_levels;
uint wallet;
}
mapping (bytes32=>Developer) public developers_all;
function train(string _name, bytes32 _skill) public {
bytes32 h = keccak256(abi.encodePacked(_name));
require(developers_all[h].owner == msg.sender, "Only the owner of the developer can train them");
require(developers_all[h].wallet >= 150, "Insufficient funds");
uint256 i = 0;
do {
if (developers_all[h].skills[i] == _skill) {
developers_all[h].skill_levels[i]++;
} else if ((i == (developers_all[h].skills.length - 1)) || (developers_all[h].skills.length == 0)) {
developers_all[h].skills.push(_skill);
developers_all[h].skill_levels.push(1);
}
i++;
} while (i < developers_all[h].skills.length);
developers_all[h].wallet = developers_all[h].wallet - 150;
}
Thank you for any help.
This is most likely because you are trying to access the first entry of an empty array. You're using a do while loop, and you're trying to access developers_all[h].skills[i] before you're checking developers_all[h].skills.length == 0, so it is possible that the array is empty at the first if statement in the do while.
You could rewrite the code to something like the following, to make sure you're never accessing an unassigned array slot.
bool foundSkill = false;
for (uint i = 0; i < developers_all[h].skills.length; i++) {
if (developers_all[h].skills[i] == _skill) {
developers_all[h].skill_levels[i]++;
foundSkill = true;
break;
}
}
if (!foundSkill) {
developers_all[h].skills.push(_skill);
developers_all[h].skill_levels.push(1);
}
Do note that looping through the whole array and doing the comparisons is quite costly, and can become impossible if the array size gets too big. You might want consider changing the structure to something like:
struct Developer {
address owner;
string name;
bytes32 namehash;
mapping(bytes32 => uint) skill_levels;
uint wallet;
}
That way you could just replace the whole thing with
developers_all[h].skill_levels[skill]++;
But you wouldn't be able to loop over the skills.

How to get keccak256 hash in Solidity

I just got started with solidity, I have used truffle to compile and deploy the code to ganache, everything works as I expect, I can call the other functions in the code, but there are certain functions that only the owner can access, the code appears to use keccak256 to get back the address calling the function and determine if the caller address is allowed, I have tried to hash my eth address using this website:
https://emn178.github.io/online-tools/keccak_256.html
and then add the hash to the code before recompiling again, but calling the owner function still throws this error:
"Error: VM Exception while processing transaction: revert"
What am i doing wrong ?
Here's the code with the original hash.
modifier onlyOwner(){
address _customerAddress = msg.sender;
require(owners[keccak256(_customerAddress)]);
_;
}
// owners list
mapping(bytes32 => bool) public owners;
function PetShop()
public
{
// add owners here
owners[0x66e62cf7a807daaf3e42f7af3befe7b2416a79ba5348820245a69fe701f80eb4] = true;
}
/*---------- Owner ONLY FUNCTIONS ----------*/
function disableDogs()
onlyOwner()
public
{
onlyDogs = false;
}
/*-----replace owner ------*/
function setOwner(bytes32 _identifier, bool _status)
onlyOwner()
public
{
owners[_identifier] = _status;
}
/*-----set price for pet adoption----*/
function setAdoptionRequirement(uint256 _amountOfTokens)
onlyOwner()
public
{
AdoptionRequirement = _amountOfTokens;
}
The keccak256 implementation in Solidity stores data differently.
keccak256(...) returns (bytes32):
compute the Ethereum-SHA-3 (Keccak-256) hash of the (tightly packed) arguments
Just use the function yourself when creating the contract:
function PetShop() public {
// add owners here
owners[keccak256(msg.sender)] = true;
}
as of now
// .encodePacked merges inputs together
owners[keccak256(abi.encodePacked(_text, _num, _addr))}=true
abi.encodePacked() , Solidity supports a non-standard packed mode where:
types shorter than 32 bytes are neither zero padded nor sign extended
dynamic types are encoded in-place and without the length.
array elements are padded, but still encoded in-place