
Million Question
Perhaps many of you have 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 do a better job than others? We decided to personally find out the answers to these questions and conduct an experiment in our private Ethereum network, simulating the described situations. What came of this, read on in the article.

We wanted to find out how loading on one smart contract of a million transactions and a large amount of data will affect.
The following parameters were measured:
Blockchain Parameters
We had at our disposal 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:
Description of smart contracts
Two smart contracts have been created. One had mapping bytes32 => bytes32 as a field, the other had a one-dimensional bytes32 array. Each of the contracts contained a function that takes bytes32 as a parameter and stores this value as an element of the corresponding mapping or array (in fact, the value was stored in the blockchain storage).
A brief description of the contract with mapping
A brief description of the array contract
First we tested a smart contract with a field-mapping. Once per second a transaction was sent to it with a random 32-byte value. Due to technical problems, testing took a little longer than planned, and the millionth transaction was sent three weeks after the first one was sent. Then a smart contract with an array was tested.
Mapping — contract
Throughout the experiment, neither the transaction cost nor the block size fluctuated by any significant values. Each transaction was processed almost instantly, both the first and the millionth. The duration of creating a block periodically changed from 1 to 9 seconds, but always symmetrically set to 5 seconds in the genesis block (if one second elapsed between the creation of block n and n + 1, then block n + 2 appeared after 9 seconds), i.e. the average block creation time was 5 seconds. However, no regularity in the occurrence of these fluctuations was noticed and, possibly, this was due to the operation of our network or server support software (antiviruses, etc.).
Array contract
In this option, due to the presence of an array search cycle (to search 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. At the same time, the duration of processing a single transaction in the first few hundred transactions has become longer than the duration of creating one block. Because of this, the size of one block in about 500 transactions fell to the minimum and did not increase anymore, since one transaction began to account for, at best, one transaction. The processing time very quickly became so large that after sending only three thousand transactions, “raking” the resulting queue took about four hours, while the network would be paralyzed (of course,
Unfortunately, we did not find a way to determine how much data in the storage is occupied by the data of a particular smart contract when using a mapping array. Perhaps one of the readers will be able to suggest their own version.

Test description
We wanted to find out how loading on one smart contract of a million transactions and a large amount of data will affect.
The following parameters were measured:
- cost of one transaction in kgas;
- the duration of the creation of one block;
- the size of one block;
Blockchain Parameters
We had at our disposal 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).
Description of smart contracts
Two smart contracts have been created. One had mapping bytes32 => bytes32 as a field, the other had a one-dimensional bytes32 array. Each of the contracts contained a function that takes bytes32 as a parameter and stores this value as an element of the corresponding mapping or array (in fact, the value was stored in the blockchain storage).
A brief description of the contract with mapping
contract TesterMapping {
mapping (bytes32 => bytes32) StoragedData;
function Storing(bytes32 data) {
if(StoragedData[data]!= "Y")
StoragedData[data] = "Y";
}
}
A brief description of the array contract
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);
}
}
Progress and test results
First we tested a smart contract with a field-mapping. Once per second a transaction was sent to it with a random 32-byte value. Due to technical problems, testing took a little longer than planned, and the millionth transaction was sent three weeks after the first one was sent. Then a smart contract with an array was tested.
Mapping — contract
Throughout the experiment, neither the transaction cost nor the block size fluctuated by any significant values. Each transaction was processed almost instantly, both the first and the millionth. The duration of creating a block periodically changed from 1 to 9 seconds, but always symmetrically set to 5 seconds in the genesis block (if one second elapsed between the creation of block n and n + 1, then block n + 2 appeared after 9 seconds), i.e. the average block creation time was 5 seconds. However, no regularity in the occurrence of these fluctuations was noticed and, possibly, this was due to the operation of our network or server support software (antiviruses, etc.).
Array contract
In this option, due to the presence of an array search cycle (to search 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. At the same time, the duration of processing a single transaction in the first few hundred transactions has become longer than the duration of creating one block. Because of this, the size of one block in about 500 transactions fell to the minimum and did not increase anymore, since one transaction began to account for, at best, one transaction. The processing time very quickly became so large that after sending only three thousand transactions, “raking” the resulting queue took about four hours, while the network would be paralyzed (of course,
conclusions
- The size of the mapping does not affect the speed of working with it or the transaction cost (at least up to 1 million elements).
- The Solidity virtual machine is extremely inefficient when working with iterative loops.
- To work with a large number of records, it 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 particular smart contract when using a mapping array. Perhaps one of the readers will be able to suggest their own version.