Skip to content

Commit

Permalink
Fix sandwich attack on honest reorgs (#12418)
Browse files Browse the repository at this point in the history
* Fix sandwich attack on honest reorgs

* fix test

---------

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
  • Loading branch information
potuz and prylabs-bulldozer[bot] authored May 22, 2023
1 parent c80019b commit e0e7c71
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 3 deletions.
10 changes: 10 additions & 0 deletions beacon-chain/forkchoice/doubly-linked-tree/reorg_late_blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ func (f *ForkChoice) ShouldOverrideFCU() (override bool) {
if head.weight*100 > f.store.committeeWeight*params.BeaconConfig().ReorgWeightThreshold {
return
}

// Only orphan a block if the parent LMD vote is strong
if parent.weight*100 < f.store.committeeWeight*params.BeaconConfig().ReorgParentWeightThreshold {
panic(f.store.committeeWeight)
}
return true
}

Expand Down Expand Up @@ -137,6 +142,11 @@ func (f *ForkChoice) GetProposerHead() [32]byte {
return head.root
}

// Only orphan a block if the parent LMD vote is strong
if parent.weight*100 < f.store.committeeWeight*params.BeaconConfig().ReorgParentWeightThreshold {
return head.root
}

// Only reorg if we are proposing early
secs, err := slots.SecondsSinceSlotStart(head.slot+1, f.store.genesisTime, uint64(time.Now().Unix()))
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ func TestForkChoice_ShouldOverrideFCU(t *testing.T) {
st, root, err := prepareForkchoiceState(ctx, 1, [32]byte{'a'}, [32]byte{}, [32]byte{'A'}, 0, 0)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, st, root))
f.ProcessAttestation(ctx, []uint64{0, 1, 2}, root, 0)
attesters := make([]uint64, f.numActiveValidators-64)
for i := range attesters {
attesters[i] = uint64(i + 64)
}
f.ProcessAttestation(ctx, attesters, root, 0)

driftGenesisTime(f, 2, orphanLateBlockFirstThreshold+1)
st, root, err = prepareForkchoiceState(ctx, 2, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 0, 0)
Expand Down Expand Up @@ -101,7 +105,11 @@ func TestForkChoice_GetProposerHead(t *testing.T) {
st, root, err := prepareForkchoiceState(ctx, 1, parentRoot, [32]byte{}, [32]byte{'A'}, 0, 0)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, st, root))
f.ProcessAttestation(ctx, []uint64{0, 1, 2}, root, 0)
attesters := make([]uint64, f.numActiveValidators-64)
for i := range attesters {
attesters[i] = uint64(i + 64)
}
f.ProcessAttestation(ctx, attesters, root, 0)

driftGenesisTime(f, 3, 1)
childRoot := [32]byte{'b'}
Expand Down
4 changes: 3 additions & 1 deletion beacon-chain/rpc/eth/beacon/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func TestGetSpec(t *testing.T) {
resp, err := server.GetSpec(context.Background(), &emptypb.Empty{})
require.NoError(t, err)

assert.Equal(t, 105, len(resp.Data))
assert.Equal(t, 106, len(resp.Data))
for k, v := range resp.Data {
switch k {
case "CONFIG_NAME":
Expand Down Expand Up @@ -361,6 +361,8 @@ func TestGetSpec(t *testing.T) {
assert.Equal(t, "2", v)
case "REORG_WEIGHT_THRESHOLD":
assert.Equal(t, "20", v)
case "REORG_PARENT_WEIGHT_THRESHOLD":
assert.Equal(t, "160", v)
case "SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY":
default:
t.Errorf("Incorrect key: %s", k)
Expand Down
1 change: 1 addition & 0 deletions config/params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ type BeaconChainConfig struct {
// Fork choice algorithm constants.
ProposerScoreBoost uint64 `yaml:"PROPOSER_SCORE_BOOST" spec:"true"` // ProposerScoreBoost defines a value that is a % of the committee weight for fork-choice boosting.
ReorgWeightThreshold uint64 `yaml:"REORG_WEIGHT_THRESHOLD" spec:"true"` // ReorgWeightThreshold defines a value that is a % of the committee weight to consider a block weak and subject to being orphaned.
ReorgParentWeightThreshold uint64 `yaml:"REORG_PARENT_WEIGHT_THRESHOLD" spec:"true"` // ReorgParentWeightThreshold defines a value that is a % of the committee weight to consider a parent block strong and subject its child to being orphaned.
ReorgMaxEpochsSinceFinalization primitives.Epoch `yaml:"REORG_MAX_EPOCHS_SINCE_FINALIZATION" spec:"true"` // This defines a limit to consider safe to orphan a block if the network is finalizing
IntervalsPerSlot uint64 `yaml:"INTERVALS_PER_SLOT" spec:"true"` // IntervalsPerSlot defines the number of fork choice intervals in a slot defined in the fork choice spec.

Expand Down
1 change: 1 addition & 0 deletions config/params/mainnet_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{
// Fork choice algorithm constants.
ProposerScoreBoost: 40,
ReorgWeightThreshold: 20,
ReorgParentWeightThreshold: 160,
ReorgMaxEpochsSinceFinalization: 2,
IntervalsPerSlot: 3,

Expand Down

0 comments on commit e0e7c71

Please sign in to comment.