Skip to content

Commit

Permalink
Added process slashings (#6728)
Browse files Browse the repository at this point in the history
  • Loading branch information
Giulio2002 authored Jan 27, 2023
1 parent 6933b0d commit a0d236d
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 0 deletions.
8 changes: 8 additions & 0 deletions cmd/erigon-cl/core/state/accessors.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ func (b *BeaconState) GetTotalActiveBalance() (uint64, error) {
return b.GetTotalBalance(b.GetActiveValidatorsIndices(b.Epoch()))
}

// GetTotalSlashingAmount return the sum of all slashings.
func (b *BeaconState) GetTotalSlashingAmount() (t uint64) {
for _, slash := range &b.slashings {
t += slash
}
return
}

// GetBlockRoot returns blook root at start of a given epoch
func (b *BeaconState) GetBlockRoot(epoch uint64) (libcommon.Hash, error) {
return b.GetBlockRootAtSlot(epoch * b.beaconConfig.SlotsPerEpoch)
Expand Down
5 changes: 5 additions & 0 deletions cmd/erigon-cl/core/state/setters.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ func (b *BeaconState) SetBalances(balances []uint64) {
b.balances = balances
}

func (b *BeaconState) AddBalance(balance uint64) {
b.touchedLeaves[BalancesLeafIndex] = true
b.balances = append(b.balances, balance)
}

func (b *BeaconState) SetValidatorBalance(index int, balance uint64) {
b.touchedLeaves[BalancesLeafIndex] = true
b.balances[index] = balance
Expand Down
6 changes: 6 additions & 0 deletions cmd/erigon-cl/core/state/test_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,9 @@ func GetEmptyBeaconState() *BeaconState {
b.initBeaconState()
return b
}

func GetEmptyBeaconStateWithVersion(v clparams.StateVersion) *BeaconState {
b := GetEmptyBeaconState()
b.version = v
return b
}
47 changes: 47 additions & 0 deletions cmd/erigon-cl/core/transition/process_slashings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package transition

import "github.com/ledgerwatch/erigon/cl/clparams"

func (s *StateTransistor) processSlashings(slashingMultiplier uint64) error {
// Get the current epoch
epoch := s.state.Epoch()
// Get the total active balance
totalBalance, err := s.state.GetTotalActiveBalance()
if err != nil {
return err
}
// Calculate the total slashing amount
// by summing all slashings and multiplying by the provided multiplier
slashing := s.state.GetTotalSlashingAmount() * slashingMultiplier
// Adjust the total slashing amount to be no greater than the total active balance
if totalBalance < slashing {
slashing = totalBalance
}
// Apply penalties to validators who have been slashed and reached the withdrawable epoch
for i, validator := range s.state.Validators() {
if !validator.Slashed || epoch+s.beaconConfig.EpochsPerSlashingsVector/2 != validator.WithdrawableEpoch {
continue
}
// Get the effective balance increment
increment := s.beaconConfig.EffectiveBalanceIncrement
// Calculate the penalty numerator by multiplying the validator's effective balance by the total slashing amount
penaltyNumerator := validator.EffectiveBalance / increment * slashing
// Calculate the penalty by dividing the penalty numerator by the total balance and multiplying by the increment
penalty := penaltyNumerator / totalBalance * increment
// Decrease the validator's balance by the calculated penalty
s.state.DecreaseBalance(uint64(i), penalty)
}
return nil
}

func (s *StateTransistor) ProcessSlashings() error {
// Depending on the version of the state, use different multipliers
switch s.state.Version() {
case clparams.Phase0Version:
return s.processSlashings(s.beaconConfig.ProportionalSlashingMultiplier)
case clparams.AltairVersion:
return s.processSlashings(s.beaconConfig.ProportionalSlashingMultiplierAltair)
default:
return s.processSlashings(s.beaconConfig.ProportionalSlashingMultiplierBellatrix)
}
}
97 changes: 97 additions & 0 deletions cmd/erigon-cl/core/transition/process_slashings_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package transition_test

import (
"fmt"
"testing"

"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state"
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/transition"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestProcessSlashingsNoSlash(t *testing.T) {
base := state.GetEmptyBeaconStateWithVersion(clparams.AltairVersion)
base.AddValidator(&cltypes.Validator{
Slashed: true,
})
base.AddBalance(clparams.MainnetBeaconConfig.MaxEffectiveBalance)
base.SetSlashingSegmentAt(0, 0)
base.SetSlashingSegmentAt(1, 1e9)
s := transition.New(base, &clparams.MainnetBeaconConfig, nil)
require.NoError(t, s.ProcessSlashings())
wanted := clparams.MainnetBeaconConfig.MaxEffectiveBalance
require.Equal(t, wanted, base.Balances()[0], "Unexpected slashed balance")
}

func getTestStateSlashings1() *state.BeaconState {
state := state.GetEmptyBeaconStateWithVersion(clparams.AltairVersion)
state.AddValidator(&cltypes.Validator{Slashed: true,
WithdrawableEpoch: clparams.MainnetBeaconConfig.EpochsPerSlashingsVector / 2,
EffectiveBalance: clparams.MainnetBeaconConfig.MaxEffectiveBalance})
state.AddValidator(&cltypes.Validator{ExitEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch, EffectiveBalance: clparams.MainnetBeaconConfig.MaxEffectiveBalance})
state.SetBalances([]uint64{clparams.MainnetBeaconConfig.MaxEffectiveBalance, clparams.MainnetBeaconConfig.MaxEffectiveBalance})
state.SetSlashingSegmentAt(0, 0)
state.SetSlashingSegmentAt(1, 1e9)
return state
}

func getTestStateSlashings2() *state.BeaconState {
state := getTestStateSlashings1()
state.AddValidator(&cltypes.Validator{ExitEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch, EffectiveBalance: clparams.MainnetBeaconConfig.MaxEffectiveBalance})
return state
}

func getTestStateSlashings3() *state.BeaconState {
state := getTestStateSlashings2()
state.SetSlashingSegmentAt(1, 2*1e9)
return state
}

func getTestStateSlashings4() *state.BeaconState {
state := getTestStateSlashings1()
state.SetValidatorAt(1, &cltypes.Validator{ExitEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch, EffectiveBalance: clparams.MainnetBeaconConfig.MaxEffectiveBalance - clparams.MainnetBeaconConfig.EffectiveBalanceIncrement})
state.SetBalances([]uint64{clparams.MainnetBeaconConfig.MaxEffectiveBalance - clparams.MainnetBeaconConfig.EffectiveBalanceIncrement, clparams.MainnetBeaconConfig.MaxEffectiveBalance - clparams.MainnetBeaconConfig.EffectiveBalanceIncrement})
return state
}

func TestProcessSlashingsSlash(t *testing.T) {
tests := []struct {
state *state.BeaconState
want uint64
}{
{
state: getTestStateSlashings1(),
want: uint64(30000000000),
},
{
state: getTestStateSlashings2(),
want: uint64(31000000000),
},
{
state: getTestStateSlashings3(),
want: uint64(30000000000),
},
{
state: getTestStateSlashings4(),
want: uint64(29000000000),
},
}

for i, tt := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
transitistor := transition.New(tt.state, &clparams.MainnetBeaconConfig, nil)
require.NoError(t, transitistor.ProcessSlashings())
assert.Equal(t, tt.want, tt.state.Balances()[0])
})
}
}

/*
func TestProcessSlashings_SlashedLess(t *testing.T) {
}
*/

0 comments on commit a0d236d

Please sign in to comment.