-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
qip-0011: Paying for Account State Usage
- Loading branch information
Showing
2 changed files
with
148 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
``` | ||
QIP: 11 | ||
Layer: Consensus (hard fork) | ||
Title: Paying for Account State Usage | ||
Author: wizeguyy <[email protected]> | ||
Comments-Summary: No comments yet. | ||
Comments-URI: https://github.com/quainetwork/qips/wiki/Comments:QIP-0011 | ||
Status: Draft | ||
Type: Standards Track | ||
Created: 2024-04-01 | ||
License: BSD-2-Clause | ||
``` | ||
|
||
## Abstract | ||
This QIP proposes a mechanism for paying for the state used by an account in | ||
the state tree. State pricing is dominated by the disk IOPS necessary to | ||
load/store trie nodes to perform state root updates. Therefore, we price | ||
account slots logarithmically according to the size of the account trie, and | ||
let the market drive the price through its ability to buy/sell account space. | ||
|
||
## Motivation | ||
As the popularity of a blockchain grows, the data necessary to maintain the | ||
state of each account grows. This state trie growth degrades performance, as | ||
the cost of recomputing state root updates becomes the dominant processing cost | ||
associated with processing a transaction. | ||
|
||
Given the material costs associated with account slots, the protocol needs to | ||
impose that cost on users to prevent unsustainable state usage. Because these | ||
costs are born by the entire network, and not simply the transactor, it is not | ||
sufficient to impose this cost in the form of transaction fees. A long-term | ||
cost must exist, proportional to each account's impact on the state tree and | ||
the duration of that impact (i.e. not just at the time the transaction is | ||
processed). | ||
|
||
## Rationale | ||
The complexity to update the state root is proportional to the number of | ||
accounts in the state tree. Since we use Patricia Merkle trie (PMT) with its | ||
extension node optimization, the tree complexity is rarely worst-case, but for | ||
the reader's intuition, the worst case update cost is bounded by its radix-16 | ||
tree update cost: $O(log_{16}(N))$ for $N$ accounts. In the case of a PMT, the | ||
physical limitation is often the number of disk IOPS necessary to update each | ||
database record for each trie node. | ||
|
||
### Letting Markets Decide the Price | ||
Since node operators may be running any number of hardware configurations, with | ||
different CPU, memory, storage, or network constraints, it is impossible to | ||
pick a concrete price for any of these resources that makes any sense. In fact, | ||
even if we could, the concrete number selected today may be very different as | ||
node operators upgrade hardware or experience failures over time. The solution | ||
to this, is to expose these limited resources to the market so that market | ||
participants can decide the price of these resources based on each's own | ||
subjective preference. | ||
|
||
To accomplish this, we build the protocol to enforce account prices | ||
according to the current size of the account trie. Then we make it possible to | ||
buy and sell account slots back at whatever the current price | ||
is. | ||
Every account must | ||
pay for its index in the PMT, but it may sell its account space back if it | ||
no longer requires it. This accomplishes two things: | ||
|
||
1) The market determines efficient price for account slots | ||
|
||
2) Users are incentivized to clean up the state trie by destroying their | ||
accounts when they no longer need them. | ||
|
||
An important thing to consider, is that Quai's design has the ability to scale | ||
and add more capacity if these limits end up being too small. If, for example, | ||
speculators buy up too many account slots to resell them to future buyers, they | ||
run the risk of increasing block processing latency, which through | ||
[QIP-0008](qip-0008.md) will ultimately lead to the addition of more chains | ||
with more resources. If this happens, speculators will have to compete with | ||
these newly available resources, which would harm their speculative investment. | ||
So there is some negative feedback here, which incentivizes speculators to | ||
participate and help determine market pricing, without fully consuming | ||
resources that would trigger a trie expansion. In fact, when the network gets | ||
close to that point, there is a strong incentive for account holders to sell | ||
back any account space they no longer need, which helps balance resource usage | ||
as the network scales. | ||
|
||
## Specification | ||
### Account Pricing | ||
Every new account added to the tree must pay for its address space. The cost of | ||
this address space must increase as the number of addresses increases. This | ||
will create negative feedback: speculators will occupy address space with new | ||
accounts when its cheap, and destroy their accounts when if it becomes | ||
expensive. This balance of speculator preference with user demand, is how the | ||
market determines the appropriate address space price. | ||
|
||
To achieve this, we use the radix-16 computational bound described above, to | ||
set the account slot price. The price function is: | ||
|
||
$$ P_a = K_a* \lfloor log_{16}(N) \rfloor $$ | ||
|
||
where $P_a$ is the price to create or sell an account slot in Quai per account, | ||
$N$ is the total number of accounts in the trie, and $K_a$ is a constant | ||
scaling factor chosen to adjust price responsiveness to trie size. | ||
|
||
#### Choosing $K_a$ | ||
We choose $K_a$ to set a Schelling point about a reasonable acceptable trie | ||
size, while understanding that the actual size will again depend on the | ||
subjective demand for account space. We choose 1 billion (2^30) accounts per | ||
chain as a reasonable upper bound, and we choose 0.1 Quai per account to be a | ||
high cost which will lead to reduced demand in the account space market. | ||
|
||
We choose: | ||
|
||
$$ K_a = 0.1*\frac{Quai}{account^2} $$ | ||
|
||
$$ \approx 9.31*10^{-11} \frac{Quai}{account^2} $$ | ||
|
||
### Protocols for Buying and Selling Account Slots | ||
For a new account to be created, enough Quai must be sent to cover the account | ||
creation price $P_a$. The new account will be credited with the balance of the | ||
transaction minus the creation price, $P_a$. Any transaction to a new account, | ||
which does not satisfy the creation price, will fail. | ||
|
||
Conversely, to sell account space back, we provide a precompiled contract with | ||
a destruction method. The destruction method will allow the user to provide a | ||
"beneficiary transaction", which may transfer the balance including the sale | ||
price of the account (along with optional TX data) to any other address in the | ||
trie. Upon successful execution of the transaction, the account will be deleted | ||
from the state trie. | ||
|
||
Contract address and ABI TBD. | ||
|
||
### Dynamic Load/Store Gas | ||
The demand curve defined above only works if the load/store costs for accounts | ||
and account data are appropriately priced. Specifically, there cannot be a | ||
fixed price to load an account, load code/data stored within an account, or to | ||
store it back. Since all of these operations depend on merkelization of the | ||
data, the gas used in each operation is dependent on the size of the trie. | ||
Accordingly, these operations cannot have a fixed gas cost as implemented in | ||
the vanilla EVM. | ||
|
||
#### Account Access Gas | ||
The gas required for processing a transaction will be updated to dynamically | ||
compute the account load/store cost according to merkle trie depth. Every trie | ||
node which is loaded will cost $\lfloor log_{16}(N) \rfloor$ times the vanilla | ||
EVM gas cost. | ||
|
||
#### Account Data Access Gas | ||
The gas required for accessing code and storage data will similarly be multiplied | ||
by $\lfloor log_{16}(N) \rfloor$ times the vanilla EVM gas cost for each such opcode. | ||
|
||
## Copyright | ||
This QIP licensed under the BSD 2-clause license. |