Skip to content
42 changes: 36 additions & 6 deletions proposals/0123-block-revenue-distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,15 @@ This proposal depends on the following previously accepted proposals:
Introduces a new instruction type for setting commission rates in basis
points

[SIMD-0180]: https://github.com/solana-foundation/solana-improvement-documents/pull/180
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobcreech can we add a lint to prevent simds from linking to pull requests like this? we only want simds merged referencing merged simds. if there's valuable context in the pr comments, that should make it to the simd text, not be left to be dug out of the conversation

[SIMD-0185]: https://github.com/solana-foundation/solana-improvement-documents/pull/185
[SIMD-0232]: https://github.com/solana-foundation/solana-improvement-documents/pull/232
[SIMD-0291]: https://github.com/solana-foundation/solana-improvement-documents/pull/291
- **[SIMD-0392]: Runtime Adjustments for Rent Increase**

Updates delegation calculation based on `Rent` sysvar parameters

[SIMD-0180]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0180-vote-account-leader-schedule.md
[SIMD-0185]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0185-vote-account-v4.md
[SIMD-0232]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0232-custom-commission-collector.md
[SIMD-0291]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0291-commission-rate-in-basis-points.md
[SIMD-0392]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0392-rent-increase-adaptations.md

## Alternatives Considered

Expand All @@ -61,7 +66,7 @@ they will have to manage themselves. [SIMD-0022] aims to make this experience
better for stakers by allowing stake accounts to separately delegate any
unstaked balance in their accounts.

[SIMD-0022]: https://github.com/solana-foundation/solana-improvement-documents/pull/22
[SIMD-0022]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0022-multi-stake.md

### Out of protocol reward distribution

Expand Down Expand Up @@ -175,7 +180,32 @@ rewards distribution, the delegated vote account for each rewarded stake account
must have its `pending_delegator_rewards` field and its balance deducted with
the amount of rewards distributed to keep capitalization consistent.

[SIMD-0118]: https://github.com/solana-foundation/solana-improvement-documents/pull/118
[SIMD-0118]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0118-partitioned-epoch-reward-distribution.md

#### Stake Delegation Adjustment

The new delegation amount for a stake account MUST account for individual
delegator rewards, by adapting the calculation from [SIMD-0392]:

```
post_delegation = min(
delegation + stake_rewards,
balance + stake_rewards + block_rewards - rent_exempt_reserve
)
```

Where `block_rewards` represents the individual block rewards earned by the
stake account in that epoch. All other variables are the same as before:

- `post_delegation`: the account's post-reward delegated lamport amount
- `pre_delegation`: the account's pre-reward delegated lamport amount
- `stake_rewards`: the account's calculated stake reward lamport amount for the
past epoch
- `balance`: the account's pre-reward balance, in lamports
- `rent_exempt_reserve`: the minimum lamport balance required for the stake
account

All arithmetic operations MUST be saturating and use unsigned 64-bit integers.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we link to the appropriate section of 0392 instead of replicoding here?


### Vote Program

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
---
simd: '0392'
title: Relax Post-Execution Minimum Balance Check
title: Adapt Runtime for Rent Increases
authors:
- Igor Durovic (anza)
- Jon C (anza)
category: Standard
type: Core
status: Idea
Expand All @@ -12,15 +13,26 @@ feature: (fill in with feature key and github tracking issues once accepted)

## Summary

To allow for non-disruptive rent increases, relax post-execution account
minimum balance checks. The new lower-bound on post-exec balance is
To allow for non-disruptive rent increases, the Solana runtime relaxes
post-execution minimum balance checks and adjusts stake delegations during epoch
rewards calculations.

### Relax Post-Execution Minimum Balance Check

During transaction execution, the new lower-bound on post-exec balance is
`min(acc.pre_exec_balance, calculate_min_balance(acc.size()))`.

This maintains the invariant that every account has a balance at or above the
minimum balance requirement calculated at any point since the most recent
allocation occurred. When enabled, only newly allocated accounts will be
subject to rent increases.

### Adjust Stake Delegations during Reward Calculation

A new calculation is proposed to adjust stake delegation amounts during the
epoch rewards payout system, based on the `Rent` sysvar parameters at the
beginning of that epoch.

Sidenote: this proposal doesn't include any mechanism for increasing rent,
but when such a mechanism is added in the future it should cap the
effective rent-per-byte at the legacy rent-exempt per-byte rate. This
Expand All @@ -31,11 +43,25 @@ need to be updated to be compatible.

## Motivation

This proposal is a prerequisite for
[SIMD-0438 (Rent Increase)](https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0438-rent-increase-safeguard.md).

In order to safely reduce rent there must be a mechanism available for
non-disruptive rent increases. Without this change, a rent increase would
non-disruptive rent increases. Without these changes, a rent increase would
either place existing accounts in a gray area undefined by the protocol or
prevent write-locking all accounts with balances below the new rent value.

For stake accounts, any meaningful user (on-chain programs, dapps, etc)
typically assumes the following invariant:

```
balance - delegation - rent_exempt_reserve >= 0 lamports
```

If a rent lamport can also be a delegation lamport, at best programs or users
will abort operations due to incorrect values, at worst they might overestimate
the value of a stake account and create a loss-of-funds scenario.

## New Terminology

- `calculate_min_balance(acc_size) = acc_size * current_rent_per_byte`.
Expand All @@ -53,7 +79,9 @@ prevent write-locking all accounts with balances below the new rent value.

## Detailed Design

### Current behavior
### Post-Execution Balance Checks

#### Current behavior

For all write-locked accounts, post-execution account balance checks
currently verify:
Expand All @@ -70,7 +98,7 @@ If the rent price is increased then existing accounts may become sub-exempt,
which isn't currently allowed in the protocol as rent paying accounts have been
deprecated.

### Proposed behavior
#### Proposed behavior

For all write-locked accounts, post-execution account balance checks MUST
verify:
Expand Down Expand Up @@ -112,7 +140,7 @@ The owner check is intended to make reselling low-rent account state more
difficult so a secondary market doesn't develop. See the security considerations
section for more details.

### Implementation details
#### Implementation details

- The pre-execution balance MUST be captured before any state is modified
(e.g. before fee collection, instruction execution, etc). This same
Expand All @@ -130,7 +158,7 @@ section for more details.
`min()` clause.
- As before, 0 post-balance is allowed and equivalent to closing an account.

### Edge cases
#### Edge cases

**Account creation:**

Expand Down Expand Up @@ -163,6 +191,42 @@ section for more details.
- If the account owner changes, always enforce the current rent-exempt minimum
for the post-exec size; the `min(pre_exec_balance, …)` clause does not apply.

### Rent-Adjusted Stake Delegations

During the epoch rewards calculation phase, a stake's updated delegation MUST be
calculated with the following formula:

```
post_delegation = min(
pre_delegation + stake_rewards,
balance + stake_rewards - rent_exempt_reserve
)
```

Where:

- `post_delegation`: the account's post-reward delegated lamport amount
- `pre_delegation`: the account's pre-reward delegated lamport amount
- `stake_rewards`: the account's calculated stake reward lamport amount for the
past epoch
- `balance`: the account's pre-reward balance, in lamports
- `rent_exempt_reserve`: the minimum lamport balance required for the stake
account
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
account
account (see below)


All arithmetic operations MUST be saturating and use unsigned 64-bit integers.

The `rent_exempt_reserve` calculation MUST use current `Rent` sysvar parameters.
Any updates to the `Rent` sysvar values MUST take place before epoch rewards
calculation takes place.

During distribution, the `delegation.stake` field (absolute offset `[156,164)`)
in the stake account's data MUST be set to the new delegation amount, expressed
as a little-endian unsigned 64-bit integer.

If the new delegation amount is 0, then `delegation.deactivation_epoch`
(absolute offset `[172,180)`) MUST be set to the rewarded epoch, expressed as a
little-endian unsigned 64-bit integer.

## Alternatives Considered

### Always enforce current rent price post-execution
Expand All @@ -183,6 +247,13 @@ can be made stricter: every account's balance is bounded below by the rent
price at the most recent allocation rather than the minimum rent price *since*
the last allocation.

### Fix Minimum Balance for Stake Accounts

We could fix the minimum balance for stake accounts to the current minimum
balance for 200 bytes. This approach breaks any existing on-chain programs or
tooling that use the Rent sysvar to calculate the minimum balance of a stake
account.

## Impact

- Dapp developers: Enables non-disruptive rent increases. Existing accounts are
Expand Down Expand Up @@ -215,10 +286,19 @@ the last allocation.

## Backwards Compatibility

This is a **relaxation** of existing constraints:
For post-execution balance checks, this is a **relaxation** of existing
constraints:

- The change makes the balance check less strict by allowing accounts to retain
their original rent price when not upwards reallocating.
- This is backwards compatible in the sense that transactions that currently
succeed will continue to succeed.
- However, it changes consensus rules and must be activated behind a feature gate.

For stake accounts:

- A stake delegation MAY decrease between epochs, so consumers MUST relax
assumptions that delegation amounts only increase or stay the same.
- Consumers MUST allow for stake accounts to become inactive as a result of
reward distribution, without an explicit call to `Deactivate` or
`DeactivateDelinquent`.
Comment on lines +303 to +304
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to consider updating block metadata to signal these occurrences since there will now be no onchain reference to the deactivation event nor easily accessible time of deactivation state snapshot?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a very good question -- we could add a new bool field to Reward like instant_destake.

On the other hand, clients could figure it out based on the post_balance field and the rent parameters at the time of rewards payout. Is that clear enough?

Just to double-check, block metadata is out of protocol, correct?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a very good question -- we could add a new bool field to Reward like instant_destake.

On the other hand, clients could figure it out based on the post_balance field and the rent parameters at the time of rewards payout. Is that clear enough?

we don't have the rent parameters either tho. even if we did, we don't necessarily know the data size of the stake account at that time.

i was originally thinking add the min_balance field for each account, but we don't have enough info to make sense of that either.

i think easiest would be a new RewardType variant StakingInactive or similar. we could also emit it on requested deactivation final reward epoch.

Just to double-check, block metadata is out of protocol, correct?

technically, tho that's almost certainly a mistake. staking and validator rewards must be the most numerous taxable events in the protocol and there is no record of them without this metadata

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think easiest would be a new RewardType variant StakingInactive or similar. we could also emit it on requested deactivation final reward epoch.

I didn't like the idea of adding a new status for just this edge case, but I'm down if we do it for all deactivations

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

way easier than changing layout 😅

Loading