Call function with another uint type - solidity

I would like to know what is happening under the hood when I call a function which uses normally receive a uint256 as argument, but with another uint type, for example uint8.
I have the impression that there is no error.
For example:
function sqrt(uint256 y) public pure returns (uint256) {
if (y > 3) {
uint256 z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
return z;
} else if (y != 0) {
return 1;
} else {
return 0;
}
}
function sqrtTest(uint8 y) public pure returns (uint256) {
return sqrt(y);
}
Here when I call sqrtTest with 4, it works.
Is there a reason why I should avoid this type of operation?

When you replace the input uint256 parameter type to a smaller one, the function will only accept the largest value of the type.
Example:
function sqrt(uint8 y) public pure returns (uint256) {
The largest value of uint8 is 255.
When you try to pass 256, the function call throws an out-of-bounds exception. And since this exception is not handled, the call reverts.

Related

Hello, do you know how to fix this problem? It seems not working

pragma solidity >= 0.7.0 < 0.9.0;
contract FinalExcercise {
uint a = 300;
uint b = 12;
uint f = 47;
function finalize () public view returns (uint) {
uint d = 23;
returns = d;
if (a <= a && b < f) {
return = d(2) - b
return = result;
}
}
}
I tried in different ways but I got this mistake: ParserError: Expected primary expression
Is this what you are trying to do, return is a reserved keyword you cannot use it for naming variables!
pragma solidity >=0.7.0 <0.9.0;
contract FinalExcercise {
uint256 a = 300;
uint256 b = 12;
uint256 f = 47;
function finalize() public view returns (uint256) {
uint256 d = 23;
if (a <= a && b < f) {
return (d * 2) - b;
}
}
}

How to check if one value exists in an array?

I need to check if all the values in X array exist in Y array do something.
The order does not matter.
contract test {
uint[] numbers1;
uint[] numbers2;
function push1(uint num1, uint num2, uint num3) public {
numbers1.push(num1);
numbers1.push(num2);
numbers1.push(num3);
}
function push2(uint num1, uint num2, uint num3) public {
numbers2.push(num1);
numbers2.push(num2);
numbers2.push(num3);
}
}
How can I check all numbers in numbers1 exist in numbers2 or not?
There are two approaches.
You can create a view function (docs) that loops through the array and returns true if the item is found. Mind that a view function can be invoked using a gas-free read-only call instead of a (read-write) transaction costing gas fees.
function exists1(uint num) public view returns (bool) {
for (uint i = 0; i < numbers1.length; i++) {
if (numbers1[i] == num) {
return true;
}
}
return false;
}
This approach has a linear complexity. So if you need to validate the value existence during a transaction, it might be costly depending on the total amount of items in the array.
So there's a second approach - duplicate the values as keys of a mapping (docs) that can be accessed directly through its key. There's a constant complexity to search the value but it costs double to store the value.
uint[] numbers1;
mapping(uint => bool) public exists1; // default value for each key is false
function push1(uint num1, uint num2, uint num3) public {
numbers1.push(num1);
numbers1.push(num2);
numbers1.push(num3);
exists1[num1] = true;
exists1[num2] = true;
exists1[num3] = true;
}

Try to return an array in a for loop

I am very new to Solidity, so sorry for the silly question. I am trying to add an element of a struct and then return it, here is my code:
struct Flat {
uint256 priceInWei;
address currentOccupant;
bool flatIsAvailable;
}
Flat[8] public flatDB;
modifier landlordOnly() {
require(msg.sender == landlordAddress);
_;
}
constructor() public {
landlordAddress = msg.sender;
for (uint i=0; i<8; i++) {
flatDB[i].flatIsAvailable = true;
if (i % 2 == 0) {
flatDB[i].priceInWei = 0.1 ether;
} else {
flatDB[i].priceInWei = 0.2 ether;
}
}
}
uint256[] array;
function getFlatDB() payable public returns (uint256) {
for (uint i=0; i<8; i++) {
array.push(flatDB[i].priceInWei);
}
return array;
}
But when I try to compile I have an error at line 41:
TypeError: Return argument type uint256[] storage ref is not implicitly convertible to expected type (type of first return variable) uint256. return array; ^---^
Can someone explain me what's wrong? Thanks!
Seems like the return type you have (uint256) doesn't correspond to the type you're actually trying to return (uint256[]). Try rewriting your getFlatDB function in the following way:
function getFlatDB() payable public returns (uint256[]) {
uint256[] memory array = new uint256[](8);
for (uint i=0; i<8; i++) {
array[i] = flatDB[i].priceInWei;
}
return array;
}
Note how we declare the temporary fixed size return array inside the function with memory keyword.

Send oraclize query with variables

I need to send a solidity request, which looks like this:
validId[oraclize_query(60, "URL", "json(http://myIp.something/wallet_check.json?wallet=".toSlice().concat(toString(msg.sender).toSlice()).toSlice().concat(").white_listed".toSlice()) )] = msg.sender;
However, conversion toString return unreadable string, which is probably why oracle can't handle the request. How do i convert address to string or go around the conversion?
code for toString():
function toString(address x) returns (string) {
bytes memory b = new bytes(20);
for (uint i = 0; i < 20; i++)
b[i] = byte(uint8(uint(x) / (2**(8*(19 - i)))));
return string(b);
}

When I use Y-Combinator and block in C, I meet a strange thing in parameter value

When I try to caculate sinh−1(x) using functions:
double asinh_recursion(double buf, double increment, double input_var, unsigned long item_count) {
if (fabs(increment) < 1E-5) {
return buf;
}
return asinh_recursion(buf + increment, increment * (-1) * (2 * item_count - 1) * (2 * item_count -1) / (2 * item_count + 1) / 2 / item_count * input_var, input_var, item_count + 1);
}
double asinh(double x) {
if (!(fabs(x) < 1.0)) {
printf("error asinh():wrong param x(fabs(x) > 1.0)");
return -1.0;
}
return asinh_recursion(0.0, x, x * x, 1);
}
it seem works.
but when I try to use block and Y-Combinator to do it:
typedef void * (^YCBlock)(void *);
YCBlock Y;
double asinh_with_block(double x) {
if (!(fabs(x) < 1.0)) {
printf("error asinh():wrong param x(fabs(x) > 1.0)");
return -1.0;
}
Y= (YCBlock) ^ (YCBlock f) {
return (YCBlock) ^ (YCBlock g) {
return g(g);
}(
(YCBlock) ^ (YCBlock h) {
return f(^ (void * x) { return ((YCBlock)h(h))(x); });
}
);
};
typedef double (^ RECUR_BLK_TYPE)(double, double, unsigned long);
RECUR_BLK_TYPE recur_block = Y(^(RECUR_BLK_TYPE recur_block){
return Block_copy(^ double (double buf, double increment, unsigned long item_count){
if (item_count < 4) {
printf("param:%lf,%lf,%lu\n", buf, increment, item_count);
}
if (fabs(increment) < 1E-5) {
return buf;
}
buf = buf + increment;
increment = increment * (-1) * (2 * item_count - 1) * (2 * item_count -1) / (2 * item_count + 1) / 2 / item_count * (x * x);
++item_count;
if (item_count < 4) {
printf("\tbuf:%lf\n", buf);
}
return recur_block(buf, increment, item_count);
});
});
double ret = recur_block(0, x, 1);
Block_release(recur_block);
Block_release(Y);
return ret;
}
but it works strangely in the output(x=0.5):
param:0.000000,0.500000,1
buf:0.500000
param:0.500000,-0.020833,2
buf:0.479167
param:0.500000,0.002344,3
...
asinh_with_block(0.500000):0.500000
it seem like that in the block, at some time,when I pass buf=0.479167, next time when I print it, it is still 0.500000.
I wanna to find why it works like this, maybe I wrote some wrong code at somewhere...
The problem is that your Y combinator is only made to work with an underlying function that takes one void * parameter and returns a void *. You can see that in the line:
return f(^ (void * x) { return ((YCBlock)h(h))(x); });
The block in there that takes x (one argument) and passed the x to another thing as one argument. For it to work with a recursive function of multiple arguments, this function must take those multiple arguments and pass them all on (of course, the types all need to be right too, because different types have different sizes, and the ABI for passing and returning things of different types is different). So you will need a different Y combinator for each function signature.
You have a recursive function that takes three parameters (two doubles and an unsigned long) and returns a double. You can (minimally) make it work by changing the relevant block in the Y combinator and coercing it from the wrong type to the right type:
return f(^ (double buf, double increment, unsigned long item_count) {
return ((RECUR_BLK_TYPE)((YCBlock)h(h)))(buf, increment, item_count);
});
But to really make it clean with correct type safety without this unsafe casting would require you to carefully set up the types. Something like this:
typedef double (^Func)(double, double, unsigned long);
typedef Func (^FuncFunc)(Func);
typedef Func (^RecursiveFunc)(void *);
typedef Func (^YCBlock)(FuncFunc);
Y = ^(FuncFunc f) {
return ^(RecursiveFunc g) {
return g(g);
}(
^(void *temp) {
RecursiveFunc h = temp; // trick to hide the recursive typing
return f(^(double buf, double increment, unsigned long item_count) {
return h(h)(buf, increment, item_count);
});
}
);
};