--- tags: rent --- # RSKJ Node Performance with Storage Rent Updated: December 8, 2020 **Context for this update:** A recent update to [RSKJ](https://github.com/rsksmart/rskj/pull/1258) includes the option of *native crypto implementation* leading to significant performance improvements in *signature recovery* and (therefore) in *Block Validation* times. This provides an opportunity to reevaluate the performance of our experimental storage rent implementation. **Objective** The *experimental* implementation of *Storage Rent in RSKJ* has not been optimized in any way. While we expect it to run somewhat slower than an unmodified RSKJ node, it is important to quantify the performance impact. This can help improve the implementation and also guide future design decisions. **Summary:** We expect 3 main areas of impact: 1. an increase in Trie Get Value operations 2. an increase in VM execution time for rent tracking and payments 3. an increase in RAM usage This chart shows the quantitative impact for 3 classes of transactions - ERC20 contract **deployment** transactions - transactions for initial **token allocation** to some randomly selected users - and **transfer** transactions (1/2 coin and 1/2 token transfers) ![FigComp](https://i.imgur.com/3LfU8Dl.png) Naturally, the impact of the additional VM computations or Trie getValue operations depends on the type of transactions. Those that already involve more computations are less affected by the introduction of storage rent. The increases in VM execution and Trie GetValue times lead to predictable increases in **Block Execution** and **Connection** times. The quantitative impact (*% increase* ) is summarized in the following table. |Metric | Deployment| Token Allocation|Transfers| |--------|--------|--------|--------| |Block Exec Time | 14.1% |21.8% | 25.6%| |Block Connect Time | 12.6% |15.5% | 15.1%| |VM Exec Time | 35.4% |28.5% | 79.4%| |Trie GetValue Time | 33.6% |30.4% | 17.7%| |Block Connect RAM | 5.4% | 6.3% | 11.2%| **Note:** *values in table represent percentage increase in storage rent implementation compared to baseline RSKJ* Once we have accounted for VM execution and Trie gets, all *remaining variation* in *Block Execution* or *Block Connection* times are have no further statistical links with storage rent. We confirmed this with Multiple Linear Regression analysis (simple *t-tests* also indicate the same). ### Details Comparison framework: - As before we use an in-house benchmarking tool developed by Raul Laprida from the resarch team at IOV Labs. - We generate data from **6 simulated blockchain runs**: one set each for Baseline and Storage Rent. - Each simulation generates 100 blocks with 180 transactions in each block. - **Half** of the transactions involve *pure coin* transfers while the remaining are transfers of *ERC20 tokens*. - The`gasLimits` are **set higher** (exactly double) in the storage rent case. This is needed to keep the number and mix of transactions identical across the two settings. - In order to generate transfer transactions, the simulation tool first **deploys** 5 ERC20 token contracts and then **randomly pre-allocates** initial token balances to some accounts (from a set of 1000 accounts). - We also track the performance impact of blocks containing these setup (deployment, token-allocation) transactions. Deployment only needs a couple of blocks. The initial allocations take about 120 blocks. ### Execution Time We expect to see *higher VM execution time* due to additional computation for tracking and collecting rent. ![Fig1](https://i.imgur.com/Lb7f3Im.png) As expected VM execution takes longer. As a consequence, we see this effect spill over to block execution and connection times. But as we saw earlier, the impact is markedly lower for other types of transactions (e.g. contract deployment) or preallocations. Generally the impact of introducing rent may be smaller for transactions that require more computations anyway. ### Trie Task Times Storage rent does not require querying nodes that would not normally (without rent) be touched by a transaction. Thus, we do not expect any difference in the number of trie nodes generated using calls to `fromMessage`. We *do expect* to see more trie `getValue` operations with storage rent. These additional operations are to obtain the *last rent paid timestamp*s for value containing nodes. Naturally, these additional operations will consume more time. ![Fig2](https://i.imgur.com/WKPHQwU.png) :point_right: **Takeaway:** While there are a lot more trie `getValue` operations with rent, the *time taken* by those operations does not increase linearly. :point_right: **Takeaway:** Another key takeaway is that introducing storage rent does not increase the number of trie nodes loaded into memory, this can be observed from the plots of `TriefromMsg`events. ### Database and Memory We do not expect significant difference in database IO, but we do expect somewhat higher RAM use with storage rent for the additional tracking of rent timestamps and outstanding amounts. ![Fig3](https://i.imgur.com/TIOhEYA.png) ### Miscellaneous Some aggregated results to compare across transaction classes (for those who are curious). #### ERC20 contract deployment ![FigDeploy](https://i.imgur.com/oKAz86a.png) ### ERC20 initial balance allocations ![](https://i.imgur.com/2Cc0T0Y.png) ### Transfer transactions Some of these plots have already appeared above in groups ![](https://i.imgur.com/bBqLL96.png) *** *** #### Previous version ==All of the following material is from an earlier set of experiments and will be removed in the future.== **Summary:** We use simulations to explore the performance implications of implementing storage rent in RSK. - There is some performance degradation, mainly **VM execution, Trie GetValue** and **block execution** are slower. - However, these contribute to a small portion of system time, which is dominated by **key recovery from signature** and **block validation**. - While further evaluation is needed, the results indicate that the "performance cost" of implementing rent is likely to remain small. - This is encouraging as we continue to explore the benefits of implementing storage rent e.g. improved resource use, better state caching, reducing gas arbitrage, improve security from IO attacks. ## Setup One concern with implementing storage rent is that node performance may be adversely impacted by modifcations to the Unitrie, additional computations and caches. We use the following setup for evaluation. ($2\times2 = 4$) experimental settings: - 2 nodes: **baseline version (RSKJ 2.0.1 snapshot)** and **storage rent** implementation (implemented on top of the snapshot) - 2 user activity settings: **Pareto** and **uniform** - 6 simulations for each setting **Measurement and data generation** is based on Raul's benchmarking tool, which is doing all the hard work. In the Pareto case, 20% of users are repsonsible for 80% of the transactions. The Pareto (80/20) distribution is the default in Raul's tool. I "approximate" the uniform case by altering the 80:20 distribution (of user groups and transactions within those groups) to an even 50:50. **Gas limits** *are set higher in the storage rent* case (slightly more than double than the baseline case). This is because, in the rent implementation, the transaction gaslimit is split equally between execution and rent gas budgets. The results are from runs with 1000 user accounts and 100 blocks containing **177 transfer** (of native coins or 5 tokens) transactions in each block. System time used for various tasks is reported on a *per-transaction basis* in milliseconds. The initial blocks for contract creation and token (pre) distribution have been excluded. The examples represent simulated data from 6 runs from each of the 4 experimental setttings. ### Trie fromMessage and getValue The rent implementation adds a new field to the trie which changes the encoding, and modifies the trie get method. The impact can be seen in the time taken to load tries from encodeded representation and in trie get operations. The top row is for the Pareto case, bottom row for the Uniform case. Baseline RSKJ version is on the left column, while the rent implementation is on the right column. ![Trie decoding and get value](https://i.imgur.com/CehXuvl.png) ### Block Execution and Validation ![block execution and validation times](https://i.imgur.com/s2FIYyS.png) ## Average task times (per transaction in block) When examining these figures, please keep in mind that each of the $4\times6=24$ simulations is a fresh run with new `genesis`, new `valueGenerator` with 1000 accounts and 100 transaction blocks with a new set of 177 transfer (token + coin) transactions in each block. ![mean task times](https://i.imgur.com/2jexUOf.png) As expected, the rent version runs a bit slower, but the difference is small in practical terms. ## From the reporting tool: Overall time use **Note:** These pie charts are from a **single** simulated run from each setting. ### Baseline This image shows the distribution of execution time for **baseline Pareto** (i.e without storage rent). ![baseline pareto](https://i.imgur.com/0FbbTgM.png) And the following image shows the baseline case when transactions are uniformly distributed. ![baseline uniform](https://i.imgur.com/GPl2YQ1.png) ### Storage rent Pareto case ![rent pareto](https://i.imgur.com/kIaIkOY.png) and finally the uniform case with storage rent ![rent uniform](https://i.imgur.com/Idg5QLY.png) ## Code - The source for the experimental node with storage rent on [github](https://github.com/optimalbrew/rskj/tree/mish) - The benchmarking tool is proprietary and is currently not in public domain.