From a14870fa3f938300d674a448dbf496a48898a698 Mon Sep 17 00:00:00 2001 From: Jim McDonald Date: Wed, 28 Oct 2020 15:31:28 +0000 Subject: [PATCH] Add calculations for slot scaling --- .../best/beaconblockproposal.go | 7 +- .../beaconblockproposal/best/parameters.go | 1 + strategies/beaconblockproposal/best/score.go | 17 +- .../best/score_internal_test.go | 222 ++++++++++++++++-- 4 files changed, 228 insertions(+), 19 deletions(-) diff --git a/strategies/beaconblockproposal/best/beaconblockproposal.go b/strategies/beaconblockproposal/best/beaconblockproposal.go index 4844fcf..d18278a 100644 --- a/strategies/beaconblockproposal/best/beaconblockproposal.go +++ b/strategies/beaconblockproposal/best/beaconblockproposal.go @@ -55,8 +55,13 @@ func (s *Service) BeaconBlockProposal(ctx context.Context, slot uint64, randaoRe log.Trace().Dur("elapsed", time.Since(started)).Msg("Obtained beacon block proposal") cancel() + // Obtain the slot of the block to which the proposal refers. + // We use this to allow the scorer to score blocks with earlier parents lower. + // TODO need a go-eth2-client provider to obtain this information. + parentSlot := uint64(slot - 1) + mu.Lock() - score := scoreBeaconBlockProposal(ctx, name, proposal) + score := scoreBeaconBlockProposal(ctx, name, parentSlot, proposal) if score > bestScore || bestProposal == nil { bestScore = score bestProposal = proposal diff --git a/strategies/beaconblockproposal/best/parameters.go b/strategies/beaconblockproposal/best/parameters.go index 04bb62b..e3f39f3 100644 --- a/strategies/beaconblockproposal/best/parameters.go +++ b/strategies/beaconblockproposal/best/parameters.go @@ -32,6 +32,7 @@ type parameters struct { clientMonitor metrics.ClientMonitor processConcurrency int64 beaconBlockProposalProviders map[string]eth2client.BeaconBlockProposalProvider + signedBeaconBlockProvider eth2client.SignedBeaconBlockProvider timeout time.Duration } diff --git a/strategies/beaconblockproposal/best/score.go b/strategies/beaconblockproposal/best/score.go index aae5f83..85369dc 100644 --- a/strategies/beaconblockproposal/best/score.go +++ b/strategies/beaconblockproposal/best/score.go @@ -22,7 +22,7 @@ import ( // scoreBeaconBlockPropsal generates a score for a beacon block. // The score is relative to the reward expected by proposing the block. -func scoreBeaconBlockProposal(ctx context.Context, name string, blockProposal *spec.BeaconBlock) float64 { +func scoreBeaconBlockProposal(ctx context.Context, name string, parentSlot uint64, blockProposal *spec.BeaconBlock) float64 { if blockProposal == nil { return 0 } @@ -83,17 +83,28 @@ func scoreBeaconBlockProposal(ctx context.Context, name string, blockProposal *s } attesterSlashingScore := slashingWeight * float64(indicesSlashed) + // Scale scores by the distance between the proposal and parent slots. + scale := uint64(1) + if blockProposal.Slot <= parentSlot { + log.Warn().Uint64("slot", blockProposal.Slot).Uint64("parent_slot", parentSlot).Msg("Invalid parent slot for proposal") + scale = 32 + } else { + scale = blockProposal.Slot - parentSlot + } + log.Trace(). Uint64("slot", blockProposal.Slot). + Uint64("parent_slot", parentSlot). Str("provider", name). Float64("immediate_attestations", immediateAttestationScore). Float64("attestations", attestationScore). Float64("proposer_slashings", proposerSlashingScore). Float64("attester_slashings", attesterSlashingScore). - Float64("total", attestationScore+proposerSlashingScore+attesterSlashingScore). + Uint64("scale", scale). + Float64("total", (attestationScore+proposerSlashingScore+attesterSlashingScore)/float64(scale)). Msg("Scored block") - return attestationScore + proposerSlashingScore + attesterSlashingScore + return (attestationScore + proposerSlashingScore + attesterSlashingScore) / float64(scale) } // intersection returns a list of items common between the two sets. diff --git a/strategies/beaconblockproposal/best/score_internal_test.go b/strategies/beaconblockproposal/best/score_internal_test.go index a566088..27e4d06 100644 --- a/strategies/beaconblockproposal/best/score_internal_test.go +++ b/strategies/beaconblockproposal/best/score_internal_test.go @@ -15,6 +15,8 @@ package best import ( "context" + "encoding/hex" + "strings" "testing" spec "github.com/attestantio/go-eth2-client/spec/phase0" @@ -22,6 +24,14 @@ import ( "github.com/stretchr/testify/assert" ) +func _bytes(input string) []byte { + res, err := hex.DecodeString(strings.TrimPrefix(input, "0x")) + if err != nil { + panic(err) + } + return res +} + func aggregationBits(set uint64, total uint64) bitfield.Bitlist { bits := bitfield.NewBitlist(total) for i := uint64(0); i < set; i++ { @@ -40,19 +50,22 @@ func specificAggregationBits(set []uint64, total uint64) bitfield.Bitlist { func TestScore(t *testing.T) { tests := []struct { - name string - block *spec.BeaconBlock - score float64 - err string + name string + block *spec.BeaconBlock + parentSlot uint64 + score float64 + err string }{ { - name: "Nil", - score: 0, + name: "Nil", + parentSlot: 1, + score: 0, }, { - name: "Empty", - block: &spec.BeaconBlock{}, - score: 0, + name: "Empty", + block: &spec.BeaconBlock{}, + parentSlot: 1, + score: 0, }, { name: "SingleAttestation", @@ -69,7 +82,26 @@ func TestScore(t *testing.T) { }, }, }, - score: 1, + parentSlot: 12344, + score: 1, + }, + { + name: "SingleAttestationParentRootDistance2", + block: &spec.BeaconBlock{ + Slot: 12345, + Body: &spec.BeaconBlockBody{ + Attestations: []*spec.Attestation{ + { + AggregationBits: aggregationBits(1, 128), + Data: &spec.AttestationData{ + Slot: 12344, + }, + }, + }, + }, + }, + parentSlot: 12343, + score: 0.5, }, { name: "SingleAttestationDistance2", @@ -86,7 +118,8 @@ func TestScore(t *testing.T) { }, }, }, - score: 0.875, + parentSlot: 12344, + score: 0.875, }, { name: "TwoAttestations", @@ -109,7 +142,8 @@ func TestScore(t *testing.T) { }, }, }, - score: 2.8125, + parentSlot: 12344, + score: 2.8125, }, { name: "AttesterSlashing", @@ -136,7 +170,8 @@ func TestScore(t *testing.T) { }, }, }, - score: 1450, + parentSlot: 12344, + score: 1450, }, { name: "DuplicateAttestations", @@ -159,13 +194,170 @@ func TestScore(t *testing.T) { }, }, }, - score: 4, + parentSlot: 12344, + score: 4, + }, + { + name: "Full", + block: &spec.BeaconBlock{ + Slot: 12345, + Body: &spec.BeaconBlockBody{ + Attestations: []*spec.Attestation{ + { + AggregationBits: aggregationBits(50, 128), + Data: &spec.AttestationData{ + Slot: 12344, + }, + }, + }, + AttesterSlashings: []*spec.AttesterSlashing{ + { + Attestation1: &spec.IndexedAttestation{ + AttestingIndices: []uint64{1, 2, 3}, + }, + Attestation2: &spec.IndexedAttestation{ + AttestingIndices: []uint64{2, 3, 4}, + }, + }, + }, + ProposerSlashings: []*spec.ProposerSlashing{ + { + Header1: &spec.SignedBeaconBlockHeader{ + Message: &spec.BeaconBlockHeader{ + Slot: 10, + ProposerIndex: 1, + ParentRoot: _bytes("0x0101010101010101010101010101010101010101010101010101010101010101"), + StateRoot: _bytes("0x0202020202020202020202020202020202020202020202020202020202020202"), + BodyRoot: _bytes("0x0303030303030303030303030303030303030303030303030303030303030303"), + }, + Signature: _bytes("0x040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404"), + }, + Header2: &spec.SignedBeaconBlockHeader{ + Message: &spec.BeaconBlockHeader{ + Slot: 10, + ProposerIndex: 1, + ParentRoot: _bytes("0x0404040404040404040404040404040404040404040404040404040404040404"), + StateRoot: _bytes("0x0202020202020202020202020202020202020202020202020202020202020202"), + BodyRoot: _bytes("0x0303030303030303030303030303030303030303030303030303030303030303"), + }, + Signature: _bytes("0x040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404"), + }, + }, + }, + }, + }, + parentSlot: 12344, + score: 2150, + }, + { + name: "FullParentRootDistance2", + block: &spec.BeaconBlock{ + Slot: 12345, + Body: &spec.BeaconBlockBody{ + Attestations: []*spec.Attestation{ + { + AggregationBits: aggregationBits(50, 128), + Data: &spec.AttestationData{ + Slot: 12344, + }, + }, + }, + AttesterSlashings: []*spec.AttesterSlashing{ + { + Attestation1: &spec.IndexedAttestation{ + AttestingIndices: []uint64{1, 2, 3}, + }, + Attestation2: &spec.IndexedAttestation{ + AttestingIndices: []uint64{2, 3, 4}, + }, + }, + }, + ProposerSlashings: []*spec.ProposerSlashing{ + { + Header1: &spec.SignedBeaconBlockHeader{ + Message: &spec.BeaconBlockHeader{ + Slot: 10, + ProposerIndex: 1, + ParentRoot: _bytes("0x0101010101010101010101010101010101010101010101010101010101010101"), + StateRoot: _bytes("0x0202020202020202020202020202020202020202020202020202020202020202"), + BodyRoot: _bytes("0x0303030303030303030303030303030303030303030303030303030303030303"), + }, + Signature: _bytes("0x040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404"), + }, + Header2: &spec.SignedBeaconBlockHeader{ + Message: &spec.BeaconBlockHeader{ + Slot: 10, + ProposerIndex: 1, + ParentRoot: _bytes("0x0404040404040404040404040404040404040404040404040404040404040404"), + StateRoot: _bytes("0x0202020202020202020202020202020202020202020202020202020202020202"), + BodyRoot: _bytes("0x0303030303030303030303030303030303030303030303030303030303030303"), + }, + Signature: _bytes("0x040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404"), + }, + }, + }, + }, + }, + parentSlot: 12343, + score: 1075, + }, + { + name: "FullParentRootDistance4", + block: &spec.BeaconBlock{ + Slot: 12345, + Body: &spec.BeaconBlockBody{ + Attestations: []*spec.Attestation{ + { + AggregationBits: aggregationBits(50, 128), + Data: &spec.AttestationData{ + Slot: 12344, + }, + }, + }, + AttesterSlashings: []*spec.AttesterSlashing{ + { + Attestation1: &spec.IndexedAttestation{ + AttestingIndices: []uint64{1, 2, 3}, + }, + Attestation2: &spec.IndexedAttestation{ + AttestingIndices: []uint64{2, 3, 4}, + }, + }, + }, + ProposerSlashings: []*spec.ProposerSlashing{ + { + Header1: &spec.SignedBeaconBlockHeader{ + Message: &spec.BeaconBlockHeader{ + Slot: 10, + ProposerIndex: 1, + ParentRoot: _bytes("0x0101010101010101010101010101010101010101010101010101010101010101"), + StateRoot: _bytes("0x0202020202020202020202020202020202020202020202020202020202020202"), + BodyRoot: _bytes("0x0303030303030303030303030303030303030303030303030303030303030303"), + }, + Signature: _bytes("0x040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404"), + }, + Header2: &spec.SignedBeaconBlockHeader{ + Message: &spec.BeaconBlockHeader{ + Slot: 10, + ProposerIndex: 1, + ParentRoot: _bytes("0x0404040404040404040404040404040404040404040404040404040404040404"), + StateRoot: _bytes("0x0202020202020202020202020202020202020202020202020202020202020202"), + BodyRoot: _bytes("0x0303030303030303030303030303030303030303030303030303030303030303"), + }, + Signature: _bytes("0x040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404"), + }, + }, + }, + }, + }, + parentSlot: 12341, + score: 537.5, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - score := scoreBeaconBlockProposal(context.Background(), test.name, test.block) + score := scoreBeaconBlockProposal(context.Background(), test.name, test.parentSlot, test.block) assert.Equal(t, test.score, score) }) }