Perhaps many of you wondered: how will the behavior of a smart contract change, if its data weighs hundreds of megabytes and stores hundreds of thousands or millions of records? Will transactions go up? How will this affect the network as a whole? Will some types of variables in solidity cope with this task better than others? We decided to personally find out the answers to these questions and conduct an experiment in our private Ethereum network, simulating the situations described. What came out of this, read further in the article.
Test description
We wanted to find out how the load will affect one smart contract of one million transactions and a large amount of data.
Measured such parameters:
')
- the cost of one transaction in kgas;
- the duration of the creation of one unit;
- single block size;
Blockchain parametersWe had a private PoA blockchain with two authorized writing nodes and one “passive” from which transactions were sent.
All three nodes were running on identical servers:
- Processor: 2 Intel Xeon E5-2670 2.60 GHz.
- RAM: 8 GB.
- OS: Windows Server 2012 R2 Datacenter (64-bit).
Smart Contract DescriptionIt was created two smart contract. One had mapping bytes32 as the field, => bytes32, the other had a one-dimensional bytes32 array. Each of the contracts contained a function that takes as a parameter the value of bytes32 and saves this value as an element of the corresponding mapping or array (in fact, the value was stored in the blockchain's storage).
Brief description of the mapping contractcontract TesterMapping { mapping (bytes32 => bytes32) StoragedData; function Storing(bytes32 data) { if(StoragedData[data]!= "Y") StoragedData[data] = "Y"; } }
Brief description of the contract with the array Con tract TesterArray { bytes32[] StoragedArray; function Storing(bytes32 data) { for(uint256 i = 0; i < StoragedArray.length; i++) { if(StoragedArray[i] == data) return; } StoragedArray.push(data); } }
Test progress and results
First, a smart contract with a field-mapping was tested. Once a second, a transaction with a random 32-byte value was sent to it. Due to technical problems, testing took a little longer than planned, and the million transaction was sent three weeks after sending the first one. Then a smart contract with an array was tested.
Mapping — contractThroughout the experiment, neither the transaction value nor the block size fluctuated by any meaningful amount. Each transaction was processed almost instantly, both the first and the millionth. The duration of the block creation periodically varied from 1 to 9 seconds, but always a value of 5 seconds symmetrically set in the genesis block (if one second passed between creating the block n and n + 1, then the block n + 2 appeared after 9 seconds), that is the average block creation time remained equal to 5 seconds. However, some patterns in the occurrence of these fluctuations were not noticed and, perhaps, this was due to the operation of our network or supporting server software (antiviruses, etc.).
Array contractIn this variant, due to the presence of an array looping cycle (for searching for matching values), the cost of one transaction increased from 40 thousand KGas to more than 2 million KGas in the first two thousand transactions. In this case, the duration of processing a single transaction in the first few hundred transactions has already become longer than the creation time of one block. Because of this, the size of one block for approximately 500 transactions fell to its minimum and did not increase any more, since one transaction began to fall at best into one block. The processing time very quickly became so long that after sending only three thousand transactions, “raking” the resulting queue took about four hours, while the network would be paralyzed (of course, if the sender in the “combat” network had enough money to pay for expensive transactions).
findings
- The size of the mapping does not affect the speed of working with it or the cost of the transaction (at least up to 1 million items).
- The Solidity virtual machine is extremely inefficient when working with iterative loops.
- To work with a large number of records is better to use mapping.
Unfortunately, we did not find a way to determine how much data in the storage is occupied by the data of a specific smart contract when using the mapping array. Perhaps someone from the readers will be able to tell your version.