Fix sandwich attack on honest reorgs (#12418)

* Fix sandwich attack on honest reorgs

* fix test

---------

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
Potuz
2023-05-22 14:23:20 -03:00
committed by GitHub
parent c80019bd0b
commit e0e7c71eb5
5 changed files with 25 additions and 3 deletions

View File

@@ -82,6 +82,11 @@ func (f *ForkChoice) ShouldOverrideFCU() (override bool) {
if head.weight*100 > f.store.committeeWeight*params.BeaconConfig().ReorgWeightThreshold { if head.weight*100 > f.store.committeeWeight*params.BeaconConfig().ReorgWeightThreshold {
return 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 return true
} }
@@ -137,6 +142,11 @@ func (f *ForkChoice) GetProposerHead() [32]byte {
return head.root 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 // Only reorg if we are proposing early
secs, err := slots.SecondsSinceSlotStart(head.slot+1, f.store.genesisTime, uint64(time.Now().Unix())) secs, err := slots.SecondsSinceSlotStart(head.slot+1, f.store.genesisTime, uint64(time.Now().Unix()))
if err != nil { if err != nil {

View File

@@ -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) st, root, err := prepareForkchoiceState(ctx, 1, [32]byte{'a'}, [32]byte{}, [32]byte{'A'}, 0, 0)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, st, root)) 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) driftGenesisTime(f, 2, orphanLateBlockFirstThreshold+1)
st, root, err = prepareForkchoiceState(ctx, 2, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 0, 0) st, root, err = prepareForkchoiceState(ctx, 2, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 0, 0)
@@ -101,7 +105,11 @@ func TestForkChoice_GetProposerHead(t *testing.T) {
st, root, err := prepareForkchoiceState(ctx, 1, parentRoot, [32]byte{}, [32]byte{'A'}, 0, 0) st, root, err := prepareForkchoiceState(ctx, 1, parentRoot, [32]byte{}, [32]byte{'A'}, 0, 0)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, st, root)) 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) driftGenesisTime(f, 3, 1)
childRoot := [32]byte{'b'} childRoot := [32]byte{'b'}

View File

@@ -136,7 +136,7 @@ func TestGetSpec(t *testing.T) {
resp, err := server.GetSpec(context.Background(), &emptypb.Empty{}) resp, err := server.GetSpec(context.Background(), &emptypb.Empty{})
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 105, len(resp.Data)) assert.Equal(t, 106, len(resp.Data))
for k, v := range resp.Data { for k, v := range resp.Data {
switch k { switch k {
case "CONFIG_NAME": case "CONFIG_NAME":
@@ -361,6 +361,8 @@ func TestGetSpec(t *testing.T) {
assert.Equal(t, "2", v) assert.Equal(t, "2", v)
case "REORG_WEIGHT_THRESHOLD": case "REORG_WEIGHT_THRESHOLD":
assert.Equal(t, "20", v) assert.Equal(t, "20", v)
case "REORG_PARENT_WEIGHT_THRESHOLD":
assert.Equal(t, "160", v)
case "SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY": case "SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY":
default: default:
t.Errorf("Incorrect key: %s", k) t.Errorf("Incorrect key: %s", k)

View File

@@ -69,6 +69,7 @@ type BeaconChainConfig struct {
// Fork choice algorithm constants. // 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. 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. 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 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. 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.

View File

@@ -115,6 +115,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{
// Fork choice algorithm constants. // Fork choice algorithm constants.
ProposerScoreBoost: 40, ProposerScoreBoost: 40,
ReorgWeightThreshold: 20, ReorgWeightThreshold: 20,
ReorgParentWeightThreshold: 160,
ReorgMaxEpochsSinceFinalization: 2, ReorgMaxEpochsSinceFinalization: 2,
IntervalsPerSlot: 3, IntervalsPerSlot: 3,