mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
WIP
This commit is contained in:
@@ -5,6 +5,8 @@ go_library(
|
|||||||
srcs = [
|
srcs = [
|
||||||
"activation.go",
|
"activation.go",
|
||||||
"attestation_data.go",
|
"attestation_data.go",
|
||||||
|
"attester_slashings.go",
|
||||||
|
"attester_slashings_helpers.go",
|
||||||
"beacon_api_beacon_chain_client.go",
|
"beacon_api_beacon_chain_client.go",
|
||||||
"beacon_api_helpers.go",
|
"beacon_api_helpers.go",
|
||||||
"beacon_api_node_client.go",
|
"beacon_api_node_client.go",
|
||||||
@@ -65,6 +67,8 @@ go_test(
|
|||||||
srcs = [
|
srcs = [
|
||||||
"activation_test.go",
|
"activation_test.go",
|
||||||
"attestation_data_test.go",
|
"attestation_data_test.go",
|
||||||
|
"attester_slashings_helpers_test.go",
|
||||||
|
"attester_slashings_test.go",
|
||||||
"beacon_api_helpers_test.go",
|
"beacon_api_helpers_test.go",
|
||||||
"beacon_api_validator_client_test.go",
|
"beacon_api_validator_client_test.go",
|
||||||
"beacon_block_converter_test.go",
|
"beacon_block_converter_test.go",
|
||||||
|
|||||||
73
validator/client/beacon-api/attester_slashings.go
Normal file
73
validator/client/beacon-api/attester_slashings.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package beacon_api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c beaconApiSlasherClient) getSlashableAttestations(ctx context.Context, in *ethpb.IndexedAttestation) (*ethpb.AttesterSlashingResponse, error) {
|
||||||
|
attesterSlashingsPoolResponse := apimiddleware.AttesterSlashingsPoolResponseJson{}
|
||||||
|
if _, err := c.jsonRestHandler.GetRestJsonResponse(ctx, "/eth/v1/beacon/pool/attester_slashings", &attesterSlashingsPoolResponse); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to get attester slashings")
|
||||||
|
}
|
||||||
|
|
||||||
|
attesterSlashings, err := convertAttesterSlashingsToProto(attesterSlashingsPoolResponse.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to convert attester slashings")
|
||||||
|
}
|
||||||
|
|
||||||
|
type mapKey struct {
|
||||||
|
targetEpoch primitives.Epoch
|
||||||
|
attestingIndex uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a map of the requested attesting indices to easily filter them
|
||||||
|
attestingIndicesMap := make(map[mapKey]bool, len(in.AttestingIndices))
|
||||||
|
for _, attestingIndex := range in.AttestingIndices {
|
||||||
|
attestingIndicesMap[mapKey{
|
||||||
|
targetEpoch: in.Data.Target.Epoch,
|
||||||
|
attestingIndex: attestingIndex,
|
||||||
|
}] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredAttesterSlashings := make([]*ethpb.AttesterSlashing, 0)
|
||||||
|
for _, attesterSlashing := range attesterSlashings {
|
||||||
|
// Keep the intersection of the Attestation_1 and Attestion_2 attesting indices
|
||||||
|
attestingIndices1Map := make(map[uint64]bool, len(attesterSlashing.Attestation_1.AttestingIndices))
|
||||||
|
for _, attestingIndex := range attesterSlashing.Attestation_1.AttestingIndices {
|
||||||
|
attestingIndices1Map[attestingIndex] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
attestingIndicesIntersection := make([]uint64, 0, len(attesterSlashing.Attestation_1.AttestingIndices))
|
||||||
|
for _, attestingIndex := range attesterSlashing.Attestation_2.AttestingIndices {
|
||||||
|
if _, ok := attestingIndices1Map[attestingIndex]; ok {
|
||||||
|
attestingIndicesIntersection = append(attestingIndicesIntersection, attestingIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, attestingIndex := range attestingIndicesIntersection {
|
||||||
|
_, foundAttestation1Match := attestingIndicesMap[mapKey{
|
||||||
|
targetEpoch: attesterSlashing.Attestation_1.Data.Target.Epoch,
|
||||||
|
attestingIndex: attestingIndex,
|
||||||
|
}]
|
||||||
|
|
||||||
|
_, foundAttestation2Match := attestingIndicesMap[mapKey{
|
||||||
|
targetEpoch: attesterSlashing.Attestation_2.Data.Target.Epoch,
|
||||||
|
attestingIndex: attestingIndex,
|
||||||
|
}]
|
||||||
|
|
||||||
|
if foundAttestation1Match || foundAttestation2Match {
|
||||||
|
filteredAttesterSlashings = append(filteredAttesterSlashings, attesterSlashing)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ðpb.AttesterSlashingResponse{
|
||||||
|
AttesterSlashings: filteredAttesterSlashings,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
70
validator/client/beacon-api/attester_slashings_helpers.go
Normal file
70
validator/client/beacon-api/attester_slashings_helpers.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package beacon_api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func convertAttesterSlashingsToProto(jsonAttesterSlashings []*apimiddleware.AttesterSlashingJson) ([]*ethpb.AttesterSlashing, error) {
|
||||||
|
attesterSlashings := make([]*ethpb.AttesterSlashing, len(jsonAttesterSlashings))
|
||||||
|
|
||||||
|
for index, jsonAttesterSlashing := range jsonAttesterSlashings {
|
||||||
|
if jsonAttesterSlashing == nil {
|
||||||
|
return nil, errors.Errorf("attester slashing at index `%d` is nil", index)
|
||||||
|
}
|
||||||
|
|
||||||
|
attestation1, err := convertIndexedAttestationToProto(jsonAttesterSlashing.Attestation_1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to get attestation 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
attestation2, err := convertIndexedAttestationToProto(jsonAttesterSlashing.Attestation_2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to get attestation 2")
|
||||||
|
}
|
||||||
|
|
||||||
|
attesterSlashings[index] = ðpb.AttesterSlashing{
|
||||||
|
Attestation_1: attestation1,
|
||||||
|
Attestation_2: attestation2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attesterSlashings, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertIndexedAttestationToProto(jsonAttestation *apimiddleware.IndexedAttestationJson) (*ethpb.IndexedAttestation, error) {
|
||||||
|
if jsonAttestation == nil {
|
||||||
|
return nil, errors.New("indexed attestation is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
attestingIndices := make([]uint64, len(jsonAttestation.AttestingIndices))
|
||||||
|
|
||||||
|
for index, jsonAttestingIndex := range jsonAttestation.AttestingIndices {
|
||||||
|
attestingIndex, err := strconv.ParseUint(jsonAttestingIndex, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to parse attesting index `%s`", jsonAttestingIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
attestingIndices[index] = attestingIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
signature, err := hexutil.Decode(jsonAttestation.Signature)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to decode attestation signature `%s`", jsonAttestation.Signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
attestationData, err := convertAttestationDataToProto(jsonAttestation.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to get attestation data")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ðpb.IndexedAttestation{
|
||||||
|
AttestingIndices: attestingIndices,
|
||||||
|
Data: attestationData,
|
||||||
|
Signature: signature,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
223
validator/client/beacon-api/attester_slashings_helpers_test.go
Normal file
223
validator/client/beacon-api/attester_slashings_helpers_test.go
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
package beacon_api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBeaconBlockProtoHelpers_ConvertAttesterSlashingsToProto(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
generateInput func() []*apimiddleware.AttesterSlashingJson
|
||||||
|
expectedResult []*ethpb.AttesterSlashing
|
||||||
|
expectedErrorMessage string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "nil attester slashing",
|
||||||
|
expectedErrorMessage: "attester slashing at index `0` is nil",
|
||||||
|
generateInput: func() []*apimiddleware.AttesterSlashingJson {
|
||||||
|
return []*apimiddleware.AttesterSlashingJson{
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bad attestation 1",
|
||||||
|
expectedErrorMessage: "failed to get attestation 1",
|
||||||
|
generateInput: func() []*apimiddleware.AttesterSlashingJson {
|
||||||
|
return []*apimiddleware.AttesterSlashingJson{
|
||||||
|
{
|
||||||
|
Attestation_1: nil,
|
||||||
|
Attestation_2: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bad attestation 2",
|
||||||
|
expectedErrorMessage: "failed to get attestation 2",
|
||||||
|
generateInput: func() []*apimiddleware.AttesterSlashingJson {
|
||||||
|
input := generateAttesterSlashingsJson()
|
||||||
|
input[0].Attestation_2 = nil
|
||||||
|
return input
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid",
|
||||||
|
generateInput: generateAttesterSlashingsJson,
|
||||||
|
expectedResult: generateAttesterSlashingsProto(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
|
result, err := convertAttesterSlashingsToProto(testCase.generateInput())
|
||||||
|
|
||||||
|
if testCase.expectedResult != nil {
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.DeepEqual(t, testCase.expectedResult, result)
|
||||||
|
} else if testCase.expectedErrorMessage != "" {
|
||||||
|
assert.ErrorContains(t, testCase.expectedErrorMessage, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateAttesterSlashingsJson() []*apimiddleware.AttesterSlashingJson {
|
||||||
|
return []*apimiddleware.AttesterSlashingJson{
|
||||||
|
{
|
||||||
|
Attestation_1: &apimiddleware.IndexedAttestationJson{
|
||||||
|
AttestingIndices: []string{"1", "2"},
|
||||||
|
Data: &apimiddleware.AttestationDataJson{
|
||||||
|
Slot: "3",
|
||||||
|
CommitteeIndex: "4",
|
||||||
|
BeaconBlockRoot: hexutil.Encode([]byte{5}),
|
||||||
|
Source: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "6",
|
||||||
|
Root: hexutil.Encode([]byte{7}),
|
||||||
|
},
|
||||||
|
Target: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "8",
|
||||||
|
Root: hexutil.Encode([]byte{9}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: hexutil.Encode([]byte{10}),
|
||||||
|
},
|
||||||
|
Attestation_2: &apimiddleware.IndexedAttestationJson{
|
||||||
|
AttestingIndices: []string{"11", "12"},
|
||||||
|
Data: &apimiddleware.AttestationDataJson{
|
||||||
|
Slot: "13",
|
||||||
|
CommitteeIndex: "14",
|
||||||
|
BeaconBlockRoot: hexutil.Encode([]byte{15}),
|
||||||
|
Source: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "16",
|
||||||
|
Root: hexutil.Encode([]byte{17}),
|
||||||
|
},
|
||||||
|
Target: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "18",
|
||||||
|
Root: hexutil.Encode([]byte{19}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: hexutil.Encode([]byte{20}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Attestation_1: &apimiddleware.IndexedAttestationJson{
|
||||||
|
AttestingIndices: []string{"21", "22"},
|
||||||
|
Data: &apimiddleware.AttestationDataJson{
|
||||||
|
Slot: "23",
|
||||||
|
CommitteeIndex: "24",
|
||||||
|
BeaconBlockRoot: hexutil.Encode([]byte{25}),
|
||||||
|
Source: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "26",
|
||||||
|
Root: hexutil.Encode([]byte{27}),
|
||||||
|
},
|
||||||
|
Target: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "28",
|
||||||
|
Root: hexutil.Encode([]byte{29}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: hexutil.Encode([]byte{30}),
|
||||||
|
},
|
||||||
|
Attestation_2: &apimiddleware.IndexedAttestationJson{
|
||||||
|
AttestingIndices: []string{"31", "32"},
|
||||||
|
Data: &apimiddleware.AttestationDataJson{
|
||||||
|
Slot: "33",
|
||||||
|
CommitteeIndex: "34",
|
||||||
|
BeaconBlockRoot: hexutil.Encode([]byte{35}),
|
||||||
|
Source: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "36",
|
||||||
|
Root: hexutil.Encode([]byte{37}),
|
||||||
|
},
|
||||||
|
Target: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "38",
|
||||||
|
Root: hexutil.Encode([]byte{39}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: hexutil.Encode([]byte{40}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateAttesterSlashingsProto() []*ethpb.AttesterSlashing {
|
||||||
|
return []*ethpb.AttesterSlashing{
|
||||||
|
{
|
||||||
|
Attestation_1: ðpb.IndexedAttestation{
|
||||||
|
AttestingIndices: []uint64{1, 2},
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: 3,
|
||||||
|
CommitteeIndex: 4,
|
||||||
|
BeaconBlockRoot: []byte{5},
|
||||||
|
Source: ðpb.Checkpoint{
|
||||||
|
Epoch: 6,
|
||||||
|
Root: []byte{7},
|
||||||
|
},
|
||||||
|
Target: ðpb.Checkpoint{
|
||||||
|
Epoch: 8,
|
||||||
|
Root: []byte{9},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: []byte{10},
|
||||||
|
},
|
||||||
|
Attestation_2: ðpb.IndexedAttestation{
|
||||||
|
AttestingIndices: []uint64{11, 12},
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: 13,
|
||||||
|
CommitteeIndex: 14,
|
||||||
|
BeaconBlockRoot: []byte{15},
|
||||||
|
Source: ðpb.Checkpoint{
|
||||||
|
Epoch: 16,
|
||||||
|
Root: []byte{17},
|
||||||
|
},
|
||||||
|
Target: ðpb.Checkpoint{
|
||||||
|
Epoch: 18,
|
||||||
|
Root: []byte{19},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: []byte{20},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Attestation_1: ðpb.IndexedAttestation{
|
||||||
|
AttestingIndices: []uint64{21, 22},
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: 23,
|
||||||
|
CommitteeIndex: 24,
|
||||||
|
BeaconBlockRoot: []byte{25},
|
||||||
|
Source: ðpb.Checkpoint{
|
||||||
|
Epoch: 26,
|
||||||
|
Root: []byte{27},
|
||||||
|
},
|
||||||
|
Target: ðpb.Checkpoint{
|
||||||
|
Epoch: 28,
|
||||||
|
Root: []byte{29},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: []byte{30},
|
||||||
|
},
|
||||||
|
Attestation_2: ðpb.IndexedAttestation{
|
||||||
|
AttestingIndices: []uint64{31, 32},
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: 33,
|
||||||
|
CommitteeIndex: 34,
|
||||||
|
BeaconBlockRoot: []byte{35},
|
||||||
|
Source: ðpb.Checkpoint{
|
||||||
|
Epoch: 36,
|
||||||
|
Root: []byte{37},
|
||||||
|
},
|
||||||
|
Target: ðpb.Checkpoint{
|
||||||
|
Epoch: 38,
|
||||||
|
Root: []byte{39},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: []byte{40},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
167
validator/client/beacon-api/attester_slashings_test.go
Normal file
167
validator/client/beacon-api/attester_slashings_test.go
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
package beacon_api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
const getSlashableAttestationsTestEndpoint = "/eth/v1/beacon/pool/attester_slashings"
|
||||||
|
|
||||||
|
func TestGetSlashableAttestations_Valid(t *testing.T) {
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
jsonAttesterSlashings := &apimiddleware.AttesterSlashingsPoolResponseJson{}
|
||||||
|
|
||||||
|
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
|
||||||
|
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
||||||
|
ctx,
|
||||||
|
getSlashableAttestationsTestEndpoint,
|
||||||
|
jsonAttesterSlashings,
|
||||||
|
).Return(
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
).SetArg(
|
||||||
|
2,
|
||||||
|
apimiddleware.AttesterSlashingsPoolResponseJson{
|
||||||
|
Data: []*apimiddleware.AttesterSlashingJson{
|
||||||
|
{
|
||||||
|
Attestation_1: &apimiddleware.IndexedAttestationJson{
|
||||||
|
AttestingIndices: []string{"1", "2", "3", "4"},
|
||||||
|
Data: &apimiddleware.AttestationDataJson{
|
||||||
|
Slot: "5",
|
||||||
|
CommitteeIndex: "6",
|
||||||
|
BeaconBlockRoot: hexutil.Encode([]byte{7}),
|
||||||
|
Source: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "8",
|
||||||
|
Root: hexutil.Encode([]byte{9}),
|
||||||
|
},
|
||||||
|
Target: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "10",
|
||||||
|
Root: hexutil.Encode([]byte{11}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: hexutil.Encode([]byte{12}),
|
||||||
|
},
|
||||||
|
Attestation_2: &apimiddleware.IndexedAttestationJson{
|
||||||
|
AttestingIndices: []string{"3", "4", "13", "14"},
|
||||||
|
Data: &apimiddleware.AttestationDataJson{
|
||||||
|
Slot: "15",
|
||||||
|
CommitteeIndex: "16",
|
||||||
|
BeaconBlockRoot: hexutil.Encode([]byte{17}),
|
||||||
|
Source: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "18",
|
||||||
|
Root: hexutil.Encode([]byte{19}),
|
||||||
|
},
|
||||||
|
Target: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "10",
|
||||||
|
Root: hexutil.Encode([]byte{21}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: hexutil.Encode([]byte{22}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Attestation_1: &apimiddleware.IndexedAttestationJson{
|
||||||
|
AttestingIndices: []string{"23", "24"},
|
||||||
|
Data: &apimiddleware.AttestationDataJson{
|
||||||
|
Slot: "25",
|
||||||
|
CommitteeIndex: "26",
|
||||||
|
BeaconBlockRoot: hexutil.Encode([]byte{27}),
|
||||||
|
Source: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "28",
|
||||||
|
Root: hexutil.Encode([]byte{29}),
|
||||||
|
},
|
||||||
|
Target: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "30",
|
||||||
|
Root: hexutil.Encode([]byte{31}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: hexutil.Encode([]byte{32}),
|
||||||
|
},
|
||||||
|
Attestation_2: &apimiddleware.IndexedAttestationJson{
|
||||||
|
AttestingIndices: []string{"33", "34"},
|
||||||
|
Data: &apimiddleware.AttestationDataJson{
|
||||||
|
Slot: "35",
|
||||||
|
CommitteeIndex: "36",
|
||||||
|
BeaconBlockRoot: hexutil.Encode([]byte{37}),
|
||||||
|
Source: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "38",
|
||||||
|
Root: hexutil.Encode([]byte{39}),
|
||||||
|
},
|
||||||
|
Target: &apimiddleware.CheckpointJson{
|
||||||
|
Epoch: "40",
|
||||||
|
Root: hexutil.Encode([]byte{41}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: hexutil.Encode([]byte{42}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
).Times(1)
|
||||||
|
|
||||||
|
slasherClient := beaconApiSlasherClient{jsonRestHandler: jsonRestHandler}
|
||||||
|
|
||||||
|
expectedAttesterSlashingResponse := ðpb.AttesterSlashingResponse{
|
||||||
|
AttesterSlashings: []*ethpb.AttesterSlashing{
|
||||||
|
{
|
||||||
|
Attestation_1: ðpb.IndexedAttestation{
|
||||||
|
AttestingIndices: []uint64{1, 2, 3, 4},
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: 5,
|
||||||
|
CommitteeIndex: 6,
|
||||||
|
BeaconBlockRoot: []byte{7},
|
||||||
|
Source: ðpb.Checkpoint{
|
||||||
|
Epoch: 8,
|
||||||
|
Root: []byte{9},
|
||||||
|
},
|
||||||
|
Target: ðpb.Checkpoint{
|
||||||
|
Epoch: 10,
|
||||||
|
Root: []byte{11},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: []byte{12},
|
||||||
|
},
|
||||||
|
Attestation_2: ðpb.IndexedAttestation{
|
||||||
|
AttestingIndices: []uint64{3, 4, 13, 14},
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: 15,
|
||||||
|
CommitteeIndex: 16,
|
||||||
|
BeaconBlockRoot: []byte{17},
|
||||||
|
Source: ðpb.Checkpoint{
|
||||||
|
Epoch: 18,
|
||||||
|
Root: []byte{19},
|
||||||
|
},
|
||||||
|
Target: ðpb.Checkpoint{
|
||||||
|
Epoch: 10,
|
||||||
|
Root: []byte{21},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: []byte{22},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
attesterSlashingResponse, err := slasherClient.getSlashableAttestations(ctx, ðpb.IndexedAttestation{
|
||||||
|
AttestingIndices: []uint64{13, 2, 14, 4, 3, 1, 23, 24, 33, 34},
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Target: ðpb.Checkpoint{
|
||||||
|
Epoch: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.DeepEqual(t, expectedAttesterSlashingResponse, attesterSlashingResponse)
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package beacon_api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -15,12 +16,30 @@ type beaconApiSlasherClient struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c beaconApiSlasherClient) IsSlashableAttestation(ctx context.Context, in *ethpb.IndexedAttestation) (*ethpb.AttesterSlashingResponse, error) {
|
func (c beaconApiSlasherClient) IsSlashableAttestation(ctx context.Context, in *ethpb.IndexedAttestation) (*ethpb.AttesterSlashingResponse, error) {
|
||||||
if c.fallbackClient != nil {
|
grpcResult, err := c.fallbackClient.IsSlashableAttestation(ctx, in)
|
||||||
return c.fallbackClient.IsSlashableAttestation(ctx, in)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement me
|
restResult, err := c.getSlashableAttestations(ctx, in)
|
||||||
panic("beaconApiSlasherClient.IsSlashableAttestation is not implemented. To use a fallback client, pass a fallback client as the last argument of NewBeaconApiSlasherClientWithFallback.")
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
marshalledGrpcResult, err := json.Marshal(grpcResult)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
marshalledRestResult, err := json.Marshal(restResult)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Errorf("***************GRPC RESULT: %s", string(marshalledGrpcResult))
|
||||||
|
log.Errorf("***************REST RESULT: %s", string(marshalledRestResult))
|
||||||
|
|
||||||
|
return c.getSlashableAttestations(ctx, in)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c beaconApiSlasherClient) IsSlashableBlock(ctx context.Context, in *ethpb.SignedBeaconBlockHeader) (*ethpb.ProposerSlashingResponse, error) {
|
func (c beaconApiSlasherClient) IsSlashableBlock(ctx context.Context, in *ethpb.SignedBeaconBlockHeader) (*ethpb.ProposerSlashingResponse, error) {
|
||||||
|
|||||||
@@ -89,66 +89,6 @@ func convertProposerSlashingSignedHeaderToProto(signedHeader *apimiddleware.Sign
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertAttesterSlashingsToProto(jsonAttesterSlashings []*apimiddleware.AttesterSlashingJson) ([]*ethpb.AttesterSlashing, error) {
|
|
||||||
attesterSlashings := make([]*ethpb.AttesterSlashing, len(jsonAttesterSlashings))
|
|
||||||
|
|
||||||
for index, jsonAttesterSlashing := range jsonAttesterSlashings {
|
|
||||||
if jsonAttesterSlashing == nil {
|
|
||||||
return nil, errors.Errorf("attester slashing at index `%d` is nil", index)
|
|
||||||
}
|
|
||||||
|
|
||||||
attestation1, err := convertIndexedAttestationToProto(jsonAttesterSlashing.Attestation_1)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to get attestation 1")
|
|
||||||
}
|
|
||||||
|
|
||||||
attestation2, err := convertIndexedAttestationToProto(jsonAttesterSlashing.Attestation_2)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to get attestation 2")
|
|
||||||
}
|
|
||||||
|
|
||||||
attesterSlashings[index] = ðpb.AttesterSlashing{
|
|
||||||
Attestation_1: attestation1,
|
|
||||||
Attestation_2: attestation2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return attesterSlashings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertIndexedAttestationToProto(jsonAttestation *apimiddleware.IndexedAttestationJson) (*ethpb.IndexedAttestation, error) {
|
|
||||||
if jsonAttestation == nil {
|
|
||||||
return nil, errors.New("indexed attestation is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
attestingIndices := make([]uint64, len(jsonAttestation.AttestingIndices))
|
|
||||||
|
|
||||||
for index, jsonAttestingIndex := range jsonAttestation.AttestingIndices {
|
|
||||||
attestingIndex, err := strconv.ParseUint(jsonAttestingIndex, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "failed to parse attesting index `%s`", jsonAttestingIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
attestingIndices[index] = attestingIndex
|
|
||||||
}
|
|
||||||
|
|
||||||
signature, err := hexutil.Decode(jsonAttestation.Signature)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "failed to decode attestation signature `%s`", jsonAttestation.Signature)
|
|
||||||
}
|
|
||||||
|
|
||||||
attestationData, err := convertAttestationDataToProto(jsonAttestation.Data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to get attestation data")
|
|
||||||
}
|
|
||||||
|
|
||||||
return ðpb.IndexedAttestation{
|
|
||||||
AttestingIndices: attestingIndices,
|
|
||||||
Data: attestationData,
|
|
||||||
Signature: signature,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertCheckpointToProto(jsonCheckpoint *apimiddleware.CheckpointJson) (*ethpb.Checkpoint, error) {
|
func convertCheckpointToProto(jsonCheckpoint *apimiddleware.CheckpointJson) (*ethpb.Checkpoint, error) {
|
||||||
if jsonCheckpoint == nil {
|
if jsonCheckpoint == nil {
|
||||||
return nil, errors.New("checkpoint is nil")
|
return nil, errors.New("checkpoint is nil")
|
||||||
|
|||||||
@@ -219,137 +219,6 @@ func TestBeaconBlockProtoHelpers_ConvertProposerSlashingSignedHeaderToProto(t *t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBeaconBlockProtoHelpers_ConvertAttesterSlashingsToProto(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
generateInput func() []*apimiddleware.AttesterSlashingJson
|
|
||||||
expectedResult []*ethpb.AttesterSlashing
|
|
||||||
expectedErrorMessage string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "nil attester slashing",
|
|
||||||
expectedErrorMessage: "attester slashing at index `0` is nil",
|
|
||||||
generateInput: func() []*apimiddleware.AttesterSlashingJson {
|
|
||||||
return []*apimiddleware.AttesterSlashingJson{
|
|
||||||
nil,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bad attestation 1",
|
|
||||||
expectedErrorMessage: "failed to get attestation 1",
|
|
||||||
generateInput: func() []*apimiddleware.AttesterSlashingJson {
|
|
||||||
return []*apimiddleware.AttesterSlashingJson{
|
|
||||||
{
|
|
||||||
Attestation_1: nil,
|
|
||||||
Attestation_2: nil,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bad attestation 2",
|
|
||||||
expectedErrorMessage: "failed to get attestation 2",
|
|
||||||
generateInput: func() []*apimiddleware.AttesterSlashingJson {
|
|
||||||
input := generateAttesterSlashings()
|
|
||||||
input[0].Attestation_2 = nil
|
|
||||||
return input
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid",
|
|
||||||
generateInput: generateAttesterSlashings,
|
|
||||||
expectedResult: []*ethpb.AttesterSlashing{
|
|
||||||
{
|
|
||||||
Attestation_1: ðpb.IndexedAttestation{
|
|
||||||
AttestingIndices: []uint64{1, 2},
|
|
||||||
Data: ðpb.AttestationData{
|
|
||||||
Slot: 3,
|
|
||||||
CommitteeIndex: 4,
|
|
||||||
BeaconBlockRoot: []byte{5},
|
|
||||||
Source: ðpb.Checkpoint{
|
|
||||||
Epoch: 6,
|
|
||||||
Root: []byte{7},
|
|
||||||
},
|
|
||||||
Target: ðpb.Checkpoint{
|
|
||||||
Epoch: 8,
|
|
||||||
Root: []byte{9},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Signature: []byte{10},
|
|
||||||
},
|
|
||||||
Attestation_2: ðpb.IndexedAttestation{
|
|
||||||
AttestingIndices: []uint64{11, 12},
|
|
||||||
Data: ðpb.AttestationData{
|
|
||||||
Slot: 13,
|
|
||||||
CommitteeIndex: 14,
|
|
||||||
BeaconBlockRoot: []byte{15},
|
|
||||||
Source: ðpb.Checkpoint{
|
|
||||||
Epoch: 16,
|
|
||||||
Root: []byte{17},
|
|
||||||
},
|
|
||||||
Target: ðpb.Checkpoint{
|
|
||||||
Epoch: 18,
|
|
||||||
Root: []byte{19},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Signature: []byte{20},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Attestation_1: ðpb.IndexedAttestation{
|
|
||||||
AttestingIndices: []uint64{21, 22},
|
|
||||||
Data: ðpb.AttestationData{
|
|
||||||
Slot: 23,
|
|
||||||
CommitteeIndex: 24,
|
|
||||||
BeaconBlockRoot: []byte{25},
|
|
||||||
Source: ðpb.Checkpoint{
|
|
||||||
Epoch: 26,
|
|
||||||
Root: []byte{27},
|
|
||||||
},
|
|
||||||
Target: ðpb.Checkpoint{
|
|
||||||
Epoch: 28,
|
|
||||||
Root: []byte{29},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Signature: []byte{30},
|
|
||||||
},
|
|
||||||
Attestation_2: ðpb.IndexedAttestation{
|
|
||||||
AttestingIndices: []uint64{31, 32},
|
|
||||||
Data: ðpb.AttestationData{
|
|
||||||
Slot: 33,
|
|
||||||
CommitteeIndex: 34,
|
|
||||||
BeaconBlockRoot: []byte{35},
|
|
||||||
Source: ðpb.Checkpoint{
|
|
||||||
Epoch: 36,
|
|
||||||
Root: []byte{37},
|
|
||||||
},
|
|
||||||
Target: ðpb.Checkpoint{
|
|
||||||
Epoch: 38,
|
|
||||||
Root: []byte{39},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Signature: []byte{40},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
|
||||||
result, err := convertAttesterSlashingsToProto(testCase.generateInput())
|
|
||||||
|
|
||||||
if testCase.expectedResult != nil {
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.DeepEqual(t, testCase.expectedResult, result)
|
|
||||||
} else if testCase.expectedErrorMessage != "" {
|
|
||||||
assert.ErrorContains(t, testCase.expectedErrorMessage, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBeaconBlockProtoHelpers_ConvertAttestationToProto(t *testing.T) {
|
func TestBeaconBlockProtoHelpers_ConvertAttestationToProto(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -1143,83 +1012,6 @@ func generateSignedBeaconBlockHeader() *apimiddleware.SignedBeaconBlockHeaderJso
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateAttesterSlashings() []*apimiddleware.AttesterSlashingJson {
|
|
||||||
return []*apimiddleware.AttesterSlashingJson{
|
|
||||||
{
|
|
||||||
Attestation_1: &apimiddleware.IndexedAttestationJson{
|
|
||||||
AttestingIndices: []string{"1", "2"},
|
|
||||||
Data: &apimiddleware.AttestationDataJson{
|
|
||||||
Slot: "3",
|
|
||||||
CommitteeIndex: "4",
|
|
||||||
BeaconBlockRoot: hexutil.Encode([]byte{5}),
|
|
||||||
Source: &apimiddleware.CheckpointJson{
|
|
||||||
Epoch: "6",
|
|
||||||
Root: hexutil.Encode([]byte{7}),
|
|
||||||
},
|
|
||||||
Target: &apimiddleware.CheckpointJson{
|
|
||||||
Epoch: "8",
|
|
||||||
Root: hexutil.Encode([]byte{9}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Signature: hexutil.Encode([]byte{10}),
|
|
||||||
},
|
|
||||||
Attestation_2: &apimiddleware.IndexedAttestationJson{
|
|
||||||
AttestingIndices: []string{"11", "12"},
|
|
||||||
Data: &apimiddleware.AttestationDataJson{
|
|
||||||
Slot: "13",
|
|
||||||
CommitteeIndex: "14",
|
|
||||||
BeaconBlockRoot: hexutil.Encode([]byte{15}),
|
|
||||||
Source: &apimiddleware.CheckpointJson{
|
|
||||||
Epoch: "16",
|
|
||||||
Root: hexutil.Encode([]byte{17}),
|
|
||||||
},
|
|
||||||
Target: &apimiddleware.CheckpointJson{
|
|
||||||
Epoch: "18",
|
|
||||||
Root: hexutil.Encode([]byte{19}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Signature: hexutil.Encode([]byte{20}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Attestation_1: &apimiddleware.IndexedAttestationJson{
|
|
||||||
AttestingIndices: []string{"21", "22"},
|
|
||||||
Data: &apimiddleware.AttestationDataJson{
|
|
||||||
Slot: "23",
|
|
||||||
CommitteeIndex: "24",
|
|
||||||
BeaconBlockRoot: hexutil.Encode([]byte{25}),
|
|
||||||
Source: &apimiddleware.CheckpointJson{
|
|
||||||
Epoch: "26",
|
|
||||||
Root: hexutil.Encode([]byte{27}),
|
|
||||||
},
|
|
||||||
Target: &apimiddleware.CheckpointJson{
|
|
||||||
Epoch: "28",
|
|
||||||
Root: hexutil.Encode([]byte{29}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Signature: hexutil.Encode([]byte{30}),
|
|
||||||
},
|
|
||||||
Attestation_2: &apimiddleware.IndexedAttestationJson{
|
|
||||||
AttestingIndices: []string{"31", "32"},
|
|
||||||
Data: &apimiddleware.AttestationDataJson{
|
|
||||||
Slot: "33",
|
|
||||||
CommitteeIndex: "34",
|
|
||||||
BeaconBlockRoot: hexutil.Encode([]byte{35}),
|
|
||||||
Source: &apimiddleware.CheckpointJson{
|
|
||||||
Epoch: "36",
|
|
||||||
Root: hexutil.Encode([]byte{37}),
|
|
||||||
},
|
|
||||||
Target: &apimiddleware.CheckpointJson{
|
|
||||||
Epoch: "38",
|
|
||||||
Root: hexutil.Encode([]byte{39}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Signature: hexutil.Encode([]byte{40}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateIndexedAttestation() *apimiddleware.IndexedAttestationJson {
|
func generateIndexedAttestation() *apimiddleware.IndexedAttestationJson {
|
||||||
return &apimiddleware.IndexedAttestationJson{
|
return &apimiddleware.IndexedAttestationJson{
|
||||||
AttestingIndices: []string{"1", "2"},
|
AttestingIndices: []string{"1", "2"},
|
||||||
|
|||||||
Reference in New Issue
Block a user