An address consumes 20,000 gas via SSTORE.
Given is a gas price of 35 Gwei.
If I store 10,000 addresses in a map, it will cost me:
20,000 gas * 10,000 = 200,000,000 gas
200,000,000 Gas * 35 Gwei = 7 Ether.
Is the calculation correct?
If I do the same on a layer2 chain, does the whole thing cost me 7 matic for example, or is there something else I need to consider?
Your calculation is correct.
I'm assuming you want to store the values in an array instead of 10k separate storage variables. If it's a dynamic-length array, you should also consider the cost of sstore while updating a (non-zero to non-zero) value of the slot holding the array length (currently 2900 gas for each .push() function resizing the array).
You should also consider the block gas limit - a transaction costing 200M gas is not going to fit into a block on probably any network, so any miner won't mine it.
So based on your use case, you might want to change the approach. For example, if the addresses are used for validation, you might be able to store just the merkle tree root (1 value instead of the 10k) and then validate against it using the address and its merkle proof.
Related
I am writing a smart contract that requires a number of random words to be generated via the Chainlink VRF.
Now, according to Chailink VRFV2Consumer contract, you can request the number of random words like so:
uint32 numWords = 2;
My question is, will it cost more if you increase the number of random words requested or will the fees remain same? I haven't seen any explanation of this yet so I think it would be helpful for developers if they knew how this would impact the fees.
As they mentioned in their documents yes it depends on the number random values you asked.
Read the document linked below carefully.
https://docs.chain.link/docs/chainlink-vrf/
Gas price:
Callback gas:
Verification gas:
These variables depend on current network conditions, your specified limit on callback gas, and the number of random values in your request. The cost of each request is final only after the transaction is complete, but you define the limits you are willing to spend for the request with the following variables:
I'm taking a look at the uniswapv2 tutorial walkthrough.
The followng is in reference to this function in the github repo and the tutorial states the following:
uint _kLast = kLast; // gas savings
The kLast state variable is located in storage, so it will have a
value between different calls to the contract. Access to storage is a
lot more expensive than access to the volatile memory that is released
when the function call to the contract ends, so we use an internal
variable to save on gas.
So in traditional programming, _kLast would be a reference to kLast. _kLast is referenced 3 more times after it's instantiation.
Had they used just kLast as the variable, and not assigned it to uint, would it cost a storage read each time kLast is used?
If this is NOT the case, then I really don't understand how they're saving on gas, can someone explain?
Each storage read (opcode sload) of the same slot costs 2,100 gas the first time during a transaction, and then 100 gas each other time during the same transaction. (After the EIP-2929 implemented in the Berlin hardfork. Before that, it was 800 for each read no matter how many times you performed the reads.)
Each memory write (opcode mstore) and each memory read (opcode mload) cost 3 gas.
So in traditional programming, _kLast would be a reference to kLast
In this particular Solidity snippet, _kLast is not a reference pointing to the storage. It's a memory variable that has value assigned from the storage variable.
So 3 storage reads - not creating the memory variable - would cost 2,300 gas (= 2,100 + 100 + 100).
But because the code creates the memory variable, it performs one storage read (2,100 gas), one memory write (3 gas), and three memory reads (3 x 3 gas) - totalling 2,112 gas. Which is a cheaper option.
Some other EVM-compatible networks, such as BSC, might still use the original gas calculation of 800 per each sload. Which would make even larger difference - non-optimized 2,400 gas (3 x 800), and optimized 812 gas (800 + 3 + 3x3).
I'm trying to figure out a solution to this problem, to do with transaction confirmation order and setting values to 0
pragma solidity ^0.5.17;
contract Test {
uint256 amount;
constructor() public {}
function join() public {
amount += 100;
}
function leave() public {
amount -= 100;
}
}
Given these transactions (tested on ropsten):
tx 1) Call Join Confirmed
amount == 100
tx 2) Call Join (gas price 1) Pending
amount == 100 should tx3 get mined first
tx 3) Call Leave (gas price 100) Pending
amount == 0
However tx 2 will always fail with an out of gas error for as long as the amount is set back to 0. This doesn't happen if the value is any higher than 0. My understanding is that it costs more gas to set a value to its 0 state instead of a positive integer, and the gas estimation isn't taking this into account. I've tried delete hoping this would give a gas refund to compensate for the too-low gas limit, but it still failed.
Is there an elegant way to handle this scenario? The only ways I can think of are over-estimating the gas for all join transactions, which has its obvious drawbacks, or never setting amount back to 0.
You are making correct observations.
by setting it to 0 you delete storage, and get gas refund. This is why it takes less amount of gas. But gas refunds have top limit, so you can't use it to store ETH.
It costs 20,000 gas to store one value in a slot (source:https://github.com/ethereum/go-ethereum/blob/d13c59fef0926af0ef0cff0a2e793f95d46442f0/params/protocol_params.go#L41 )
it costs 2,200 gas to load one value from a storage slot (source: https://github.com/ethereum/go-ethereum/blob/d13c59fef0926af0ef0cff0a2e793f95d46442f0/params/protocol_params.go#L89)
That's why you are seeing different gas consumption values.
Just set your gasLimit to some empirically found roughly-estimated value.
Do a trace of your transaction and you will see all gas consumption values.
Now, the way gas refunds work is that during the state transition function, you're asked for the full gas for the run of your contract. During this run, all gas refunds are accumulated in StateDB (temporary state object). At the end of the state transition function, you will get refunds for all storage releases your contract is going to make. This is why you have to set higher gas limit that Etherscan shows, because lets say your contract needs 15,000 gas to run, after storage is released (say for 5,000 gas) , Etherscan will show like the transaction needed 10,000 gas. This is not true because you have got gas refunds at the end, but at the beginning you needed the whole amount of gas (15,000). Gas refunds are sponsored by the miner, his account is going to get less ETH because he is paying you these refunds.
I have seen some transactions in etherscan.io.But I have found that even invoking the same function in the same smart contract, the gas used by txn are different.I try to found that maybe the input data result in it.Really?
The input data might be different, but also the state stored in the smart contract might be different (and change e.g. the number of times a loop iterates). Also, if storing nonzero data in a state variable that previously held zero data, or vice versa, will change the gas usage. For example, a simple function that toggles a boolean variable will not use the same amount of gas on any two consecutive calls.
Check out https://ethereum.stackexchange.com/ for future questions like this!
Each time you invoke a function in contract that requires state change in the block,it would cost x amount of gas , so every time you call different or same function in a contract that requires a state change,you would see that x amount of gas is being deducted along with its taxation Id.This is the reason you see different Txn on same function.
More about Gas and Transaction in the link below. http://solidity.readthedocs.io/en/develop/introduction-to-smart-contracts.html
Does the value returned by MySQL's MD5 hash function continue to change indefinitely as the string given to it grows indefinitely?
E.g., will these continue to return different values:
MD5("A"+"B"+"C")
MD5("A"+"B"+"C"+"D")
MD5("A"+"B"+"C"+"D"+"E")
MD5("A"+"B"+"C"+"D"+"E"+"D")
... and so on until a very long list of values ....
At some point, when we are giving the function very long input strings, will the results stop changing, as if the input were being truncated?
I'm asking because I want to use the MD5 function to compare two records with a large set of fields by storing the MD5 hash of these fields.
======== MADE-UP EXAMPLE (YOU DON'T NEED THIS TO ANSWER THE QUESTION BUT IT MIGHT INTEREST YOU: ========
I have a database application that periodically grabs data from an external source and uses it to update a MySQL table.
Let's imagine that in month #1, I do my first download:
downloaded data, where the first field is an ID, a key:
1,"A","B","C"
2,"A","D","E"
3,"B","D","E"
I store this
1,"A","B","C"
2,"A","D","E"
3,"B","D","E"
Month #2, I get
1,"A","B","C"
2,"A","D","X"
3,"B","D","E"
4,"B","F","E"
Notice that the record with ID 2 has changed. Record with ID 4 is new. So I store two new records:
1,"A","B","C"
2,"A","D","E"
3,"B","D","E"
2,"A","D","X"
4,"B","F","E"
This way I have a history of *changes* to the data.
I don't want have to compare each field of the incoming data with each field of each of the stored records.
E.g., if I'm comparing incoming record x with exiting record a, I don't want to have to say:
Add record x to the stored data if there is no record a such that x.ID == a.ID AND x.F1 == a.F1 AND x.F2 == a.F2 AND x.F3 == a.F3 [4 comparisons]
What I want to do is to compute an MD5 hash and store it:
1,"A","B","C",MD5("A"+"B"+"C")
Let's suppose that it is month #3, and I get a record:
1,"A","G","C"
What I want to do is compute the MD5 hash of the new fields: MD5("A"+"G"+"C") and compare the resulting hash with the hashes in the stored data.
If it doesn't match, then I add it as a new record.
I.e., Add record x to the stored data if there is no record a such that x.ID == a.ID AND MD5(x.F1 + x.F2 + x.F3) == a.stored_MD5_value [2 comparisons]
My question is "Can I compare the MD5 hash of, say, 50 fields without increasing the likelihood of clashes?"
Yes, practically, it should keep changing. Due to the pigeonhole principle, if you continue doing that enough, you should eventually get a collision, but it's impractical that you'll reach that point.
The security of the MD5 hash function is severely compromised. A collision attack exists that can find collisions within seconds on a computer with a 2.6Ghz Pentium4 processor (complexity of 224).
Further, there is also a chosen-prefix collision attack that can produce a collision for two chosen arbitrarily different inputs within hours, using off-the-shelf computing hardware (complexity 239).
The ability to find collisions has been greatly aided by the use of off-the-shelf GPUs. On an NVIDIA GeForce 8400GS graphics processor, 16-18 million hashes per second can be computed. An NVIDIA GeForce 8800 Ultra can calculate more than 200 million hashes per second.
These hash and collision attacks have been demonstrated in the public in various situations, including colliding document files and digital certificates.
See http://www.win.tue.nl/hashclash/On%20Collisions%20for%20MD5%20-%20M.M.J.%20Stevens.pdf
A number of projects have published MD5 rainbow tables online, that can be used to reverse many MD5 hashes into strings that collide with the original input, usually for the purposes of password cracking.