Skip to content

Commit

Permalink
Defer delegatee rewards to the end of the validator staking period (a…
Browse files Browse the repository at this point in the history
…va-labs#1262)

Co-authored-by: Stephen <[email protected]>
  • Loading branch information
dhrubabasu and StephenButtolph authored Apr 3, 2023
1 parent b8d5738 commit 729883a
Show file tree
Hide file tree
Showing 22 changed files with 713 additions and 93 deletions.
1 change: 1 addition & 0 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,7 @@ func (n *Node) initVMs() error {
ApricotPhase3Time: version.GetApricotPhase3Time(n.Config.NetworkID),
ApricotPhase5Time: version.GetApricotPhase5Time(n.Config.NetworkID),
BanffTime: version.GetBanffTime(n.Config.NetworkID),
CortinaTime: version.GetCortinaTime(n.Config.NetworkID),
MinPercentConnectedStakeHealthy: n.Config.MinPercentConnectedStakeHealthy,
UseCurrentHeight: n.Config.UseCurrentHeight,
},
Expand Down
4 changes: 3 additions & 1 deletion vms/platformvm/blocks/builder/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,9 @@ func addSubnet(env *environment) {
}

stateDiff.AddTx(testSubnet1, status.Committed)
stateDiff.Apply(env.state)
if err := stateDiff.Apply(env.state); err != nil {
panic(err)
}
}

func defaultState(
Expand Down
12 changes: 9 additions & 3 deletions vms/platformvm/blocks/executor/acceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ func (a *acceptor) ApricotAtomicBlock(b *blocks.ApricotAtomicBlock) error {
}

// Update the state to reflect the changes made in [onAcceptState].
blkState.onAcceptState.Apply(a.state)
if err := blkState.onAcceptState.Apply(a.state); err != nil {
return err
}

defer a.state.Abort()
batch, err := a.state.CommitBatch()
Expand Down Expand Up @@ -233,7 +235,9 @@ func (a *acceptor) optionBlock(b, parent blocks.Block) error {
if !ok {
return fmt.Errorf("couldn't find state of block %s", blkID)
}
blkState.onAcceptState.Apply(a.state)
if err := blkState.onAcceptState.Apply(a.state); err != nil {
return err
}
return a.state.Commit()
}

Expand Down Expand Up @@ -271,7 +275,9 @@ func (a *acceptor) standardBlock(b blocks.Block) error {
}

// Update the state to reflect the changes made in [onAcceptState].
blkState.onAcceptState.Apply(a.state)
if err := blkState.onAcceptState.Apply(a.state); err != nil {
return err
}

defer a.state.Abort()
batch, err := a.state.CommitBatch()
Expand Down
4 changes: 3 additions & 1 deletion vms/platformvm/blocks/executor/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,9 @@ func addSubnet(env *environment) {
}

stateDiff.AddTx(testSubnet1, status.Committed)
stateDiff.Apply(env.state)
if err := stateDiff.Apply(env.state); err != nil {
panic(err)
}
}

func defaultState(
Expand Down
3 changes: 3 additions & 0 deletions vms/platformvm/blocks/executor/proposal_block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ func TestApricotProposalBlockTimeVerification(t *testing.T) {
}, nil)
onParentAccept.EXPECT().GetTx(addValTx.ID()).Return(addValTx, status.Committed, nil)
onParentAccept.EXPECT().GetCurrentSupply(constants.PrimaryNetworkID).Return(uint64(1000), nil).AnyTimes()
onParentAccept.EXPECT().GetDelegateeReward(constants.PrimaryNetworkID, utx.NodeID()).Return(uint64(0), nil).AnyTimes()

env.mockedState.EXPECT().GetUptime(gomock.Any(), constants.PrimaryNetworkID).Return(
time.Duration(1000), /*upDuration*/
Expand Down Expand Up @@ -229,6 +230,8 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) {
currentStakersIt.EXPECT().Release().AnyTimes()
onParentAccept.EXPECT().GetCurrentStakerIterator().Return(currentStakersIt, nil).AnyTimes()

onParentAccept.EXPECT().GetDelegateeReward(constants.PrimaryNetworkID, unsignedNextStakerTx.NodeID()).Return(uint64(0), nil).AnyTimes()

pendingStakersIt := state.NewMockStakerIterator(ctrl)
pendingStakersIt.EXPECT().Next().Return(false).AnyTimes() // no pending stakers
pendingStakersIt.EXPECT().Release().AnyTimes()
Expand Down
3 changes: 3 additions & 0 deletions vms/platformvm/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ type Config struct {
// Time of the Banff network upgrade
BanffTime time.Time

// Time of the Cortina network upgrade
CortinaTime time.Time

// Subnet ID --> Minimum portion of the subnet's stake this node must be
// connected to in order to report healthy.
// [constants.PrimaryNetworkID] is always a key in this map.
Expand Down
41 changes: 38 additions & 3 deletions vms/platformvm/state/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var (
type Diff interface {
Chain

Apply(State)
Apply(State) error
}

type diff struct {
Expand All @@ -37,7 +37,9 @@ type diff struct {
currentSupply map[ids.ID]uint64

currentStakerDiffs diffStakers
pendingStakerDiffs diffStakers
// map of subnetID -> nodeID -> total accrued delegatee rewards
modifiedDelegateeRewards map[ids.ID]map[ids.NodeID]uint64
pendingStakerDiffs diffStakers

addedSubnets []*txs.Tx
// Subnet ID --> Tx that transforms the subnet
Expand Down Expand Up @@ -121,6 +123,31 @@ func (d *diff) GetCurrentValidator(subnetID ids.ID, nodeID ids.NodeID) (*Staker,
}
}

func (d *diff) SetDelegateeReward(subnetID ids.ID, nodeID ids.NodeID, amount uint64) error {
if d.modifiedDelegateeRewards == nil {
d.modifiedDelegateeRewards = make(map[ids.ID]map[ids.NodeID]uint64)
}
nodes, ok := d.modifiedDelegateeRewards[subnetID]
if !ok {
nodes = make(map[ids.NodeID]uint64)
d.modifiedDelegateeRewards[subnetID] = nodes
}
nodes[nodeID] = amount
return nil
}

func (d *diff) GetDelegateeReward(subnetID ids.ID, nodeID ids.NodeID) (uint64, error) {
amount, modified := d.modifiedDelegateeRewards[subnetID][nodeID]
if modified {
return amount, nil
}
parentState, ok := d.stateVersions.GetState(d.parentID)
if !ok {
return 0, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID)
}
return parentState.GetDelegateeReward(subnetID, nodeID)
}

func (d *diff) PutCurrentValidator(staker *Staker) {
d.currentStakerDiffs.PutValidator(staker)
}
Expand Down Expand Up @@ -430,7 +457,7 @@ func (d *diff) DeleteUTXO(utxoID ids.ID) {
}
}

func (d *diff) Apply(baseState State) {
func (d *diff) Apply(baseState State) error {
baseState.SetTimestamp(d.timestamp)
for subnetID, supply := range d.currentSupply {
baseState.SetCurrentSupply(subnetID, supply)
Expand All @@ -455,6 +482,13 @@ func (d *diff) Apply(baseState State) {
}
}
}
for subnetID, nodes := range d.modifiedDelegateeRewards {
for nodeID, amount := range nodes {
if err := baseState.SetDelegateeReward(subnetID, nodeID, amount); err != nil {
return err
}
}
}
for _, subnetValidatorDiffs := range d.pendingStakerDiffs.validatorDiffs {
for _, validatorDiff := range subnetValidatorDiffs {
switch validatorDiff.validatorStatus {
Expand Down Expand Up @@ -501,4 +535,5 @@ func (d *diff) Apply(baseState State) {
baseState.DeleteUTXO(utxoID)
}
}
return nil
}
29 changes: 29 additions & 0 deletions vms/platformvm/state/mock_chain.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 33 additions & 2 deletions vms/platformvm/state/mock_diff.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions vms/platformvm/state/mock_state.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions vms/platformvm/state/stakers.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ type CurrentStakers interface {
// Invariant: [staker] is currently a CurrentValidator
DeleteCurrentValidator(staker *Staker)

// SetDelegateeReward sets the accrued delegation rewards for [nodeID] on
// [subnetID] to [amount].
SetDelegateeReward(subnetID ids.ID, nodeID ids.NodeID, amount uint64) error

// GetDelegateeReward returns the accrued delegation rewards for [nodeID] on
// [subnetID].
GetDelegateeReward(subnetID ids.ID, nodeID ids.NodeID) (uint64, error)

// GetCurrentDelegatorIterator returns the delegators associated with the
// validator on [subnetID] with [nodeID]. Delegators are sorted by their
// removal from current staker set.
Expand Down
8 changes: 1 addition & 7 deletions vms/platformvm/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -1609,13 +1609,7 @@ func (s *state) writeCurrentStakers(updateValidators bool, height uint64) error
PotentialDelegateeReward: 0,
}

// TODO: Remove once we want to write the new disk format
prevMetadata := preDelegateeRewardMetadata{
UpDuration: metadata.UpDuration,
LastUpdated: metadata.LastUpdated,
PotentialReward: metadata.PotentialReward,
}
metadataBytes, err := blocks.GenesisCodec.Marshal(blocks.Version, prevMetadata)
metadataBytes, err := blocks.GenesisCodec.Marshal(blocks.Version, metadata)
if err != nil {
return fmt.Errorf("failed to serialize current validator: %w", err)
}
Expand Down
Loading

0 comments on commit 729883a

Please sign in to comment.