Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CIP-ShawnMcMurdo-CurvePledgeBenefit #12

Merged
merged 1 commit into from Oct 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,133 @@
---
CIP: ?
Title: Curve Pledge Benefit
Author: Shawn McMurdo <shawn_mcmurdo@yahoo.com>
Discussions-To:
Comments-Summary:
Comments-URI:
Status: Draft
Type: Standards
Created: 2020-08-11
License: Apache 2.0
Post-History: https://forum.cardano.org/t/protocol-parameters-pledge-and-sybil-resistance/35100 and https://github.com/input-output-hk/cardano-node/issues/1518
---

## Summary

Use a n-root curve instead of current linear a0 pledge benefit factor in the rewards equation.

## Abstract

Modifying the current rewards calculation equation by substituting a n-root curved relationship between pledge and pledge benefit rewards for the current linear relationship will better achieve the original design goal of incentivizing pledge to help prevent Sybil attacks.
This also reduces the unfortunate side effect in the current equation that over rewards private pools which provide no additional security benefit.

## Motivation

There are two main reasons for changing the current linear a0 pledge benefit factor in the rewards equation.

1. Pools pledging less than 1 million ADA see very little reward benefit. This is not a strong incentive for pool operators as at current prices that is approximately $150,000 USD.

2. Private pools get massive reward benefit without providing any additional protection against Sybil attacks. Why should a private pool make 29% more rewards than a pool with 5m ADA pledge while doing the same work?

## Specification

This is a modification of the maxPool function defined in section 11.8 Rewards Distribution Calculation of “A Formal Specification of the Cardano Ledger”.

maxPool = (R / (1 + a0)) * (o + (s * a0 * ((o - (s * ((z0 - o) / z0))) / z0)))

where:
R = ((reserve * rho) + fees) * (1 - tau)
o = min(pool_stake / total_stake, z0) = z0 for fully saturated pool
s = pledge / total_stake
z0 = 1 / k
and the following are current protocol parameters:
k = 150
rho = 0.0022
a0 = 0.3
tau = .05

The idea is to replace s in the above equation with an n-root curve expression of pledge rather than the linear pledge value.

We use an expression called crossover to represent the point where the curve crosses the line and the benefit in the new and original equations is identical.
Because the a0 pledge benefit is spread over the pledge range from 0 to saturation there is a dependence on k and total_stake.
Since k and total_stake will likely change over time it is best to express crossover in terms of k and total_stake as follows:

crossover = total_stake / (k * crossover_factor)

where crossover_factor is any real number greater than or equal to 1.
So crossover_factor is essentially a divisor of the pool saturation amount.
For example, setting crossover_factor to 20 with k = 150 and total_stake = 31 billion gives a crossover of approximately 10.3 million.

Also, we can parameterize the n-root curve exponent.
This gives us:

s = pow(pledge, (1 / curve_root)) * pow(crossover, ((curve_root - 1) / curve_root)) / total_stake

The curve_root could be set to any integer greater than 0 and when set to 1 produces the current rewards equation.
The curve_root is n in n-root. For example, 1 = linear, 2 = square root, 3 = cube root, 4 = fourth root, etc.

By making this modification to the rewards equation we introduce two new protocol parameters, crossover_factor and curve_root, that need to be set thoughtfully.

## Rationale

Using the n-root curve pledge benefit shows a much more reasonable distribution of pledge related rewards which will encourage meaningful pledges from more pool operators thus making the network more secure against Sybil attacks.
It also provides higher rewards for higher pledge without disproportionately rewarding a very few private pool operators who provide no additional security value to the network.
This modification maintains the general principles of the current rewards equation and does not introduce any hard limits.
It improves the incentives that were originally designed to make them more meaningful for the majority of pool operators.

## Backward Compatibility

This proposal is backwards compatible with the current reward function by setting the curve_root parameter to 1.

## Test Cases

See rewards.php for some simple PHP code that allows you to try different values for crossover_factor and curve_root and compare the resulting rewards to the current equation.
For usage, run "php -f rewards.php help".

An interesting set of parameters as an example is:

curve_root = 3
crossover_factor = 8

Running "php -f rewards.php 3 8" produces:

Assumptions
Reserve: 14b
Total stake: 31.7b
Tx fees: 0
Fully Saturated Pool
Rewards available in epoch: 29.3m
Pool saturation: 211.3m

Curve root: 3
Crossover factor: 8
Crossover: 26.4m

Pledge Rewards Benefit Alt Rwd Alt Bnft
0k 150051 0% 150051 0%
10k 150053 0% 150458 0.27%
50k 150062 0.01% 150747 0.46%
100k 150073 0.01% 150928 0.58%
200k 150094 0.03% 151156 0.74%
500k 150158 0.07% 151551 1%
1m 150264 0.14% 151941 1.26%
2m 150477 0.28% 152432 1.59%
5m 151116 0.71% 153282 2.15%
10m 152181 1.42% 154122 2.71%
20m 154311 2.84% 155180 3.42%
50m 160702 7.1% 157012 4.64%
100m 171352 14.2% 158821 5.84%
211.3m 195067 30% 161305 7.5%

As you can see this gives meaningful pledge benefit rewards to pools pledging less than 1m ADA.

## Implementations

If someone will show me where the current maxPool reward equation is implemented in the code, I could produce an implementation of this change as a pull request.

## Copyright

Copyright 2020 Shawn McMurdo

This CIP is licensed under the Apache-2.0 license.

91 changes: 91 additions & 0 deletions CIP-ShawnMcMurdo-CurvePledgeBenefit/rewards.php
@@ -0,0 +1,91 @@
<?php

$argc = count($argv);

if ($argc == 1) {
// The n-root curve exponent. 1 = linear, 2 = square root, 3 = cube root, 4 = fourth root, etc.
$curve_roots = array(2, 3, 4);

// Divisor of saturation that calculates the pledge where the curve crosses the line
$crossover_factors = array(10, 20, 50);
} else if ($argc == 3) {
$curve_roots = array($argv[1]);
$crossover_factors = array($argv[2]);
} else {
echo "Usage: php -f " . $argv[0] . " <curve_root> <crossover_factor>" . PHP_EOL;
echo " curve_root: The n-root curve exponent. 1 = linear, 2 = square root, 3 = cube root, etc." . PHP_EOL;
echo " An integer greater than 0." . PHP_EOL;
echo " crossover_factor: Divisor of saturation that calculates the pledge where the curve crosses the line." . PHP_EOL;
echo " A real number greater than or equal to 1." . PHP_EOL;
exit;
}

// Assumptions
$reserve = 14000000000;
$total_stake = 31700000000;
$fees = 0;

echo "Assumptions" . PHP_EOL;
echo "Reserve: " . round($reserve / 1000000000, 1) . "b" . PHP_EOL;
echo "Total stake: " . round($total_stake / 1000000000, 1) . "b" . PHP_EOL;
echo "Tx fees: " . $fees . PHP_EOL;
echo "Fully Saturated Pool" . PHP_EOL;

// Protocol parameters
$k = 150;
$rho = 0.0022;
$a0 = 0.3;
$tau = .05;

// Calculated values
$R = (($reserve * $rho) + $fees) * (1 - $tau);
$z0 = 1 / $k;
$o = $z0; // for fully saturated pool
$saturation = round($total_stake / $k);

echo "Rewards available in epoch: " . round($R / 1000000, 1) . "m" . PHP_EOL;
echo "Pool saturation: " . round($saturation / 1000000, 1) . "m" . PHP_EOL;
echo PHP_EOL;

// Pool pledge
$pledges = array(0, 10000, 50000, 100000, 200000, 500000, 1000000, 2000000, 5000000, 10000000, 20000000, 50000000, 100000000, $saturation);

// Compare to zero pledge
$comparison_pledge = 0;
$comparison_s = $comparison_pledge / $total_stake;
$comparison_rewards = round(($R / (1 + $a0)) * ($o + ($comparison_s * $a0 * (($o - ($comparison_s * (($z0 - $o) / $z0))) / $z0))));

foreach ($curve_roots as $curve_root) {
foreach ($crossover_factors as $crossover_factor) {
$crossover = $total_stake / ($k * $crossover_factor);
echo "Curve root: " . $curve_root . PHP_EOL;
echo "Crossover factor: " . $crossover_factor . PHP_EOL;
echo "Crossover: " . round($crossover / 1000000, 1) . "m" . PHP_EOL;
echo PHP_EOL;

echo "Pledge\tRewards\tBenefit\tAlt Rwd\tAlt Bnft" . PHP_EOL;

foreach ($pledges as $pledge) {
if ($pledge < 1000000) {
$pledge_str = round($pledge / 1000, 1) . "k";
} else {
$pledge_str = round($pledge / 1000000, 1) . "m";
}

// Current Formula (same as alternate formula with curve_root = 1)
$s = $pledge / $total_stake;
$rewards = round(($R / (1 + $a0)) * ($o + ($s * $a0 * (($o - ($s * (($z0 - $o) / $z0))) / $z0))));
$benefit = round(((($rewards / $comparison_rewards) - 1) * 100), 2);

$alt_numerator = pow($pledge, (1 / $curve_root)) * pow($crossover, (($curve_root - 1) / $curve_root));
$alt_s = $alt_numerator / $total_stake;
$alt_rewards = round(($R / (1 + $a0)) * ($o + ($alt_s * $a0 * (($o - ($alt_s * (($z0 - $o) / $z0))) / $z0))));
$alt_benefit = round(((($alt_rewards / $comparison_rewards) - 1) * 100), 2);

echo $pledge_str . "\t" . $rewards . "\t" . $benefit . "%\t" . $alt_rewards . "\t" . $alt_benefit . "%" . PHP_EOL;
}

echo PHP_EOL;
}
}