mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 21:38:05 -05:00
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:
@@ -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 {
|
||||||
|
|||||||
@@ -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'}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user