Can ETH miners check all the data which is stored in Ethereum? - ethereum

My doubt is from the below code:
contract RandomNumber{
uint number;
function get_random() public{
bytes32 ramdonNumber = keccak256(abi.encodePacked(block.timestamp,blockhash(block.number-1)));
number = uint(ramdonNumber);
}
}
We assign a random number to the variable number but if I don't set number public or create another public function to retrieve the value then nobody would know the exactly value through Etherscan. But what about the miners? Can they retrieve these unrevealed data in some ways?
I have tried:
Google, Ethereum whitepaper, Solidity documentation

Assuming that the contract is deployed on a public network (e.g. Ethereum), then the value is always readable.
Not directly through the autogenerated getter function (that's available only for public properties), which means it's not available onchain.
But anyone (including miners) can create an offchain app (for example in JavaScript) that queries the specific storage slot where the value is stored - in this case it's in slot number 0. And it returns the "secret" value.
JS code using ethers library, a wrapper to RPC API of Ethereum nodes:
const number = await provider.getStorageAt(CONTRACT_ADDRESS, SLOT_NUMBER);
Docs: https://docs.ethers.org/v5/api/providers/provider/#Provider-getStorageAt
And the actual RPC API method: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getstorageat

Related

Solidity : submit string array, key value pair or an object as parameter to a function

In order to change the state of the smart contract from front end inputs, wanted to submit string array to a smart contract , key value pair or objects.
Is it possible to use string array as parameter?
No solidity doesn't support arrays of strings as parameter. You would have to serialize and deserialize it in a string yourself to have the desired result but that would be expensive to do in solidity. You can test that on remix if you want. However, on remix the error message says that this function is supported in the experimental ABI encoder but I have never tested that, or how well it works with other libraries, and it is experimental after all.
As seen in below example from solidity document we can send bytes array to constructor
constructor(bytes32[] memory proposalNames) public {
chairperson = msg.sender;
voters[chairperson].weight = 1;
// For each of the provided proposal names,
// create a new proposal object and add it
// to the end of the array.
for (uint i = 0; i < proposalNames.length; i++) {
// `Proposal({...})` creates a temporary
// Proposal object and `proposals.push(...)`
// appends it to the end of `proposals`.
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}
If you are trying to send string/Objects data specifically then it's better to separate out the methods and call each methods separately or within each other as currently solidity does not support that (using ABIencodere v2 is exceptional as it is only recommended for development purpose- as per on the date of this answer written)
struct A{
uint date,
B[] b
}
You can separate this out to
struct A{
uint date
}
struct B{
string goods,
uint quantity
}
so now for 1 A you can call N B from your service. Use mapping for binding both(if dependent).
In current situation it's better to design a contract which does not take bulk inputs or give out bulk outputs. However contracts are not for storage of huge data it's for storage of related data which fulfills agreement between parties

Ethereum Transaction Error while calling a contract function from another contract

Following smart contract works fine in Remix and Ganache. However doesn't work on private ethereum blockchains like Kaleido or Azure. What am I missing. When I call setA it consumes all gas and then fails.
pragma solidity ^0.4.24;
contract TestA {
uint public someValue;
function setValue(uint a) public returns (bool){
someValue = a;
return true;
}
}
contract TestB {
address public recentA;
function createA() public returns (address) {
recentA = new TestA();
return recentA;
}
function setA() public returns (bool) {
TestA(recentA).setValue(6);
return true;
}
}
I tried your contract in Kaleido, and found even calling eth_estimateGas with very large numbers was resulting in "out of gas".
I changed the setValue cross-contract call to set a gas value, and I was then able to call setA, and estimating the gas for setA showed just 31663.
recentA.setValue.gas(10000)(6);
I suspect this EVM behavior is related to permissioned chains with a gasprice of zero. However, that is speculation as I haven't investigated the internals.
I've also added eth_estimateGas, and support for multiple contracts in a Solidity file, to kaleido-go here in case it's helpful:
https://github.com/kaleido-io/kaleido-go
Another possibility for others encountering "out of gas" calling across contracts - In Geth if a require call fails in a called contract, the error is reported as "out of gas" (rather than "execution reverted", or a detailed reason for the require failing).
You are hitting the limit of gas allowed to be spent per block. Information about gas limit is included into every block, so you can check what's this value is right now in your blockchain. Currently on Ethereum MainNet, GasLimit (per block) is about 8 millions (see here https://etherscan.io/blocks)
To fix this, you can start your blockchain with modified genesis file. Try to increase value of gasLimit parameter in your genesis file, which specifies the maximum amount of gas processed per block. Try "gasLimit": "8000000".
Try to discard the return statement of setValue method in contract TestA.
pragma solidity ^0.4.24;
contract TestA {
uint public someValue;
function setValue(uint a) public {
someValue = a;
}
}

Retrieving multidimensional balance

I am developing an Ethereum based Card Game. A user can collect n amount of individual/unique Cards. Everything is up and running, I am using the following balance mapping:
mapping (address => mapping (uint256 => uint256)) balances;
The first uint is the Card ID, the second uint is the Card count. I will have up to 1000 Cards, right now I am testing with 700 Cards.
I retrieve the balances on DApp Start by calling:
function balanceOf(address _owner, uint256 _id) view external returns(uint256) {
return balances[_owner][_id];
}
for every single ID. On balance changes I do partial balance updates. This generally works. It is free, but it is also extremely slow as the initial retrieval call has to be done 640 times. I have researched a lot and also tried various implementations, but the main problem is that I need to retrieve an address mapped array holding the Card ID and Count information. Currently you can not easily retrieve dynamic sized Arrays or Structs.
What would be the proposal to resolve the issue? Am I stuck with up to 1000 balanceOf calls on DApp Start until Solidity introduces simple Array calls?
I thought about caching data on my WebServer, but for this to work I would need to run a node on the WebServer which I would like to avoid.
A Client based caching, where the Client posts the balance to the WebServer may also run into an inconsistent state because of the asynchronous nature of the Blockchain.
You can also use struct for managing data more easily. I made one contract using struct and retained data too. Please let me know if this approach didnt work for you.
pragma solidity ^0.4.18;
contract Test{
struct User{
uint cardId;
uint cardCount;
}
address user_address;
mapping (address => User) public Users;
function add_user() public {
user_address = msg.sender ;
var new_user = Users[user_address];
new_user.cardId =2;
new_user.cardCount = 50;
}
function get() public returns(uint,uint)
{
return(Users[user_address].cardId,Users[user_address].cardCount);
}
}
Your best chance is to use a secondary mapping to store the card IDs some user has, query it first, and than, for each ID, check the count for that user and that card ID.
Here is the code, tested on Remix:
pragma solidity 0.4.24;
contract Test {
mapping (address => uint[]) cardsOwned;
mapping (address => mapping (uint => uint)) cardsCounter;
function cardsOwnedBy(address _owner) view public returns (uint[]) {
return (cardsOwned[_owner]);
}
function cardsCounterFor(address _owner, uint _id) view public returns (uint) {
return cardsCounter[_owner][_id];
}
}
I kept on trying various different solutions but couldn't find any good way to handle this. I found a setup which will work for me for now, until Solidity is updated to be more functional when it comes to array handling and especially dynamically sized variables.
Fastest solution for my requirements:
mapping (address => uint256[1000]) public balances;
The mapping now assigns addresses to a fixed size array. I can now retrieve the full list on DApp Start by using:
function balancesOf(address _owner) view external returns (uint256[1000]) {
return balances[_owner];
}
The main advantage is that it is extremely fast, compared to any other solution. The main disadvantage is, that I lost my dynamically sized array and I have to know the maximum Card Count in advance - which I do not. I used a safety buffer now but if I hit the 1000 Cards mark I will have to update the contract. Hopefully there will be better solutions in the future.

Initialize a big fixed length array in Solidity

I'm building a game on ethereum as my first project and I'm facing with the storage and gas limits. I would like to store a storage smart contract on the blockchain to be queried after the deployment. I really need to initialize a fixed length array with constant values I insert manually. My situation is the following:
contract A {
...some states variables/modifiers and events......
uint[] public vector = new uint[](162);
vector = [.......1, 2, 3,......];
function A () {
....some code....
ContractB contract = new ContractB(vector);
}
....functions....
}
This code doesn't deploy. Apparently I exceed gas limits on remix. I tried the following:
I split the vector in 10 different vectors and then pass just one of them to the constructor. With this the deploy works.
I really need to have just one single vector because it represents the edges set of a graph where ContractB is the data structure to build a graph. Vectors elements are ordered like this:
vector = [edge1From, edge1To, edge2From, edge2To,.......]
and I got 81 edges (162 entries in the vector).
I tought I can create a setData function that push the values in the vector one by one calling this function after the deployment but this is not my case because I need to have the vector filled before the call
ContractB contract = new ContractB(vector);
Now I can see I have two doubts:
1) Am I wrong trying to pass a vector as parameter in a function call inside the A constructor ?
2) I can see that I can create a double mapping for the edges. Something like
mapping (bool => mapping(uint => uint))
but then I will need multi-key valued mappings (more edges starting from the same point) and I will have the problem to initialize all the mappings at once like I do with the vector?
Why does the contract need to be initialized at construction time?
This should work
pragma solidity ^0.4.2;
contract Graph {
address owner;
struct GraphEdge {
uint128 from;
uint128 to;
}
GraphEdge[] public graph;
bool public initialized = false;
constructor() public {
owner = msg.sender;
}
function addEdge(uint128 edgeFrom, uint128 edgeTo) public {
require(!initialized);
graph.push(GraphEdge({
from: edgeFrom,
to: edgeTo
}));
}
function finalize() public {
require(msg.sender == owner);
initialized = true;
}
}
contract ContractB {
Graph graph;
constructor(address graphAddress) public {
Graph _graph = Graph(graphAddress);
require(_graph.initialized());
graph = _graph;
}
}
If the range of values for you array are small enough, you can save on gas consumption by using a more appropriate size for your uints. Ethereum stores values into 32-bytes slots and you pay 20,000 gas for every slot used. If you are able to use a smaller sized uint (remember, uint is the same as uint256), you'll be able to save on gas usage.
For example, consider the following contract:
pragma solidity ^0.4.19;
contract Test {
uint256[100] big;
uint128[100] small;
function addBig(uint8 index, uint256 num) public {
big[index] = num;
}
function addSmall(uint8 index, uint128 num1, uint128 num2) public {
small[index] = num1;
small[index + 1] = num2;
}
}
Calling addBig() each time with a previously unused index will have an execution cost of a little over 20,000 gas and results in one value being added to an array. Calling addSmall() each time will cost about 26,000, but you're adding 2 elements to the array. Both only use 1 slot of storage. You can get even better results if you can go smaller than uint128.
Another option (depending on if you need to manipulate the array data) is to store your vector off chain. You can use an oracle to retrieve data or store your data in IPFS.
If neither of those options work for your use case, then you'll have to change your data structure and/or use multiple transactions to initialize your array.

web3 calls Solidity contract function with extra parameter?

In the http://truffleframework.com/tutorials/pet-shop example, there is the following contract, and the function adopt(uint petId) has only one parameter.
contract Adoption {
address[16] public adopters;
function adopt(uint petId) public returns (uint) {
require(petId >= 0 && petId <= 15);
adopters[petId] = msg.sender;
return petId;
}
function getAdopters() public returns (address[16]) {
return adopters;
}
}
However, in the javascript code app.js, the handleAdopt function call the contract function using the following code.
App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
return adoptionInstance.adopt(petId, {from: account});
})
The function is called with the extra object {from: account}. Why? And is this parameter discarded in the solidity code?
BTW, there is an undefined global variable web3? Is the value be assigned by the MetaMask extension?
That is the transactionObject which describes general information about all transaction calls (gas limit, price, amount of ether to send, etc.). The JS code you posted is using the web3 library. That's not the direct call to the contract API. The web3 library converts it to an RPC. The transactionObject comes after all of the contract parameters. There is another parameter that comes after which is the callback with the results of the contract call (see here).
These are all of the options for the transactionobject described from the docs:
from: String - The address for the sending account. Uses the web3.eth.defaultAccount property, if not specified.
to: String - (optional) The destination address of the message, left undefined for a contract-creation transaction.
value: Number|String|BigNumber - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction.
gas: Number|String|BigNumber - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded).
gasPrice: Number|String|BigNumber - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price.
data: String - (optional) Either a byte string containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code.
nonce: Number - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.