From 21b2300cdc9f78eb3fcd9bdca4c4bede5ec749b3 Mon Sep 17 00:00:00 2001 From: Potuz Date: Mon, 6 May 2024 11:34:34 -0300 Subject: [PATCH] Add testing utility methods to return randomly populated ePBS objects --- testing/util/BUILD.bazel | 1 - testing/util/payload_attestation.go | 45 -- testing/util/random/BUILD.bazel | 15 + testing/util/random/epbs.go | 419 +++++++++++++++++++ validator/client/BUILD.bazel | 1 + validator/client/payload_attestation_test.go | 4 +- 6 files changed, 437 insertions(+), 48 deletions(-) delete mode 100644 testing/util/payload_attestation.go create mode 100644 testing/util/random/BUILD.bazel create mode 100644 testing/util/random/epbs.go diff --git a/testing/util/BUILD.bazel b/testing/util/BUILD.bazel index b895908b5a1b..7871191c5ad3 100644 --- a/testing/util/BUILD.bazel +++ b/testing/util/BUILD.bazel @@ -19,7 +19,6 @@ go_library( "electra.go", "helpers.go", "merge.go", - "payload_attestation.go", "state.go", "sync_aggregate.go", "sync_committee.go", diff --git a/testing/util/payload_attestation.go b/testing/util/payload_attestation.go deleted file mode 100644 index a66a4d1e5a7b..000000000000 --- a/testing/util/payload_attestation.go +++ /dev/null @@ -1,45 +0,0 @@ -package util - -import ( - "crypto/rand" - "math/big" - "testing" - - fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" - "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" - ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" -) - -// GenerateRandomPayloadAttestationData generates a random PayloadAttestationData for testing purposes. -func GenerateRandomPayloadAttestationData(t *testing.T) *ethpb.PayloadAttestationData { - // Generate a random BeaconBlockRoot - randomBytes := make([]byte, fieldparams.RootLength) - _, err := rand.Read(randomBytes) - if err != nil { - t.Fatalf("Failed to generate random BeaconBlockRoot: %v", err) - } - - // Generate a random Slot value - randomSlot, err := rand.Int(rand.Reader, big.NewInt(10000)) - if err != nil { - t.Fatalf("Failed to generate random Slot: %v", err) - } - - payloadStatuses := []primitives.PTCStatus{ - primitives.PAYLOAD_ABSENT, - primitives.PAYLOAD_PRESENT, - primitives.PAYLOAD_WITHHELD, - } - // Select a random PayloadStatus - index, err := rand.Int(rand.Reader, big.NewInt(int64(len(payloadStatuses)))) - if err != nil { - t.Fatalf("Failed to select random PayloadStatus: %v", err) - } - randomPayloadStatus := payloadStatuses[index.Int64()] - - return ðpb.PayloadAttestationData{ - BeaconBlockRoot: randomBytes, - Slot: primitives.Slot(randomSlot.Uint64()), - PayloadStatus: randomPayloadStatus, - } -} diff --git a/testing/util/random/BUILD.bazel b/testing/util/random/BUILD.bazel new file mode 100644 index 000000000000..c3d7b9595a4b --- /dev/null +++ b/testing/util/random/BUILD.bazel @@ -0,0 +1,15 @@ +load("@prysm//tools/go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["epbs.go"], + importpath = "github.com/prysmaticlabs/prysm/v5/testing/util/random", + visibility = ["//visibility:public"], + deps = [ + "//config/fieldparams:go_default_library", + "//consensus-types/primitives:go_default_library", + "//proto/engine/v1:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + "@com_github_prysmaticlabs_go_bitfield//:go_default_library", + ], +) diff --git a/testing/util/random/epbs.go b/testing/util/random/epbs.go new file mode 100644 index 000000000000..4a26b75ac63f --- /dev/null +++ b/testing/util/random/epbs.go @@ -0,0 +1,419 @@ +package random + +import ( + "crypto/rand" + "encoding/binary" + "math/big" + "testing" + + "github.com/prysmaticlabs/go-bitfield" + fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" +) + +// SignedBeaconBlock creates a random SignedBeaconBlockEPBS for testing purposes. +func SignedBeaconBlock(t *testing.T) *ethpb.SignedBeaconBlockEpbs { + return ðpb.SignedBeaconBlockEpbs{ + Block: BeaconBlock(t), + Signature: randomBytes(96, t), + } +} + +// BeaconBlock creates a random BeaconBlockEPBS for testing purposes. +func BeaconBlock(t *testing.T) *ethpb.BeaconBlockEpbs { + return ðpb.BeaconBlockEpbs{ + Slot: primitives.Slot(randomUint64(t)), + ProposerIndex: primitives.ValidatorIndex(randomUint64(t)), + ParentRoot: randomBytes(32, t), + StateRoot: randomBytes(32, t), + Body: BeaconBlockBody(t), + } +} + +// BeaconBlockBody creates a random BeaconBlockBodyEPBS for testing purposes. +func BeaconBlockBody(t *testing.T) *ethpb.BeaconBlockBodyEpbs { + return ðpb.BeaconBlockBodyEpbs{ + RandaoReveal: randomBytes(96, t), + Eth1Data: ðpb.Eth1Data{ + DepositRoot: randomBytes(32, t), + DepositCount: randomUint64(t), + BlockHash: randomBytes(32, t), + }, + Graffiti: randomBytes(32, t), + ProposerSlashings: []*ethpb.ProposerSlashing{ + {Header_1: SignedBeaconBlockHeader(t), + Header_2: SignedBeaconBlockHeader(t)}, + }, + AttesterSlashings: []*ethpb.AttesterSlashing{ + { + Attestation_1: IndexedAttestation(t), + Attestation_2: IndexedAttestation(t), + }, + }, + Attestations: []*ethpb.Attestation{Attestation(t), Attestation(t), Attestation(t)}, + Deposits: []*ethpb.Deposit{Deposit(t), Deposit(t), Deposit(t)}, + VoluntaryExits: []*ethpb.SignedVoluntaryExit{SignedVoluntaryExit(t), SignedVoluntaryExit(t)}, + SyncAggregate: ðpb.SyncAggregate{ + SyncCommitteeBits: bitfield.NewBitvector512(), + SyncCommitteeSignature: randomBytes(96, t), + }, + BlsToExecutionChanges: []*ethpb.SignedBLSToExecutionChange{SignedBLSToExecutionChange(t), SignedBLSToExecutionChange(t)}, + SignedExecutionPayloadHeader: SignedExecutionPayloadHeader(t), + PayloadAttestations: []*ethpb.PayloadAttestation{ + PayloadAttestation(t), PayloadAttestation(t), PayloadAttestation(t), PayloadAttestation(t), + }, + } +} + +// SignedBeaconBlockHeader creates a random SignedBeaconBlockHeader for testing purposes. +func SignedBeaconBlockHeader(t *testing.T) *ethpb.SignedBeaconBlockHeader { + return ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: primitives.Slot(randomUint64(t)), + ProposerIndex: primitives.ValidatorIndex(randomUint64(t)), + ParentRoot: randomBytes(32, t), + StateRoot: randomBytes(32, t), + BodyRoot: randomBytes(32, t), + }, + Signature: randomBytes(96, t), + } +} + +// IndexedAttestation creates a random IndexedAttestation for testing purposes. +func IndexedAttestation(t *testing.T) *ethpb.IndexedAttestation { + return ðpb.IndexedAttestation{ + AttestingIndices: []uint64{randomUint64(t), randomUint64(t), randomUint64(t)}, + Data: AttestationData(t), + Signature: randomBytes(96, t), + } +} + +// Attestation creates a random Attestation for testing purposes. +func Attestation(t *testing.T) *ethpb.Attestation { + return ðpb.Attestation{ + AggregationBits: bitfield.NewBitlist(123), + Data: AttestationData(t), + Signature: randomBytes(96, t), + } +} + +// AttestationData creates a random AttestationData for testing purposes. +func AttestationData(t *testing.T) *ethpb.AttestationData { + return ðpb.AttestationData{ + Slot: primitives.Slot(randomUint64(t)), + CommitteeIndex: primitives.CommitteeIndex(randomUint64(t)), + BeaconBlockRoot: randomBytes(32, t), + Source: ðpb.Checkpoint{ + Epoch: primitives.Epoch(randomUint64(t)), + Root: randomBytes(32, t), + }, + Target: ðpb.Checkpoint{ + Epoch: primitives.Epoch(randomUint64(t)), + Root: randomBytes(32, t), + }, + } +} + +// Deposit creates a random Deposit for testing purposes. +func Deposit(t *testing.T) *ethpb.Deposit { + return ðpb.Deposit{ + Proof: [][]byte{randomBytes(32, t), randomBytes(32, t), randomBytes(32, t)}, + Data: DepositData(t), + } +} + +// DepositData creates a random DepositData for testing purposes. +func DepositData(t *testing.T) *ethpb.Deposit_Data { + return ðpb.Deposit_Data{ + PublicKey: randomBytes(48, t), + WithdrawalCredentials: randomBytes(32, t), + Amount: randomUint64(t), + Signature: randomBytes(96, t), + } +} + +// SignedBLSToExecutionChange creates a random SignedBLSToExecutionChange for testing purposes. +func SignedBLSToExecutionChange(t *testing.T) *ethpb.SignedBLSToExecutionChange { + return ðpb.SignedBLSToExecutionChange{ + Message: BLSToExecutionChange(t), + Signature: randomBytes(96, t), + } +} + +// BLSToExecutionChange creates a random BLSToExecutionChange for testing purposes. +func BLSToExecutionChange(t *testing.T) *ethpb.BLSToExecutionChange { + return ðpb.BLSToExecutionChange{ + ValidatorIndex: primitives.ValidatorIndex(randomUint64(t)), + FromBlsPubkey: randomBytes(48, t), + ToExecutionAddress: randomBytes(20, t), + } +} + +// SignedVoluntaryExit creates a random SignedVoluntaryExit for testing purposes. +func SignedVoluntaryExit(t *testing.T) *ethpb.SignedVoluntaryExit { + return ðpb.SignedVoluntaryExit{ + Exit: VoluntaryExit(t), + Signature: randomBytes(96, t), + } +} + +// VoluntaryExit creates a random VoluntaryExit for testing purposes. +func VoluntaryExit(t *testing.T) *ethpb.VoluntaryExit { + return ðpb.VoluntaryExit{ + Epoch: primitives.Epoch(randomUint64(t)), + ValidatorIndex: primitives.ValidatorIndex(randomUint64(t)), + } +} + +// BeaconState creates a random BeaconStateEPBS for testing purposes. +func BeaconState(t *testing.T) *ethpb.BeaconStateEPBS { + return ðpb.BeaconStateEPBS{ + GenesisTime: randomUint64(t), + GenesisValidatorsRoot: randomBytes(32, t), + Slot: primitives.Slot(randomUint64(t)), + Fork: ðpb.Fork{ + PreviousVersion: randomBytes(4, t), + CurrentVersion: randomBytes(4, t), + Epoch: primitives.Epoch(randomUint64(t)), + }, + LatestBlockHeader: ðpb.BeaconBlockHeader{ + Slot: primitives.Slot(randomUint64(t)), + ProposerIndex: primitives.ValidatorIndex(randomUint64(t)), + ParentRoot: randomBytes(32, t), + StateRoot: randomBytes(32, t), + BodyRoot: randomBytes(32, t), + }, + BlockRoots: [][]byte{randomBytes(32, t), randomBytes(32, t), randomBytes(32, t)}, + StateRoots: [][]byte{randomBytes(32, t), randomBytes(32, t), randomBytes(32, t)}, + HistoricalRoots: [][]byte{randomBytes(32, t), randomBytes(32, t), randomBytes(32, t)}, + Eth1Data: ðpb.Eth1Data{ + DepositRoot: randomBytes(32, t), + DepositCount: randomUint64(t), + BlockHash: randomBytes(32, t), + }, + Eth1DataVotes: []*ethpb.Eth1Data{{DepositRoot: randomBytes(32, t), DepositCount: randomUint64(t), BlockHash: randomBytes(32, t)}}, + Eth1DepositIndex: randomUint64(t), + Validators: []*ethpb.Validator{ + { + PublicKey: randomBytes(48, t), + WithdrawalCredentials: randomBytes(32, t), + EffectiveBalance: randomUint64(t), + ActivationEligibilityEpoch: primitives.Epoch(randomUint64(t)), + ActivationEpoch: primitives.Epoch(randomUint64(t)), + ExitEpoch: primitives.Epoch(randomUint64(t)), + WithdrawableEpoch: primitives.Epoch(randomUint64(t)), + }, + }, + Balances: []uint64{randomUint64(t)}, + RandaoMixes: [][]byte{randomBytes(32, t), randomBytes(32, t), randomBytes(32, t)}, + Slashings: []uint64{randomUint64(t)}, + PreviousEpochParticipation: randomBytes(32, t), + CurrentEpochParticipation: randomBytes(32, t), + JustificationBits: randomBytes(1, t), + PreviousJustifiedCheckpoint: ðpb.Checkpoint{Epoch: primitives.Epoch(randomUint64(t)), Root: randomBytes(32, t)}, + CurrentJustifiedCheckpoint: ðpb.Checkpoint{Epoch: primitives.Epoch(randomUint64(t)), Root: randomBytes(32, t)}, + FinalizedCheckpoint: ðpb.Checkpoint{Epoch: primitives.Epoch(randomUint64(t)), Root: randomBytes(32, t)}, + InactivityScores: []uint64{randomUint64(t)}, + CurrentSyncCommittee: ðpb.SyncCommittee{ + Pubkeys: [][]byte{randomBytes(48, t), randomBytes(48, t), randomBytes(48, t)}, + AggregatePubkey: randomBytes(48, t), + }, + NextSyncCommittee: ðpb.SyncCommittee{ + Pubkeys: [][]byte{randomBytes(48, t), randomBytes(48, t), randomBytes(48, t)}, + AggregatePubkey: randomBytes(48, t), + }, + NextWithdrawalIndex: randomUint64(t), + NextWithdrawalValidatorIndex: primitives.ValidatorIndex(randomUint64(t)), + HistoricalSummaries: []*ethpb.HistoricalSummary{{ + BlockSummaryRoot: randomBytes(32, t), + StateSummaryRoot: randomBytes(32, t), + }}, + PreviousInclusionListProposer: primitives.ValidatorIndex(randomUint64(t)), + PreviousInclusionListSlot: primitives.Slot(randomUint64(t)), + LatestInclusionListProposer: primitives.ValidatorIndex(randomUint64(t)), + LatestInclusionListSlot: primitives.Slot(randomUint64(t)), + LatestBlockHash: randomBytes(32, t), + LatestFullSlot: primitives.Slot(randomUint64(t)), + ExecutionPayloadHeader: &enginev1.ExecutionPayloadHeaderEPBS{ + ParentBlockHash: randomBytes(32, t), + ParentBlockRoot: randomBytes(32, t), + BlockHash: randomBytes(32, t), + BuilderIndex: primitives.ValidatorIndex(randomUint64(t)), + Slot: primitives.Slot(randomUint64(t)), + Value: randomUint64(t), + BlobKzgCommitmentsRoot: randomBytes(32, t), + }, + LatestWithdrawalsRoot: randomBytes(32, t), + } +} + +// SignedExecutionPayloadHeader creates a random SignedExecutionPayloadHeader for testing purposes. +func SignedExecutionPayloadHeader(t *testing.T) *enginev1.SignedExecutionPayloadHeader { + return &enginev1.SignedExecutionPayloadHeader{ + Message: ExecutionPayloadHeader(t), + Signature: randomBytes(96, t), + } +} + +// ExecutionPayloadHeader creates a random ExecutionPayloadHeaderEPBS for testing. +func ExecutionPayloadHeader(t *testing.T) *enginev1.ExecutionPayloadHeaderEPBS { + return &enginev1.ExecutionPayloadHeaderEPBS{ + ParentBlockHash: randomBytes(32, t), + ParentBlockRoot: randomBytes(32, t), + BlockHash: randomBytes(32, t), + BuilderIndex: primitives.ValidatorIndex(randomUint64(t)), + Slot: primitives.Slot(randomUint64(t)), + Value: randomUint64(t), + BlobKzgCommitmentsRoot: randomBytes(32, t), + } +} + +// PayloadAttestation creates a random PayloadAttestation for testing purposes. +func PayloadAttestation(t *testing.T) *ethpb.PayloadAttestation { + bv := bitfield.NewBitvector512() + b := randomBytes(64, t) + copy(bv[:], b) + return ðpb.PayloadAttestation{ + AggregationBits: bv, + Data: PayloadAttestationData(t), + Signature: randomBytes(96, t), + } +} + +// PayloadAttestationData generates a random PayloadAttestationData for testing purposes. +func PayloadAttestationData(t *testing.T) *ethpb.PayloadAttestationData { + // Generate a random BeaconBlockRoot + randomBytes := make([]byte, fieldparams.RootLength) + _, err := rand.Read(randomBytes) + if err != nil { + t.Fatalf("Failed to generate random BeaconBlockRoot: %v", err) + } + + // Generate a random Slot value + randomSlot, err := rand.Int(rand.Reader, big.NewInt(10000)) + if err != nil { + t.Fatalf("Failed to generate random Slot: %v", err) + } + + payloadStatuses := []primitives.PTCStatus{ + primitives.PAYLOAD_ABSENT, + primitives.PAYLOAD_PRESENT, + primitives.PAYLOAD_WITHHELD, + } + // Select a random PayloadStatus + index, err := rand.Int(rand.Reader, big.NewInt(int64(len(payloadStatuses)))) + if err != nil { + t.Fatalf("Failed to select random PayloadStatus: %v", err) + } + randomPayloadStatus := payloadStatuses[index.Int64()] + + return ðpb.PayloadAttestationData{ + BeaconBlockRoot: randomBytes, + Slot: primitives.Slot(randomSlot.Uint64()), + PayloadStatus: randomPayloadStatus, + } +} + +// SignedExecutionPayloadEnvelope creates a random SignedExecutionPayloadEnvelope for testing purposes. +func SignedExecutionPayloadEnvelope(t *testing.T) *enginev1.SignedExecutionPayloadEnvelope { + return &enginev1.SignedExecutionPayloadEnvelope{ + Message: ExecutionPayloadEnvelope(t), + Signature: randomBytes(96, t), + } +} + +// ExecutionPayloadEnvelope creates a random ExecutionPayloadEnvelope for testing purposes. +func ExecutionPayloadEnvelope(t *testing.T) *enginev1.ExecutionPayloadEnvelope { + withheld := randomUint64(t)%2 == 0 + return &enginev1.ExecutionPayloadEnvelope{ + Payload: ExecutionPayload(t), + BuilderIndex: primitives.ValidatorIndex(randomUint64(t)), + BeaconBlockRoot: randomBytes(32, t), + BlobKzgCommitments: [][]byte{randomBytes(48, t), randomBytes(48, t), randomBytes(48, t)}, + InclusionListProposerIndex: primitives.ValidatorIndex(randomUint64(t)), + InclusionListSlot: primitives.Slot(randomUint64(t)), + InclusionListSignature: randomBytes(96, t), + PayloadWithheld: withheld, + StateRoot: randomBytes(32, t), + } +} + +// ExecutionPayload creates a random ExecutionPayloadEPBS for testing purposes. +func ExecutionPayload(t *testing.T) *enginev1.ExecutionPayloadEPBS { + return &enginev1.ExecutionPayloadEPBS{ + ParentHash: randomBytes(32, t), + FeeRecipient: randomBytes(20, t), + StateRoot: randomBytes(32, t), + ReceiptsRoot: randomBytes(32, t), + LogsBloom: randomBytes(256, t), + PrevRandao: randomBytes(32, t), + BlockNumber: randomUint64(t), + GasLimit: randomUint64(t), + GasUsed: randomUint64(t), + Timestamp: randomUint64(t), + ExtraData: randomBytes(32, t), + BaseFeePerGas: randomBytes(32, t), + BlockHash: randomBytes(32, t), + Transactions: [][]byte{randomBytes(32, t), randomBytes(32, t), randomBytes(32, t)}, + Withdrawals: []*enginev1.Withdrawal{ + { + Index: randomUint64(t), + ValidatorIndex: primitives.ValidatorIndex(randomUint64(t)), + Address: randomBytes(20, t), + Amount: randomUint64(t), + }, + }, + BlobGasUsed: randomUint64(t), + ExcessBlobGas: randomUint64(t), + InclusionListSummary: [][]byte{randomBytes(20, t), randomBytes(20, t), randomBytes(20, t)}, + } +} + +// InclusionList creates a random InclusionList for testing purposes. +func InclusionList(t *testing.T) *enginev1.InclusionList { + return &enginev1.InclusionList{ + SignedSummary: &enginev1.SignedInclusionListSummary{ + Message: InclusionSummary(t), + Signature: randomBytes(96, t), + }, + ParentBlockHash: randomBytes(32, t), + Transactions: [][]byte{ + randomBytes(123, t), + randomBytes(456, t), + randomBytes(789, t), + randomBytes(1011, t), + }, + } +} + +// InclusionSummary creates a random InclusionListSummary for testing purposes. +func InclusionSummary(t *testing.T) *enginev1.InclusionListSummary { + return &enginev1.InclusionListSummary{ + ProposerIndex: primitives.ValidatorIndex(randomUint64(t)), + Slot: primitives.Slot(randomUint64(t)), + Summary: [][]byte{ + randomBytes(20, t), + randomBytes(20, t), + randomBytes(20, t), + randomBytes(20, t), + }, + } +} + +func randomBytes(n int, t *testing.T) []byte { + b := make([]byte, n) + _, err := rand.Read(b) + if err != nil { + t.Fatalf("Failed to generate random bytes: %v", err) + } + return b +} + +func randomUint64(t *testing.T) uint64 { + var num uint64 + b := randomBytes(8, t) + num = binary.BigEndian.Uint64(b) + return num +} diff --git a/validator/client/BUILD.bazel b/validator/client/BUILD.bazel index 5c683dd218e5..6665337bb23e 100644 --- a/validator/client/BUILD.bazel +++ b/validator/client/BUILD.bazel @@ -147,6 +147,7 @@ go_test( "//testing/mock:go_default_library", "//testing/require:go_default_library", "//testing/util:go_default_library", + "//testing/util/random:go_default_library", "//testing/validator-mock:go_default_library", "//time:go_default_library", "//time/slots:go_default_library", diff --git a/validator/client/payload_attestation_test.go b/validator/client/payload_attestation_test.go index 6c2f356404f5..2f7a0dc09f61 100644 --- a/validator/client/payload_attestation_test.go +++ b/validator/client/payload_attestation_test.go @@ -11,7 +11,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v5/testing/require" - "github.com/prysmaticlabs/prysm/v5/testing/util" + "github.com/prysmaticlabs/prysm/v5/testing/util/random" "go.uber.org/mock/gomock" ) @@ -32,7 +32,7 @@ func Test_validator_signPayloadAttestation(t *testing.T) { }, nil) // Generate random payload attestation data - pa := util.GenerateRandomPayloadAttestationData(t) + pa := random.PayloadAttestationData(t) pa.Slot = primitives.Slot(e) * params.BeaconConfig().SlotsPerEpoch // Verify that go mock EXPECT() gets the correct epoch. // Perform the signature operation