Background
EOSIO incorporates an innovative resource model which doesn’t require paying fees on a per transaction basis to utilize the network. The reason the blockchain is designed this way is for two primary reasons:
- Improved performance: Not requiring a token transfer with each action improves the system level performance and scalability of transactions, especially for multithreaded scaling.
- Less user-facing friction: Users don’t have to worry about paying a cost every time they want to perform basic day-to-day actions on the blockchain.
The resource model unlocks innovative use-cases of the blockchain that is unique to EOSIO. When users have sufficient resources staked they experience incredible speeds and usability when interacting with the blockchain. If you calculate the transaction “cost” vs similar public blockchains, the cost per transaction of EOSIO networks is orders of magnitude less expensive. Wallets for traditional fee based blockchains incorporate transaction fee estimation algorithms, the fee is automatically calculated for the user when the user sends a transaction.
Problems
CPU/NET
The current CPU/NET resource allocation issues users experience can be traced back to two major features.
- The default EOSIO deployment (EOS Public Network) includes a fractional resource allocation model, where accounts can access a much larger portion of network resources than they have claim to, so long as the reserved resources are not being used by other accounts. This resource allocation method created a false utopia in the early days of the network where most users and wallets did not need to worry about CPU/NET allocation. Most users of the network did not understand what percentage of their daily usage was being provided from the public fractional allocation vs their owned allocation. Additionally, wallets and block explorers rarely implement functionality to make this clear to users. This fractional allocation devalued the importance of resource allocation including the staking of EOS tokens for resources by individuals.
- The Resource Exchange (REX) was implemented as a potential solution to improve voter participation and make resource allocation more efficient, especially for large-scale applications and future cosigning functionality. Due to the existence of fractional resource allocation, the REX market was substantially undervalued (why pay for resources that you can get for free?). This reliance on public resources prevented the REX market from finding a true market value, enabling massive allocations of resources to be leased for a relatively small fee. It’s important to note that REX is just a system wide standardization of EOS CPU leasing. The same functionality that REX provides can also be provided by any third party contracts (Chintai etc.), so “REX Free” EOSIO blockchains are not protected from potential resource leasing market arbitrage attacks. REX is actually a very efficient resource allocation method, for example: for a nominal cost of .1 EOS per month REX fee (1.2 EOS per year) an account can make 5+ actions per day without worrying about resource management.
The combination of fractional resource allocation combined with REX created a negative feedback loop where the true value of EOS CPU was never discovered by the market, price discovery simply never happened due to artificially cheap resources. Eventually the EIDOS project found a mechanism to take advantage of the cheap REX resources, forcing the network into CPU congestion mode and removing the fractional resource allocation from all accounts and forcing many users, Dapps, and wallets to think about resource allocation for the first time. Additionally, major EOSIO wallets such as Scatter do not perform any kind of proactive resource cost calculation when the user sends a transaction. This means the wallet will not check if the user has proper resources before sending the transaction. The user receives a confusing error message, and is forced to navigate to a different UI and manually stake EOS or purchase stake from REX in order to perform basic actions. This is a user experience akin to a Bitcoin wallet asking the end user to manually calculate their own transaction fee. Cosigning of transactions by Dapps only solves the issue when users are interacting with Dapps, and creates a new set of problems, including centralization concerns and potential resource attack vectors for Dapp providers.
RAM
RAM has a reputation of being expensive, but most individual accounts only need to consume less than .5 EOS worth of RAM, advanced users might use up to 2 EOS worth of RAM, but it’s rare to see a normal account using more than that. Much of the confusion and friction around RAM usage stems from two problems.
- RAM usage cost is not made clear to the end user before signing a transaction. Users need to trust the smart contract developer to use RAM efficiently and hope that they have enough unused RAM already available on their account.
- Users need to trust smart contract developers to provide actions to reclaim utilized RAM. Many smart contracts essentially trap user RAM without providing any way for the user to reclaim that usage.
Wallets do not automatically include a RAM purchase or notify the end user about RAM requirements. If a user doesn’t already own a sufficient amount of RAM the user receives a confusing error about RAM requirements after signing a transaction. This is a very poor user experience and is akin to asking the user to manually calculate their transaction fee. Asking Dapps to pay for user RAM does not solve this problem because Dapp developers are then exposed to resource attacks, additionally, Dapp developers are not able to free up unused accounts without centralized control over contracts. The cost for an individual account to participate in a Dapp is very small, but if a Dapp developer is expected to pay for all user RAM costs, this becomes a large monetary responsibility and centralization risk for the Dapp developer. Asking the Dapp developer to pay for all user resources requires them to implement methods to delete user information in order to recover RAM spent due to inactive accounts or spam. Asking end users to pay very small initial RAM cost to participate in a Dapp (and providing an easy and standardized way to revoke their RAM usage in the future) is a much more trustless and scalable solution.
Solution
We are proposing a universal standard for proactive resource calculation. Essentially an API which could be implemented by Dapps and also by wallets. The Dapp or wallet would propose an initial transaction which would be sent as input into the API. The API would return suggestions about how the final transaction should be constructed as well as additional user facing information that the end user should be informed about. End users could specify their preferences, and the end user could always opt to manually control resource allocation instead of following the suggestion of the API. The API is made up of two major components and one optional service.
On-chain resource provider registry
The RPR would be a smart contract where potential resource providers could register their intention to provide resources towards end user accounts. A provider registering on the RPR would provide various metadata such as :
- Name
- URL
- Public website of the provider, might provide more information about the resources provided.
- Actions whitelist/blacklist
- Accounts whitelist/blacklist
- Minimum requirement logic
- Some providers might have basic logic such as “5000 ms per account per day”
- Other providers might have more complex logic “needs to participate in our dapp, needs to vote for our BP, needs to join our mailing list”
- Basic logic could be implemented directly in the RPR as a smart contract logic. More complex logic would be implemented off-chain, or rely on a trusted oracle provider.
Cosigning endpoint
- The cosign endpoint would receive a potential transaction and return either:
- A cosign transaction for the user to sign
- A rejection error message that explains why the transaction was not signed
- The rejection error message would conform to a standard format. Because the logic to decide if a transaction should be signed is already published, the API can check if a transaction should be signed before the transaction is submitted. This means submitted transactions should rarely be rejected so long as the API and requirement logic is kept up to date and followed by dapps/wallets that submit transactions.
Javascript Library
The JS library would be integrated inside Dapps and/or wallet providers. It is responsible for communicating with the RPR, RES, and resource provider URLs in order to create transaction suggestions.
JS Library function overview
- Dapp/Wallet submits initial transaction
- JS Library checks RES to estimate transaction cost
- JS LIbrary checks RPR to find a potential resource provider
- JS Library constructs a transaction with proper resource/cosigning requirements included
- User reviews and signs the transaction, they can also opt to use a different resource provider other than the default or customize resource allocations.
- Final transaction is submitted, if an error is thrown, the JS Library informs the user and proposes an alternative transaction.
Resource Estimation Service
The RES is an off-chain api service that the javascript library would communicate with. The implementation is simple and many different endpoints could be run by different providers. The JS library could be configured to talk to a specific endpoint, aggregate results from multiple, or operate without any RES specified.
The RES takes transaction metadata as an input and tries to predict the resource cost of the transaction. For most transactions, the potential resource cost can be ascertained by finding an average of the cost paid to perform the action recently. Querying this information can be done using dfuse or light history node implementations. The RES node would cache common requests for up to 24 hrs, only relying on a history node to update the internal cache or collect data for a transaction type that is not already in the cache.
Example
Proposed Transaction: Transfer 1 EOS from account1 to account2
RES Result: {CPU:.02ms,RAM:0,NET:0}
The results from the RES can be read by the JS Library to ascertain if an additional transaction should be included. For example, the JS Library may include a RAM purchase, CPU Stake or REX rental in order to ensure the transaction does not throw an error.
Implementation Mockup
In this example the wallet is presenting to the user a transfer action and the JS Library has predicted that the transaction will cost .2 ms. The JS Library queried the RPR for a potential resource sponsor and automatically selected EOS Nation as the sponsor. The user has the option to manually select a different sponsor, or opt to pay a small REX rental fee to cover the transaction. When the user hits submit, the consigned transaction will be signed. The EOS Nation sponsor has specified that they will offer bonus CPU for users who vote for them and also join their mailing list. By offering free resources, resource sponsors are able to grow their network and market to new users.