Attributes
- Author(s): @toshi @conkleris @bulutcambazi in C0D3R
- Implementer(s): The proposal authors
- Category: Protocol Upgrade
GitHub:
[v0.11 feature] Per-chain Relays To Token Multiplier by msmania · Pull Request #1580 · pokt-network/pocket-core · GitHub
[v0.11 feature] Built-in Reward Share by msmania · Pull Request #1581 · pokt-network/pocket-core · GitHub
Summary
We propose two consensus breaking features to improve v0 experience.
- Per-chain Relays To Token Multiplier
- Built-in Reward Share feature
Feature 1: Per-chain Relays To Token Multiplier
Abstract
The calculation of relay rewards is determined by the following formula [1]
Number of relays * Relays To Tokens Multiplier * Reward Multiplier
where Reward Multiplier is determined by the node’s stake amount, and Relays To Tokens Multiplier (= RTTM) is the value of the network parameter pos/RelaysToTokensMultiplier
[2].
We propose a new parameter pos/RelaysToTokensMultiplierMap
so that we can set RTTM per chain.
Motivation / Rationale
The operational costs of running a node can differ significantly across various blockchain networks. For instance, maintaining an archival node is considerably more expensive than operating a pruned node, and enabling debug/trace calls on a node incurs additional computational costs. That’s why Pocket Network provides separated chain IDs for an archival network and a non-archival network for some blockchains. For example, there are three chain IDs for Ethereum Mainnet, Ethereum Mainnet (0021), Ethereum Mainnet Archival (0022), and Ethereum Mainnet Archival with trace calls (0028). It’s intuitive to expect that relay rewards for 0028 should be higher than relay rewards for 0022, and rewards for 0022 should be higher than rewards for 0021. With the introduction of our new parameter, pos/RelaysToTokensMultiplierMap
, we can now implement this flexible reward structure by adjusting the network parameter.
Perhaps more importantly, Pocket is an RPC infrastructure, and RPC is not limited to blockchain calls. We envision that Pocket can be used to make calls into more complex API endpoints. A good example is newly emerging generative AI interfaces such as LLMs. These endpoints cost 100 to 1000 times more per call. Proper rewarding is needed if we will make these new non-blockchain RPC chains feasible.
Finally, this also helps keeping “quiet” chains feasible. Currently, node operators are incentivized to host “busy” and established chains because performing more relays is the way to get more rewards. With pos/RelaysToTokensMultiplierMap
, we can incentivize node operators to host brand new chains / quiet chains with little traffic by setting higher RTTMs for such chains.
Specification
The new parameter is added in the pos module side by side with the existing pos/RelaysToTokensMultiplier
. Its parameter defines a mapping from a chain ID to a custom multiplier as follows.
http://localhost:8082/v1/query/nodeparams
{
"relays_to_tokens_multiplier": "181",
"relays_to_tokens_multiplier_map": { // <--- New
"0028": "12345"
},
...
}
When a node mints relay rewards, it looks up the pos/RelaysToTokensMultiplierMap
, and the relayed chain is defined there, it adopts a custom multiplier for that chain to calculate the amount of relay rewards, otherwise it adopts the default multiplier of pos/RelaysToTokensMultiplier
.
[1] Node Economics - Pocket Network
[2] Protocol Parameters - Pocket Network
Feature 2: Built-in Reward Share feature
Abstract
We suggest introducing a built-in reward sharing feature that enables a staked node to distribute block/relay rewards across multiple wallets with the percentages defined per wallet. Node operators can leverage this functionality to offer a reward sharing pricing model.
Motivation / Rationale
The Non-Custodial Staking feature [1] reduced the security risks associated with staked funds being held in the custody of third-party node operators. From the standpoint of node operators, however, non-custodial staking and a reward share pricing model do not coexist naturally because the service rewards are now in the custody of customers. A bad-intentioned customer can abscond with rewards, and a node operator would have no recourse to recoup the losses (except for legal action, which is costly and in some cases impossible internationally). This can be a barrier for node operators to fully go into non-custodial staking.
This also helps reduce the number of transactions in the network because with this feature, commission transfers happen without issuing send transactions. To facilitate zero-maintenance non-custodial staking, we also included fixes of minor issues —namely, negative rewards and operator topping-off— in this feature, as detailed below.
Specification
The built-in reward share is achieved by introducing a new field delegators in a staked node side by side with the existing output_address field as below, which defines reward share percentages for multiple addresses.
type Validator struct {
Address sdk.Address
PublicKey crypto.PublicKey
Jailed bool
Status sdk.StakeStatus
Chains []string
ServiceURL string
StakedTokens sdk.BigInt
UnstakingCompletionTime time.Time
OutputAddress sdk.Address
Delegators map[string]uint32 // <--- New
}
For a servicer to earn relay rewards from a single evidence submission, its operator address needs to submit two transactions, a claim and a proof. Since each of these transactions costs the hardcoded amount 0.01 POKT [2], the operator wallet incurs a fee of 0.02 POKT. If a servicer is staked in a non-custodial manner, relay rewards are distributed to three wallets, DAO, BlockProposer, and the servicer’s output address. Intriguingly, the operator address receives no rewards, even though a transaction fee of 0.02 POKT is debited from this wallet. As a result, node operators must regularly replenish the operator address of their non-custodial nodes.
We implemented a solution to this issue in this feature. With the introduction of delegators, the workflow is as follows: after the DAO and BlockProposer portions are deducted, the node first allocates the transaction fee cost to the operator address. It then distributes the delegators’ shares to their respective wallets and sends the remaining tokens to the output address. This means that relay rewards are now distributed across five types of wallets: the DAO, the BlockProposer, the servicer’s operator, the delegators, and the output address.
With the current RTTM, the relay rewards from a single evidence submission can be less than 0.02 POKT. Earning such a minuscule reward ultimately results in a net loss. To prevent it, we implemented a mechanism not to submit a claim transaction if the rewards from it are expected to be less than the reward cost. It’s “expected” because we cannot accurately calculate the amount when we claim it. The amount of the relay rewards is calculated when a node processes a proof transaction. It’s possible that RTTM or a servicer’s stake amount may be changed. Therefore, we put this part of change behind a new configuration so that a node operator can choose which logic is preferable.
This distribution to delegators is applied to block rewards too. Unlike relay rewards, there is no cost to earn block rewards.
Another topic we need to discuss is “editing”. The upgrade to RC-0.10.4 enabled the new feature Output Address Edit [3], which allows an MsgStake transaction signed by the current output address to change the output address to another. Now who should be able to change delegators? We propose that only the owner of the node operator should have the authority to make changes as follows:
- OutputAddress:
Only the current output address owner has the authority to modify. (since RC-0.10.4) - Delegators:
Only the node operator address owner should have the authority to modify. (Our proposal)
You may think that this reinstates the security risk that relay rewards are now in the custody of the node operator because they can change the commission percentages to 100 so that zero rewards go to the output address. You’re right. With this model, node operators can change the percentages to any value any time. Nevertheless we think this is acceptable for the following reasons.
Node operators may want to increase/decrease the commission percentage for a legitimate reason.
If a node operator illegitimately appropriates rewards by tampering the percentages, customers still have the option to unstake nodes and reclaim their staked tokens immediately. And that would severely damage the reputation of the node operator, likely rendering them unable to continue in the business.
Compared to the staked amount, which is still in the custody of the output address owner, the amount of relay rewards is much smaller.
[1] PIP-9 Consensus Rule Change – RC-0.8.0
[2] https://github.com/pokt-network/pocket-core/blob/353dd1047a5621a6dbc8351b28196cd39f5e7445/x/pocketcore/types/fee.go#L4-L5
[3] PIP-30: Consensus Rule Change – RC-0.10.0
Dissenting Opinions
As discussed above, the proposed features enhance the Non-Custodial staking feature. We believe there is no downside in the ideas. If there is any opinions which disagree with this proposal, it could be the risk of regressions or upgrade operations, which should be addressed in testing.
Viability
- New unit tests to verify the new features are included in the PRs we implemented.
- We perform end-to-end testing, where we submit relays and verify the rewards are distributed correctly, on Pocket Testnet before upgrading Mainnet.
- We prepare upgrade plan after this proposal is approved.
Implementation
This proposal includes two working implementations as GitHub PRs above. They’ve been verified on our private devnet:
- submit gov transactions
- keep sending relays throughout a test (before/after gov transactions) and wait until relay rewards are minted
- verify the amount of rewards
Deployment:
- If this proposal is approved, and after testing has taken place for BETA-0.11.0 on Testnet, RC-0.11.0 will be published for node runner adoption. Anyone can monitor node runner adoption of RC-0.11.0 using the Servicers and Validators version pie charts displayed here or the equivalent “Staked Tokens by Node Version” chart displayed here .
- Once ≥67% of validator power has updated to this version, an upgrade height will be selected by the Foundation Directors based on the preferences expressed by node runners (e.g. through Discord polls) and they will pass this height to the chain through the
pocket gov upgrade
transaction. - The upgrade height chosen by the Foundation Directors will be communicated in advance to ensure node runners are prepared to react if necessary. A time will be targeted that maximizes the availability of node runners, accounting for all time zones and working hours.
- Once the network is upgraded, each of the new features will be enabled by the Foundation submitting the
pocket gov enable
txs and working with the protocol developers to ensure there are no issues. - For avoidance of doubt, this PIP does not approve any values for the new
RelaysToTokensMultiplierMap
parameter, which means the globalRelaysToTokensMultiplier
will continue to apply to all chains until a subsequent PUP is approved modifying the newRelaysToTokensMultiplierMap
parameter.
Here’s an example command to submit a tx.
$ export POKT=<path to pocket>
$ export DAO=<DAO address>
$ export NETWORK=mainnet
$ $POKT gov change_param $DAO $NETWORK pos/RelaysToTokensMultiplierMap '{"0001":"12345","03DF":"42","0028":"3141592"}' 10000
Once it’s accepted by the network, the new parameter looks like this.
$ $POKT query node-params
2023/09/19 11:30:20 Initializing Pocket Datadir
2023/09/19 11:30:20 datadir = /home/john/.pocket
http://localhost:8082/v1/query/nodeparams
{
"dao_allocation": "10",
"downtime_jail_duration": "3600000000000",
"max_evidence_age": "120000000000",
"max_jailed_blocks": "37960",
"max_validators": "5",
"maximum_chains": "20",
"min_signed_per_window": "0.600000000000000000",
"proposer_allocation": "1",
"relays_to_tokens_multiplier": "8461",
"relays_to_tokens_multiplier_map": {
"0001": "12345",
"0028": "3141592",
"03DF": "42"
},
"servicer_stake_floor_multipler": "15000000000",
"servicer_stake_floor_multiplier_exponent": "1.000000000000000000",
"servicer_stake_weight_ceiling": "15000000000",
"servicer_stake_weight_multipler": "1.000000000000000000",
"session_block_frequency": "4",
"signed_blocks_window": "10",
"slash_fraction_double_sign": "0.000001000000000000",
"slash_fraction_downtime": "0.000001000000000000",
"stake_denom": "upokt",
"stake_minimum": "15000000000",
"unstaking_time": "300000000000"
}
Audit
There will be no external audit, refer to Viability.
Copyright
Copyright and related rights waived via CC0.
9/8: Made following inline edits:
- remove “instead of decreasing the value of pos/MaximumChains [3] which is proposed as GANDALF [4].”
- remove “[3] Protocol Parameters - Pocket Network” and “[4] Pre-proposal: GANDALF (Decrease MaximumChains)”
- there was a mistype in “five types of wallets: the DAO, the BlockProposer, the servicer’s operator, the delegators, and the operator address.” → s/the operator address/the output address/
9/20:
- Added more details to implementation section.