Updated 20/06/22 by @JackALaing to make the proposal co-authored by Andy, myself, and @luyzdeleon. Our amendments include integrating our own motivations, adding more specification details, removing specified parameter values from the proposal, and adding the core dev team’s recommended implementation details.
Updated 13/06/22 to include @luyzdeleon 's suggested changes: Addition of DAO configurable parameters and decoupling of max weight from 1 using ServicerStakeWeightCeiling
Updated 13/06/22: Have changed the weighting to be against the top bin and decrease linearly to 1/X being the bottom bin. This solves the issues spotted by @addison (and ensures it is the same/deflationary from where we are now as opposed to inflationary with the previous approach). Whilst still preserving the “simpleness”.
Attributes
-
Author(s):
- @Andy-Liquify: the founder of Liquify, an infrastructure as a service company catering to projects and institutions. I have over 10 years experience in developing safety critical software.
- @luyzdeleon: CTO, Pocket Network Inc.
- @JackALaing: CGO, Pocket Network Inc.
- Implementer(s): Liquify team with support from pocket core team
- Category: Protocol Upgrade
Summary
Enable weighted staking by scaling per-relay rewards according to the stake size of a servicer.
Background / Motivation
There are a number of proposals (formal in the forum and informal in chat) that aim to consolidate the node count in order to reduce the network’s operating costs. The majority of these have trade-offs and known unknowns:
- Uses Negative Incentives: e.g. increase StakeMinimum to force everyone to consolidate – the number of single node runners is anticipated to be in the thousands and it’s unknown how they’d react to being told that the rules of entry have changed
- Diminishes Servicer Incentives: e.g. increase ProposerAllocation to incentivize optimizing to be a validator rather than a servicer, since validators are stake-weighted – it’s unknown how many would continue maintaining their backend RelayChain nodes if/when they realize that producing blocks is more profitable than servicing relays and their backend RelayChain nodes are now the majority of their operating expense, and thus it’s unknown the 2nd-order effects this could have on the quality of Pocket’s service
- Creates More Inefficiencies: e.g. stake-weighted servicer selection, meaning that larger staked servicers are selected more often into sessions and ultimately receive more relays – it’s unknown the 2nd-order effects this could have on block processing and node resources, since it involves making the session generation algorithm more complicated and session generation is currently a bottleneck in block processing. We’d increase individual node operating expenses in the process of reducing total node counts, bringing us back to square one.
When these debates first started, some core team members gravitated towards stake-weighted servicing since it didn’t introduce either of the first two trade-offs - 1) it is a positive incentive that rewards consolidation rather than penalizing non-consolidation, 2) it reinforces servicer incentives. However, our enthusiasm for this solution was dampened by the 3rd category of trade-off, since we knew that complicating the session generation algorithm was a big undertaking that could make operating costs more expensive again.
@Andy-Liquify’s proposal took a creative approach to stake-weighting which doesn’t touch the session generation algorithm and instead scales per-relay rewards according to stake. In other words, we had assumed the only way to stake-weight was on the front-end (more sessions, more relays), but Andy introduced the notion that we can stake-weight on the back-end (more rewards per relay). And it seems to be a lot simpler computationally.
We’ve spent the last week discussing this proposal internally, getting Andy’s consent to become co-authors, and now here we are with an amended PIP-22 for your consideration.
Specification
Instead of stake-weighting session selection, which adds state bloat, we can stake-weight rewards according to the formula below. The stake-weighted rewards formula should be parameterized to allow for the DAO to calibrate incentives.
reward = NUM_RELAYS * RelaysToTokensMultiplier * ((FLOOR/ValidatorStakeFloorMultiplier)/( ValidatorStakeWeightMultiplier*ValidatorStakeFloorMultiplier))^(ValidatorStakeFloorMultiplierExponent)
New DAO ACL parameters:
-
ValidatorStakeFloorMultiplier
- This corresponds to the bin widths, i.e. the size of the stake increments, or number of extra tokens required to increase the stake; -
ValidatorStakeWeightMultiplier
- This is the maximum multiple/divisor allowed to scale the rewards; -
ServicerStakeWeightCeiling
- This sets the upper limit for consolidation; -
ValidatorStakeFloorMultiplierExponent
- Defines the linearity of the stake-weighting curve, with 1 being linear and <1 non-linear.
These parameters are new economic levers that the DAO can pull to refine the incentives of servicer consolidation.
For example, if servicers are spamming edit stake transactions to compound as quickly as possible, we can increase the ValidatorStakeFloorMultiplier (perhaps paired with an increased transaction fee). As another example, if the DAO wants to more aggressively incentivize consolidation, it can set ValidatorStakeFloorMultiplierExponent closer to 1, whereas if the DAO wants to encourage more horizontal scaling (or equalize rewards for the single node runners) it can set the param closer to 0.
Example If ValidatorStakeWeightMultiplier = 5, ValidatorStakeFloorMultiplier = 15000, ServicerStakeWeightCeiling = 5 * 15000 = 75k, and ValidatorStakeFloorMultiplierExponent = 1 :
| Stake | Floored Value | Reward Rate |
|--------|---------------|-------------|
| 15000 | 15000 | 1/5 |
| 17200 | 15000 | 1/5 |
| 30000 | 30000 | 2/5 |
| 45000 | 45000 | 3/5 |
| 60000 | 60000 | 4/5 |
| 75000 | 75000 | 5/5 |
| 150000 | 75000 | 5/5 |
Feature Flags
In order to fully realize the configurability of this functionality, new feature flags would need to be implemented:
-
RSCAL
(Reward Scaling): This flag would tell the protocol that reward scaling is active when on and to use the formulas proposed. When off, this would go back to the original formula ofcoins = RelaysToTokensMultiplier * Relays
. The idea behind this feature flag is that if any issues arise with the mechanism overall, the whole mechanism can be disabled and the network can fallback into the already known behavior as a default in case of crises and/or unknown unknowns. -
VEDIT
(Validate Edit Stake): If RSCAL is true, this flag would activate the edit stake validation feature described below, meaning that edit stake transactions would be invalid if they do not cause the stake size to reach the next bin. This will give the DAO an emergency fallback to counteract edit stake spamming.
State transition rules
The below pseudo-code is meant to illustrate the business rules of the state transitions that are impacted by this change, the Implementers (PNI core devs) have full discretion on the actual implementation as long as it achieves the same results being illustrated.
Proof lifecycle validation (rewards calculation)
Entrypoint function: https://github.com/pokt-network/pocket-core/blob/8ad860a86be1cb9b891c1b6f244f3511d56a9949/x/nodes/keeper/reward.go#L11
IF RSCAL == TRUE
// Calculate bin
flooredStake = MIN(nodeStake - (nodeStake % ValidatorStakeFloorMultiplier), ServicerStakeWeightCeiling)
// Calculate weight
weight = (flooredStake/ValidatorStakeFloorMultiplier)^(ValidatorStakeFloorMultiplierExponent)/(ValidatorStakeWeightMultiplier)
// Calculate coins based on weight
coins = RelaysToTokensMultiplier * totalRelays * weight
ELSE
coins = RelaysToTokensMultiplier * totalRelays
END
Validate Edit Stake
Entrypoint Function: https://github.com/pokt-network/pocket-core/blob/de8ec8c46cdcf17606b1491e2fca9f8ea3f7d716/x/nodes/keeper/valStateChanges.go#L197
In this case, the following pseudocode doesn’t replace the existing validations, but it’s added to them. The goal with this state transition is only allow stake increases when a node is actually increasing their stake to the next bin, up to ServicerStakeWeightCeiling
, if the new stake amount is higher than that, then allow the transaction to go through.
IF RSCAL == TRUE AND VEDIT == TRUE
// We only enforce if someone is trying to stake within the limits of reward scaling
IF newStakeAmount < ServicerStakeWeightCeiling
// Calculate the bin in which the new stake would fall under
flooredStake = newStakeAmount - (newStakeAmount % ValidatorStakeFloorMultiplier)
IF flooredStake < currentStakeAmount
// Throw invalid edit stake error
END
END
END
We want to include the option to protect the Validate Edit Stake functionality because in practice we’ve seen the economic incentive not to be enough of a deterrent for Node Runners to want see state transitions play out as soon as possible to earn as much as an advantage as possible given that there’s limited block space to accommodate new node configurations.
This feature will be flagged and deactivated to begin with. If the incentives alone are not enough to prevent edit stake spamming, this feature can be activated. Note that activating this feature introduces the trade-off of making it harder to do slash-prevention top-ups, which may necessitate a revisit of edit stake logic.
Burn Challenge
Entrypoint function: https://github.com/pokt-network/pocket-core/blob/98a12e0f1ecb98e40cd2012e081de842daf43e90/x/nodes/keeper/slash.go#L15
In this case we want to scale slashing for servicing related offenses (replay attempts at proofs and client side challenges) in regards to weight when reward scaling is active
IF RSCAL == TRUE
// Calculate bin
flooredStake = MIN(nodeStake - (nodeStake % ValidatorStakeFloorMultiplier), ServicerStakeWeightCeiling)
// Calculate weight
weight = (flooredStake/ValidatorStakeFloorMultiplier)^(ValidatorStakeFloorMultiplierExponent)/(ValidatorStakeWeightMultiplier)
// Calculate coins based on weight
burnedCoins = RelaysToTokensMultiplier * totalChallenges * weight
ELSE
burnedCoins = RelaysToTokensMultiplier * totalChallenges
END
Rationale
We covered some of this in the Background section but here’s a cost-benefit summary:
Benefits
- Consolidation of nodes = reduced cost to run the network
- (Relatively) simple change
- Easy to calibrate by adjusting the new DAO params
- Positive side-effect of increasing the minimum validator stake, since servicer consolidation = validator consolidation
Costs
- Nodes don’t get paid to do the same work
- Harder to track rewards – but Andy suggests that we could just shift the metric to be relay based not reward based (or some changes to indexers)
Dissenting Opinions
The dissenting opinions in the previous version of this proposal have been addressed in the amended specification.
While we recognize that this mechanism introduces a deflationary component, it’s our view that if the deflation starts to squeeze smaller node runners the RelaysToTokensMultiplier parameter can be adjusted upwards. This proposal is focused on the introduction of a new mechanism with new economic levers that the DAO can calibrate; we believe economic concerns like this can and should be addressed in a separate PUP defining the initial parameter values and subsequent PUPs if adjustment is needed.
We believe that staying horizontally scaled for the chance of getting more relays, relative to the guaranteed multiplier on rewards from consolidating, is a more uncertain strategy. This would mean that, even if outliers adopt a horizontal strategy, the majority of node runners would adopt the more certain consolidation strategy.
Implementation
Scope of Proposal
This proposal has been narrowed in scope to an abstract parameterized mechanism. Approving this proposal means approving the mechanism of weighting servicer rewards by servicer stake, which is the signal that the core devs need to begin coding it up. Before activating this mechanism, a separate PUP must be approved defining the initial values of the new DAO parameters.
Technical Discretion
The formula, parameters, and pseudo-code outlined in the Specification section are meant to illustrate how this new stake-weighting mechanism is likely to work. The Implementers (PNI core devs) have full discretion on the actual implementation as long as it achieves the same results being illustrated.
Release & Timeline
The changes included in this proposal should be included in the next consensus breaking release for Pocket Core RC-0.9.0, which is targeted for mid-July.