Compare commits

...

15 Commits

Author SHA1 Message Date
Preston Van Loon
721eb0b404 gofmt with go1.23.5 2025-01-22 22:34:36 -06:00
Preston Van Loon
43b233a4d5 Update go to 1.23.5 2025-01-22 22:34:36 -06:00
Preston Van Loon
74eb56020a Remove problematic ginkgo and gomega test helpers. Rewrote tests without these test libraries. 2025-01-22 22:34:36 -06:00
Preston Van Loon
13d2594cea Update errcheck by re-exporting the upstream repo 2025-01-22 22:34:36 -06:00
Preston Van Loon
d503b8014c Fix violations of SA3000 2025-01-22 22:34:36 -06:00
Preston Van Loon
a8ed5c2aa6 Update golang.org/x/tools 2025-01-22 22:34:36 -06:00
Preston Van Loon
d0aace409a Update go_honnef_go_tools 2025-01-22 22:34:36 -06:00
Preston Van Loon
955321286a Use toolchains_protoc 2025-01-22 22:34:36 -06:00
Preston Van Loon
48a879930e Update rules_go 2025-01-22 22:27:26 -06:00
Preston Van Loon
605cad0a8c Update bazel version 2025-01-22 22:27:26 -06:00
Manu NALEPA
78722239da nodeFilter: Add GossipBlobSidecarMessage case. (#14822)
Before this commit, this kind of logs were possible:

```
[2025-01-22 17:18:48]  DEBUG sync: Could not search for peers error=node filter: no subnet exists for provided topic: /eth2/d1f05cae/blob_sidecar_0/ssz_snappy
[2025-01-22 17:18:48]  DEBUG sync: Could not search for peers error=node filter: no subnet exists for provided topic: /eth2/d1f05cae/blob_sidecar_1/ssz_snappy
[2025-01-22 17:18:48]  DEBUG sync: Could not search for peers error=node filter: no subnet exists for provided topic: /eth2/d1f05cae/blob_sidecar_2/ssz_snappy
[2025-01-22 17:18:48]  DEBUG sync: Could not search for peers error=node filter: no subnet exists for provided topic: /eth2/d1f05cae/blob_sidecar_3/ssz_snappy
[2025-01-22 17:18:48]  DEBUG sync: Could not search for peers error=node filter: no subnet exists for provided topic: /eth2/d1f05cae/blob_sidecar_4/ssz_snappy
[2025-01-22 17:18:48]  DEBUG sync: Could not search for peers error=node filter: no subnet exists for provided topic: /eth2/d1f05cae/blob_sidecar_5/ssz_snappy
[2025-01-22 17:18:48]  DEBUG sync: Could not search for peers error=node filter: no subnet exists for provided topic: /eth2/d1f05cae/blob_sidecar_6/ssz_snappy
[2025-01-22 17:18:48]  DEBUG sync: Could not search for peers error=node filter: no subnet exists for provided topic: /eth2/d1f05cae/blob_sidecar_7/ssz_snappy
[2025-01-22 17:18:48]  DEBUG sync: Could not search for peers error=node filter: no subnet exists for provided topic: /eth2/d1f05cae/blob_sidecar_8/ssz_snappy
```

Note this bug has no real other impact than logging these errors: Since all nodes are subscribed to these subnets, as soon as some peers are found, there is no more issue.

Why not using `s.subscribe` instead of `s.subscribeWithParameters`?
Blobs subnets were before considered as static subnets. But since Electra, the number of subnets is a function of the epoch.
So it's better to use `s.subscribeWithParameters` than 2 specific but almost identic functions in `s.subscribe`.

Why `filterPeerForBlobSubnet` is the only one returning always `true`?
Because blobs subnets are actually the only subnets which are both dynamic AND which have to be subscribed by all the nodes.
So, `filterPeerForBlobSubnet` does not filter out any node.
2025-01-22 19:56:55 +00:00
Manu NALEPA
3ffef024c7 UpgradeToFulu: Respect the specification. (#14821)
188a2ff818/specs/fulu/fork.md (upgrading-the-state)

Before this commit, the `UpgradeToFulu` did not really respect the specification. This commit fixes that.

How can we be sure now the specification is really respected?

As long as the equivalent of https://github.com/ethereum/consensus-spec-tests/tree/master/tests/mainnet/electra/fork/fork/pyspec_tests are not released, we cannot be sure.

However, with this commit, Prysm and Lighthouse do agree with the post state after the Fulu fork (which is not the case without this commit).

So either both Prysm and Lighthouse are both right,
either the are both wrong (but in the exact same way, which has a pretty low likelyhood).
2025-01-22 18:39:12 +00:00
Radosław Kapka
a1eef44492 Update slasher service to Electra (#14812)
* Update slasher service to Electra

* Update beacon-chain/slasher/chunks.go

Co-authored-by: Manu NALEPA <enalepa@offchainlabs.com>

* Update beacon-chain/slasher/chunks_test.go

Co-authored-by: Manu NALEPA <enalepa@offchainlabs.com>

* Manu's review

* Manu's review again

---------

Co-authored-by: Manu NALEPA <enalepa@offchainlabs.com>
2025-01-22 17:32:19 +00:00
Radosław Kapka
2845ab9365 Update proto_test.go to Electra (#14817) 2025-01-21 20:30:52 +00:00
Radosław Kapka
4f43c15ebb Update rewards API to Electra (#14816) 2025-01-21 20:13:36 +00:00
56 changed files with 2359 additions and 3383 deletions

View File

@@ -1 +1 @@
7.1.0
7.4.1

1689
MODULE.bazel.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,33 @@ load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies")
rules_pkg_dependencies()
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "toolchains_protoc",
sha256 = "abb1540f8a9e045422730670ebb2f25b41fa56ca5a7cf795175a110a0a68f4ad",
strip_prefix = "toolchains_protoc-0.3.6",
url = "https://github.com/aspect-build/toolchains_protoc/releases/download/v0.3.6/toolchains_protoc-v0.3.6.tar.gz",
)
load("@toolchains_protoc//protoc:repositories.bzl", "rules_protoc_dependencies")
rules_protoc_dependencies()
load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies")
rules_proto_dependencies()
load("@bazel_features//:deps.bzl", "bazel_features_deps")
bazel_features_deps()
load("@toolchains_protoc//protoc:toolchain.bzl", "protoc_toolchains")
protoc_toolchains(
name = "protoc_toolchains",
version = "v25.3",
)
HERMETIC_CC_TOOLCHAIN_VERSION = "v3.0.1"
http_archive(
@@ -137,10 +164,10 @@ http_archive(
# Expose internals of go_test for custom build transitions.
"//third_party:io_bazel_rules_go_test.patch",
],
sha256 = "80a98277ad1311dacd837f9b16db62887702e9f1d1c4c9f796d0121a46c8e184",
sha256 = "b2038e2de2cace18f032249cb4bb0048abf583a36369fa98f687af1b3f880b26",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.46.0/rules_go-v0.46.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.46.0/rules_go-v0.46.0.zip",
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.1/rules_go-v0.48.1.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.48.1/rules_go-v0.48.1.zip",
],
)
@@ -182,7 +209,7 @@ load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_depe
go_rules_dependencies()
go_register_toolchains(
go_version = "1.22.10",
go_version = "1.23.5",
nogo = "@//:nogo",
)

View File

@@ -2,6 +2,7 @@ package blockchain
import (
"io"
"os"
"testing"
"github.com/sirupsen/logrus"
@@ -11,5 +12,5 @@ func TestMain(m *testing.M) {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(io.Discard)
m.Run()
os.Exit(m.Run())
}

View File

@@ -1,9 +1,10 @@
package cache
import (
"os"
"testing"
)
func TestMain(m *testing.M) {
m.Run()
os.Exit(m.Run())
}

View File

@@ -6,15 +6,12 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/fulu",
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
)
@@ -24,7 +21,6 @@ go_test(
srcs = ["upgrade_test.go"],
deps = [
":go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/time:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
@@ -32,6 +28,5 @@ go_test(
"//proto/prysm/v1alpha1:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"//time/slots:go_default_library",
],
)

View File

@@ -1,18 +1,13 @@
package fulu
import (
"sort"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v5/config/params"
"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"
"github.com/prysmaticlabs/prysm/v5/time/slots"
)
// UpgradeToFulu updates inputs a generic state to return the version Fulu state.
@@ -74,32 +69,37 @@ func UpgradeToFulu(beaconState state.BeaconState) (state.BeaconState, error) {
if err != nil {
return nil, err
}
earliestExitEpoch := helpers.ActivationExitEpoch(time.CurrentEpoch(beaconState))
preActivationIndices := make([]primitives.ValidatorIndex, 0)
compoundWithdrawalIndices := make([]primitives.ValidatorIndex, 0)
if err = beaconState.ReadFromEveryValidator(func(index int, val state.ReadOnlyValidator) error {
if val.ExitEpoch() != params.BeaconConfig().FarFutureEpoch && val.ExitEpoch() > earliestExitEpoch {
earliestExitEpoch = val.ExitEpoch()
}
if val.ActivationEpoch() == params.BeaconConfig().FarFutureEpoch {
preActivationIndices = append(preActivationIndices, primitives.ValidatorIndex(index))
}
if val.HasCompoundingWithdrawalCredentials() {
compoundWithdrawalIndices = append(compoundWithdrawalIndices, primitives.ValidatorIndex(index))
}
return nil
}); err != nil {
depositBalanceToConsume, err := beaconState.DepositBalanceToConsume()
if err != nil {
return nil, err
}
earliestExitEpoch++ // Increment to find the earliest possible exit epoch
// note: should be the same in prestate and post beaconState.
// we are deviating from the specs a bit as it calls for using the post beaconState
tab, err := helpers.TotalActiveBalance(beaconState)
exitBalanceToConsume, err := beaconState.ExitBalanceToConsume()
if err != nil {
return nil, errors.Wrap(err, "failed to get total active balance")
return nil, err
}
earliestExitEpoch, err := beaconState.EarliestExitEpoch()
if err != nil {
return nil, err
}
consolidationBalanceToConsume, err := beaconState.ConsolidationBalanceToConsume()
if err != nil {
return nil, err
}
earliestConsolidationEpoch, err := beaconState.EarliestConsolidationEpoch()
if err != nil {
return nil, err
}
pendingDeposits, err := beaconState.PendingDeposits()
if err != nil {
return nil, err
}
pendingPartialWithdrawals, err := beaconState.PendingPartialWithdrawals()
if err != nil {
return nil, err
}
pendingConsolidations, err := beaconState.PendingConsolidations()
if err != nil {
return nil, err
}
s := &ethpb.BeaconStateFulu{
@@ -155,25 +155,16 @@ func UpgradeToFulu(beaconState state.BeaconState) (state.BeaconState, error) {
HistoricalSummaries: summaries,
DepositRequestsStartIndex: params.BeaconConfig().UnsetDepositRequestsStartIndex,
DepositBalanceToConsume: 0,
ExitBalanceToConsume: helpers.ActivationExitChurnLimit(primitives.Gwei(tab)),
DepositBalanceToConsume: depositBalanceToConsume,
ExitBalanceToConsume: exitBalanceToConsume,
EarliestExitEpoch: earliestExitEpoch,
ConsolidationBalanceToConsume: helpers.ConsolidationChurnLimit(primitives.Gwei(tab)),
EarliestConsolidationEpoch: helpers.ActivationExitEpoch(slots.ToEpoch(beaconState.Slot())),
PendingDeposits: make([]*ethpb.PendingDeposit, 0),
PendingPartialWithdrawals: make([]*ethpb.PendingPartialWithdrawal, 0),
PendingConsolidations: make([]*ethpb.PendingConsolidation, 0),
ConsolidationBalanceToConsume: consolidationBalanceToConsume,
EarliestConsolidationEpoch: earliestConsolidationEpoch,
PendingDeposits: pendingDeposits,
PendingPartialWithdrawals: pendingPartialWithdrawals,
PendingConsolidations: pendingConsolidations,
}
// Sorting preActivationIndices based on a custom criteria
sort.Slice(preActivationIndices, func(i, j int) bool {
// Comparing based on ActivationEligibilityEpoch and then by index if the epochs are the same
if s.Validators[preActivationIndices[i]].ActivationEligibilityEpoch == s.Validators[preActivationIndices[j]].ActivationEligibilityEpoch {
return preActivationIndices[i] < preActivationIndices[j]
}
return s.Validators[preActivationIndices[i]].ActivationEligibilityEpoch < s.Validators[preActivationIndices[j]].ActivationEligibilityEpoch
})
// Need to cast the beaconState to use in helper functions
post, err := state_native.InitializeFromProtoUnsafeFulu(s)
if err != nil {

View File

@@ -4,7 +4,6 @@ import (
"testing"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/fulu"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
@@ -12,7 +11,6 @@ import (
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/time/slots"
)
func TestUpgradeToFulu(t *testing.T) {
@@ -33,57 +31,6 @@ func TestUpgradeToFulu(t *testing.T) {
require.Equal(t, preForkState.GenesisTime(), mSt.GenesisTime())
require.DeepSSZEqual(t, preForkState.GenesisValidatorsRoot(), mSt.GenesisValidatorsRoot())
require.Equal(t, preForkState.Slot(), mSt.Slot())
require.DeepSSZEqual(t, preForkState.LatestBlockHeader(), mSt.LatestBlockHeader())
require.DeepSSZEqual(t, preForkState.BlockRoots(), mSt.BlockRoots())
require.DeepSSZEqual(t, preForkState.StateRoots(), mSt.StateRoots())
require.DeepSSZEqual(t, preForkState.Validators()[2:], mSt.Validators()[2:])
require.DeepSSZEqual(t, preForkState.Balances()[2:], mSt.Balances()[2:])
require.DeepSSZEqual(t, preForkState.Eth1Data(), mSt.Eth1Data())
require.DeepSSZEqual(t, preForkState.Eth1DataVotes(), mSt.Eth1DataVotes())
require.DeepSSZEqual(t, preForkState.Eth1DepositIndex(), mSt.Eth1DepositIndex())
require.DeepSSZEqual(t, preForkState.RandaoMixes(), mSt.RandaoMixes())
require.DeepSSZEqual(t, preForkState.Slashings(), mSt.Slashings())
require.DeepSSZEqual(t, preForkState.JustificationBits(), mSt.JustificationBits())
require.DeepSSZEqual(t, preForkState.PreviousJustifiedCheckpoint(), mSt.PreviousJustifiedCheckpoint())
require.DeepSSZEqual(t, preForkState.CurrentJustifiedCheckpoint(), mSt.CurrentJustifiedCheckpoint())
require.DeepSSZEqual(t, preForkState.FinalizedCheckpoint(), mSt.FinalizedCheckpoint())
require.Equal(t, len(preForkState.Validators()), len(mSt.Validators()))
preVal, err := preForkState.ValidatorAtIndex(0)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, preVal.EffectiveBalance)
preVal2, err := preForkState.ValidatorAtIndex(1)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, preVal2.EffectiveBalance)
// TODO: Fix this test
// mVal, err := mSt.ValidatorAtIndex(0)
_, err = mSt.ValidatorAtIndex(0)
require.NoError(t, err)
// require.Equal(t, uint64(0), mVal.EffectiveBalance)
mVal2, err := mSt.ValidatorAtIndex(1)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MinActivationBalance, mVal2.EffectiveBalance)
numValidators := mSt.NumValidators()
p, err := mSt.PreviousEpochParticipation()
require.NoError(t, err)
require.DeepSSZEqual(t, make([]byte, numValidators), p)
p, err = mSt.CurrentEpochParticipation()
require.NoError(t, err)
require.DeepSSZEqual(t, make([]byte, numValidators), p)
s, err := mSt.InactivityScores()
require.NoError(t, err)
require.DeepSSZEqual(t, make([]uint64, numValidators), s)
hr1, err := preForkState.HistoricalRoots()
require.NoError(t, err)
hr2, err := mSt.HistoricalRoots()
require.NoError(t, err)
require.DeepEqual(t, hr1, hr2)
f := mSt.Fork()
require.DeepSSZEqual(t, &ethpb.Fork{
@@ -91,11 +38,50 @@ func TestUpgradeToFulu(t *testing.T) {
CurrentVersion: params.BeaconConfig().FuluForkVersion,
Epoch: time.CurrentEpoch(st),
}, f)
require.DeepSSZEqual(t, preForkState.LatestBlockHeader(), mSt.LatestBlockHeader())
require.DeepSSZEqual(t, preForkState.BlockRoots(), mSt.BlockRoots())
require.DeepSSZEqual(t, preForkState.StateRoots(), mSt.StateRoots())
hr1, err := preForkState.HistoricalRoots()
require.NoError(t, err)
hr2, err := mSt.HistoricalRoots()
require.NoError(t, err)
require.DeepEqual(t, hr1, hr2)
require.DeepSSZEqual(t, preForkState.Eth1Data(), mSt.Eth1Data())
require.DeepSSZEqual(t, preForkState.Eth1DataVotes(), mSt.Eth1DataVotes())
require.DeepSSZEqual(t, preForkState.Eth1DepositIndex(), mSt.Eth1DepositIndex())
require.DeepSSZEqual(t, preForkState.Validators(), mSt.Validators())
require.DeepSSZEqual(t, preForkState.Balances(), mSt.Balances())
require.DeepSSZEqual(t, preForkState.RandaoMixes(), mSt.RandaoMixes())
require.DeepSSZEqual(t, preForkState.Slashings(), mSt.Slashings())
numValidators := mSt.NumValidators()
p, err := mSt.PreviousEpochParticipation()
require.NoError(t, err)
require.DeepSSZEqual(t, make([]byte, numValidators), p)
p, err = mSt.CurrentEpochParticipation()
require.NoError(t, err)
require.DeepSSZEqual(t, make([]byte, numValidators), p)
require.DeepSSZEqual(t, preForkState.JustificationBits(), mSt.JustificationBits())
require.DeepSSZEqual(t, preForkState.PreviousJustifiedCheckpoint(), mSt.PreviousJustifiedCheckpoint())
require.DeepSSZEqual(t, preForkState.CurrentJustifiedCheckpoint(), mSt.CurrentJustifiedCheckpoint())
require.DeepSSZEqual(t, preForkState.FinalizedCheckpoint(), mSt.FinalizedCheckpoint())
s, err := mSt.InactivityScores()
require.NoError(t, err)
require.DeepSSZEqual(t, make([]uint64, numValidators), s)
csc, err := mSt.CurrentSyncCommittee()
require.NoError(t, err)
psc, err := preForkState.CurrentSyncCommittee()
require.NoError(t, err)
require.DeepSSZEqual(t, psc, csc)
nsc, err := mSt.NextSyncCommittee()
require.NoError(t, err)
psc, err = preForkState.NextSyncCommittee()
@@ -110,7 +96,6 @@ func TestUpgradeToFulu(t *testing.T) {
require.NoError(t, err)
txRoot, err := prevHeader.TransactionsRoot()
require.NoError(t, err)
wdRoot, err := prevHeader.WithdrawalsRoot()
require.NoError(t, err)
wanted := &enginev1.ExecutionPayloadHeaderDeneb{
@@ -144,45 +129,57 @@ func TestUpgradeToFulu(t *testing.T) {
require.NoError(t, err)
require.Equal(t, 0, len(summaries))
startIndex, err := mSt.DepositRequestsStartIndex()
preDepositRequestsStartIndex, err := preForkState.DepositRequestsStartIndex()
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().UnsetDepositRequestsStartIndex, startIndex)
postDepositRequestsStartIndex, err := mSt.DepositRequestsStartIndex()
require.NoError(t, err)
require.Equal(t, preDepositRequestsStartIndex, postDepositRequestsStartIndex)
balance, err := mSt.DepositBalanceToConsume()
preDepositBalanceToConsume, err := preForkState.DepositBalanceToConsume()
require.NoError(t, err)
require.Equal(t, primitives.Gwei(0), balance)
postDepositBalanceToConsume, err := mSt.DepositBalanceToConsume()
require.NoError(t, err)
require.Equal(t, preDepositBalanceToConsume, postDepositBalanceToConsume)
tab, err := helpers.TotalActiveBalance(mSt)
preExitBalanceToConsume, err := preForkState.ExitBalanceToConsume()
require.NoError(t, err)
postExitBalanceToConsume, err := mSt.ExitBalanceToConsume()
require.NoError(t, err)
require.Equal(t, preExitBalanceToConsume, postExitBalanceToConsume)
ebtc, err := mSt.ExitBalanceToConsume()
preEarliestExitEpoch, err := preForkState.EarliestExitEpoch()
require.NoError(t, err)
require.Equal(t, helpers.ActivationExitChurnLimit(primitives.Gwei(tab)), ebtc)
postEarliestExitEpoch, err := mSt.EarliestExitEpoch()
require.NoError(t, err)
require.Equal(t, preEarliestExitEpoch, postEarliestExitEpoch)
eee, err := mSt.EarliestExitEpoch()
preConsolidationBalanceToConsume, err := preForkState.ConsolidationBalanceToConsume()
require.NoError(t, err)
require.Equal(t, helpers.ActivationExitEpoch(primitives.Epoch(1)), eee)
postConsolidationBalanceToConsume, err := mSt.ConsolidationBalanceToConsume()
require.NoError(t, err)
require.Equal(t, preConsolidationBalanceToConsume, postConsolidationBalanceToConsume)
cbtc, err := mSt.ConsolidationBalanceToConsume()
preEarliesConsolidationEoch, err := preForkState.EarliestConsolidationEpoch()
require.NoError(t, err)
require.Equal(t, helpers.ConsolidationChurnLimit(primitives.Gwei(tab)), cbtc)
postEarliestConsolidationEpoch, err := mSt.EarliestConsolidationEpoch()
require.NoError(t, err)
require.Equal(t, preEarliesConsolidationEoch, postEarliestConsolidationEpoch)
earliestConsolidationEpoch, err := mSt.EarliestConsolidationEpoch()
prePendingDeposits, err := preForkState.PendingDeposits()
require.NoError(t, err)
require.Equal(t, helpers.ActivationExitEpoch(slots.ToEpoch(preForkState.Slot())), earliestConsolidationEpoch)
postPendingDeposits, err := mSt.PendingDeposits()
require.NoError(t, err)
require.DeepSSZEqual(t, prePendingDeposits, postPendingDeposits)
// TODO: Fix this test
// pendingDeposits, err := mSt.PendingDeposits()
_, err = mSt.PendingDeposits()
prePendingPartialWithdrawals, err := preForkState.PendingPartialWithdrawals()
require.NoError(t, err)
// require.Equal(t, 2, len(pendingDeposits))
// require.Equal(t, uint64(1000), pendingDeposits[1].Amount)
postPendingPartialWithdrawals, err := mSt.PendingPartialWithdrawals()
require.NoError(t, err)
require.DeepSSZEqual(t, prePendingPartialWithdrawals, postPendingPartialWithdrawals)
numPendingPartialWithdrawals, err := mSt.NumPendingPartialWithdrawals()
prePendingConsolidations, err := preForkState.PendingConsolidations()
require.NoError(t, err)
require.Equal(t, uint64(0), numPendingPartialWithdrawals)
consolidations, err := mSt.PendingConsolidations()
postPendingConsolidations, err := mSt.PendingConsolidations()
require.NoError(t, err)
require.Equal(t, 0, len(consolidations))
require.DeepSSZEqual(t, prePendingConsolidations, postPendingConsolidations)
}

View File

@@ -2,6 +2,7 @@ package slasherkv
import (
"io"
"os"
"testing"
"github.com/sirupsen/logrus"
@@ -10,5 +11,5 @@ import (
func TestMain(m *testing.M) {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(io.Discard)
m.Run()
os.Exit(m.Run())
}

View File

@@ -2,6 +2,7 @@ package execution
import (
"io"
"os"
"testing"
"github.com/sirupsen/logrus"
@@ -11,5 +12,5 @@ func TestMain(m *testing.M) {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(io.Discard)
m.Run()
os.Exit(m.Run())
}

View File

@@ -355,7 +355,7 @@ func TestStaticPeering_PeersAreAdded(t *testing.T) {
func TestHostIsResolved(t *testing.T) {
// ip.addr.tools - construct domain names that resolve to any given IP address
// ex: 192-0-2-1.ip.addr.tools resolves to 192.0.2.1.
// ex: 192-0-2-1.ip.addr.tools resolves to 192.0.2.1.
exampleHost := "96-7-129-13.ip.addr.tools"
exampleIP := "96.7.129.13"

View File

@@ -2,6 +2,7 @@ package peers_test
import (
"io"
"os"
"testing"
"github.com/prysmaticlabs/prysm/v5/cmd/beacon-chain/flags"
@@ -28,5 +29,5 @@ func TestMain(m *testing.M) {
defer func() {
flags.Init(resetFlags)
}()
m.Run()
os.Exit(m.Run())
}

View File

@@ -3,6 +3,7 @@ package scorers_test
import (
"io"
"math"
"os"
"testing"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/peers/scorers"
@@ -28,7 +29,7 @@ func TestMain(m *testing.M) {
defer func() {
flags.Init(resetFlags)
}()
m.Run()
os.Exit(m.Run())
}
// roundScore returns score rounded in accordance with the score manager's rounding factor.

View File

@@ -54,6 +54,8 @@ func (s *Service) nodeFilter(topic string, index uint64) (func(node *enode.Node)
return s.filterPeerForAttSubnet(index), nil
case strings.Contains(topic, GossipSyncCommitteeMessage):
return s.filterPeerForSyncSubnet(index), nil
case strings.Contains(topic, GossipBlobSidecarMessage):
return s.filterPeerForBlobSubnet(), nil
default:
return nil, errors.Errorf("no subnet exists for provided topic: %s", topic)
}
@@ -266,6 +268,14 @@ func (s *Service) filterPeerForSyncSubnet(index uint64) func(node *enode.Node) b
}
}
// returns a method with filters peers specifically for a particular blob subnet.
// All peers are supposed to be subscribed to all blob subnets.
func (s *Service) filterPeerForBlobSubnet() func(_ *enode.Node) bool {
return func(_ *enode.Node) bool {
return true
}
}
// lower threshold to broadcast object compared to searching
// for a subnet. So that even in the event of poor peer
// connectivity, we can still broadcast an attestation.

View File

@@ -63,6 +63,7 @@ go_test(
"//encoding/bytesutil:go_default_library",
"//network/httputil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",

View File

@@ -32,45 +32,52 @@ import (
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/network/httputil"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util"
)
func BlockRewardTestSetup(t *testing.T, forkName string) (state.BeaconState, interfaces.SignedBeaconBlock, error) {
func BlockRewardTestSetup(t *testing.T, ver int) (state.BeaconState, interfaces.SignedBeaconBlock, error) {
helpers.ClearCache()
var sbb interfaces.SignedBeaconBlock
var st state.BeaconState
var err error
switch forkName {
case "phase0":
switch ver {
case version.Phase0:
return nil, nil, errors.New("phase0 not supported")
case "altair":
case version.Altair:
st, err = util.NewBeaconStateAltair()
require.NoError(t, err)
b := util.HydrateSignedBeaconBlockAltair(util.NewBeaconBlockAltair())
sbb, err = blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
case "bellatrix":
case version.Bellatrix:
st, err = util.NewBeaconStateBellatrix()
require.NoError(t, err)
b := util.HydrateSignedBeaconBlockBellatrix(util.NewBeaconBlockBellatrix())
sbb, err = blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
case "capella":
case version.Capella:
st, err = util.NewBeaconStateCapella()
require.NoError(t, err)
b := util.HydrateSignedBeaconBlockCapella(util.NewBeaconBlockCapella())
sbb, err = blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
case "deneb":
case version.Deneb:
st, err = util.NewBeaconStateDeneb()
require.NoError(t, err)
b := util.HydrateSignedBeaconBlockDeneb(util.NewBeaconBlockDeneb())
sbb, err = blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
case version.Electra:
st, err = util.NewBeaconStateElectra()
require.NoError(t, err)
b := util.HydrateSignedBeaconBlockElectra(util.NewBeaconBlockElectra())
sbb, err = blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
default:
return nil, nil, errors.New("fork is not supported")
return nil, nil, fmt.Errorf("fork %s is not supported", version.String(ver))
}
valCount := 64
require.NoError(t, st.SetSlot(1))
@@ -102,20 +109,47 @@ func BlockRewardTestSetup(t *testing.T, forkName string) (state.BeaconState, int
require.NoError(t, st.SetBlockRoots(bRoots))
sbb.SetSlot(2)
// we have to set the proposer index to the value that will be randomly chosen (fortunately it's deterministic)
sbb.SetProposerIndex(12)
require.NoError(t, sbb.SetAttestations([]eth.Att{
&eth.Attestation{
AggregationBits: bitfield.Bitlist{0b00000111},
Data: util.HydrateAttestationData(&eth.AttestationData{}),
Signature: make([]byte, fieldparams.BLSSignatureLength),
},
&eth.Attestation{
AggregationBits: bitfield.Bitlist{0b00000111},
Data: util.HydrateAttestationData(&eth.AttestationData{}),
Signature: make([]byte, fieldparams.BLSSignatureLength),
},
}))
if ver >= version.Electra {
sbb.SetProposerIndex(4)
} else {
sbb.SetProposerIndex(12)
}
var atts []eth.Att
if ver >= version.Electra {
cb := primitives.NewAttestationCommitteeBits()
cb.SetBitAt(0, true)
atts = []eth.Att{
&eth.AttestationElectra{
AggregationBits: bitfield.Bitlist{0b00000111},
Data: util.HydrateAttestationData(&eth.AttestationData{}),
Signature: make([]byte, fieldparams.BLSSignatureLength),
CommitteeBits: cb,
},
&eth.AttestationElectra{
AggregationBits: bitfield.Bitlist{0b00000111},
Data: util.HydrateAttestationData(&eth.AttestationData{}),
Signature: make([]byte, fieldparams.BLSSignatureLength),
CommitteeBits: cb,
},
}
} else {
atts = []eth.Att{
&eth.Attestation{
AggregationBits: bitfield.Bitlist{0b00000111},
Data: util.HydrateAttestationData(&eth.AttestationData{}),
Signature: make([]byte, fieldparams.BLSSignatureLength),
},
&eth.Attestation{
AggregationBits: bitfield.Bitlist{0b00000111},
Data: util.HydrateAttestationData(&eth.AttestationData{}),
Signature: make([]byte, fieldparams.BLSSignatureLength),
},
}
}
require.NoError(t, sbb.SetAttestations(atts))
attData1 := util.HydrateAttestationData(&eth.AttestationData{BeaconBlockRoot: bytesutil.PadTo([]byte("root1"), 32)})
attData2 := util.HydrateAttestationData(&eth.AttestationData{BeaconBlockRoot: bytesutil.PadTo([]byte("root2"), 32)})
@@ -125,8 +159,23 @@ func BlockRewardTestSetup(t *testing.T, forkName string) (state.BeaconState, int
require.NoError(t, err)
sigRoot2, err := signing.ComputeSigningRoot(attData2, domain)
require.NoError(t, err)
require.NoError(t, sbb.SetAttesterSlashings([]eth.AttSlashing{
&eth.AttesterSlashing{
var attSlashing eth.AttSlashing
if ver >= version.Electra {
attSlashing = &eth.AttesterSlashingElectra{
Attestation_1: &eth.IndexedAttestationElectra{
AttestingIndices: []uint64{0},
Data: attData1,
Signature: secretKeys[0].Sign(sigRoot1[:]).Marshal(),
},
Attestation_2: &eth.IndexedAttestationElectra{
AttestingIndices: []uint64{0},
Data: attData2,
Signature: secretKeys[0].Sign(sigRoot2[:]).Marshal(),
},
}
} else {
attSlashing = &eth.AttesterSlashing{
Attestation_1: &eth.IndexedAttestation{
AttestingIndices: []uint64{0},
Data: attData1,
@@ -137,8 +186,10 @@ func BlockRewardTestSetup(t *testing.T, forkName string) (state.BeaconState, int
Data: attData2,
Signature: secretKeys[0].Sign(sigRoot2[:]).Marshal(),
},
},
}))
}
}
require.NoError(t, sbb.SetAttesterSlashings([]eth.AttSlashing{attSlashing}))
header1 := &eth.BeaconBlockHeader{
Slot: 0,
ProposerIndex: 1,
@@ -179,11 +230,21 @@ func BlockRewardTestSetup(t *testing.T, forkName string) (state.BeaconState, int
sszBytes := primitives.SSZBytes(slot0bRoot)
r, err := signing.ComputeSigningRoot(&sszBytes, domain)
require.NoError(t, err)
// Bits set in sync committee bits determine which validators will be treated as participating in sync committee.
// These validators have to sign the message.
sig1, err := blst.SignatureFromBytes(secretKeys[47].Sign(r[:]).Marshal())
var scValIdx1 int
var scValIdx2 int
if ver >= version.Electra {
scValIdx1 = 14
scValIdx2 = 27
} else {
scValIdx1 = 47
scValIdx2 = 19
}
sig1, err := blst.SignatureFromBytes(secretKeys[scValIdx1].Sign(r[:]).Marshal())
require.NoError(t, err)
sig2, err := blst.SignatureFromBytes(secretKeys[19].Sign(r[:]).Marshal())
sig2, err := blst.SignatureFromBytes(secretKeys[scValIdx2].Sign(r[:]).Marshal())
require.NoError(t, err)
aggSig := bls.AggregateSignatures([]bls.Signature{sig1, sig2}).Marshal()
err = sbb.SetSyncAggregate(&eth.SyncAggregate{SyncCommitteeBits: scBits, SyncCommitteeSignature: aggSig})
@@ -211,14 +272,14 @@ func TestBlockRewards(t *testing.T) {
writer.Body = &bytes.Buffer{}
s.BlockRewards(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
require.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
require.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, "Block rewards are not supported for Phase 0 blocks", e.Message)
})
t.Run("altair", func(t *testing.T) {
st, sbb, err := BlockRewardTestSetup(t, "altair")
st, sbb, err := BlockRewardTestSetup(t, version.Altair)
require.NoError(t, err)
mockChainService := &mock.ChainService{Optimistic: true}
@@ -241,7 +302,7 @@ func TestBlockRewards(t *testing.T) {
writer.Body = &bytes.Buffer{}
s.BlockRewards(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
require.Equal(t, http.StatusOK, writer.Code)
resp := &structs.BlockRewardsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, "12", resp.Data.ProposerIndex)
@@ -254,7 +315,7 @@ func TestBlockRewards(t *testing.T) {
assert.Equal(t, false, resp.Finalized)
})
t.Run("bellatrix", func(t *testing.T) {
st, sbb, err := BlockRewardTestSetup(t, "bellatrix")
st, sbb, err := BlockRewardTestSetup(t, version.Bellatrix)
require.NoError(t, err)
mockChainService := &mock.ChainService{Optimistic: true}
@@ -277,7 +338,7 @@ func TestBlockRewards(t *testing.T) {
writer.Body = &bytes.Buffer{}
s.BlockRewards(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
require.Equal(t, http.StatusOK, writer.Code)
resp := &structs.BlockRewardsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, "12", resp.Data.ProposerIndex)
@@ -290,7 +351,7 @@ func TestBlockRewards(t *testing.T) {
assert.Equal(t, false, resp.Finalized)
})
t.Run("capella", func(t *testing.T) {
st, sbb, err := BlockRewardTestSetup(t, "capella")
st, sbb, err := BlockRewardTestSetup(t, version.Capella)
require.NoError(t, err)
mockChainService := &mock.ChainService{Optimistic: true}
@@ -313,7 +374,7 @@ func TestBlockRewards(t *testing.T) {
writer.Body = &bytes.Buffer{}
s.BlockRewards(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
require.Equal(t, http.StatusOK, writer.Code)
resp := &structs.BlockRewardsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, "12", resp.Data.ProposerIndex)
@@ -326,7 +387,7 @@ func TestBlockRewards(t *testing.T) {
assert.Equal(t, false, resp.Finalized)
})
t.Run("deneb", func(t *testing.T) {
st, sbb, err := BlockRewardTestSetup(t, "deneb")
st, sbb, err := BlockRewardTestSetup(t, version.Deneb)
require.NoError(t, err)
mockChainService := &mock.ChainService{Optimistic: true}
@@ -349,7 +410,7 @@ func TestBlockRewards(t *testing.T) {
writer.Body = &bytes.Buffer{}
s.BlockRewards(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
require.Equal(t, http.StatusOK, writer.Code)
resp := &structs.BlockRewardsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, "12", resp.Data.ProposerIndex)
@@ -361,6 +422,42 @@ func TestBlockRewards(t *testing.T) {
assert.Equal(t, true, resp.ExecutionOptimistic)
assert.Equal(t, false, resp.Finalized)
})
t.Run("electra", func(t *testing.T) {
st, sbb, err := BlockRewardTestSetup(t, version.Electra)
require.NoError(t, err)
mockChainService := &mock.ChainService{Optimistic: true}
s := &Server{
Blocker: &testutil.MockBlocker{SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{
0: phase0block,
2: sbb,
}},
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
BlockRewardFetcher: &BlockRewardService{
Replayer: mockstategen.NewReplayerBuilder(mockstategen.WithMockState(st)),
DB: db,
},
}
url := "http://only.the.slot.number.at.the.end.is.important/2"
request := httptest.NewRequest("GET", url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.BlockRewards(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
resp := &structs.BlockRewardsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, "4", resp.Data.ProposerIndex)
assert.Equal(t, "15714490", resp.Data.Total)
assert.Equal(t, "89442", resp.Data.Attestations)
assert.Equal(t, "48", resp.Data.SyncAggregate)
assert.Equal(t, "7812500", resp.Data.AttesterSlashings)
assert.Equal(t, "7812500", resp.Data.ProposerSlashings)
assert.Equal(t, true, resp.ExecutionOptimistic)
assert.Equal(t, false, resp.Finalized)
})
}
func TestAttestationRewards(t *testing.T) {

View File

@@ -1,6 +1,7 @@
package beacon
import (
"os"
"testing"
"github.com/prysmaticlabs/prysm/v5/cmd/beacon-chain/flags"
@@ -21,5 +22,5 @@ func TestMain(m *testing.M) {
flags.Init(resetFlags)
}()
m.Run()
os.Exit(m.Run())
}

View File

@@ -2,6 +2,7 @@ package validator
import (
"io"
"os"
"testing"
"github.com/prysmaticlabs/prysm/v5/config/params"
@@ -16,5 +17,5 @@ func TestMain(m *testing.M) {
defer params.OverrideBeaconConfig(prevConfig)
params.OverrideBeaconConfig(params.MinimalSpecConfig())
m.Run()
os.Exit(m.Run())
}

View File

@@ -41,6 +41,7 @@ go_library(
"//encoding/bytesutil:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
@@ -83,6 +84,7 @@ go_test(
"//crypto/bls/common:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",

View File

@@ -11,6 +11,7 @@ import (
slashertypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher/types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/sirupsen/logrus"
)
@@ -232,6 +233,43 @@ func (m *MinSpanChunksSlice) CheckSlashable(
surroundingVotesTotal.Inc()
// Both attestations should have the same type. If not, we convert both to Electra attestations.
unifyAttWrapperVersion(existingAttWrapper, incomingAttWrapper)
postElectra := existingAttWrapper.IndexedAttestation.Version() >= version.Electra
if postElectra {
existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf(
"existing attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestationElectra{},
existingAttWrapper.IndexedAttestation,
)
}
incoming, ok := incomingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf(
"incoming attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestationElectra{},
incomingAttWrapper.IndexedAttestation,
)
}
slashing := &ethpb.AttesterSlashingElectra{
Attestation_1: existing,
Attestation_2: incoming,
}
// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(existingAttWrapper.DataRoot[:], incomingAttWrapper.DataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: incoming,
Attestation_2: existing,
}
}
return slashing, nil
}
existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
@@ -328,6 +366,43 @@ func (m *MaxSpanChunksSlice) CheckSlashable(
surroundedVotesTotal.Inc()
// Both attestations should have the same type. If not, we convert the non-Electra attestation into an Electra attestation.
unifyAttWrapperVersion(existingAttWrapper, incomingAttWrapper)
postElectra := existingAttWrapper.IndexedAttestation.Version() >= version.Electra
if postElectra {
existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf(
"existing attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestationElectra{},
existingAttWrapper.IndexedAttestation,
)
}
incoming, ok := incomingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf(
"incoming attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestationElectra{},
incomingAttWrapper.IndexedAttestation,
)
}
slashing := &ethpb.AttesterSlashingElectra{
Attestation_1: existing,
Attestation_2: incoming,
}
// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(existingAttWrapper.DataRoot[:], incomingAttWrapper.DataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: incoming,
Attestation_2: existing,
}
}
return slashing, nil
}
existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(

View File

@@ -3,12 +3,14 @@ package slasher
import (
"context"
"math"
"reflect"
"testing"
dbtest "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
slashertypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher/types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
@@ -82,6 +84,99 @@ func TestMaxSpanChunksSlice_MaxChunkSpanFrom(t *testing.T) {
func TestMinSpanChunksSlice_CheckSlashable(t *testing.T) {
ctx := context.Background()
for _, v := range []int{version.Phase0, version.Electra} {
t.Run(version.String(v), func(t *testing.T) {
slasherDB := dbtest.SetupSlasherDB(t)
params := &Parameters{
chunkSize: 3,
validatorChunkSize: 2,
historyLength: 3,
}
validatorIdx := primitives.ValidatorIndex(1)
source := primitives.Epoch(1)
target := primitives.Epoch(2)
att := createAttestationWrapperEmptySig(t, v, source, target, nil, nil)
// A faulty chunk should lead to error.
chunk := &MinSpanChunksSlice{
params: params,
data: []uint16{},
}
_, err := chunk.CheckSlashable(ctx, nil, validatorIdx, att)
require.ErrorContains(t, "could not get min target for validator", err)
// We initialize a proper slice with 2 chunks with chunk size 3, 2 validators, and
// a history length of 3 representing a perfect attesting history.
//
// val0 val1
// { } { }
// [2, 2, 2, 2, 2, 2]
data := []uint16{2, 2, 2, 2, 2, 2}
chunk, err = MinChunkSpansSliceFrom(params, data)
require.NoError(t, err)
// An attestation with source 1 and target 2 should not be slashable
// based on our min chunk for either validator.
slashing, err := chunk.CheckSlashable(ctx, slasherDB, validatorIdx, att)
require.NoError(t, err)
require.Equal(t, nil, slashing)
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx.Sub(1), att)
require.NoError(t, err)
require.Equal(t, nil, slashing)
// Next up we initialize an empty chunks slice and mark an attestation
// with (source 1, target 2) as attested.
chunk = EmptyMinSpanChunksSlice(params)
source = primitives.Epoch(1)
target = primitives.Epoch(2)
att = createAttestationWrapperEmptySig(t, v, source, target, nil, nil)
chunkIndex := uint64(0)
startEpoch := target
currentEpoch := target
_, err = chunk.Update(chunkIndex, currentEpoch, validatorIdx, startEpoch, target)
require.NoError(t, err)
// Next up, we create a surrounding vote, but it should NOT be slashable
// because we DO NOT have an existing attestation record in our database at the min target epoch.
source = primitives.Epoch(0)
target = primitives.Epoch(3)
surroundingVote := createAttestationWrapperEmptySig(t, v, source, target, nil, nil)
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx, surroundingVote)
require.NoError(t, err)
require.Equal(t, nil, slashing)
// Next up, we save the old attestation record, then check if the
// surrounding vote is indeed slashable.
attData := att.IndexedAttestation.GetData()
attRecord := createAttestationWrapperEmptySig(t, v, attData.Source.Epoch, attData.Target.Epoch, []uint64{uint64(validatorIdx)}, []byte{1})
err = slasherDB.SaveAttestationRecordsForValidators(
ctx,
[]*slashertypes.IndexedAttestationWrapper{attRecord},
)
require.NoError(t, err)
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx, surroundingVote)
require.NoError(t, err)
require.Equal(t, false, reflect.ValueOf(slashing).IsNil())
// We check the attestation with the lower data root is the first attestation.
// Firstly we require the setup to have the surrounding vote as the second attestation.
// Then we modify the root of the surrounding vote and expect the vote to be the first attestation.
require.DeepEqual(t, surroundingVote.IndexedAttestation, slashing.SecondAttestation())
surroundingVote.DataRoot = [32]byte{}
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx, surroundingVote)
require.NoError(t, err)
require.Equal(t, false, reflect.ValueOf(slashing).IsNil())
assert.DeepEqual(t, surroundingVote.IndexedAttestation, slashing.FirstAttestation())
})
}
}
func TestMinSpanChunksSlice_CheckSlashable_DifferentVersions(t *testing.T) {
ctx := context.Background()
slasherDB := dbtest.SetupSlasherDB(t)
params := &Parameters{
chunkSize: 3,
@@ -91,75 +186,138 @@ func TestMinSpanChunksSlice_CheckSlashable(t *testing.T) {
validatorIdx := primitives.ValidatorIndex(1)
source := primitives.Epoch(1)
target := primitives.Epoch(2)
att := createAttestationWrapperEmptySig(t, source, target, nil, nil)
// A faulty chunk should lead to error.
chunk := &MinSpanChunksSlice{
params: params,
data: []uint16{},
}
_, err := chunk.CheckSlashable(ctx, nil, validatorIdx, att)
require.ErrorContains(t, "could not get min target for validator", err)
// We create a vote with Phase0 version.
att := createAttestationWrapperEmptySig(t, version.Phase0, source, target, nil, nil)
// We initialize a proper slice with 2 chunks with chunk size 3, 2 validators, and
// a history length of 3 representing a perfect attesting history.
//
// val0 val1
// { } { }
// [2, 2, 2, 2, 2, 2]
data := []uint16{2, 2, 2, 2, 2, 2}
chunk, err = MinChunkSpansSliceFrom(params, data)
require.NoError(t, err)
// An attestation with source 1 and target 2 should not be slashable
// based on our min chunk for either validator.
slashing, err := chunk.CheckSlashable(ctx, slasherDB, validatorIdx, att)
require.NoError(t, err)
require.Equal(t, nil, slashing)
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx.Sub(1), att)
require.NoError(t, err)
require.Equal(t, nil, slashing)
// Next up we initialize an empty chunks slice and mark an attestation
// with (source 1, target 2) as attested.
chunk = EmptyMinSpanChunksSlice(params)
source = primitives.Epoch(1)
target = primitives.Epoch(2)
att = createAttestationWrapperEmptySig(t, source, target, nil, nil)
// We initialize an empty chunks slice and mark an attestation with (source 1, target 2) as attested.
chunk := EmptyMinSpanChunksSlice(params)
chunkIndex := uint64(0)
startEpoch := target
currentEpoch := target
_, err = chunk.Update(chunkIndex, currentEpoch, validatorIdx, startEpoch, target)
_, err := chunk.Update(chunkIndex, currentEpoch, validatorIdx, startEpoch, target)
require.NoError(t, err)
// Next up, we create a surrounding vote, but it should NOT be slashable
// because we DO NOT have an existing attestation record in our database at the min target epoch.
// We create a surrounding vote with Electra version.
source = primitives.Epoch(0)
target = primitives.Epoch(3)
surroundingVote := createAttestationWrapperEmptySig(t, source, target, nil, nil)
surroundingVote := createAttestationWrapperEmptySig(t, version.Electra, source, target, nil, nil)
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx, surroundingVote)
require.NoError(t, err)
require.Equal(t, nil, slashing)
// Next up, we save the old attestation record, then check if the
// surrounding vote is indeed slashable.
// We save the old attestation record, then check if the surrounding vote is indeed slashable.
attData := att.IndexedAttestation.GetData()
attRecord := createAttestationWrapperEmptySig(t, attData.Source.Epoch, attData.Target.Epoch, []uint64{uint64(validatorIdx)}, []byte{1})
attRecord := createAttestationWrapperEmptySig(t, version.Phase0, attData.Source.Epoch, attData.Target.Epoch, []uint64{uint64(validatorIdx)}, []byte{1})
err = slasherDB.SaveAttestationRecordsForValidators(
ctx,
[]*slashertypes.IndexedAttestationWrapper{attRecord},
)
require.NoError(t, err)
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx, surroundingVote)
slashing, err := chunk.CheckSlashable(ctx, slasherDB, validatorIdx, surroundingVote)
require.NoError(t, err)
require.NotEqual(t, (*ethpb.AttesterSlashing)(nil), slashing)
// The old record should be converted to Electra and the resulting slashing should be an Electra slashing.
electraSlashing, ok := slashing.(*ethpb.AttesterSlashingElectra)
require.Equal(t, true, ok, "slashing has the wrong type")
assert.NotNil(t, electraSlashing)
}
func TestMaxSpanChunksSlice_CheckSlashable(t *testing.T) {
ctx := context.Background()
for _, v := range []int{version.Phase0, version.Electra} {
t.Run(version.String(v), func(t *testing.T) {
slasherDB := dbtest.SetupSlasherDB(t)
params := &Parameters{
chunkSize: 4,
validatorChunkSize: 2,
historyLength: 4,
}
validatorIdx := primitives.ValidatorIndex(1)
source := primitives.Epoch(1)
target := primitives.Epoch(2)
att := createAttestationWrapperEmptySig(t, v, source, target, nil, nil)
// A faulty chunk should lead to error.
chunk := &MaxSpanChunksSlice{
params: params,
data: []uint16{},
}
_, err := chunk.CheckSlashable(ctx, nil, validatorIdx, att)
require.ErrorContains(t, "could not get max target for validator", err)
// We initialize a proper slice with 2 chunks with chunk size 4, 2 validators, and
// a history length of 4 representing a perfect attesting history.
//
// val0 val1
// { } { }
// [0, 0, 0, 0, 0, 0, 0, 0]
data := []uint16{0, 0, 0, 0, 0, 0, 0, 0}
chunk, err = MaxChunkSpansSliceFrom(params, data)
require.NoError(t, err)
// An attestation with source 1 and target 2 should not be slashable
// based on our max chunk for either validator.
slashing, err := chunk.CheckSlashable(ctx, slasherDB, validatorIdx, att)
require.NoError(t, err)
require.Equal(t, nil, slashing)
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx.Sub(1), att)
require.NoError(t, err)
require.Equal(t, nil, slashing)
// Next up we initialize an empty chunks slice and mark an attestation
// with (source 0, target 3) as attested.
chunk = EmptyMaxSpanChunksSlice(params)
source = primitives.Epoch(0)
target = primitives.Epoch(3)
att = createAttestationWrapperEmptySig(t, v, source, target, nil, nil)
chunkIndex := uint64(0)
startEpoch := source
currentEpoch := target
_, err = chunk.Update(chunkIndex, currentEpoch, validatorIdx, startEpoch, target)
require.NoError(t, err)
// Next up, we create a surrounded vote, but it should NOT be slashable
// because we DO NOT have an existing attestation record in our database at the max target epoch.
source = primitives.Epoch(1)
target = primitives.Epoch(2)
surroundedVote := createAttestationWrapperEmptySig(t, v, source, target, nil, nil)
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx, surroundedVote)
require.NoError(t, err)
require.Equal(t, nil, slashing)
// Next up, we save the old attestation record, then check if the
// surroundedVote vote is indeed slashable.
attData := att.IndexedAttestation.GetData()
signingRoot := [32]byte{1}
attRecord := createAttestationWrapperEmptySig(
t, v, attData.Source.Epoch, attData.Target.Epoch, []uint64{uint64(validatorIdx)}, signingRoot[:],
)
err = slasherDB.SaveAttestationRecordsForValidators(
ctx,
[]*slashertypes.IndexedAttestationWrapper{attRecord},
)
require.NoError(t, err)
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx, surroundedVote)
require.NoError(t, err)
require.Equal(t, false, reflect.ValueOf(slashing).IsNil())
// We check the attestation with the lower data root is the first attestation.
// Firstly we require the setup to have the surrounded vote as the second attestation.
// Then we modify the root of the surrounded vote and expect the vote to be the first attestation.
require.DeepEqual(t, surroundedVote.IndexedAttestation, slashing.SecondAttestation())
surroundedVote.DataRoot = [32]byte{}
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx, surroundedVote)
require.NoError(t, err)
require.Equal(t, false, reflect.ValueOf(slashing).IsNil())
assert.DeepEqual(t, surroundedVote.IndexedAttestation, slashing.FirstAttestation())
})
}
}
func TestMaxSpanChunksSlice_CheckSlashable_DifferentVersions(t *testing.T) {
ctx := context.Background()
slasherDB := dbtest.SetupSlasherDB(t)
params := &Parameters{
chunkSize: 4,
@@ -167,76 +325,38 @@ func TestMaxSpanChunksSlice_CheckSlashable(t *testing.T) {
historyLength: 4,
}
validatorIdx := primitives.ValidatorIndex(1)
source := primitives.Epoch(1)
target := primitives.Epoch(2)
att := createAttestationWrapperEmptySig(t, source, target, nil, nil)
source := primitives.Epoch(0)
target := primitives.Epoch(3)
// A faulty chunk should lead to error.
chunk := &MaxSpanChunksSlice{
params: params,
data: []uint16{},
}
_, err := chunk.CheckSlashable(ctx, nil, validatorIdx, att)
require.ErrorContains(t, "could not get max target for validator", err)
// We create a vote with Phase0 version.
att := createAttestationWrapperEmptySig(t, version.Phase0, source, target, nil, nil)
// We initialize a proper slice with 2 chunks with chunk size 4, 2 validators, and
// a history length of 4 representing a perfect attesting history.
//
// val0 val1
// { } { }
// [0, 0, 0, 0, 0, 0, 0, 0]
data := []uint16{0, 0, 0, 0, 0, 0, 0, 0}
chunk, err = MaxChunkSpansSliceFrom(params, data)
require.NoError(t, err)
// An attestation with source 1 and target 2 should not be slashable
// based on our max chunk for either validator.
slashing, err := chunk.CheckSlashable(ctx, slasherDB, validatorIdx, att)
require.NoError(t, err)
require.Equal(t, nil, slashing)
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx.Sub(1), att)
require.NoError(t, err)
require.Equal(t, nil, slashing)
// Next up we initialize an empty chunks slice and mark an attestation
// with (source 0, target 3) as attested.
chunk = EmptyMaxSpanChunksSlice(params)
source = primitives.Epoch(0)
target = primitives.Epoch(3)
att = createAttestationWrapperEmptySig(t, source, target, nil, nil)
// We initialize an empty chunks slice and mark an attestation with (source 0, target 3) as attested.
chunk := EmptyMaxSpanChunksSlice(params)
chunkIndex := uint64(0)
startEpoch := source
currentEpoch := target
_, err = chunk.Update(chunkIndex, currentEpoch, validatorIdx, startEpoch, target)
_, err := chunk.Update(chunkIndex, target, validatorIdx, source, target)
require.NoError(t, err)
// Next up, we create a surrounded vote, but it should NOT be slashable
// because we DO NOT have an existing attestation record in our database at the max target epoch.
// We create a surrounded vote with Electra version.
source = primitives.Epoch(1)
target = primitives.Epoch(2)
surroundedVote := createAttestationWrapperEmptySig(t, source, target, nil, nil)
surroundedVote := createAttestationWrapperEmptySig(t, version.Electra, source, target, nil, nil)
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx, surroundedVote)
require.NoError(t, err)
require.Equal(t, nil, slashing)
// Next up, we save the old attestation record, then check if the
// surroundedVote vote is indeed slashable.
// We save the old attestation record, then check if the surrounded vote is indeed slashable.
attData := att.IndexedAttestation.GetData()
signingRoot := [32]byte{1}
attRecord := createAttestationWrapperEmptySig(
t, attData.Source.Epoch, attData.Target.Epoch, []uint64{uint64(validatorIdx)}, signingRoot[:],
)
attRecord := createAttestationWrapperEmptySig(t, version.Phase0, attData.Source.Epoch, attData.Target.Epoch, []uint64{uint64(validatorIdx)}, []byte{1})
err = slasherDB.SaveAttestationRecordsForValidators(
ctx,
[]*slashertypes.IndexedAttestationWrapper{attRecord},
)
require.NoError(t, err)
slashing, err = chunk.CheckSlashable(ctx, slasherDB, validatorIdx, surroundedVote)
slashing, err := chunk.CheckSlashable(ctx, slasherDB, validatorIdx, surroundedVote)
require.NoError(t, err)
require.NotEqual(t, (*ethpb.AttesterSlashing)(nil), slashing)
// The old record should be converted to Electra and the resulting slashing should be an Electra slashing.
electraSlashing, ok := slashing.(*ethpb.AttesterSlashingElectra)
require.Equal(t, true, ok, "slashing has wrong type")
assert.NotNil(t, electraSlashing)
}
func TestMinSpanChunksSlice_Update_MultipleChunks(t *testing.T) {

View File

@@ -11,6 +11,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"golang.org/x/exp/maps"
)
@@ -193,33 +194,69 @@ func (s *Service) checkDoubleVotes(
// This is a double vote.
doubleVotesTotal.Inc()
existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"existing attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
existingAttWrapper.IndexedAttestation,
)
}
incoming, ok := incomingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"incoming attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
incomingAttWrapper.IndexedAttestation,
)
}
var slashing ethpb.AttSlashing
slashing := &ethpb.AttesterSlashing{
Attestation_1: existing,
Attestation_2: incoming,
}
// Both attestations should have the same type. If not, we convert both to Electra attestations.
unifyAttWrapperVersion(existingAttWrapper, incomingAttWrapper)
// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(existingAttWrapper.DataRoot[:], incomingAttWrapper.DataRoot[:]) > 0 {
postElectra := existingAttWrapper.IndexedAttestation.Version() >= version.Electra
if postElectra {
existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf(
"existing attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestationElectra{},
existingAttWrapper.IndexedAttestation,
)
}
incoming, ok := incomingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf(
"incoming attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestationElectra{},
incomingAttWrapper.IndexedAttestation,
)
}
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: existing,
Attestation_2: incoming,
}
// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(existingAttWrapper.DataRoot[:], incomingAttWrapper.DataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: incoming,
Attestation_2: existing,
}
}
} else {
existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"existing attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
existingAttWrapper.IndexedAttestation,
)
}
incoming, ok := incomingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"incoming attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
incomingAttWrapper.IndexedAttestation,
)
}
slashing = &ethpb.AttesterSlashing{
Attestation_1: incoming,
Attestation_2: existing,
Attestation_1: existing,
Attestation_2: incoming,
}
// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(existingAttWrapper.DataRoot[:], incomingAttWrapper.DataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashing{
Attestation_1: incoming,
Attestation_2: existing,
}
}
}
@@ -245,33 +282,69 @@ func (s *Service) checkDoubleVotes(
wrapper_1 := doubleVote.Wrapper_1
wrapper_2 := doubleVote.Wrapper_2
att_1, ok := wrapper_1.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"first attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
wrapper_1.IndexedAttestation,
)
}
att_2, ok := wrapper_2.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"second attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
wrapper_2.IndexedAttestation,
)
}
var slashing ethpb.AttSlashing
slashing := &ethpb.AttesterSlashing{
Attestation_1: att_1,
Attestation_2: att_2,
}
// Both attestations should have the same type. If not, we convert both to Electra attestations.
unifyAttWrapperVersion(wrapper_1, wrapper_2)
// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(wrapper_1.DataRoot[:], wrapper_2.DataRoot[:]) > 0 {
postElectra := wrapper_1.IndexedAttestation.Version() >= version.Electra
if postElectra {
att_1, ok := wrapper_1.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf(
"first attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestationElectra{},
wrapper_1.IndexedAttestation,
)
}
att_2, ok := wrapper_2.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf(
"second attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestationElectra{},
wrapper_2.IndexedAttestation,
)
}
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: att_1,
Attestation_2: att_2,
}
// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(wrapper_1.DataRoot[:], wrapper_2.DataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: att_2,
Attestation_2: att_1,
}
}
} else {
att_1, ok := wrapper_1.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"first attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
wrapper_1.IndexedAttestation,
)
}
att_2, ok := wrapper_2.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"second attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
wrapper_2.IndexedAttestation,
)
}
slashing = &ethpb.AttesterSlashing{
Attestation_1: att_2,
Attestation_2: att_1,
Attestation_1: att_1,
Attestation_2: att_2,
}
// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(wrapper_1.DataRoot[:], wrapper_2.DataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashing{
Attestation_1: att_2,
Attestation_2: att_1,
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/container/slice"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/sirupsen/logrus"
)
@@ -249,3 +250,24 @@ func closeDB(d *slasherkv.Store) {
log.WithError(err).Error("could not close database")
}
}
// unifyAttWrapperVersion ensures that the two wrappers wrap indexed attestations of the same version.
// If versions differ, the wrapped attestation with the lower version will be converted to the higher version.
func unifyAttWrapperVersion(w1 *slashertypes.IndexedAttestationWrapper, w2 *slashertypes.IndexedAttestationWrapper) {
if w1.IndexedAttestation.Version() == w2.IndexedAttestation.Version() {
return
}
if w1.IndexedAttestation.Version() != version.Electra {
w1.IndexedAttestation = &ethpb.IndexedAttestationElectra{
AttestingIndices: w1.IndexedAttestation.GetAttestingIndices(),
Data: w1.IndexedAttestation.GetData(),
Signature: w1.IndexedAttestation.GetSignature(),
}
return
}
w2.IndexedAttestation = &ethpb.IndexedAttestationElectra{
AttestingIndices: w2.IndexedAttestation.GetAttestingIndices(),
Data: w2.IndexedAttestation.GetData(),
Signature: w2.IndexedAttestation.GetSignature(),
}
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/require"
logTest "github.com/sirupsen/logrus/hooks/test"
)
@@ -32,13 +33,13 @@ func TestService_groupByValidatorChunkIndex(t *testing.T) {
validatorChunkSize: 2,
},
atts: []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 0, []uint64{0, 1}, nil),
createAttestationWrapperEmptySig(t, 0, 0, []uint64{0, 1}, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, []uint64{0, 1}, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, []uint64{0, 1}, nil),
},
want: map[uint64][]*slashertypes.IndexedAttestationWrapper{
0: {
createAttestationWrapperEmptySig(t, 0, 0, []uint64{0, 1}, nil),
createAttestationWrapperEmptySig(t, 0, 0, []uint64{0, 1}, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, []uint64{0, 1}, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, []uint64{0, 1}, nil),
},
},
},
@@ -48,17 +49,17 @@ func TestService_groupByValidatorChunkIndex(t *testing.T) {
validatorChunkSize: 2,
},
atts: []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 0, []uint64{0, 2, 4}, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, []uint64{0, 2, 4}, nil),
},
want: map[uint64][]*slashertypes.IndexedAttestationWrapper{
0: {
createAttestationWrapperEmptySig(t, 0, 0, []uint64{0, 2, 4}, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, []uint64{0, 2, 4}, nil),
},
1: {
createAttestationWrapperEmptySig(t, 0, 0, []uint64{0, 2, 4}, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, []uint64{0, 2, 4}, nil),
},
2: {
createAttestationWrapperEmptySig(t, 0, 0, []uint64{0, 2, 4}, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, []uint64{0, 2, 4}, nil),
},
},
},
@@ -95,13 +96,13 @@ func TestService_groupByChunkIndex(t *testing.T) {
historyLength: 3,
},
atts: []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 0, nil, nil),
createAttestationWrapperEmptySig(t, 1, 0, nil, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, nil, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 1, 0, nil, nil),
},
want: map[uint64][]*slashertypes.IndexedAttestationWrapper{
0: {
createAttestationWrapperEmptySig(t, 0, 0, nil, nil),
createAttestationWrapperEmptySig(t, 1, 0, nil, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, nil, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 1, 0, nil, nil),
},
},
},
@@ -112,17 +113,17 @@ func TestService_groupByChunkIndex(t *testing.T) {
historyLength: 3,
},
atts: []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 0, nil, nil),
createAttestationWrapperEmptySig(t, 1, 0, nil, nil),
createAttestationWrapperEmptySig(t, 2, 0, nil, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, nil, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 1, 0, nil, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 2, 0, nil, nil),
},
want: map[uint64][]*slashertypes.IndexedAttestationWrapper{
0: {
createAttestationWrapperEmptySig(t, 0, 0, nil, nil),
createAttestationWrapperEmptySig(t, 1, 0, nil, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, nil, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 1, 0, nil, nil),
},
1: {
createAttestationWrapperEmptySig(t, 2, 0, nil, nil),
createAttestationWrapperEmptySig(t, version.Phase0, 2, 0, nil, nil),
},
},
},
@@ -207,7 +208,7 @@ func TestService_filterAttestations(t *testing.T) {
{
name: "Source > target gets dropped",
input: []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 1, 0, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 1, 0, []uint64{1}, make([]byte, 32)),
},
inputEpoch: 0,
wantedDropped: 1,
@@ -215,33 +216,33 @@ func TestService_filterAttestations(t *testing.T) {
{
name: "Source < target is valid",
input: []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 1, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 1, []uint64{1}, make([]byte, 32)),
},
inputEpoch: 1,
wantedValid: []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 1, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 1, []uint64{1}, make([]byte, 32)),
},
wantedDropped: 0,
},
{
name: "Source == target is valid",
input: []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 0, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, []uint64{1}, make([]byte, 32)),
},
inputEpoch: 1,
wantedValid: []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 0, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, []uint64{1}, make([]byte, 32)),
},
wantedDropped: 0,
},
{
name: "Attestation from the future is deferred",
input: []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 2, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 2, []uint64{1}, make([]byte, 32)),
},
inputEpoch: 1,
wantedDeferred: []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 2, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 2, []uint64{1}, make([]byte, 32)),
},
wantedDropped: 0,
},
@@ -271,22 +272,22 @@ func Test_logSlashingEvent(t *testing.T) {
{
name: "Surrounding vote",
slashing: &ethpb.AttesterSlashing{
Attestation_1: createAttestationWrapperEmptySig(t, 0, 0, nil, nil).IndexedAttestation.(*ethpb.IndexedAttestation),
Attestation_2: createAttestationWrapperEmptySig(t, 0, 0, nil, nil).IndexedAttestation.(*ethpb.IndexedAttestation),
Attestation_1: createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, nil, nil).IndexedAttestation.(*ethpb.IndexedAttestation),
Attestation_2: createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, nil, nil).IndexedAttestation.(*ethpb.IndexedAttestation),
},
},
{
name: "Surrounded vote",
slashing: &ethpb.AttesterSlashing{
Attestation_1: createAttestationWrapperEmptySig(t, 0, 0, nil, nil).IndexedAttestation.(*ethpb.IndexedAttestation),
Attestation_2: createAttestationWrapperEmptySig(t, 0, 0, nil, nil).IndexedAttestation.(*ethpb.IndexedAttestation),
Attestation_1: createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, nil, nil).IndexedAttestation.(*ethpb.IndexedAttestation),
Attestation_2: createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, nil, nil).IndexedAttestation.(*ethpb.IndexedAttestation),
},
},
{
name: "Double vote",
slashing: &ethpb.AttesterSlashing{
Attestation_1: createAttestationWrapperEmptySig(t, 0, 0, nil, nil).IndexedAttestation.(*ethpb.IndexedAttestation),
Attestation_2: createAttestationWrapperEmptySig(t, 0, 0, nil, nil).IndexedAttestation.(*ethpb.IndexedAttestation),
Attestation_1: createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, nil, nil).IndexedAttestation.(*ethpb.IndexedAttestation),
Attestation_2: createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, nil, nil).IndexedAttestation.(*ethpb.IndexedAttestation),
},
},
}

View File

@@ -5,6 +5,7 @@ import (
slashertypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher/types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
@@ -12,8 +13,8 @@ func Test_attestationsQueue(t *testing.T) {
t.Run("push_and_dequeue", func(tt *testing.T) {
attQueue := newAttestationsQueue()
wantedAtts := []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 1, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, 1, 2, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 1, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 1, 2, []uint64{1}, make([]byte, 32)),
}
attQueue.push(wantedAtts[0])
attQueue.push(wantedAtts[1])
@@ -27,8 +28,8 @@ func Test_attestationsQueue(t *testing.T) {
t.Run("extend_and_dequeue", func(tt *testing.T) {
attQueue := newAttestationsQueue()
wantedAtts := []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 1, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, 1, 2, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 1, []uint64{1}, make([]byte, 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 1, 2, []uint64{1}, make([]byte, 32)),
}
attQueue.extend(wantedAtts)
require.DeepEqual(t, 2, attQueue.size())

View File

@@ -13,6 +13,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util"
@@ -38,8 +39,8 @@ func TestSlasher_receiveAttestations_OK(t *testing.T) {
}()
firstIndices := []uint64{1, 2, 3}
secondIndices := []uint64{4, 5, 6}
att1 := createAttestationWrapperEmptySig(t, 1, 2, firstIndices, nil)
att2 := createAttestationWrapperEmptySig(t, 1, 2, secondIndices, nil)
att1 := createAttestationWrapperEmptySig(t, version.Phase0, 1, 2, firstIndices, nil)
att2 := createAttestationWrapperEmptySig(t, version.Phase0, 1, 2, secondIndices, nil)
wrappedAtt1 := &slashertypes.WrappedIndexedAtt{IndexedAtt: att1.IndexedAttestation}
wrappedAtt2 := &slashertypes.WrappedIndexedAtt{IndexedAtt: att2.IndexedAttestation}
indexedAttsChan <- wrappedAtt1
@@ -67,14 +68,14 @@ func TestService_pruneSlasherDataWithinSlidingWindow_AttestationsPruned(t *testi
// Setup attestations for 2 validators at each epoch for epochs 0, 1, 2, 3.
err := slasherDB.SaveAttestationRecordsForValidators(ctx, []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 0, []uint64{0}, bytesutil.PadTo([]byte("0a"), 32)),
createAttestationWrapperEmptySig(t, 0, 0, []uint64{1}, bytesutil.PadTo([]byte("0b"), 32)),
createAttestationWrapperEmptySig(t, 0, 1, []uint64{0}, bytesutil.PadTo([]byte("1a"), 32)),
createAttestationWrapperEmptySig(t, 0, 1, []uint64{1}, bytesutil.PadTo([]byte("1b"), 32)),
createAttestationWrapperEmptySig(t, 0, 2, []uint64{0}, bytesutil.PadTo([]byte("2a"), 32)),
createAttestationWrapperEmptySig(t, 0, 2, []uint64{1}, bytesutil.PadTo([]byte("2b"), 32)),
createAttestationWrapperEmptySig(t, 0, 3, []uint64{0}, bytesutil.PadTo([]byte("3a"), 32)),
createAttestationWrapperEmptySig(t, 0, 3, []uint64{1}, bytesutil.PadTo([]byte("3b"), 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, []uint64{0}, bytesutil.PadTo([]byte("0a"), 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 0, []uint64{1}, bytesutil.PadTo([]byte("0b"), 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 1, []uint64{0}, bytesutil.PadTo([]byte("1a"), 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 1, []uint64{1}, bytesutil.PadTo([]byte("1b"), 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 2, []uint64{0}, bytesutil.PadTo([]byte("2a"), 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 2, []uint64{1}, bytesutil.PadTo([]byte("2b"), 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 3, []uint64{0}, bytesutil.PadTo([]byte("3a"), 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 3, []uint64{1}, bytesutil.PadTo([]byte("3b"), 32)),
})
require.NoError(t, err)
@@ -95,8 +96,8 @@ func TestService_pruneSlasherDataWithinSlidingWindow_AttestationsPruned(t *testi
// Setup attestations for 2 validators at epoch 4.
err = slasherDB.SaveAttestationRecordsForValidators(ctx, []*slashertypes.IndexedAttestationWrapper{
createAttestationWrapperEmptySig(t, 0, 4, []uint64{0}, bytesutil.PadTo([]byte("4a"), 32)),
createAttestationWrapperEmptySig(t, 0, 4, []uint64{1}, bytesutil.PadTo([]byte("4b"), 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 4, []uint64{0}, bytesutil.PadTo([]byte("4a"), 32)),
createAttestationWrapperEmptySig(t, version.Phase0, 0, 4, []uint64{1}, bytesutil.PadTo([]byte("4b"), 32)),
})
require.NoError(t, err)
@@ -224,7 +225,7 @@ func TestSlasher_receiveAttestations_OnlyValidAttestations(t *testing.T) {
firstIndices := []uint64{1, 2, 3}
secondIndices := []uint64{4, 5, 6}
// Add a valid attestation.
validAtt := createAttestationWrapperEmptySig(t, 1, 2, firstIndices, nil)
validAtt := createAttestationWrapperEmptySig(t, version.Phase0, 1, 2, firstIndices, nil)
wrappedValidAtt := &slashertypes.WrappedIndexedAtt{IndexedAtt: validAtt.IndexedAttestation}
indexedAttsChan <- wrappedValidAtt
// Send an invalid, bad attestation which will not

View File

@@ -3,6 +3,7 @@ package slasher
import (
"context"
"io"
"os"
"testing"
"time"
@@ -23,7 +24,7 @@ func TestMain(m *testing.M) {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(io.Discard)
m.Run()
os.Exit(m.Run())
}
func TestService_StartStop_ChainInitialized(t *testing.T) {

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
"os"
"sync"
"testing"
"time"
@@ -70,7 +71,7 @@ func TestMain(m *testing.M) {
flags.Init(resetFlags)
}()
m.Run()
os.Exit(m.Run())
}
func initializeTestServices(t *testing.T, slots []primitives.Slot, peers []*peerData) (*mock.ChainService, *p2pt.TestP2P, db.Database) {

View File

@@ -2,6 +2,7 @@ package sync
import (
"io"
"os"
"testing"
"github.com/prysmaticlabs/prysm/v5/cmd/beacon-chain/flags"
@@ -22,5 +23,5 @@ func TestMain(m *testing.M) {
defer func() {
flags.Init(resetFlags)
}()
m.Run()
os.Exit(m.Run())
}

View File

@@ -0,0 +1,3 @@
### Fixed
- `nodeFilter`: Implement `filterPeerForBlobSubnet` to avoid error logs.

View File

@@ -0,0 +1,3 @@
### Fixed
- `UpgradeToFulu`: Respect the specification.

View File

@@ -0,0 +1,3 @@
### Added
- Update slasher service to Electra

View File

@@ -0,0 +1,3 @@
### Added
- Update `proto_test.go` to Electra.

View File

@@ -0,0 +1,3 @@
### Added
- Add Electra test case to rewards API.

View File

@@ -55,6 +55,7 @@ go_test(
embed = [":go_default_library"],
deps = [
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",

View File

@@ -4,6 +4,8 @@ import (
"testing"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
@@ -17,8 +19,10 @@ type fields struct {
sig [96]byte
deposits []*eth.Deposit
atts []*eth.Attestation
attsElectra []*eth.AttestationElectra
proposerSlashings []*eth.ProposerSlashing
attesterSlashings []*eth.AttesterSlashing
attesterSlashingsElectra []*eth.AttesterSlashingElectra
voluntaryExits []*eth.SignedVoluntaryExit
syncAggregate *eth.SyncAggregate
execPayload *enginev1.ExecutionPayload
@@ -29,6 +33,7 @@ type fields struct {
execPayloadHeaderDeneb *enginev1.ExecutionPayloadHeaderDeneb
blsToExecutionChanges []*eth.SignedBLSToExecutionChange
kzgCommitments [][]byte
execRequests *enginev1.ExecutionRequests
}
func Test_SignedBeaconBlock_Proto(t *testing.T) {
@@ -306,6 +311,74 @@ func Test_SignedBeaconBlock_Proto(t *testing.T) {
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
t.Run("Electra", func(t *testing.T) {
expectedBlock := &eth.SignedBeaconBlockElectra{
Block: &eth.BeaconBlockElectra{
Slot: 128,
ProposerIndex: 128,
ParentRoot: f.root[:],
StateRoot: f.root[:],
Body: bodyPbElectra(),
},
Signature: f.sig[:],
}
block := &SignedBeaconBlock{
version: version.Electra,
block: &BeaconBlock{
version: version.Electra,
slot: 128,
proposerIndex: 128,
parentRoot: f.root,
stateRoot: f.root,
body: bodyElectra(t),
},
signature: f.sig,
}
result, err := block.Proto()
require.NoError(t, err)
resultBlock, ok := result.(*eth.SignedBeaconBlockElectra)
require.Equal(t, true, ok)
resultHTR, err := resultBlock.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBlock.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
t.Run("ElectraBlind", func(t *testing.T) {
expectedBlock := &eth.SignedBlindedBeaconBlockElectra{
Message: &eth.BlindedBeaconBlockElectra{
Slot: 128,
ProposerIndex: 128,
ParentRoot: f.root[:],
StateRoot: f.root[:],
Body: bodyPbBlindedElectra(),
},
Signature: f.sig[:],
}
block := &SignedBeaconBlock{
version: version.Electra,
block: &BeaconBlock{
version: version.Electra,
slot: 128,
proposerIndex: 128,
parentRoot: f.root,
stateRoot: f.root,
body: bodyBlindedElectra(t),
},
signature: f.sig,
}
result, err := block.Proto()
require.NoError(t, err)
resultBlock, ok := result.(*eth.SignedBlindedBeaconBlockElectra)
require.Equal(t, true, ok)
resultHTR, err := resultBlock.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBlock.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
}
func Test_BeaconBlock_Proto(t *testing.T) {
@@ -527,6 +600,60 @@ func Test_BeaconBlock_Proto(t *testing.T) {
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
t.Run("Electra", func(t *testing.T) {
expectedBlock := &eth.BeaconBlockElectra{
Slot: 128,
ProposerIndex: 128,
ParentRoot: f.root[:],
StateRoot: f.root[:],
Body: bodyPbElectra(),
}
block := &BeaconBlock{
version: version.Electra,
slot: 128,
proposerIndex: 128,
parentRoot: f.root,
stateRoot: f.root,
body: bodyElectra(t),
}
result, err := block.Proto()
require.NoError(t, err)
resultBlock, ok := result.(*eth.BeaconBlockElectra)
require.Equal(t, true, ok)
resultHTR, err := resultBlock.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBlock.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
t.Run("ElectraBlind", func(t *testing.T) {
expectedBlock := &eth.BlindedBeaconBlockElectra{
Slot: 128,
ProposerIndex: 128,
ParentRoot: f.root[:],
StateRoot: f.root[:],
Body: bodyPbBlindedElectra(),
}
block := &BeaconBlock{
version: version.Electra,
slot: 128,
proposerIndex: 128,
parentRoot: f.root,
stateRoot: f.root,
body: bodyBlindedElectra(t),
}
result, err := block.Proto()
require.NoError(t, err)
resultBlock, ok := result.(*eth.BlindedBeaconBlockElectra)
require.Equal(t, true, ok)
resultHTR, err := resultBlock.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBlock.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
}
func Test_BeaconBlockBody_Proto(t *testing.T) {
@@ -635,6 +762,32 @@ func Test_BeaconBlockBody_Proto(t *testing.T) {
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
t.Run("Electra", func(t *testing.T) {
expectedBody := bodyPbElectra()
body := bodyElectra(t)
result, err := body.Proto()
require.NoError(t, err)
resultBlock, ok := result.(*eth.BeaconBlockBodyElectra)
require.Equal(t, true, ok)
resultHTR, err := resultBlock.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBody.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
t.Run("ElectraBlind", func(t *testing.T) {
expectedBody := bodyPbBlindedElectra()
body := bodyBlindedElectra(t)
result, err := body.Proto()
require.NoError(t, err)
resultBlock, ok := result.(*eth.BlindedBeaconBlockBodyElectra)
require.Equal(t, true, ok)
resultHTR, err := resultBlock.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBody.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
})
t.Run("Bellatrix - wrong payload type", func(t *testing.T) {
body := bodyBellatrix(t)
body.executionPayload = &executionPayloadHeader{}
@@ -671,6 +824,18 @@ func Test_BeaconBlockBody_Proto(t *testing.T) {
_, err := body.Proto()
require.ErrorIs(t, err, errPayloadHeaderWrongType)
})
t.Run("Electra - wrong payload type", func(t *testing.T) {
body := bodyElectra(t)
body.executionPayload = &executionPayloadHeaderDeneb{}
_, err := body.Proto()
require.ErrorIs(t, err, errPayloadWrongType)
})
t.Run("ElectraBlind - wrong payload type", func(t *testing.T) {
body := bodyBlindedElectra(t)
body.executionPayloadHeader = &executionPayloadDeneb{}
_, err := body.Proto()
require.ErrorIs(t, err, errPayloadHeaderWrongType)
})
}
func Test_initSignedBlockFromProtoPhase0(t *testing.T) {
@@ -849,6 +1014,50 @@ func Test_initBlindedSignedBlockFromProtoDeneb(t *testing.T) {
assert.DeepEqual(t, expectedBlock.Signature, resultBlock.signature[:])
}
func Test_initSignedBlockFromProtoElectra(t *testing.T) {
f := getFields()
expectedBlock := &eth.SignedBeaconBlockElectra{
Block: &eth.BeaconBlockElectra{
Slot: 128,
ProposerIndex: 128,
ParentRoot: f.root[:],
StateRoot: f.root[:],
Body: bodyPbElectra(),
},
Signature: f.sig[:],
}
resultBlock, err := initSignedBlockFromProtoElectra(expectedBlock)
require.NoError(t, err)
resultHTR, err := resultBlock.block.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBlock.Block.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
assert.DeepEqual(t, expectedBlock.Signature, resultBlock.signature[:])
}
func Test_initBlindedSignedBlockFromProtoElectra(t *testing.T) {
f := getFields()
expectedBlock := &eth.SignedBlindedBeaconBlockElectra{
Message: &eth.BlindedBeaconBlockElectra{
Slot: 128,
ProposerIndex: 128,
ParentRoot: f.root[:],
StateRoot: f.root[:],
Body: bodyPbBlindedElectra(),
},
Signature: f.sig[:],
}
resultBlock, err := initBlindedSignedBlockFromProtoElectra(expectedBlock)
require.NoError(t, err)
resultHTR, err := resultBlock.block.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBlock.Message.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
assert.DeepEqual(t, expectedBlock.Signature, resultBlock.signature[:])
}
func Test_initBlockFromProtoPhase0(t *testing.T) {
f := getFields()
expectedBlock := &eth.BeaconBlock{
@@ -993,6 +1202,42 @@ func Test_initBlockFromProtoBlindedDeneb(t *testing.T) {
assert.DeepEqual(t, expectedHTR, resultHTR)
}
func Test_initBlockFromProtoElectra(t *testing.T) {
f := getFields()
expectedBlock := &eth.BeaconBlockElectra{
Slot: 128,
ProposerIndex: 128,
ParentRoot: f.root[:],
StateRoot: f.root[:],
Body: bodyPbElectra(),
}
resultBlock, err := initBlockFromProtoElectra(expectedBlock)
require.NoError(t, err)
resultHTR, err := resultBlock.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBlock.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
}
func Test_initBlockFromProtoBlindedElectra(t *testing.T) {
f := getFields()
expectedBlock := &eth.BlindedBeaconBlockElectra{
Slot: 128,
ProposerIndex: 128,
ParentRoot: f.root[:],
StateRoot: f.root[:],
Body: bodyPbBlindedElectra(),
}
resultBlock, err := initBlindedBlockFromProtoElectra(expectedBlock)
require.NoError(t, err)
resultHTR, err := resultBlock.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBlock.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
}
func Test_initBlockBodyFromProtoPhase0(t *testing.T) {
expectedBody := bodyPbPhase0()
resultBody, err := initBlockBodyFromProtoPhase0(expectedBody)
@@ -1081,6 +1326,28 @@ func Test_initBlockBodyFromProtoBlindedDeneb(t *testing.T) {
assert.DeepEqual(t, expectedHTR, resultHTR)
}
func Test_initBlockBodyFromProtoElectra(t *testing.T) {
expectedBody := bodyPbElectra()
resultBody, err := initBlockBodyFromProtoElectra(expectedBody)
require.NoError(t, err)
resultHTR, err := resultBody.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBody.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
}
func Test_initBlockBodyFromProtoBlindedElectra(t *testing.T) {
expectedBody := bodyPbBlindedElectra()
resultBody, err := initBlindedBlockBodyFromProtoElectra(expectedBody)
require.NoError(t, err)
resultHTR, err := resultBody.HashTreeRoot()
require.NoError(t, err)
expectedHTR, err := expectedBody.HashTreeRoot()
require.NoError(t, err)
assert.DeepEqual(t, expectedHTR, resultHTR)
}
func bodyPbPhase0() *eth.BeaconBlockBody {
f := getFields()
return &eth.BeaconBlockBody{
@@ -1244,6 +1511,52 @@ func bodyPbBlindedDeneb() *eth.BlindedBeaconBlockBodyDeneb {
}
}
func bodyPbElectra() *eth.BeaconBlockBodyElectra {
f := getFields()
return &eth.BeaconBlockBodyElectra{
RandaoReveal: f.sig[:],
Eth1Data: &eth.Eth1Data{
DepositRoot: f.root[:],
DepositCount: 128,
BlockHash: f.root[:],
},
Graffiti: f.root[:],
ProposerSlashings: f.proposerSlashings,
AttesterSlashings: f.attesterSlashingsElectra,
Attestations: f.attsElectra,
Deposits: f.deposits,
VoluntaryExits: f.voluntaryExits,
SyncAggregate: f.syncAggregate,
ExecutionPayload: f.execPayloadDeneb,
BlsToExecutionChanges: f.blsToExecutionChanges,
BlobKzgCommitments: f.kzgCommitments,
ExecutionRequests: f.execRequests,
}
}
func bodyPbBlindedElectra() *eth.BlindedBeaconBlockBodyElectra {
f := getFields()
return &eth.BlindedBeaconBlockBodyElectra{
RandaoReveal: f.sig[:],
Eth1Data: &eth.Eth1Data{
DepositRoot: f.root[:],
DepositCount: 128,
BlockHash: f.root[:],
},
Graffiti: f.root[:],
ProposerSlashings: f.proposerSlashings,
AttesterSlashings: f.attesterSlashingsElectra,
Attestations: f.attsElectra,
Deposits: f.deposits,
VoluntaryExits: f.voluntaryExits,
SyncAggregate: f.syncAggregate,
ExecutionPayloadHeader: f.execPayloadHeaderDeneb,
BlsToExecutionChanges: f.blsToExecutionChanges,
BlobKzgCommitments: f.kzgCommitments,
ExecutionRequests: f.execRequests,
}
}
func bodyPhase0() *BeaconBlockBody {
f := getFields()
return &BeaconBlockBody{
@@ -1427,6 +1740,58 @@ func bodyBlindedDeneb(t *testing.T) *BeaconBlockBody {
}
}
func bodyElectra(t *testing.T) *BeaconBlockBody {
f := getFields()
p, err := WrappedExecutionPayloadDeneb(f.execPayloadDeneb)
require.NoError(t, err)
return &BeaconBlockBody{
version: version.Electra,
randaoReveal: f.sig,
eth1Data: &eth.Eth1Data{
DepositRoot: f.root[:],
DepositCount: 128,
BlockHash: f.root[:],
},
graffiti: f.root,
proposerSlashings: f.proposerSlashings,
attesterSlashingsElectra: f.attesterSlashingsElectra,
attestationsElectra: f.attsElectra,
deposits: f.deposits,
voluntaryExits: f.voluntaryExits,
syncAggregate: f.syncAggregate,
executionPayload: p,
blsToExecutionChanges: f.blsToExecutionChanges,
blobKzgCommitments: f.kzgCommitments,
executionRequests: f.execRequests,
}
}
func bodyBlindedElectra(t *testing.T) *BeaconBlockBody {
f := getFields()
ph, err := WrappedExecutionPayloadHeaderDeneb(f.execPayloadHeaderDeneb)
require.NoError(t, err)
return &BeaconBlockBody{
version: version.Electra,
randaoReveal: f.sig,
eth1Data: &eth.Eth1Data{
DepositRoot: f.root[:],
DepositCount: 128,
BlockHash: f.root[:],
},
graffiti: f.root,
proposerSlashings: f.proposerSlashings,
attesterSlashingsElectra: f.attesterSlashingsElectra,
attestationsElectra: f.attsElectra,
deposits: f.deposits,
voluntaryExits: f.voluntaryExits,
syncAggregate: f.syncAggregate,
executionPayloadHeader: ph,
blsToExecutionChanges: f.blsToExecutionChanges,
blobKzgCommitments: f.kzgCommitments,
executionRequests: f.execRequests,
}
}
func getFields() fields {
b20 := make([]byte, 20)
b48 := make([]byte, 48)
@@ -1452,11 +1817,14 @@ func getFields() fields {
Signature: sig[:],
}
}
atts := make([]*eth.Attestation, 128)
attBits := bitfield.NewBitlist(1)
committeeBits := primitives.NewAttestationCommitteeBits()
atts := make([]*eth.Attestation, params.BeaconConfig().MaxAttestations)
for i := range atts {
atts[i] = &eth.Attestation{}
atts[i].Signature = sig[:]
atts[i].AggregationBits = bitfield.NewBitlist(1)
atts[i].AggregationBits = attBits
atts[i].Data = &eth.AttestationData{
Slot: 128,
CommitteeIndex: 128,
@@ -1471,6 +1839,27 @@ func getFields() fields {
},
}
}
attsElectra := make([]*eth.AttestationElectra, params.BeaconConfig().MaxAttestationsElectra)
for i := range attsElectra {
attsElectra[i] = &eth.AttestationElectra{}
attsElectra[i].Signature = sig[:]
attsElectra[i].AggregationBits = attBits
attsElectra[i].CommitteeBits = committeeBits
attsElectra[i].Data = &eth.AttestationData{
Slot: 128,
CommitteeIndex: 128,
BeaconBlockRoot: root[:],
Source: &eth.Checkpoint{
Epoch: 128,
Root: root[:],
},
Target: &eth.Checkpoint{
Epoch: 128,
Root: root[:],
},
}
}
proposerSlashing := &eth.ProposerSlashing{
Header_1: &eth.SignedBeaconBlockHeader{
Header: &eth.BeaconBlockHeader{
@@ -1529,6 +1918,42 @@ func getFields() fields {
Signature: sig[:],
},
}
attesterSlashingElectra := &eth.AttesterSlashingElectra{
Attestation_1: &eth.IndexedAttestationElectra{
AttestingIndices: []uint64{1, 2, 8},
Data: &eth.AttestationData{
Slot: 128,
CommitteeIndex: 128,
BeaconBlockRoot: root[:],
Source: &eth.Checkpoint{
Epoch: 128,
Root: root[:],
},
Target: &eth.Checkpoint{
Epoch: 128,
Root: root[:],
},
},
Signature: sig[:],
},
Attestation_2: &eth.IndexedAttestationElectra{
AttestingIndices: []uint64{1, 2, 8},
Data: &eth.AttestationData{
Slot: 128,
CommitteeIndex: 128,
BeaconBlockRoot: root[:],
Source: &eth.Checkpoint{
Epoch: 128,
Root: root[:],
},
Target: &eth.Checkpoint{
Epoch: 128,
Root: root[:],
},
},
Signature: sig[:],
},
}
voluntaryExit := &eth.SignedVoluntaryExit{
Exit: &eth.VoluntaryExit{
Epoch: 128,
@@ -1689,13 +2114,35 @@ func getFields() fields {
bytesutil.PadTo([]byte{143}, 48),
}
execRequests := &enginev1.ExecutionRequests{
Deposits: []*enginev1.DepositRequest{{
Pubkey: b48,
WithdrawalCredentials: root[:],
Amount: 128,
Signature: sig[:],
Index: 128,
}},
Withdrawals: []*enginev1.WithdrawalRequest{{
SourceAddress: b20,
ValidatorPubkey: b48,
Amount: 128,
}},
Consolidations: []*enginev1.ConsolidationRequest{{
SourceAddress: b20,
SourcePubkey: b48,
TargetPubkey: b48,
}},
}
return fields{
root: root,
sig: sig,
deposits: deposits,
atts: atts,
attsElectra: attsElectra,
proposerSlashings: []*eth.ProposerSlashing{proposerSlashing},
attesterSlashings: []*eth.AttesterSlashing{attesterSlashing},
attesterSlashingsElectra: []*eth.AttesterSlashingElectra{attesterSlashingElectra},
voluntaryExits: []*eth.SignedVoluntaryExit{voluntaryExit},
syncAggregate: syncAggregate,
execPayload: execPayload,
@@ -1706,5 +2153,6 @@ func getFields() fields {
execPayloadHeaderDeneb: execPayloadHeaderDeneb,
blsToExecutionChanges: blsToExecutionChanges,
kzgCommitments: kzgCommitments,
execRequests: execRequests,
}
}

View File

@@ -37,8 +37,8 @@ def prysm_deps():
go_repository(
name = "co_honnef_go_tools",
importpath = "honnef.co/go/tools",
sum = "h1:VUeHARd+9362HPYyFWjsRa6jBIAf2xWbDv6QXMRztbQ=",
version = "v0.5.0-0.dev.0.20231205170804-aef76f4feee2",
sum = "h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=",
version = "v0.5.1",
)
go_repository(
name = "com_github_aclements_go_moremath",
@@ -331,8 +331,8 @@ def prysm_deps():
go_repository(
name = "com_github_burntsushi_toml",
importpath = "github.com/BurntSushi/toml",
sum = "h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=",
version = "v1.3.2",
sum = "h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=",
version = "v1.4.1-0.20240526193622-a339e1f7089c",
)
go_repository(
name = "com_github_burntsushi_xgb",
@@ -1802,8 +1802,8 @@ def prysm_deps():
go_repository(
name = "com_github_kisielk_errcheck",
importpath = "github.com/kisielk/errcheck",
sum = "h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY=",
version = "v1.5.0",
sum = "h1:ZX/URYa7ilESY19ik/vBmCn6zdGQLxACwjAcWbHlYlg=",
version = "v1.8.0",
)
go_repository(
name = "com_github_kisielk_gotool",
@@ -4661,8 +4661,8 @@ def prysm_deps():
go_repository(
name = "org_golang_x_crypto",
importpath = "golang.org/x/crypto",
sum = "h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=",
version = "v0.31.0",
sum = "h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=",
version = "v0.32.0",
)
go_repository(
name = "org_golang_x_exp",
@@ -4697,14 +4697,14 @@ def prysm_deps():
go_repository(
name = "org_golang_x_mod",
importpath = "golang.org/x/mod",
sum = "h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=",
version = "v0.20.0",
sum = "h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=",
version = "v0.22.0",
)
go_repository(
name = "org_golang_x_net",
importpath = "golang.org/x/net",
sum = "h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=",
version = "v0.33.0",
sum = "h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=",
version = "v0.34.0",
)
go_repository(
name = "org_golang_x_oauth2",
@@ -4727,8 +4727,8 @@ def prysm_deps():
go_repository(
name = "org_golang_x_sys",
importpath = "golang.org/x/sys",
sum = "h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=",
version = "v0.28.0",
sum = "h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=",
version = "v0.29.0",
)
go_repository(
name = "org_golang_x_telemetry",
@@ -4739,8 +4739,8 @@ def prysm_deps():
go_repository(
name = "org_golang_x_term",
importpath = "golang.org/x/term",
sum = "h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=",
version = "v0.27.0",
sum = "h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=",
version = "v0.28.0",
)
go_repository(
name = "org_golang_x_text",
@@ -4757,8 +4757,8 @@ def prysm_deps():
go_repository(
name = "org_golang_x_tools",
importpath = "golang.org/x/tools",
sum = "h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=",
version = "v0.24.0",
sum = "h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=",
version = "v0.29.0",
)
go_repository(
name = "org_golang_x_xerrors",

25
go.mod
View File

@@ -1,8 +1,6 @@
module github.com/prysmaticlabs/prysm/v5
go 1.22.0
toolchain go1.22.10
go 1.23.5
require (
github.com/MariusVanDerWijden/FuzzyVM v0.0.0-20240516070431-7828990cad7d
@@ -40,6 +38,7 @@ require (
github.com/joonix/log v0.0.0-20200409080653-9c1d2ceb5f1d
github.com/json-iterator/go v1.1.12
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213
github.com/kisielk/errcheck v1.8.0
github.com/kr/pretty v0.3.1
github.com/libp2p/go-libp2p v0.36.5
github.com/libp2p/go-libp2p-mplex v0.9.0
@@ -52,8 +51,6 @@ require (
github.com/minio/sha256-simd v1.0.1
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/multiformats/go-multiaddr v0.13.0
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.34.1
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/paulbellamy/ratecounter v0.2.0
github.com/pborman/uuid v1.2.1
@@ -89,24 +86,24 @@ require (
go.opentelemetry.io/otel/trace v1.29.0
go.uber.org/automaxprocs v1.5.2
go.uber.org/mock v0.4.0
golang.org/x/crypto v0.31.0
golang.org/x/crypto v0.32.0
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
golang.org/x/mod v0.20.0
golang.org/x/mod v0.22.0
golang.org/x/sync v0.10.0
golang.org/x/tools v0.24.0
golang.org/x/tools v0.29.0
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1
google.golang.org/grpc v1.65.0
google.golang.org/protobuf v1.34.2
gopkg.in/d4l3k/messagediff.v1 v1.2.1
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
honnef.co/go/tools v0.5.0-0.dev.0.20231205170804-aef76f4feee2
honnef.co/go/tools v0.5.1
k8s.io/apimachinery v0.30.4
k8s.io/client-go v0.30.4
)
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
github.com/DataDog/zstd v1.5.5 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect
@@ -207,7 +204,6 @@ require (
github.com/multiformats/go-multistream v0.5.0 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nxadm/tail v1.4.11 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo/v2 v2.20.0 // indirect
github.com/opencontainers/runtime-spec v1.2.0 // indirect
@@ -255,15 +251,14 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/term v0.27.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.5.0 // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
@@ -280,7 +275,7 @@ require (
github.com/go-playground/validator/v10 v10.13.0
github.com/peterh/liner v1.2.0 // indirect
github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b
golang.org/x/sys v0.28.0 // indirect
golang.org/x/sys v0.29.0 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
)

38
go.sum
View File

@@ -45,8 +45,8 @@ dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
@@ -312,7 +312,6 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
@@ -541,6 +540,8 @@ github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/errcheck v1.8.0 h1:ZX/URYa7ilESY19ik/vBmCn6zdGQLxACwjAcWbHlYlg=
github.com/kisielk/errcheck v1.8.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
@@ -731,7 +732,6 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
@@ -1153,8 +1153,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1197,8 +1197,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1255,8 +1255,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1352,7 +1352,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1377,8 +1376,8 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1387,8 +1386,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1468,7 +1467,6 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
@@ -1478,8 +1476,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1655,8 +1653,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.5.0-0.dev.0.20231205170804-aef76f4feee2 h1:VUeHARd+9362HPYyFWjsRa6jBIAf2xWbDv6QXMRztbQ=
honnef.co/go/tools v0.5.0-0.dev.0.20231205170804-aef76f4feee2/go.mod h1:J8YyqAvNy0yWpeKUOCONA1m2G4hH2CqUSo/5ZO2/5UA=
honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=
honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs=
k8s.io/api v0.30.4 h1:XASIELmW8w8q0i1Y4124LqPoWMycLjyQti/fdYHYjCs=
k8s.io/api v0.30.4/go.mod h1:ZqniWRKu7WIeLijbbzetF4U9qZ03cg5IRwl8YVs8mX0=
k8s.io/apimachinery v0.30.4 h1:5QHQI2tInzr8LsT4kU/2+fSeibH1eIHswNx480cqIoY=

View File

@@ -2,6 +2,7 @@ package attestations
import (
"io"
"os"
"sort"
"testing"
@@ -19,7 +20,7 @@ import (
func TestMain(m *testing.M) {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(io.Discard)
m.Run()
os.Exit(m.Run())
}
func TestAggregateAttestations_AggregatePair(t *testing.T) {

View File

@@ -14,15 +14,10 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"formatter_test.go",
"logrus_prefixed_formatter_suite_test.go",
],
srcs = ["formatter_test.go"],
deps = [
":go_default_library",
"//testing/require:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
"@com_github_onsi_gomega//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
],

View File

@@ -5,55 +5,76 @@ import (
"regexp"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/pkg/errors"
prefixed "github.com/prysmaticlabs/prysm/v5/runtime/logging/logrus-prefixed-formatter"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/sirupsen/logrus"
)
var _ = Describe("Formatter", func() {
var formatter *prefixed.TextFormatter
var log *logrus.Logger
var output *LogOutput
type LogOutput struct {
buffer string
}
BeforeEach(func() {
output = new(LogOutput)
formatter = new(prefixed.TextFormatter)
log = logrus.New()
log.Out = output
log.Formatter = formatter
log.Level = logrus.DebugLevel
})
func (o *LogOutput) Write(p []byte) (int, error) {
o.buffer += string(p)
return len(p), nil
}
Describe("logfmt output", func() {
It("should output simple message", func() {
func (o *LogOutput) GetValue() string {
return o.buffer
}
func TestFormatter_logfmt_output(t *testing.T) {
tests := []struct {
name string
callback func(l *logrus.Logger)
expected string
}{
{
name: "should output simple message",
callback: func(l *logrus.Logger) {
l.Debug("test")
},
expected: "level=debug msg=test\n",
},
{
name: "should output message with additional field",
callback: func(l *logrus.Logger) {
l.WithFields(logrus.Fields{"animal": "walrus"}).Debug("test")
},
expected: "level=debug msg=test animal=walrus\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
output := new(LogOutput)
formatter := new(prefixed.TextFormatter)
formatter.DisableTimestamp = true
log.Debug("test")
Ω(output.GetValue()).Should(Equal("level=debug msg=test\n"))
log := logrus.New()
log.Out = output
log.Formatter = formatter
log.Level = logrus.DebugLevel
tt.callback(log)
require.Equal(t, output.GetValue(), tt.expected)
})
}
}
It("should output message with additional field", func() {
formatter.DisableTimestamp = true
log.WithFields(logrus.Fields{"animal": "walrus"}).Debug("test")
Ω(output.GetValue()).Should(Equal("level=debug msg=test animal=walrus\n"))
})
})
func TestFormatter_formatted_output(t *testing.T) {
output := new(LogOutput)
formatter := new(prefixed.TextFormatter)
formatter.DisableTimestamp = true
formatter.ForceFormatting = true
log := logrus.New()
log.Out = output
log.Formatter = formatter
log.Level = logrus.DebugLevel
Describe("Formatted output", func() {
It("should output formatted message", func() {
formatter.DisableTimestamp = true
formatter.ForceFormatting = true
log.Debug("test")
Ω(output.GetValue()).Should(Equal("DEBUG test\n"))
})
})
Describe("Theming support", func() {
})
})
log.Debug("test")
require.Equal(t, output.GetValue(), "DEBUG test\n")
}
func TestFormatter_SuppressErrorStackTraces(t *testing.T) {
formatter := new(prefixed.TextFormatter)

View File

@@ -1,26 +0,0 @@
package prefixed_test
import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type LogOutput struct {
buffer string
}
func (o *LogOutput) Write(p []byte) (int, error) {
o.buffer += string(p)
return len(p), nil
}
func (o *LogOutput) GetValue() string {
return o.buffer
}
func TestLogrusPrefixedFormatter(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "LogrusPrefixedFormatter Suite")
}

View File

@@ -32,6 +32,7 @@ go_library(
"//crypto/rand:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
@@ -55,6 +56,7 @@ go_test(
"//crypto/bls:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/slashings:go_default_library",
"//runtime/version:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
],

View File

@@ -15,15 +15,14 @@ import (
"github.com/prysmaticlabs/prysm/v5/crypto/rand"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots"
"github.com/sirupsen/logrus"
)
func (s *Simulator) generateAttestationsForSlot(
ctx context.Context, slot primitives.Slot,
) ([]*ethpb.IndexedAttestation, []*ethpb.AttesterSlashing, error) {
attestations := make([]*ethpb.IndexedAttestation, 0)
slashings := make([]*ethpb.AttesterSlashing, 0)
func (s *Simulator) generateAttestationsForSlot(ctx context.Context, ver int, slot primitives.Slot) ([]ethpb.IndexedAtt, []ethpb.AttSlashing, error) {
attestations := make([]ethpb.IndexedAtt, 0)
slashings := make([]ethpb.AttSlashing, 0)
currentEpoch := slots.ToEpoch(slot)
committeesPerSlot := helpers.SlotCommitteeCount(s.srvConfig.Params.NumValidators)
@@ -64,12 +63,23 @@ func (s *Simulator) generateAttestationsForSlot(
for idx := i; idx < attEndIdx; idx++ {
indices = append(indices, idx)
}
att := &ethpb.IndexedAttestation{
AttestingIndices: indices,
Data: attData,
Signature: params.BeaconConfig().EmptySignature[:],
var att ethpb.IndexedAtt
if ver >= version.Electra {
att = &ethpb.IndexedAttestationElectra{
AttestingIndices: indices,
Data: attData,
Signature: params.BeaconConfig().EmptySignature[:],
}
} else {
att = &ethpb.IndexedAttestation{
AttestingIndices: indices,
Data: attData,
Signature: params.BeaconConfig().EmptySignature[:],
}
}
beaconState, err := s.srvConfig.AttestationStateFetcher.AttestationTargetState(ctx, att.Data.Target)
beaconState, err := s.srvConfig.AttestationStateFetcher.AttestationTargetState(ctx, att.GetData().Target)
if err != nil {
return nil, nil, err
}
@@ -79,7 +89,12 @@ func (s *Simulator) generateAttestationsForSlot(
if err != nil {
return nil, nil, err
}
att.Signature = aggSig.Marshal()
if ver >= version.Electra {
att.(*ethpb.IndexedAttestationElectra).Signature = aggSig.Marshal()
} else {
att.(*ethpb.IndexedAttestation).Signature = aggSig.Marshal()
}
attestations = append(attestations, att)
if rand.NewGenerator().Float64() < s.srvConfig.Params.AttesterSlashingProbab {
@@ -88,29 +103,50 @@ func (s *Simulator) generateAttestationsForSlot(
if err != nil {
return nil, nil, err
}
slashableAtt.Signature = aggSig.Marshal()
slashedIndices = append(slashedIndices, slashableAtt.AttestingIndices...)
attDataRoot, err := att.Data.HashTreeRoot()
if ver >= version.Electra {
slashableAtt.(*ethpb.IndexedAttestationElectra).Signature = aggSig.Marshal()
} else {
slashableAtt.(*ethpb.IndexedAttestation).Signature = aggSig.Marshal()
}
slashedIndices = append(slashedIndices, slashableAtt.GetAttestingIndices()...)
attDataRoot, err := att.GetData().HashTreeRoot()
if err != nil {
return nil, nil, errors.Wrap(err, "cannot compte `att` hash tree root")
}
slashableAttDataRoot, err := slashableAtt.Data.HashTreeRoot()
slashableAttDataRoot, err := slashableAtt.GetData().HashTreeRoot()
if err != nil {
return nil, nil, errors.Wrap(err, "cannot compte `slashableAtt` hash tree root")
}
slashing := &ethpb.AttesterSlashing{
Attestation_1: att,
Attestation_2: slashableAtt,
var slashing ethpb.AttSlashing
if ver >= version.Electra {
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: att.(*ethpb.IndexedAttestationElectra),
Attestation_2: slashableAtt.(*ethpb.IndexedAttestationElectra),
}
} else {
slashing = &ethpb.AttesterSlashing{
Attestation_1: att.(*ethpb.IndexedAttestation),
Attestation_2: slashableAtt.(*ethpb.IndexedAttestation),
}
}
// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(attDataRoot[:], slashableAttDataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashing{
Attestation_1: slashableAtt,
Attestation_2: att,
if ver >= version.Electra {
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: slashableAtt.(*ethpb.IndexedAttestationElectra),
Attestation_2: att.(*ethpb.IndexedAttestationElectra),
}
} else {
slashing = &ethpb.AttesterSlashing{
Attestation_1: slashableAtt.(*ethpb.IndexedAttestation),
Attestation_2: att.(*ethpb.IndexedAttestation),
}
}
}
@@ -131,46 +167,55 @@ func (s *Simulator) generateAttestationsForSlot(
}
func (s *Simulator) aggregateSigForAttestation(
beaconState state.ReadOnlyBeaconState, att *ethpb.IndexedAttestation,
beaconState state.ReadOnlyBeaconState, att ethpb.IndexedAtt,
) (bls.Signature, error) {
domain, err := signing.Domain(
beaconState.Fork(),
att.Data.Target.Epoch,
att.GetData().Target.Epoch,
params.BeaconConfig().DomainBeaconAttester,
beaconState.GenesisValidatorsRoot(),
)
if err != nil {
return nil, err
}
signingRoot, err := signing.ComputeSigningRoot(att.Data, domain)
signingRoot, err := signing.ComputeSigningRoot(att.GetData(), domain)
if err != nil {
return nil, err
}
sigs := make([]bls.Signature, len(att.AttestingIndices))
for i, validatorIndex := range att.AttestingIndices {
sigs := make([]bls.Signature, len(att.GetAttestingIndices()))
for i, validatorIndex := range att.GetAttestingIndices() {
privKey := s.srvConfig.PrivateKeysByValidatorIndex[primitives.ValidatorIndex(validatorIndex)]
sigs[i] = privKey.Sign(signingRoot[:])
}
return bls.AggregateSignatures(sigs), nil
}
func makeSlashableFromAtt(att *ethpb.IndexedAttestation, indices []uint64) *ethpb.IndexedAttestation {
if att.Data.Source.Epoch <= 2 {
func makeSlashableFromAtt(att ethpb.IndexedAtt, indices []uint64) ethpb.IndexedAtt {
if att.GetData().Source.Epoch <= 2 {
return makeDoubleVoteFromAtt(att, indices)
}
attData := &ethpb.AttestationData{
Slot: att.Data.Slot,
CommitteeIndex: att.Data.CommitteeIndex,
BeaconBlockRoot: att.Data.BeaconBlockRoot,
Slot: att.GetData().Slot,
CommitteeIndex: att.GetData().CommitteeIndex,
BeaconBlockRoot: att.GetData().BeaconBlockRoot,
Source: &ethpb.Checkpoint{
Epoch: att.Data.Source.Epoch - 3,
Root: att.Data.Source.Root,
Epoch: att.GetData().Source.Epoch - 3,
Root: att.GetData().Source.Root,
},
Target: &ethpb.Checkpoint{
Epoch: att.Data.Target.Epoch,
Root: att.Data.Target.Root,
Epoch: att.GetData().Target.Epoch,
Root: att.GetData().Target.Root,
},
}
if att.Version() >= version.Electra {
return &ethpb.IndexedAttestationElectra{
AttestingIndices: indices,
Data: attData,
Signature: params.BeaconConfig().EmptySignature[:],
}
}
return &ethpb.IndexedAttestation{
AttestingIndices: indices,
Data: attData,
@@ -178,20 +223,29 @@ func makeSlashableFromAtt(att *ethpb.IndexedAttestation, indices []uint64) *ethp
}
}
func makeDoubleVoteFromAtt(att *ethpb.IndexedAttestation, indices []uint64) *ethpb.IndexedAttestation {
func makeDoubleVoteFromAtt(att ethpb.IndexedAtt, indices []uint64) ethpb.IndexedAtt {
attData := &ethpb.AttestationData{
Slot: att.Data.Slot,
CommitteeIndex: att.Data.CommitteeIndex,
Slot: att.GetData().Slot,
CommitteeIndex: att.GetData().CommitteeIndex,
BeaconBlockRoot: bytesutil.PadTo([]byte("slash me"), 32),
Source: &ethpb.Checkpoint{
Epoch: att.Data.Source.Epoch,
Root: att.Data.Source.Root,
Epoch: att.GetData().Source.Epoch,
Root: att.GetData().Source.Root,
},
Target: &ethpb.Checkpoint{
Epoch: att.Data.Target.Epoch,
Root: att.Data.Target.Root,
Epoch: att.GetData().Target.Epoch,
Root: att.GetData().Target.Root,
},
}
if att.Version() >= version.Electra {
return &ethpb.IndexedAttestationElectra{
AttestingIndices: indices,
Data: attData,
Signature: params.BeaconConfig().EmptySignature[:],
}
}
return &ethpb.IndexedAttestation{
AttestingIndices: indices,
Data: attData,

View File

@@ -6,6 +6,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/slashings"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
@@ -20,14 +21,18 @@ func TestGenerateAttestationsForSlot_Slashing(t *testing.T) {
}
srv := setupService(t, simParams)
epoch3Atts, _, err := srv.generateAttestationsForSlot(ctx, params.BeaconConfig().SlotsPerEpoch*3)
require.NoError(t, err)
epoch4Atts, _, err := srv.generateAttestationsForSlot(ctx, params.BeaconConfig().SlotsPerEpoch*4)
require.NoError(t, err)
for i := 0; i < len(epoch3Atts); i += 2 {
goodAtt := epoch3Atts[i]
surroundAtt := epoch4Atts[i+1]
require.Equal(t, true, slashings.IsSurround(surroundAtt, goodAtt))
for _, v := range []int{version.Phase0, version.Electra} {
t.Run(version.String(v), func(t *testing.T) {
epoch3Atts, _, err := srv.generateAttestationsForSlot(ctx, v, params.BeaconConfig().SlotsPerEpoch*3)
require.NoError(t, err)
epoch4Atts, _, err := srv.generateAttestationsForSlot(ctx, v, params.BeaconConfig().SlotsPerEpoch*4)
require.NoError(t, err)
for i := 0; i < len(epoch3Atts); i += 2 {
goodAtt := epoch3Atts[i]
surroundAtt := epoch4Atts[i+1]
require.Equal(t, true, slashings.IsSurround(surroundAtt, goodAtt))
}
})
}
}
@@ -41,24 +46,29 @@ func TestGenerateAttestationsForSlot_CorrectIndices(t *testing.T) {
AttesterSlashingProbab: 0,
}
srv := setupService(t, simParams)
slot0Atts, _, err := srv.generateAttestationsForSlot(ctx, 0)
require.NoError(t, err)
slot1Atts, _, err := srv.generateAttestationsForSlot(ctx, 1)
require.NoError(t, err)
slot2Atts, _, err := srv.generateAttestationsForSlot(ctx, 2)
require.NoError(t, err)
var validatorIndices []uint64
for _, att := range append(slot0Atts, slot1Atts...) {
validatorIndices = append(validatorIndices, att.AttestingIndices...)
}
for _, att := range slot2Atts {
validatorIndices = append(validatorIndices, att.AttestingIndices...)
}
// Making sure indices are one after the other for attestations.
var validatorIndex uint64
for _, ii := range validatorIndices {
require.Equal(t, validatorIndex, ii)
validatorIndex++
for _, v := range []int{version.Phase0, version.Electra} {
t.Run(version.String(v), func(t *testing.T) {
slot0Atts, _, err := srv.generateAttestationsForSlot(ctx, v, 0)
require.NoError(t, err)
slot1Atts, _, err := srv.generateAttestationsForSlot(ctx, v, 1)
require.NoError(t, err)
slot2Atts, _, err := srv.generateAttestationsForSlot(ctx, v, 2)
require.NoError(t, err)
var validatorIndices []uint64
for _, att := range append(slot0Atts, slot1Atts...) {
validatorIndices = append(validatorIndices, att.GetAttestingIndices()...)
}
for _, att := range slot2Atts {
validatorIndices = append(validatorIndices, att.GetAttestingIndices()...)
}
// Making sure indices are one after the other for attestations.
var validatorIndex uint64
for _, ii := range validatorIndices {
require.Equal(t, validatorIndex, ii)
validatorIndex++
}
})
}
}

View File

@@ -19,6 +19,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots"
"github.com/sirupsen/logrus"
)
@@ -62,7 +63,7 @@ type Simulator struct {
sentAttSlashingFeed *event.Feed
sentBlockSlashingFeed *event.Feed
sentProposerSlashings map[[32]byte]*ethpb.ProposerSlashing
sentAttesterSlashings map[[32]byte]*ethpb.AttesterSlashing
sentAttesterSlashings map[[32]byte]ethpb.AttSlashing
genesisTime time.Time
}
@@ -111,7 +112,7 @@ func New(ctx context.Context, srvConfig *ServiceConfig) (*Simulator, error) {
sentAttSlashingFeed: sentAttSlashingFeed,
sentBlockSlashingFeed: sentBlockSlashingFeed,
sentProposerSlashings: make(map[[32]byte]*ethpb.ProposerSlashing),
sentAttesterSlashings: make(map[[32]byte]*ethpb.AttesterSlashing),
sentAttesterSlashings: make(map[[32]byte]ethpb.AttSlashing),
}, nil
}
@@ -206,7 +207,7 @@ func (s *Simulator) simulateBlocksAndAttestations(ctx context.Context) {
s.beaconBlocksFeed.Send(bb)
}
atts, attSlashings, err := s.generateAttestationsForSlot(ctx, slot)
atts, attSlashings, err := s.generateAttestationsForSlot(ctx, version.Phase0, slot)
if err != nil {
log.WithError(err).Fatal("Could not generate attestations for slot")
}
@@ -271,20 +272,20 @@ func (s *Simulator) verifySlashingsWereDetected(ctx context.Context) {
for slashingRoot, slashing := range s.sentAttesterSlashings {
if _, ok := detectedAttesterSlashings[slashingRoot]; !ok {
log.WithFields(logrus.Fields{
"targetEpoch": slashing.Attestation_1.Data.Target.Epoch,
"prevTargetEpoch": slashing.Attestation_2.Data.Target.Epoch,
"sourceEpoch": slashing.Attestation_1.Data.Source.Epoch,
"prevSourceEpoch": slashing.Attestation_2.Data.Source.Epoch,
"prevBeaconBlockRoot": fmt.Sprintf("%#x", slashing.Attestation_1.Data.BeaconBlockRoot),
"newBeaconBlockRoot": fmt.Sprintf("%#x", slashing.Attestation_2.Data.BeaconBlockRoot),
"targetEpoch": slashing.FirstAttestation().GetData().Target.Epoch,
"prevTargetEpoch": slashing.SecondAttestation().GetData().Target.Epoch,
"sourceEpoch": slashing.FirstAttestation().GetData().Source.Epoch,
"prevSourceEpoch": slashing.SecondAttestation().GetData().Source.Epoch,
"prevBeaconBlockRoot": fmt.Sprintf("%#x", slashing.FirstAttestation().GetData().BeaconBlockRoot),
"newBeaconBlockRoot": fmt.Sprintf("%#x", slashing.SecondAttestation().GetData().BeaconBlockRoot),
}).Errorf("Did not detect simulated attester slashing")
continue
}
log.WithFields(logrus.Fields{
"targetEpoch": slashing.Attestation_1.Data.Target.Epoch,
"prevTargetEpoch": slashing.Attestation_2.Data.Target.Epoch,
"sourceEpoch": slashing.Attestation_1.Data.Source.Epoch,
"prevSourceEpoch": slashing.Attestation_2.Data.Source.Epoch,
"targetEpoch": slashing.FirstAttestation().GetData().Target.Epoch,
"prevTargetEpoch": slashing.SecondAttestation().GetData().Target.Epoch,
"sourceEpoch": slashing.FirstAttestation().GetData().Source.Epoch,
"prevSourceEpoch": slashing.SecondAttestation().GetData().Source.Epoch,
}).Info("Correctly detected simulated attester slashing")
}
}

View File

@@ -1,6 +1,7 @@
package epoch_processing
import (
"os"
"testing"
"github.com/prysmaticlabs/prysm/v5/config/params"
@@ -13,5 +14,5 @@ func TestMain(m *testing.M) {
c.MinGenesisActiveValidatorCount = 16384
params.OverrideBeaconConfig(c)
m.Run()
os.Exit(m.Run())
}

View File

@@ -1,6 +1,7 @@
package epoch_processing
import (
"os"
"testing"
"github.com/prysmaticlabs/prysm/v5/config/params"
@@ -13,5 +14,5 @@ func TestMain(m *testing.M) {
c.MinGenesisActiveValidatorCount = 16384
params.OverrideBeaconConfig(c)
m.Run()
os.Exit(m.Run())
}

View File

@@ -2,6 +2,7 @@ package slots
import (
"io"
"os"
"testing"
"github.com/sirupsen/logrus"
@@ -11,5 +12,5 @@ func TestMain(m *testing.M) {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(io.Discard)
m.Run()
os.Exit(m.Run())
}

View File

@@ -1,23 +1,9 @@
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["analyzer.go"],
importpath = "github.com/prysmaticlabs/prysm/v5/tools/analyzers/errcheck",
visibility = ["//visibility:public"],
deps = [
"@org_golang_x_tools//go/analysis:go_default_library",
"@org_golang_x_tools//go/analysis/passes/inspect:go_default_library",
"@org_golang_x_tools//go/ast/inspector:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["embedded_walker_test.go"],
embed = [":go_default_library"],
deps = [
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
],
deps = ["@com_github_kisielk_errcheck//errcheck:go_default_library"],
)

View File

@@ -3,443 +3,7 @@
package errcheck
import (
"errors"
"fmt"
"go/ast"
"go/token"
"go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
analyzer "github.com/kisielk/errcheck/errcheck"
)
// Doc explaining the tool.
const Doc = "This tool enforces all errors must be handled and that type assertions test that " +
"the type implements the given interface to prevent runtime panics."
// Analyzer runs static analysis.
var Analyzer = &analysis.Analyzer{
Name: "errcheck",
Doc: Doc,
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
var exclusions = make(map[string]bool)
func init() {
for _, exc := range [...]string{
// bytes
"(*bytes.Buffer).Write",
"(*bytes.Buffer).WriteByte",
"(*bytes.Buffer).WriteRune",
"(*bytes.Buffer).WriteString",
// fmt
"fmt.Errorf",
"fmt.Print",
"fmt.Printf",
"fmt.Println",
"fmt.Fprint(*bytes.Buffer)",
"fmt.Fprintf(*bytes.Buffer)",
"fmt.Fprintln(*bytes.Buffer)",
"fmt.Fprint(*strings.Builder)",
"fmt.Fprintf(*strings.Builder)",
"fmt.Fprintln(*strings.Builder)",
"fmt.Fprint(os.Stderr)",
"fmt.Fprintf(os.Stderr)",
"fmt.Fprintln(os.Stderr)",
// math/rand
"math/rand.Read",
"(*math/rand.Rand).Read",
// hash
"(hash.Hash).Write",
} {
exclusions[exc] = true
}
}
func run(pass *analysis.Pass) (interface{}, error) {
inspection, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
if !ok {
return nil, errors.New("analyzer is not type *inspector.Inspector")
}
nodeFilter := []ast.Node{
(*ast.CallExpr)(nil),
(*ast.ExprStmt)(nil),
(*ast.GoStmt)(nil),
(*ast.DeferStmt)(nil),
(*ast.AssignStmt)(nil),
}
inspection.Preorder(nodeFilter, func(node ast.Node) {
switch stmt := node.(type) {
case *ast.ExprStmt:
if call, ok := stmt.X.(*ast.CallExpr); ok {
if !ignoreCall(pass, call) && callReturnsError(pass, call) {
reportUnhandledError(pass, call.Lparen, call)
}
}
case *ast.GoStmt:
if !ignoreCall(pass, stmt.Call) && callReturnsError(pass, stmt.Call) {
reportUnhandledError(pass, stmt.Call.Lparen, stmt.Call)
}
case *ast.DeferStmt:
if !ignoreCall(pass, stmt.Call) && callReturnsError(pass, stmt.Call) {
reportUnhandledError(pass, stmt.Call.Lparen, stmt.Call)
}
case *ast.AssignStmt:
if len(stmt.Rhs) == 1 {
// single value on rhs; check against lhs identifiers
if call, ok := stmt.Rhs[0].(*ast.CallExpr); ok {
if ignoreCall(pass, call) {
break
}
isError := errorsByArg(pass, call)
for i := 0; i < len(stmt.Lhs); i++ {
if id, ok := stmt.Lhs[i].(*ast.Ident); ok {
// We shortcut calls to recover() because errorsByArg can't
// check its return types for errors since it returns interface{}.
if id.Name == "_" && (isRecover(pass, call) || isError[i]) {
reportUnhandledError(pass, id.NamePos, call)
}
}
}
} else if assert, ok := stmt.Rhs[0].(*ast.TypeAssertExpr); ok {
if assert.Type == nil {
// type switch
break
}
if len(stmt.Lhs) < 2 {
// assertion result not read
reportUnhandledTypeAssertion(pass, stmt.Rhs[0].Pos())
} else if id, ok := stmt.Lhs[1].(*ast.Ident); ok && id.Name == "_" {
// assertion result ignored
reportUnhandledTypeAssertion(pass, id.NamePos)
}
}
} else {
// multiple value on rhs; in this case a call can't return
// multiple values. Assume len(stmt.Lhs) == len(stmt.Rhs)
for i := 0; i < len(stmt.Lhs); i++ {
if id, ok := stmt.Lhs[i].(*ast.Ident); ok {
if call, ok := stmt.Rhs[i].(*ast.CallExpr); ok {
if ignoreCall(pass, call) {
continue
}
if id.Name == "_" && callReturnsError(pass, call) {
reportUnhandledError(pass, id.NamePos, call)
}
} else if assert, ok := stmt.Rhs[i].(*ast.TypeAssertExpr); ok {
if assert.Type == nil {
// Shouldn't happen anyway, no multi assignment in type switches
continue
}
reportUnhandledError(pass, id.NamePos, nil)
}
}
}
}
default:
}
})
return nil, nil
}
func reportUnhandledError(pass *analysis.Pass, pos token.Pos, call *ast.CallExpr) {
pass.Reportf(pos, "Unhandled error for function call %s", fullName(pass, call))
}
func reportUnhandledTypeAssertion(pass *analysis.Pass, pos token.Pos) {
pass.Reportf(pos, "Unhandled type assertion check. You must test whether or not an "+
"interface implements the asserted type.")
}
func fullName(pass *analysis.Pass, call *ast.CallExpr) string {
_, fn, ok := selectorAndFunc(pass, call)
if !ok {
return ""
}
return fn.FullName()
}
// selectorAndFunc tries to get the selector and function from call expression.
// For example, given the call expression representing "a.b()", the selector
// is "a.b" and the function is "b" itself.
//
// The final return value will be true if it is able to do extract a selector
// from the call and look up the function object it refers to.
//
// If the call does not include a selector (like if it is a plain "f()" function call)
// then the final return value will be false.
func selectorAndFunc(pass *analysis.Pass, call *ast.CallExpr) (*ast.SelectorExpr, *types.Func, bool) {
if call == nil || call.Fun == nil {
return nil, nil, false
}
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok {
return nil, nil, false
}
fn, ok := pass.TypesInfo.ObjectOf(sel.Sel).(*types.Func)
if !ok {
return nil, nil, false
}
return sel, fn, true
}
func ignoreCall(pass *analysis.Pass, call *ast.CallExpr) bool {
for _, name := range namesForExcludeCheck(pass, call) {
if exclusions[name] {
return true
}
}
return false
}
var errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
func isErrorType(t types.Type) bool {
return types.Implements(t, errorType)
}
func callReturnsError(pass *analysis.Pass, call *ast.CallExpr) bool {
if isRecover(pass, call) {
return true
}
for _, isError := range errorsByArg(pass, call) {
if isError {
return true
}
}
return false
}
// errorsByArg returns a slice s such that
// len(s) == number of return types of call
// s[i] == true iff return type at position i from left is an error type
func errorsByArg(pass *analysis.Pass, call *ast.CallExpr) []bool {
switch t := pass.TypesInfo.Types[call].Type.(type) {
case *types.Named:
// Single return
return []bool{isErrorType(t)}
case *types.Pointer:
// Single return via pointer
return []bool{isErrorType(t)}
case *types.Tuple:
// Multiple returns
s := make([]bool, t.Len())
for i := 0; i < t.Len(); i++ {
switch et := t.At(i).Type().(type) {
case *types.Named:
// Single return
s[i] = isErrorType(et)
case *types.Pointer:
// Single return via pointer
s[i] = isErrorType(et)
default:
s[i] = false
}
}
return s
}
return []bool{false}
}
func isRecover(pass *analysis.Pass, call *ast.CallExpr) bool {
if fun, ok := call.Fun.(*ast.Ident); ok {
if _, ok := pass.TypesInfo.Uses[fun].(*types.Builtin); ok {
return fun.Name == "recover"
}
}
return false
}
func namesForExcludeCheck(pass *analysis.Pass, call *ast.CallExpr) []string {
sel, fn, ok := selectorAndFunc(pass, call)
if !ok {
return nil
}
name := fullName(pass, call)
if name == "" {
return nil
}
// This will be missing for functions without a receiver (like fmt.Printf),
// so just fall back to the function's fullName in that case.
selection, ok := pass.TypesInfo.Selections[sel]
if !ok {
return []string{name}
}
// This will return with ok false if the function isn't defined
// on an interface, so just fall back to the fullName.
ts, ok := walkThroughEmbeddedInterfaces(selection)
if !ok {
return []string{name}
}
result := make([]string, len(ts))
for i, t := range ts {
// Like in fullName, vendored packages will have /vendor/ in their name,
// thus not matching vendored standard library packages. If we
// want to support vendored stdlib packages, we need to implement
// additional logic here.
result[i] = fmt.Sprintf("(%s).%s", t.String(), fn.Name())
}
return result
}
// walkThroughEmbeddedInterfaces returns a slice of Interfaces that
// we need to walk through in order to reach the actual definition,
// in an Interface, of the method selected by the given selection.
//
// false will be returned in the second return value if:
// - the right side of the selection is not a function
// - the actual definition of the function is not in an Interface
//
// The returned slice will contain all the interface types that need
// to be walked through to reach the actual definition.
//
// For example, say we have:
//
// type Inner interface {Method()}
// type Middle interface {Inner}
// type Outer interface {Middle}
// type T struct {Outer}
// type U struct {T}
// type V struct {U}
//
// And then the selector:
//
// V.Method
//
// We'll return [Outer, Middle, Inner] by first walking through the embedded structs
// until we reach the Outer interface, then descending through the embedded interfaces
// until we find the one that actually explicitly defines Method.
func walkThroughEmbeddedInterfaces(sel *types.Selection) ([]types.Type, bool) {
fn, ok := sel.Obj().(*types.Func)
if !ok {
return nil, false
}
// Start off at the receiver.
currentT := sel.Recv()
// First, we can walk through any Struct fields provided
// by the selection Index() method. We ignore the last
// index because it would give the method itself.
indexes := sel.Index()
for _, fieldIndex := range indexes[:len(indexes)-1] {
currentT = typeAtFieldIndex(currentT, fieldIndex)
}
// Now currentT is either a type implementing the actual function,
// an Invalid type (if the receiver is a package), or an interface.
//
// If it's not an Interface, then we're done, as this function
// only cares about Interface-defined functions.
//
// If it is an Interface, we potentially need to continue digging until
// we find the Interface that actually explicitly defines the function.
interfaceT, ok := maybeUnname(currentT).(*types.Interface)
if !ok {
return nil, false
}
// The first interface we pass through is this one we've found. We return the possibly
// wrapping types.Named because it is more useful to work with for callers.
result := []types.Type{currentT}
// If this interface itself explicitly defines the given method
// then we're done digging.
for !explicitlyDefinesMethod(interfaceT, fn) {
// Otherwise, we find which of the embedded interfaces _does_
// define the method, add it to our list, and loop.
namedInterfaceT, ok := embeddedInterfaceDefiningMethod(interfaceT, fn)
if !ok {
// This should be impossible as long as we type-checked: either the
// interface or one of its embedded ones must implement the method...
panic(fmt.Sprintf("either %v or one of its embedded interfaces must implement %v", currentT, fn))
}
result = append(result, namedInterfaceT)
interfaceT, ok = namedInterfaceT.Underlying().(*types.Interface)
if !ok {
panic(fmt.Sprintf("either %v or one of its embedded interfaces must implement %v", currentT, fn))
}
}
return result, true
}
func typeAtFieldIndex(startingAt types.Type, fieldIndex int) types.Type {
t := maybeUnname(maybeDereference(startingAt))
s, ok := t.(*types.Struct)
if !ok {
panic(fmt.Sprintf("cannot get Field of a type that is not a struct, got a %T", t))
}
return s.Field(fieldIndex).Type()
}
// embeddedInterfaceDefiningMethod searches through any embedded interfaces of the
// passed interface searching for one that defines the given function. If found, the
// types.Named wrapping that interface will be returned along with true in the second value.
//
// If no such embedded interface is found, nil and false are returned.
func embeddedInterfaceDefiningMethod(interfaceT *types.Interface, fn *types.Func) (*types.Named, bool) {
for i := 0; i < interfaceT.NumEmbeddeds(); i++ {
embedded, ok := interfaceT.EmbeddedType(i).(*types.Named)
if !ok {
return nil, false
}
if definesMethod(embedded.Underlying().(*types.Interface), fn) {
return embedded, true
}
}
return nil, false
}
func explicitlyDefinesMethod(interfaceT *types.Interface, fn *types.Func) bool {
for i := 0; i < interfaceT.NumExplicitMethods(); i++ {
if interfaceT.ExplicitMethod(i) == fn {
return true
}
}
return false
}
func definesMethod(interfaceT *types.Interface, fn *types.Func) bool {
for i := 0; i < interfaceT.NumMethods(); i++ {
if interfaceT.Method(i) == fn {
return true
}
}
return false
}
func maybeDereference(t types.Type) types.Type {
p, ok := t.(*types.Pointer)
if ok {
return p.Elem()
}
return t
}
func maybeUnname(t types.Type) types.Type {
n, ok := t.(*types.Named)
if ok {
return n.Underlying()
}
return t
}
var Analyzer = analyzer.Analyzer

View File

@@ -1,82 +0,0 @@
package errcheck
import (
"go/ast"
"go/parser"
"go/token"
"go/types"
"testing"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
const commonSrc = `
package p
type Inner struct {}
func (Inner) Method()
type Outer struct {Inner}
type OuterP struct {*Inner}
type InnerInterface interface {
Method()
}
type OuterInterface interface {InnerInterface}
type MiddleInterfaceStruct struct {OuterInterface}
type OuterInterfaceStruct struct {MiddleInterfaceStruct}
var c = `
type testCase struct {
selector string
expectedOk bool
expected []string
}
func TestWalkThroughEmbeddedInterfaces(t *testing.T) {
cases := []testCase{
{"Inner{}.Method", false, nil},
{"(&Inner{}).Method", false, nil},
{"Outer{}.Method", false, nil},
{"InnerInterface.Method", true, []string{"test.InnerInterface"}},
{"OuterInterface.Method", true, []string{"test.OuterInterface", "test.InnerInterface"}},
{"OuterInterfaceStruct.Method", true, []string{"test.OuterInterface", "test.InnerInterface"}},
}
for _, c := range cases {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "test", commonSrc+c.selector, 0)
require.NoError(t, err)
conf := types.Config{}
info := types.Info{
Selections: make(map[*ast.SelectorExpr]*types.Selection),
}
_, err = conf.Check("test", fset, []*ast.File{f}, &info)
require.NoError(t, err)
ast.Inspect(f, func(n ast.Node) bool {
s, ok := n.(*ast.SelectorExpr)
if ok {
selection, ok := info.Selections[s]
require.Equal(t, true, ok, "No selection!")
ts, ok := walkThroughEmbeddedInterfaces(selection)
if ok != c.expectedOk {
t.Errorf("expected ok %v got %v", c.expectedOk, ok)
return false
}
if !ok {
return false
}
require.Equal(t, len(c.expected), len(ts))
for i, e := range c.expected {
assert.Equal(t, e, ts[i].String(), "mismatch at index %d", i)
}
}
return true
})
}
}

View File

@@ -5,6 +5,7 @@ import (
"crypto/rand"
"fmt"
"io"
"os"
"testing"
"time"
@@ -23,7 +24,7 @@ func TestMain(m *testing.M) {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(io.Discard)
m.Run()
os.Exit(m.Run())
}
func TestBootnode_OK(t *testing.T) {

View File

@@ -3,6 +3,7 @@ package kv
import (
"context"
"io"
"os"
"testing"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
@@ -14,7 +15,7 @@ func TestMain(m *testing.M) {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(io.Discard)
m.Run()
os.Exit(m.Run())
}
// setupDB instantiates and returns a DB instance for the validator client.