mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-29 06:37:17 +00:00
121 lines
3.2 KiB
Go
121 lines
3.2 KiB
Go
|
package evaluators
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
|
||
|
"github.com/gogo/protobuf/types"
|
||
|
eth "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||
|
"github.com/prysmaticlabs/go-bitfield"
|
||
|
"github.com/prysmaticlabs/go-ssz"
|
||
|
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||
|
"github.com/prysmaticlabs/prysm/shared/params"
|
||
|
"github.com/prysmaticlabs/prysm/shared/sliceutil"
|
||
|
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||
|
"google.golang.org/grpc"
|
||
|
)
|
||
|
|
||
|
// InjectDoubleVote broadcasts a double vote into the beacon node pool for the slasher to detect.
|
||
|
var InjectDoubleVote = Evaluator{
|
||
|
Name: "inject_double_vote_%d",
|
||
|
Policy: beforeEpoch(2),
|
||
|
Evaluation: insertDoubleAttestationIntoPool,
|
||
|
}
|
||
|
|
||
|
var slashedIndices []uint64
|
||
|
|
||
|
// Not including first epoch because of issues with genesis.
|
||
|
func beforeEpoch(epoch uint64) func(uint64) bool {
|
||
|
return func(currentEpoch uint64) bool {
|
||
|
return currentEpoch < epoch
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func insertDoubleAttestationIntoPool(conns ...*grpc.ClientConn) error {
|
||
|
conn := conns[0]
|
||
|
valClient := eth.NewBeaconNodeValidatorClient(conn)
|
||
|
beaconClient := eth.NewBeaconChainClient(conn)
|
||
|
|
||
|
ctx := context.Background()
|
||
|
chainHead, err := beaconClient.GetChainHead(ctx, &types.Empty{})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
_, privKeys, err := testutil.DeterministicDepositsAndKeys(64)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
pubKeys := make([][]byte, len(privKeys))
|
||
|
for i, priv := range privKeys {
|
||
|
pubKeys[i] = priv.PublicKey().Marshal()
|
||
|
}
|
||
|
duties, err := valClient.GetDuties(ctx, ð.DutiesRequest{
|
||
|
Epoch: chainHead.HeadEpoch,
|
||
|
PublicKeys: pubKeys,
|
||
|
})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
var committeeIndex uint64
|
||
|
var committee []uint64
|
||
|
for _, duty := range duties.Duties {
|
||
|
if duty.AttesterSlot == chainHead.HeadSlot-1 {
|
||
|
committeeIndex = duty.CommitteeIndex
|
||
|
committee = duty.Committee
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
attDataReq := ð.AttestationDataRequest{
|
||
|
CommitteeIndex: committeeIndex,
|
||
|
Slot: chainHead.HeadSlot - 1,
|
||
|
}
|
||
|
|
||
|
attData, err := valClient.GetAttestationData(ctx, attDataReq)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
blockRoot := bytesutil.ToBytes32([]byte("muahahahaha I'm an evil validator"))
|
||
|
attData.BeaconBlockRoot = blockRoot[:]
|
||
|
|
||
|
dataRoot, err := ssz.HashTreeRoot(attData)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
domainResp, err := valClient.DomainData(ctx, ð.DomainRequest{
|
||
|
Epoch: attData.Target.Epoch,
|
||
|
Domain: params.BeaconConfig().DomainBeaconAttester[:],
|
||
|
})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
valsToSlash := uint64(2)
|
||
|
for i := uint64(0); i < valsToSlash && i < uint64(len(committee)); i++ {
|
||
|
if len(sliceutil.IntersectionUint64(slashedIndices, []uint64{committee[i]})) > 0 {
|
||
|
valsToSlash++
|
||
|
continue
|
||
|
}
|
||
|
// Set the bits of half the committee to be slashed.
|
||
|
attBitfield := bitfield.NewBitlist(uint64(len(committee)))
|
||
|
attBitfield.SetBitAt(i, true)
|
||
|
|
||
|
att := ð.Attestation{
|
||
|
AggregationBits: attBitfield,
|
||
|
Data: attData,
|
||
|
Signature: privKeys[committee[i]].Sign(dataRoot[:], domainResp.SignatureDomain).Marshal(),
|
||
|
}
|
||
|
for _, conn := range conns {
|
||
|
client := eth.NewBeaconNodeValidatorClient(conn)
|
||
|
_, err = client.ProposeAttestation(ctx, att)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
slashedIndices = append(slashedIndices, committee[i])
|
||
|
}
|
||
|
return nil
|
||
|
}
|