mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 05:47:59 -05:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a264a097cc | ||
|
|
4330839bc1 | ||
|
|
835418d1e3 |
@@ -296,7 +296,7 @@ func UpdateCommitteeCache(state *pb.BeaconState) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
count, err := CommitteeCountAtSlot(state, epoch*params.BeaconConfig().SlotsPerEpoch)
|
||||
count, err := CommitteeCountAtSlot(state, StartSlot(epoch))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/sync/peerstatus"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -39,6 +41,9 @@ func (r *RegularSync) processPendingBlocks(ctx context.Context) error {
|
||||
defer span.End()
|
||||
|
||||
pids := peerstatus.Keys()
|
||||
if err := r.validatePendingSlots(); err != nil {
|
||||
return errors.Wrap(err, "could not validate pending slots")
|
||||
}
|
||||
slots := r.sortedPendingSlots()
|
||||
|
||||
span.AddAttributes(
|
||||
@@ -109,6 +114,42 @@ func (r *RegularSync) sortedPendingSlots() []int {
|
||||
slots = append(slots, int(s))
|
||||
}
|
||||
sort.Ints(slots)
|
||||
|
||||
return slots
|
||||
}
|
||||
|
||||
// validatePendingSlots validates the pending blocks
|
||||
// by their slot. If they are before the current finalized
|
||||
// checkpoint, these blocks are removed from the queue.
|
||||
func (r *RegularSync) validatePendingSlots() error {
|
||||
r.pendingQueueLock.RLock()
|
||||
defer r.pendingQueueLock.RUnlock()
|
||||
oldBlockRoots := make(map[[32]byte]bool)
|
||||
|
||||
finalizedEpoch := r.chain.FinalizedCheckpt().Epoch
|
||||
for s, b := range r.slotToPendingBlocks {
|
||||
epoch := helpers.SlotToEpoch(s)
|
||||
// remove all descendant blocks of old blocks
|
||||
if oldBlockRoots[bytesutil.ToBytes32(b.ParentRoot)] {
|
||||
root, err := ssz.SigningRoot(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldBlockRoots[root] = true
|
||||
delete(r.slotToPendingBlocks, s)
|
||||
delete(r.seenPendingBlocks, root)
|
||||
continue
|
||||
}
|
||||
// don't process old blocks
|
||||
if finalizedEpoch > 0 && epoch <= finalizedEpoch {
|
||||
blkRoot, err := ssz.SigningRoot(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldBlockRoots[blkRoot] = true
|
||||
delete(r.slotToPendingBlocks, s)
|
||||
delete(r.seenPendingBlocks, blkRoot)
|
||||
}
|
||||
}
|
||||
oldBlockRoots = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -30,8 +30,12 @@ func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks1(t *testing.T) {
|
||||
defer dbtest.TeardownDB(t, db)
|
||||
|
||||
r := &RegularSync{
|
||||
db: db,
|
||||
chain: &mock.ChainService{},
|
||||
db: db,
|
||||
chain: &mock.ChainService{
|
||||
FinalizedCheckPoint: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
},
|
||||
},
|
||||
slotToPendingBlocks: make(map[uint64]*ethpb.BeaconBlock),
|
||||
seenPendingBlocks: make(map[[32]byte]bool),
|
||||
}
|
||||
@@ -114,11 +118,14 @@ func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks2(t *testing.T) {
|
||||
})
|
||||
|
||||
r := &RegularSync{
|
||||
p2p: p1,
|
||||
db: db,
|
||||
chain: &mock.ChainService{},
|
||||
slotToPendingBlocks: make(map[uint64]*ethpb.BeaconBlock),
|
||||
seenPendingBlocks: make(map[[32]byte]bool),
|
||||
p2p: p1,
|
||||
db: db,
|
||||
chain: &mock.ChainService{
|
||||
FinalizedCheckPoint: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
},
|
||||
}, slotToPendingBlocks: make(map[uint64]*ethpb.BeaconBlock),
|
||||
seenPendingBlocks: make(map[[32]byte]bool),
|
||||
}
|
||||
peerstatus.Set(p2.PeerID(), &pb.Status{})
|
||||
|
||||
@@ -192,3 +199,66 @@ func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks2(t *testing.T) {
|
||||
t.Errorf("Incorrect size for seen pending block: got %d", len(r.seenPendingBlocks))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegularSyncBeaconBlockSubscriber_PruneOldPendingBlocks(t *testing.T) {
|
||||
db := dbtest.SetupDB(t)
|
||||
defer dbtest.TeardownDB(t, db)
|
||||
p1 := p2ptest.NewTestP2P(t)
|
||||
p2 := p2ptest.NewTestP2P(t)
|
||||
p1.Connect(p2)
|
||||
if len(p1.Host.Network().Peers()) != 1 {
|
||||
t.Error("Expected peers to be connected")
|
||||
}
|
||||
|
||||
r := &RegularSync{
|
||||
p2p: p1,
|
||||
db: db,
|
||||
chain: &mock.ChainService{
|
||||
FinalizedCheckPoint: ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
},
|
||||
}, slotToPendingBlocks: make(map[uint64]*ethpb.BeaconBlock),
|
||||
seenPendingBlocks: make(map[[32]byte]bool),
|
||||
}
|
||||
peerstatus.Set(p2.PeerID(), &pb.Status{})
|
||||
|
||||
b0 := ðpb.BeaconBlock{}
|
||||
if err := r.db.SaveBlock(context.Background(), b0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b0Root, _ := ssz.SigningRoot(b0)
|
||||
b1 := ðpb.BeaconBlock{Slot: 1, ParentRoot: b0Root[:]}
|
||||
if err := r.db.SaveBlock(context.Background(), b1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b1Root, _ := ssz.SigningRoot(b1)
|
||||
|
||||
// Incomplete block links
|
||||
b2 := ðpb.BeaconBlock{Slot: 2, ParentRoot: b1Root[:]}
|
||||
b2Root, _ := ssz.SigningRoot(b2)
|
||||
b5 := ðpb.BeaconBlock{Slot: 5, ParentRoot: b2Root[:]}
|
||||
b5Root, _ := ssz.SigningRoot(b5)
|
||||
b3 := ðpb.BeaconBlock{Slot: 3, ParentRoot: b0Root[:]}
|
||||
b3Root, _ := ssz.SigningRoot(b3)
|
||||
b4 := ðpb.BeaconBlock{Slot: 4, ParentRoot: b3Root[:]}
|
||||
b4Root, _ := ssz.SigningRoot(b4)
|
||||
|
||||
r.slotToPendingBlocks[b2.Slot] = b2
|
||||
r.seenPendingBlocks[b2Root] = true
|
||||
r.slotToPendingBlocks[b3.Slot] = b3
|
||||
r.seenPendingBlocks[b3Root] = true
|
||||
r.slotToPendingBlocks[b4.Slot] = b4
|
||||
r.seenPendingBlocks[b4Root] = true
|
||||
r.slotToPendingBlocks[b5.Slot] = b5
|
||||
r.seenPendingBlocks[b5Root] = true
|
||||
|
||||
if err := r.processPendingBlocks(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(r.slotToPendingBlocks) != 0 {
|
||||
t.Errorf("Incorrect size for slot to pending blocks cache: got %d", len(r.slotToPendingBlocks))
|
||||
}
|
||||
if len(r.seenPendingBlocks) != 0 {
|
||||
t.Errorf("Incorrect size for seen pending block: got %d", len(r.seenPendingBlocks))
|
||||
}
|
||||
}
|
||||
|
||||
5
proto/beacon/db/attestation_container.pb.go
generated
5
proto/beacon/db/attestation_container.pb.go
generated
@@ -5,12 +5,13 @@ package db
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
github_com_prysmaticlabs_go_bitfield "github.com/prysmaticlabs/go-bitfield"
|
||||
v1alpha1 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
io "io"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
@@ -5,9 +5,10 @@ package db
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
5
proto/beacon/p2p/v1/messages.pb.go
generated
5
proto/beacon/p2p/v1/messages.pb.go
generated
@@ -5,10 +5,11 @@ package ethereum_beacon_p2p_v1
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
5
proto/beacon/p2p/v1/types.pb.go
generated
5
proto/beacon/p2p/v1/types.pb.go
generated
@@ -5,12 +5,13 @@ package ethereum_beacon_p2p_v1
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
github_com_prysmaticlabs_go_bitfield "github.com/prysmaticlabs/go-bitfield"
|
||||
v1alpha1 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
io "io"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
5
proto/beacon/rpc/v1/services.pb.go
generated
5
proto/beacon/rpc/v1/services.pb.go
generated
@@ -7,13 +7,14 @@ import (
|
||||
context "context"
|
||||
encoding_binary "encoding/binary"
|
||||
fmt "fmt"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
types "github.com/gogo/protobuf/types"
|
||||
v1alpha1 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
grpc "google.golang.org/grpc"
|
||||
io "io"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
@@ -5,7 +5,6 @@ package ethereum.beacon.rpc.v1;
|
||||
import "google/protobuf/empty.proto";
|
||||
import "proto/eth/v1alpha1/beacon_block.proto";
|
||||
import "proto/eth/v1alpha1/attestation.proto";
|
||||
import "google/api/annotations.proto";
|
||||
|
||||
service AttesterService {
|
||||
rpc RequestAttestation(AttestationRequest) returns (ethereum.eth.v1alpha1.AttestationData);
|
||||
|
||||
3
proto/beacon/rpc/v1_gateway/services.pb.go
generated
3
proto/beacon/rpc/v1_gateway/services.pb.go
generated
@@ -6,6 +6,8 @@ package ethereum_beacon_rpc_v1
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
math "math"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
empty "github.com/golang/protobuf/ptypes/empty"
|
||||
v1alpha1 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
@@ -13,7 +15,6 @@ import (
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
5
proto/eth/v1alpha1/archive.pb.go
generated
5
proto/eth/v1alpha1/archive.pb.go
generated
@@ -5,10 +5,11 @@ package eth
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
5
proto/eth/v1alpha1/attestation.pb.go
generated
5
proto/eth/v1alpha1/attestation.pb.go
generated
@@ -5,11 +5,12 @@ package eth
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
github_com_prysmaticlabs_go_bitfield "github.com/prysmaticlabs/go-bitfield"
|
||||
io "io"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
5
proto/eth/v1alpha1/beacon_block.pb.go
generated
5
proto/eth/v1alpha1/beacon_block.pb.go
generated
@@ -5,10 +5,11 @@ package eth
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
5
proto/eth/v1alpha1/beacon_chain.pb.go
generated
5
proto/eth/v1alpha1/beacon_chain.pb.go
generated
@@ -6,13 +6,14 @@ package eth
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
types "github.com/gogo/protobuf/types"
|
||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
grpc "google.golang.org/grpc"
|
||||
io "io"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
5
proto/eth/v1alpha1/node.pb.go
generated
5
proto/eth/v1alpha1/node.pb.go
generated
@@ -6,12 +6,13 @@ package eth
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
types "github.com/gogo/protobuf/types"
|
||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
grpc "google.golang.org/grpc"
|
||||
io "io"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
5
proto/eth/v1alpha1/slasher.pb.go
generated
5
proto/eth/v1alpha1/slasher.pb.go
generated
@@ -6,11 +6,12 @@ package eth
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
types "github.com/gogo/protobuf/types"
|
||||
grpc "google.golang.org/grpc"
|
||||
io "io"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
5
proto/eth/v1alpha1/validator.pb.go
generated
5
proto/eth/v1alpha1/validator.pb.go
generated
@@ -7,13 +7,14 @@ import (
|
||||
context "context"
|
||||
encoding_binary "encoding/binary"
|
||||
fmt "fmt"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
types "github.com/gogo/protobuf/types"
|
||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
grpc "google.golang.org/grpc"
|
||||
io "io"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
3
proto/sharding/p2p/v1/messages.pb.go
generated
3
proto/sharding/p2p/v1/messages.pb.go
generated
@@ -5,9 +5,10 @@ package ethereum_sharding_p2p_v1
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
@@ -32,7 +32,8 @@ func detectMin(attestationEpochSpan uint64,
|
||||
attestationSourceEpoch uint64) uint64 {
|
||||
|
||||
minSpan := uint64(recorderEpochSpan.MinEpochSpan)
|
||||
if minSpan < attestationEpochSpan {
|
||||
|
||||
if minSpan > 0 && minSpan < attestationEpochSpan {
|
||||
return minSpan + attestationSourceEpoch
|
||||
}
|
||||
return 0
|
||||
@@ -45,6 +46,13 @@ func detectMin(attestationEpochSpan uint64,
|
||||
// Logic for this detection method was designed by https://github.com/protolambda
|
||||
// Detailed here: https://github.com/protolambda/eth2-surround/blob/master/README.md#min-max-surround
|
||||
func (ss *Server) DetectAndUpdateMaxEpochSpan(ctx context.Context, source uint64, target uint64, validatorIdx uint64) (uint64, error) {
|
||||
if target < source {
|
||||
return 0, fmt.Errorf(
|
||||
"target: %d < source: %d ",
|
||||
target,
|
||||
source,
|
||||
)
|
||||
}
|
||||
targetEpoch, span, spanMap, err := ss.detectSlashingByEpochSpan(source, target, validatorIdx, detectMax)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -53,7 +61,7 @@ func (ss *Server) DetectAndUpdateMaxEpochSpan(ctx context.Context, source uint64
|
||||
return targetEpoch, nil
|
||||
}
|
||||
for i := uint64(1); i < target-source; i++ {
|
||||
val := uint32(span - i - 1)
|
||||
val := uint32(span - i)
|
||||
if _, ok := spanMap.EpochSpanMap[source+i]; !ok {
|
||||
spanMap.EpochSpanMap[source+i] = ðpb.MinMaxEpochSpan{}
|
||||
}
|
||||
@@ -77,6 +85,13 @@ func (ss *Server) DetectAndUpdateMaxEpochSpan(ctx context.Context, source uint64
|
||||
// Logic is following the detection method designed by https://github.com/protolambda
|
||||
// Detailed here: https://github.com/protolambda/eth2-surround/blob/master/README.md#min-max-surround
|
||||
func (ss *Server) DetectAndUpdateMinEpochSpan(ctx context.Context, source uint64, target uint64, validatorIdx uint64) (uint64, error) {
|
||||
if target < source {
|
||||
return 0, fmt.Errorf(
|
||||
"target: %d < source: %d ",
|
||||
target,
|
||||
source,
|
||||
)
|
||||
}
|
||||
targetEpoch, _, spanMap, err := ss.detectSlashingByEpochSpan(source, target, validatorIdx, detectMin)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -109,7 +124,7 @@ func (ss *Server) DetectAndUpdateMinEpochSpan(ctx context.Context, source uint64
|
||||
// attestation target. This method receives a detector function in order to be used
|
||||
// for both surrounding and surrounded vote cases.
|
||||
func (ss *Server) detectSlashingByEpochSpan(source, target, validatorIdx uint64, detector detectFn) (uint64, uint64, *ethpb.EpochSpanMap, error) {
|
||||
span := target - source + 1
|
||||
span := target - source
|
||||
if span > params.BeaconConfig().WeakSubjectivityPeriod {
|
||||
return 0, span, nil, fmt.Errorf("target: %d - source: %d > weakSubjectivityPeriod",
|
||||
params.BeaconConfig().WeakSubjectivityPeriod,
|
||||
|
||||
@@ -45,7 +45,18 @@ func (ss *Server) IsSlashableAttestation(ctx context.Context, req *ethpb.Indexed
|
||||
}
|
||||
}
|
||||
|
||||
//TODO(#3133): add surround detection
|
||||
for _, idx := range indices {
|
||||
atts, err := ss.DetectSurroundVotes(ctx, req.Data.Source.Epoch, req.Data.Target.Epoch, idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, ia := range atts {
|
||||
atsSlashinngRes.AttesterSlashing = append(atsSlashinngRes.AttesterSlashing, ðpb.AttesterSlashing{
|
||||
Attestation_1: req,
|
||||
Attestation_2: ia,
|
||||
})
|
||||
}
|
||||
}
|
||||
return atsSlashinngRes, nil
|
||||
}
|
||||
|
||||
@@ -87,3 +98,40 @@ func (ss *Server) SlashableAttestations(req *types.Empty, server ethpb.Slasher_S
|
||||
//TODO(3133): implement stream provider for newly discovered listening to slashable attestation.
|
||||
return status.Error(codes.Unimplemented, "not implemented")
|
||||
}
|
||||
|
||||
// DetectSurroundVotes is a method used to return the attestation that were detected
|
||||
// by min max surround detection method.
|
||||
func (ss *Server) DetectSurroundVotes(ctx context.Context, source uint64, target uint64, validatorIdx uint64) ([]*ethpb.IndexedAttestation, error) {
|
||||
minTargetEpoch, err := ss.DetectAndUpdateMinEpochSpan(ctx, source, target, validatorIdx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
maxTargetEpoch, err := ss.DetectAndUpdateMaxEpochSpan(ctx, source, target, validatorIdx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var idxAtts []*ethpb.IndexedAttestation
|
||||
if minTargetEpoch > 0 {
|
||||
attestations, err := ss.SlasherDB.IndexedAttestation(minTargetEpoch, validatorIdx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, ia := range attestations {
|
||||
if ia.Data.Source.Epoch > source && ia.Data.Target.Epoch < target {
|
||||
idxAtts = append(idxAtts, ia)
|
||||
}
|
||||
}
|
||||
}
|
||||
if maxTargetEpoch > 0 {
|
||||
attestations, err := ss.SlasherDB.IndexedAttestation(maxTargetEpoch, validatorIdx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, ia := range attestations {
|
||||
if ia.Data.Source.Epoch < source && ia.Data.Target.Epoch > target {
|
||||
idxAtts = append(idxAtts, ia)
|
||||
}
|
||||
}
|
||||
}
|
||||
return idxAtts, nil
|
||||
}
|
||||
|
||||
@@ -418,3 +418,154 @@ func TestServer_DontSlashSameAttestationData(t *testing.T) {
|
||||
t.Errorf("Should not return slashaing proof for same data: %v", sr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_SlashSurroundedAttestation(t *testing.T) {
|
||||
dbs := db.SetupSlasherDB(t)
|
||||
defer db.TeardownSlasherDB(t, dbs)
|
||||
ctx := context.Background()
|
||||
slasherServer := &Server{
|
||||
ctx: ctx,
|
||||
SlasherDB: dbs,
|
||||
}
|
||||
ia1 := ðpb.IndexedAttestation{
|
||||
CustodyBit_0Indices: []uint64{0},
|
||||
CustodyBit_1Indices: []uint64{},
|
||||
Signature: []byte("sig2"),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 4*params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
Index: 0,
|
||||
BeaconBlockRoot: []byte("block1"),
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{Epoch: 4},
|
||||
},
|
||||
}
|
||||
ia2 := ðpb.IndexedAttestation{
|
||||
CustodyBit_0Indices: []uint64{0},
|
||||
CustodyBit_1Indices: []uint64{},
|
||||
Signature: []byte("sig1"),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 4*params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
Index: 0,
|
||||
BeaconBlockRoot: []byte("block2"),
|
||||
Source: ðpb.Checkpoint{Epoch: 2},
|
||||
Target: ðpb.Checkpoint{Epoch: 3},
|
||||
},
|
||||
}
|
||||
want := ðpb.AttesterSlashing{
|
||||
Attestation_1: ia2,
|
||||
Attestation_2: ia1,
|
||||
}
|
||||
|
||||
if _, err := slasherServer.IsSlashableAttestation(ctx, ia1); err != nil {
|
||||
t.Errorf("Could not call RPC method: %v", err)
|
||||
}
|
||||
sr, err := slasherServer.IsSlashableAttestation(ctx, ia2)
|
||||
if err != nil {
|
||||
t.Errorf("Could not call RPC method: %v", err)
|
||||
}
|
||||
if len(sr.AttesterSlashing) != 1 {
|
||||
t.Fatalf("Should return 1 slashaing proof: %v", sr.AttesterSlashing)
|
||||
}
|
||||
if !proto.Equal(sr.AttesterSlashing[0], want) {
|
||||
t.Errorf("Wanted slashing proof: %v got: %v", want, sr.AttesterSlashing[0])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_SlashSurroundAttestation(t *testing.T) {
|
||||
dbs := db.SetupSlasherDB(t)
|
||||
defer db.TeardownSlasherDB(t, dbs)
|
||||
ctx := context.Background()
|
||||
slasherServer := &Server{
|
||||
ctx: ctx,
|
||||
SlasherDB: dbs,
|
||||
}
|
||||
ia1 := ðpb.IndexedAttestation{
|
||||
CustodyBit_0Indices: []uint64{0},
|
||||
CustodyBit_1Indices: []uint64{},
|
||||
Signature: []byte("sig2"),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 4*params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
Index: 0,
|
||||
BeaconBlockRoot: []byte("block1"),
|
||||
Source: ðpb.Checkpoint{Epoch: 2},
|
||||
Target: ðpb.Checkpoint{Epoch: 3},
|
||||
},
|
||||
}
|
||||
ia2 := ðpb.IndexedAttestation{
|
||||
CustodyBit_0Indices: []uint64{0},
|
||||
CustodyBit_1Indices: []uint64{},
|
||||
Signature: []byte("sig1"),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 4*params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
Index: 0,
|
||||
BeaconBlockRoot: []byte("block2"),
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{Epoch: 4},
|
||||
},
|
||||
}
|
||||
want := ðpb.AttesterSlashing{
|
||||
Attestation_1: ia2,
|
||||
Attestation_2: ia1,
|
||||
}
|
||||
|
||||
if _, err := slasherServer.IsSlashableAttestation(ctx, ia1); err != nil {
|
||||
t.Errorf("Could not call RPC method: %v", err)
|
||||
}
|
||||
sr, err := slasherServer.IsSlashableAttestation(ctx, ia2)
|
||||
if err != nil {
|
||||
t.Errorf("Could not call RPC method: %v", err)
|
||||
}
|
||||
if len(sr.AttesterSlashing) != 1 {
|
||||
t.Fatalf("Should return 1 slashaing proof: %v", sr.AttesterSlashing)
|
||||
}
|
||||
if !proto.Equal(sr.AttesterSlashing[0], want) {
|
||||
t.Errorf("Wanted slashing proof: %v got: %v", want, sr.AttesterSlashing[0])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_DontSlashValidAttestations(t *testing.T) {
|
||||
dbs := db.SetupSlasherDB(t)
|
||||
defer db.TeardownSlasherDB(t, dbs)
|
||||
ctx := context.Background()
|
||||
slasherServer := &Server{
|
||||
ctx: ctx,
|
||||
SlasherDB: dbs,
|
||||
}
|
||||
ia1 := ðpb.IndexedAttestation{
|
||||
CustodyBit_0Indices: []uint64{0},
|
||||
CustodyBit_1Indices: []uint64{},
|
||||
Signature: []byte("sig2"),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 5*params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
Index: 0,
|
||||
BeaconBlockRoot: []byte("block1"),
|
||||
Source: ðpb.Checkpoint{Epoch: 2},
|
||||
Target: ðpb.Checkpoint{Epoch: 4},
|
||||
},
|
||||
}
|
||||
ia2 := ðpb.IndexedAttestation{
|
||||
CustodyBit_0Indices: []uint64{0},
|
||||
CustodyBit_1Indices: []uint64{},
|
||||
Signature: []byte("sig1"),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 5*params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
Index: 0,
|
||||
BeaconBlockRoot: []byte("block2"),
|
||||
Source: ðpb.Checkpoint{Epoch: 3},
|
||||
Target: ðpb.Checkpoint{Epoch: 5},
|
||||
},
|
||||
}
|
||||
|
||||
if _, err := slasherServer.IsSlashableAttestation(ctx, ia1); err != nil {
|
||||
t.Errorf("Could not call RPC method: %v", err)
|
||||
}
|
||||
sr, err := slasherServer.IsSlashableAttestation(ctx, ia2)
|
||||
if err != nil {
|
||||
t.Errorf("Could not call RPC method: %v", err)
|
||||
}
|
||||
if len(sr.AttesterSlashing) != 0 {
|
||||
t.Errorf("Should not return slashaing proof for same data: %v", sr)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user