mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-11 06:18:05 -05:00
Compare commits
13 Commits
develop
...
hashtree_f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4478c2d2c1 | ||
|
|
6398ac4996 | ||
|
|
bdc0713854 | ||
|
|
7e340ca377 | ||
|
|
6e560e36f1 | ||
|
|
80ae937327 | ||
|
|
c055900340 | ||
|
|
64b6bd2eb2 | ||
|
|
0a0b4ccf0a | ||
|
|
33377b4e68 | ||
|
|
bc126d758f | ||
|
|
b0ea2bdfb9 | ||
|
|
bd7fe736de |
@@ -12,6 +12,7 @@ go_library(
|
||||
"log.go",
|
||||
"registry_updates.go",
|
||||
"transition.go",
|
||||
"transition_no_verify_sig.go",
|
||||
"upgrade.go",
|
||||
"validator.go",
|
||||
"withdrawals.go",
|
||||
@@ -61,6 +62,7 @@ go_test(
|
||||
"error_test.go",
|
||||
"export_test.go",
|
||||
"registry_updates_test.go",
|
||||
"transition_no_verify_sig_test.go",
|
||||
"transition_test.go",
|
||||
"upgrade_test.go",
|
||||
"validator_test.go",
|
||||
|
||||
@@ -6,11 +6,6 @@ type execReqErr struct {
|
||||
error
|
||||
}
|
||||
|
||||
// NewExecReqError creates a new execReqErr.
|
||||
func NewExecReqError(msg string) error {
|
||||
return execReqErr{errors.New(msg)}
|
||||
}
|
||||
|
||||
// IsExecutionRequestError returns true if the error has `execReqErr`.
|
||||
func IsExecutionRequestError(e error) bool {
|
||||
if e == nil {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package transition
|
||||
package electra
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/electra"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
|
||||
v "github.com/OffchainLabs/prysm/v7/beacon-chain/core/validators"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
||||
@@ -48,7 +47,7 @@ var (
|
||||
// # [New in Electra:EIP7251]
|
||||
// for_ops(body.execution_payload.consolidation_requests, process_consolidation_request)
|
||||
|
||||
func electraOperations(ctx context.Context, st state.BeaconState, block interfaces.ReadOnlyBeaconBlock) (state.BeaconState, error) {
|
||||
func ProcessOperations(ctx context.Context, st state.BeaconState, block interfaces.ReadOnlyBeaconBlock) (state.BeaconState, error) {
|
||||
var err error
|
||||
|
||||
// 6110 validations are in VerifyOperationLengths
|
||||
@@ -64,60 +63,59 @@ func electraOperations(ctx context.Context, st state.BeaconState, block interfac
|
||||
return nil, errors.Wrap(err, "could not update total active balance cache")
|
||||
}
|
||||
}
|
||||
st, err = blocks.ProcessProposerSlashings(ctx, st, bb.ProposerSlashings(), exitInfo)
|
||||
st, err = ProcessProposerSlashings(ctx, st, bb.ProposerSlashings(), exitInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessProposerSlashingsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process altair proposer slashing")
|
||||
}
|
||||
st, err = blocks.ProcessAttesterSlashings(ctx, st, bb.AttesterSlashings(), exitInfo)
|
||||
st, err = ProcessAttesterSlashings(ctx, st, bb.AttesterSlashings(), exitInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessAttesterSlashingsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process altair attester slashing")
|
||||
}
|
||||
st, err = electra.ProcessAttestationsNoVerifySignature(ctx, st, block)
|
||||
st, err = ProcessAttestationsNoVerifySignature(ctx, st, block)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessAttestationsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process altair attestation")
|
||||
}
|
||||
if _, err := electra.ProcessDeposits(ctx, st, bb.Deposits()); err != nil {
|
||||
return nil, errors.Wrap(ErrProcessDepositsFailed, err.Error())
|
||||
if _, err := ProcessDeposits(ctx, st, bb.Deposits()); err != nil { // new in electra
|
||||
return nil, errors.Wrap(err, "could not process altair deposit")
|
||||
}
|
||||
st, err = blocks.ProcessVoluntaryExits(ctx, st, bb.VoluntaryExits(), exitInfo)
|
||||
st, err = ProcessVoluntaryExits(ctx, st, bb.VoluntaryExits(), exitInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessVoluntaryExitsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process voluntary exits")
|
||||
}
|
||||
st, err = blocks.ProcessBLSToExecutionChanges(st, block)
|
||||
st, err = ProcessBLSToExecutionChanges(st, block)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessBLSChangesFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process bls-to-execution changes")
|
||||
}
|
||||
// new in electra
|
||||
requests, err := bb.ExecutionRequests()
|
||||
if err != nil {
|
||||
return nil, electra.NewExecReqError(errors.Wrap(err, "could not get execution requests").Error())
|
||||
return nil, errors.Wrap(err, "could not get execution requests")
|
||||
}
|
||||
for _, d := range requests.Deposits {
|
||||
if d == nil {
|
||||
return nil, electra.NewExecReqError("nil deposit request")
|
||||
return nil, errors.New("nil deposit request")
|
||||
}
|
||||
}
|
||||
st, err = electra.ProcessDepositRequests(ctx, st, requests.Deposits)
|
||||
st, err = ProcessDepositRequests(ctx, st, requests.Deposits)
|
||||
if err != nil {
|
||||
return nil, electra.NewExecReqError(errors.Wrap(err, "could not process deposit requests").Error())
|
||||
return nil, execReqErr{errors.Wrap(err, "could not process deposit requests")}
|
||||
}
|
||||
|
||||
for _, w := range requests.Withdrawals {
|
||||
if w == nil {
|
||||
return nil, electra.NewExecReqError("nil withdrawal request")
|
||||
return nil, errors.New("nil withdrawal request")
|
||||
}
|
||||
}
|
||||
st, err = electra.ProcessWithdrawalRequests(ctx, st, requests.Withdrawals)
|
||||
st, err = ProcessWithdrawalRequests(ctx, st, requests.Withdrawals)
|
||||
if err != nil {
|
||||
return nil, electra.NewExecReqError(errors.Wrap(err, "could not process withdrawal requests").Error())
|
||||
return nil, execReqErr{errors.Wrap(err, "could not process withdrawal requests")}
|
||||
}
|
||||
for _, c := range requests.Consolidations {
|
||||
if c == nil {
|
||||
return nil, electra.NewExecReqError("nil consolidation request")
|
||||
return nil, errors.New("nil consolidation request")
|
||||
}
|
||||
}
|
||||
if err := electra.ProcessConsolidationRequests(ctx, st, requests.Consolidations); err != nil {
|
||||
return nil, electra.NewExecReqError(errors.Wrap(err, "could not process consolidation requests").Error())
|
||||
if err := ProcessConsolidationRequests(ctx, st, requests.Consolidations); err != nil {
|
||||
return nil, execReqErr{errors.Wrap(err, "could not process consolidation requests")}
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
60
beacon-chain/core/electra/transition_no_verify_sig_test.go
Normal file
60
beacon-chain/core/electra/transition_no_verify_sig_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package electra_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/electra"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/util"
|
||||
)
|
||||
|
||||
func TestProcessOperationsWithNilRequests(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
modifyBlk func(blockElectra *ethpb.SignedBeaconBlockElectra)
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "Nil deposit request",
|
||||
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
|
||||
blk.Block.Body.ExecutionRequests.Deposits = []*enginev1.DepositRequest{nil}
|
||||
},
|
||||
errMsg: "nil deposit request",
|
||||
},
|
||||
{
|
||||
name: "Nil withdrawal request",
|
||||
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
|
||||
blk.Block.Body.ExecutionRequests.Withdrawals = []*enginev1.WithdrawalRequest{nil}
|
||||
},
|
||||
errMsg: "nil withdrawal request",
|
||||
},
|
||||
{
|
||||
name: "Nil consolidation request",
|
||||
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
|
||||
blk.Block.Body.ExecutionRequests.Consolidations = []*enginev1.ConsolidationRequest{nil}
|
||||
},
|
||||
errMsg: "nil consolidation request",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
st, ks := util.DeterministicGenesisStateElectra(t, 128)
|
||||
blk, err := util.GenerateFullBlockElectra(st, ks, util.DefaultBlockGenConfig(), 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
tc.modifyBlk(blk)
|
||||
|
||||
b, err := blocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, st.SetSlot(1))
|
||||
|
||||
_, err = electra.ProcessOperations(t.Context(), st, b.Block())
|
||||
require.ErrorContains(t, tc.errMsg, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,6 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"electra.go",
|
||||
"errors.go",
|
||||
"log.go",
|
||||
"skip_slot_cache.go",
|
||||
"state.go",
|
||||
@@ -64,8 +62,6 @@ go_test(
|
||||
"altair_transition_no_verify_sig_test.go",
|
||||
"bellatrix_transition_no_verify_sig_test.go",
|
||||
"benchmarks_test.go",
|
||||
"electra_test.go",
|
||||
"exports_test.go",
|
||||
"skip_slot_cache_test.go",
|
||||
"state_fuzz_test.go",
|
||||
"state_test.go",
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
package transition_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/util"
|
||||
)
|
||||
|
||||
func TestProcessOperationsWithNilRequests(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
modifyBlk func(blockElectra *ethpb.SignedBeaconBlockElectra)
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "Nil deposit request",
|
||||
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
|
||||
blk.Block.Body.ExecutionRequests.Deposits = []*enginev1.DepositRequest{nil}
|
||||
},
|
||||
errMsg: "nil deposit request",
|
||||
},
|
||||
{
|
||||
name: "Nil withdrawal request",
|
||||
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
|
||||
blk.Block.Body.ExecutionRequests.Withdrawals = []*enginev1.WithdrawalRequest{nil}
|
||||
},
|
||||
errMsg: "nil withdrawal request",
|
||||
},
|
||||
{
|
||||
name: "Nil consolidation request",
|
||||
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
|
||||
blk.Block.Body.ExecutionRequests.Consolidations = []*enginev1.ConsolidationRequest{nil}
|
||||
},
|
||||
errMsg: "nil consolidation request",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
st, ks := util.DeterministicGenesisStateElectra(t, 128)
|
||||
blk, err := util.GenerateFullBlockElectra(st, ks, util.DefaultBlockGenConfig(), 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
tc.modifyBlk(blk)
|
||||
|
||||
b, err := blocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, st.SetSlot(1))
|
||||
|
||||
_, err = transition.ElectraOperations(t.Context(), st, b.Block())
|
||||
require.ErrorContains(t, tc.errMsg, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestElectraOperations_ProcessingErrors(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
modifyBlk func(blk *ethpb.SignedBeaconBlockElectra)
|
||||
errCheck func(t *testing.T, err error)
|
||||
}{
|
||||
{
|
||||
name: "ErrProcessProposerSlashingsFailed",
|
||||
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
|
||||
// Create invalid proposer slashing with out-of-bounds proposer index
|
||||
blk.Block.Body.ProposerSlashings = []*ethpb.ProposerSlashing{
|
||||
{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 1,
|
||||
ProposerIndex: 999999, // Invalid index (out of bounds)
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
},
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 1,
|
||||
ProposerIndex: 999999,
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
},
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
errCheck: func(t *testing.T, err error) {
|
||||
require.ErrorContains(t, "process proposer slashings failed", err)
|
||||
require.Equal(t, true, errors.Is(err, transition.ErrProcessProposerSlashingsFailed))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ErrProcessAttestationsFailed",
|
||||
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
|
||||
// Create attestation with invalid committee index
|
||||
blk.Block.Body.Attestations = []*ethpb.AttestationElectra{
|
||||
{
|
||||
AggregationBits: []byte{0b00000001},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1,
|
||||
CommitteeIndex: 999999, // Invalid committee index
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: make([]byte, 32),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 0,
|
||||
Root: make([]byte, 32),
|
||||
},
|
||||
},
|
||||
CommitteeBits: []byte{0b00000001},
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
}
|
||||
},
|
||||
errCheck: func(t *testing.T, err error) {
|
||||
require.ErrorContains(t, "process attestations failed", err)
|
||||
require.Equal(t, true, errors.Is(err, transition.ErrProcessAttestationsFailed))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ErrProcessDepositsFailed",
|
||||
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
|
||||
// Create deposit with invalid proof length
|
||||
blk.Block.Body.Deposits = []*ethpb.Deposit{
|
||||
{
|
||||
Proof: [][]byte{}, // Invalid: empty proof
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Amount: 32000000000, // 32 ETH in Gwei
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
errCheck: func(t *testing.T, err error) {
|
||||
require.ErrorContains(t, "process deposits failed", err)
|
||||
require.Equal(t, true, errors.Is(err, transition.ErrProcessDepositsFailed))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ErrProcessVoluntaryExitsFailed",
|
||||
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
|
||||
// Create voluntary exit with invalid validator index
|
||||
blk.Block.Body.VoluntaryExits = []*ethpb.SignedVoluntaryExit{
|
||||
{
|
||||
Exit: ðpb.VoluntaryExit{
|
||||
Epoch: 0,
|
||||
ValidatorIndex: 999999, // Invalid index (out of bounds)
|
||||
},
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
}
|
||||
},
|
||||
errCheck: func(t *testing.T, err error) {
|
||||
require.ErrorContains(t, "process voluntary exits failed", err)
|
||||
require.Equal(t, true, errors.Is(err, transition.ErrProcessVoluntaryExitsFailed))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ErrProcessBLSChangesFailed",
|
||||
modifyBlk: func(blk *ethpb.SignedBeaconBlockElectra) {
|
||||
// Create BLS to execution change with invalid validator index
|
||||
blk.Block.Body.BlsToExecutionChanges = []*ethpb.SignedBLSToExecutionChange{
|
||||
{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 999999, // Invalid index (out of bounds)
|
||||
FromBlsPubkey: make([]byte, 48),
|
||||
ToExecutionAddress: make([]byte, 20),
|
||||
},
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
}
|
||||
},
|
||||
errCheck: func(t *testing.T, err error) {
|
||||
require.ErrorContains(t, "process BLS to execution changes failed", err)
|
||||
require.Equal(t, true, errors.Is(err, transition.ErrProcessBLSChangesFailed))
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
st, ks := util.DeterministicGenesisStateElectra(t, 128)
|
||||
blk, err := util.GenerateFullBlockElectra(st, ks, util.DefaultBlockGenConfig(), 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
tc.modifyBlk(blk)
|
||||
|
||||
b, err := blocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, st.SetSlot(primitives.Slot(1)))
|
||||
|
||||
_, err = transition.ElectraOperations(ctx, st, b.Block())
|
||||
require.NotNil(t, err, "Expected an error but got nil")
|
||||
tc.errCheck(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package transition
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrAttestationsSignatureInvalid = errors.New("attestations signature invalid")
|
||||
ErrRandaoSignatureInvalid = errors.New("randao signature invalid")
|
||||
ErrBLSToExecutionChangesSignatureInvalid = errors.New("BLS to execution changes signature invalid")
|
||||
ErrProcessWithdrawalsFailed = errors.New("process withdrawals failed")
|
||||
ErrProcessRandaoFailed = errors.New("process randao failed")
|
||||
ErrProcessEth1DataFailed = errors.New("process eth1 data failed")
|
||||
ErrProcessProposerSlashingsFailed = errors.New("process proposer slashings failed")
|
||||
ErrProcessAttesterSlashingsFailed = errors.New("process attester slashings failed")
|
||||
ErrProcessAttestationsFailed = errors.New("process attestations failed")
|
||||
ErrProcessDepositsFailed = errors.New("process deposits failed")
|
||||
ErrProcessVoluntaryExitsFailed = errors.New("process voluntary exits failed")
|
||||
ErrProcessBLSChangesFailed = errors.New("process BLS to execution changes failed")
|
||||
ErrProcessSyncAggregateFailed = errors.New("process sync aggregate failed")
|
||||
)
|
||||
@@ -1,3 +0,0 @@
|
||||
package transition
|
||||
|
||||
var ElectraOperations = electraOperations
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/altair"
|
||||
b "github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/electra"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition/interop"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/validators"
|
||||
v "github.com/OffchainLabs/prysm/v7/beacon-chain/core/validators"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
||||
"github.com/OffchainLabs/prysm/v7/config/features"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls"
|
||||
@@ -69,11 +70,10 @@ func ExecuteStateTransitionNoVerifyAnySig(
|
||||
}
|
||||
|
||||
// Execute per block transition.
|
||||
sigSlice, st, err := ProcessBlockNoVerifyAnySig(ctx, st, signed)
|
||||
set, st, err := ProcessBlockNoVerifyAnySig(ctx, st, signed)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not process block")
|
||||
}
|
||||
set := sigSlice.Batch()
|
||||
|
||||
// State root validation.
|
||||
postStateRoot, err := st.HashTreeRoot(ctx)
|
||||
@@ -113,7 +113,7 @@ func ExecuteStateTransitionNoVerifyAnySig(
|
||||
// assert block.state_root == hash_tree_root(state)
|
||||
func CalculateStateRoot(
|
||||
ctx context.Context,
|
||||
rollback state.BeaconState,
|
||||
state state.BeaconState,
|
||||
signed interfaces.ReadOnlySignedBeaconBlock,
|
||||
) ([32]byte, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "core.state.CalculateStateRoot")
|
||||
@@ -122,7 +122,7 @@ func CalculateStateRoot(
|
||||
tracing.AnnotateError(span, ctx.Err())
|
||||
return [32]byte{}, ctx.Err()
|
||||
}
|
||||
if rollback == nil || rollback.IsNil() {
|
||||
if state == nil || state.IsNil() {
|
||||
return [32]byte{}, errors.New("nil state")
|
||||
}
|
||||
if signed == nil || signed.IsNil() || signed.Block().IsNil() {
|
||||
@@ -130,7 +130,7 @@ func CalculateStateRoot(
|
||||
}
|
||||
|
||||
// Copy state to avoid mutating the state reference.
|
||||
state := rollback.Copy()
|
||||
state = state.Copy()
|
||||
|
||||
// Execute per slots transition.
|
||||
var err error
|
||||
@@ -141,103 +141,14 @@ func CalculateStateRoot(
|
||||
}
|
||||
|
||||
// Execute per block transition.
|
||||
if features.Get().EnableProposerPreprocessing {
|
||||
state, err = processBlockForProposing(ctx, state, signed)
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not process block for proposing")
|
||||
}
|
||||
} else {
|
||||
state, err = ProcessBlockForStateRoot(ctx, state, signed)
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not process block")
|
||||
}
|
||||
state, err = ProcessBlockForStateRoot(ctx, state, signed)
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not process block")
|
||||
}
|
||||
|
||||
return state.HashTreeRoot(ctx)
|
||||
}
|
||||
|
||||
// processBlockVerifySigs processes the block and verifies the signatures within it. Block signatures are not verified as this block is not yet signed.
|
||||
func processBlockForProposing(ctx context.Context, st state.BeaconState, signed interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
var err error
|
||||
var set BlockSignatureBatches
|
||||
set, st, err = ProcessBlockNoVerifyAnySig(ctx, st, signed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// We first try to verify all sigantures batched optimistically. We ignore block proposer signature.
|
||||
sigSet := set.Batch()
|
||||
valid, err := sigSet.Verify()
|
||||
if err != nil || valid {
|
||||
return st, err
|
||||
}
|
||||
// Some signature failed to verify.
|
||||
// Verify Attestations signatures
|
||||
attSigs := set.AttestationSignatures
|
||||
if attSigs == nil {
|
||||
return nil, ErrAttestationsSignatureInvalid
|
||||
}
|
||||
valid, err = attSigs.Verify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !valid {
|
||||
return nil, ErrAttestationsSignatureInvalid
|
||||
}
|
||||
|
||||
// Verify Randao signature
|
||||
randaoSigs := set.RandaoSignatures
|
||||
if randaoSigs == nil {
|
||||
return nil, ErrRandaoSignatureInvalid
|
||||
}
|
||||
valid, err = randaoSigs.Verify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !valid {
|
||||
return nil, ErrRandaoSignatureInvalid
|
||||
}
|
||||
|
||||
if signed.Block().Version() < version.Capella {
|
||||
//This should not happen as we must have failed one of the above signatures.
|
||||
return st, nil
|
||||
}
|
||||
// Verify BLS to execution changes signatures
|
||||
blsChangeSigs := set.BLSChangeSignatures
|
||||
if blsChangeSigs == nil {
|
||||
return nil, ErrBLSToExecutionChangesSignatureInvalid
|
||||
}
|
||||
valid, err = blsChangeSigs.Verify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !valid {
|
||||
return nil, ErrBLSToExecutionChangesSignatureInvalid
|
||||
}
|
||||
// We should not reach this point as one of the above signatures must have failed.
|
||||
return st, nil
|
||||
}
|
||||
|
||||
// BlockSignatureBatches holds the signature batches for different parts of a beacon block.
|
||||
type BlockSignatureBatches struct {
|
||||
RandaoSignatures *bls.SignatureBatch
|
||||
AttestationSignatures *bls.SignatureBatch
|
||||
BLSChangeSignatures *bls.SignatureBatch
|
||||
}
|
||||
|
||||
// Batch returns the batch of signature batches in the BlockSignatureBatches.
|
||||
func (b BlockSignatureBatches) Batch() *bls.SignatureBatch {
|
||||
sigs := bls.NewSet()
|
||||
if b.RandaoSignatures != nil {
|
||||
sigs.Join(b.RandaoSignatures)
|
||||
}
|
||||
if b.AttestationSignatures != nil {
|
||||
sigs.Join(b.AttestationSignatures)
|
||||
}
|
||||
if b.BLSChangeSignatures != nil {
|
||||
sigs.Join(b.BLSChangeSignatures)
|
||||
}
|
||||
return sigs
|
||||
}
|
||||
|
||||
// ProcessBlockNoVerifyAnySig creates a new, modified beacon state by applying block operation
|
||||
// transformations as defined in the Ethereum Serenity specification. It does not validate
|
||||
// any block signature except for deposit and slashing signatures. It also returns the relevant
|
||||
@@ -254,48 +165,48 @@ func ProcessBlockNoVerifyAnySig(
|
||||
ctx context.Context,
|
||||
st state.BeaconState,
|
||||
signed interfaces.ReadOnlySignedBeaconBlock,
|
||||
) (BlockSignatureBatches, state.BeaconState, error) {
|
||||
) (*bls.SignatureBatch, state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "core.state.ProcessBlockNoVerifyAnySig")
|
||||
defer span.End()
|
||||
set := BlockSignatureBatches{}
|
||||
if err := blocks.BeaconBlockIsNil(signed); err != nil {
|
||||
return set, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if st.Version() != signed.Block().Version() {
|
||||
return set, nil, fmt.Errorf("state and block are different version. %d != %d", st.Version(), signed.Block().Version())
|
||||
return nil, nil, fmt.Errorf("state and block are different version. %d != %d", st.Version(), signed.Block().Version())
|
||||
}
|
||||
|
||||
blk := signed.Block()
|
||||
st, err := ProcessBlockForStateRoot(ctx, st, signed)
|
||||
if err != nil {
|
||||
return set, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
randaoReveal := signed.Block().Body().RandaoReveal()
|
||||
rSet, err := b.RandaoSignatureBatch(ctx, st, randaoReveal[:])
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return set, nil, errors.Wrap(err, "could not retrieve randao signature set")
|
||||
return nil, nil, errors.Wrap(err, "could not retrieve randao signature set")
|
||||
}
|
||||
set.RandaoSignatures = rSet
|
||||
aSet, err := b.AttestationSignatureBatch(ctx, st, signed.Block().Body().Attestations())
|
||||
if err != nil {
|
||||
return set, nil, errors.Wrap(err, "could not retrieve attestation signature set")
|
||||
return nil, nil, errors.Wrap(err, "could not retrieve attestation signature set")
|
||||
}
|
||||
set.AttestationSignatures = aSet
|
||||
|
||||
// Merge beacon block, randao and attestations signatures into a set.
|
||||
set := bls.NewSet()
|
||||
set.Join(rSet).Join(aSet)
|
||||
|
||||
if blk.Version() >= version.Capella {
|
||||
changes, err := signed.Block().Body().BLSToExecutionChanges()
|
||||
if err != nil {
|
||||
return set, nil, errors.Wrap(err, "could not get BLSToExecutionChanges")
|
||||
return nil, nil, errors.Wrap(err, "could not get BLSToExecutionChanges")
|
||||
}
|
||||
cSet, err := b.BLSChangesSignatureBatch(st, changes)
|
||||
if err != nil {
|
||||
return set, nil, errors.Wrap(err, "could not get BLSToExecutionChanges signatures")
|
||||
return nil, nil, errors.Wrap(err, "could not get BLSToExecutionChanges signatures")
|
||||
}
|
||||
set.BLSChangeSignatures = cSet
|
||||
set.Join(cSet)
|
||||
}
|
||||
return set, st, nil
|
||||
}
|
||||
@@ -357,7 +268,7 @@ func ProcessOperationsNoVerifyAttsSigs(
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
state, err = electraOperations(ctx, state, beaconBlock)
|
||||
state, err = electra.ProcessOperations(ctx, state, beaconBlock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -415,7 +326,7 @@ func ProcessBlockForStateRoot(
|
||||
if state.Version() >= version.Capella {
|
||||
state, err = b.ProcessWithdrawals(state, executionData)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessWithdrawalsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process withdrawals")
|
||||
}
|
||||
}
|
||||
if err = b.ProcessPayload(state, blk.Body()); err != nil {
|
||||
@@ -427,13 +338,13 @@ func ProcessBlockForStateRoot(
|
||||
state, err = b.ProcessRandaoNoVerify(state, randaoReveal[:])
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, errors.Wrap(ErrProcessRandaoFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not verify and process randao")
|
||||
}
|
||||
|
||||
state, err = b.ProcessEth1DataInBlock(ctx, state, signed.Block().Body().Eth1Data())
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, errors.Wrap(ErrProcessEth1DataFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process eth1 data")
|
||||
}
|
||||
|
||||
state, err = ProcessOperationsNoVerifyAttsSigs(ctx, state, signed.Block())
|
||||
@@ -452,7 +363,7 @@ func ProcessBlockForStateRoot(
|
||||
}
|
||||
state, _, err = altair.ProcessSyncAggregate(ctx, state, sa)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessSyncAggregateFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "process_sync_aggregate failed")
|
||||
}
|
||||
|
||||
return state, nil
|
||||
@@ -468,35 +379,31 @@ func altairOperations(ctx context.Context, st state.BeaconState, beaconBlock int
|
||||
exitInfo := &validators.ExitInfo{}
|
||||
if hasSlashings || hasExits {
|
||||
// ExitInformation is expensive to compute, only do it if we need it.
|
||||
exitInfo = validators.ExitInformation(st)
|
||||
exitInfo = v.ExitInformation(st)
|
||||
if err := helpers.UpdateTotalActiveBalanceCache(st, exitInfo.TotalActiveBalance); err != nil {
|
||||
return nil, errors.Wrap(err, "could not update total active balance cache")
|
||||
}
|
||||
}
|
||||
st, err = b.ProcessProposerSlashings(ctx, st, beaconBlock.Body().ProposerSlashings(), exitInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessProposerSlashingsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process altair proposer slashing")
|
||||
}
|
||||
st, err = b.ProcessAttesterSlashings(ctx, st, beaconBlock.Body().AttesterSlashings(), exitInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessAttesterSlashingsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process altair attester slashing")
|
||||
}
|
||||
st, err = altair.ProcessAttestationsNoVerifySignature(ctx, st, beaconBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessAttestationsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process altair attestation")
|
||||
}
|
||||
if _, err := altair.ProcessDeposits(ctx, st, beaconBlock.Body().Deposits()); err != nil {
|
||||
return nil, errors.Wrap(ErrProcessDepositsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process altair deposit")
|
||||
}
|
||||
st, err = b.ProcessVoluntaryExits(ctx, st, beaconBlock.Body().VoluntaryExits(), exitInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessVoluntaryExitsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process voluntary exits")
|
||||
}
|
||||
st, err = b.ProcessBLSToExecutionChanges(st, beaconBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessBLSChangesFailed, err.Error())
|
||||
}
|
||||
return st, nil
|
||||
return b.ProcessBLSToExecutionChanges(st, beaconBlock)
|
||||
}
|
||||
|
||||
// This calls phase 0 block operations.
|
||||
@@ -504,32 +411,32 @@ func phase0Operations(ctx context.Context, st state.BeaconState, beaconBlock int
|
||||
var err error
|
||||
hasSlashings := len(beaconBlock.Body().ProposerSlashings()) > 0 || len(beaconBlock.Body().AttesterSlashings()) > 0
|
||||
hasExits := len(beaconBlock.Body().VoluntaryExits()) > 0
|
||||
var exitInfo *validators.ExitInfo
|
||||
var exitInfo *v.ExitInfo
|
||||
if hasSlashings || hasExits {
|
||||
// ExitInformation is expensive to compute, only do it if we need it.
|
||||
exitInfo = validators.ExitInformation(st)
|
||||
exitInfo = v.ExitInformation(st)
|
||||
if err := helpers.UpdateTotalActiveBalanceCache(st, exitInfo.TotalActiveBalance); err != nil {
|
||||
return nil, errors.Wrap(err, "could not update total active balance cache")
|
||||
}
|
||||
}
|
||||
st, err = b.ProcessProposerSlashings(ctx, st, beaconBlock.Body().ProposerSlashings(), exitInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessProposerSlashingsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process block proposer slashings")
|
||||
}
|
||||
st, err = b.ProcessAttesterSlashings(ctx, st, beaconBlock.Body().AttesterSlashings(), exitInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessAttesterSlashingsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process block attester slashings")
|
||||
}
|
||||
st, err = b.ProcessAttestationsNoVerifySignature(ctx, st, beaconBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessAttestationsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process block attestations")
|
||||
}
|
||||
if _, err := altair.ProcessDeposits(ctx, st, beaconBlock.Body().Deposits()); err != nil {
|
||||
return nil, errors.Wrap(ErrProcessDepositsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process deposits")
|
||||
}
|
||||
st, err = b.ProcessVoluntaryExits(ctx, st, beaconBlock.Body().VoluntaryExits(), exitInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProcessVoluntaryExitsFailed, err.Error())
|
||||
return nil, errors.Wrap(err, "could not process voluntary exits")
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
@@ -132,8 +132,7 @@ func TestProcessBlockNoVerify_PassesProcessingConditions(t *testing.T) {
|
||||
set, _, err := transition.ProcessBlockNoVerifyAnySig(t.Context(), beaconState, wsb)
|
||||
require.NoError(t, err)
|
||||
// Test Signature set verifies.
|
||||
sigSet := set.Batch()
|
||||
verified, err := sigSet.Verify()
|
||||
verified, err := set.Verify()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, verified, "Could not verify signature set.")
|
||||
}
|
||||
@@ -146,8 +145,7 @@ func TestProcessBlockNoVerifyAnySigAltair_OK(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
set, _, err := transition.ProcessBlockNoVerifyAnySig(t.Context(), beaconState, wsb)
|
||||
require.NoError(t, err)
|
||||
sigSet := set.Batch()
|
||||
verified, err := sigSet.Verify()
|
||||
verified, err := set.Verify()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, verified, "Could not verify signature set")
|
||||
}
|
||||
@@ -156,9 +154,8 @@ func TestProcessBlockNoVerify_SigSetContainsDescriptions(t *testing.T) {
|
||||
beaconState, block, _, _, _ := createFullBlockWithOperations(t)
|
||||
wsb, err := blocks.NewSignedBeaconBlock(block)
|
||||
require.NoError(t, err)
|
||||
signatures, _, err := transition.ProcessBlockNoVerifyAnySig(t.Context(), beaconState, wsb)
|
||||
set, _, err := transition.ProcessBlockNoVerifyAnySig(t.Context(), beaconState, wsb)
|
||||
require.NoError(t, err)
|
||||
set := signatures.Batch()
|
||||
assert.Equal(t, len(set.Signatures), len(set.Descriptions), "Signatures and descriptions do not match up")
|
||||
assert.Equal(t, "randao signature", set.Descriptions[0])
|
||||
assert.Equal(t, "attestation signature", set.Descriptions[1])
|
||||
|
||||
@@ -602,7 +602,7 @@ func (vs *Server) GetFeeRecipientByPubKey(ctx context.Context, request *ethpb.Fe
|
||||
|
||||
// computeStateRoot computes the state root after a block has been processed through a state transition and
|
||||
// returns it to the validator client.
|
||||
func (vs *Server) computeStateRoot(ctx context.Context, block interfaces.SignedBeaconBlock) ([]byte, error) {
|
||||
func (vs *Server) computeStateRoot(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) ([]byte, error) {
|
||||
beaconState, err := vs.StateGen.StateByRoot(ctx, block.Block().ParentRoot())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not retrieve beacon state")
|
||||
@@ -613,72 +613,13 @@ func (vs *Server) computeStateRoot(ctx context.Context, block interfaces.SignedB
|
||||
block,
|
||||
)
|
||||
if err != nil {
|
||||
return vs.handleStateRootError(ctx, block, err)
|
||||
return nil, errors.Wrapf(err, "could not calculate state root at slot %d", beaconState.Slot())
|
||||
}
|
||||
|
||||
log.WithField("beaconStateRoot", fmt.Sprintf("%#x", root)).Debugf("Computed state root")
|
||||
return root[:], nil
|
||||
}
|
||||
|
||||
type computeStateRootAttemptsKeyType string
|
||||
|
||||
const computeStateRootAttemptsKey = computeStateRootAttemptsKeyType("compute-state-root-attempts")
|
||||
const maxComputeStateRootAttempts = 3
|
||||
|
||||
// handleStateRootError retries block construction in some error cases.
|
||||
func (vs *Server) handleStateRootError(ctx context.Context, block interfaces.SignedBeaconBlock, err error) ([]byte, error) {
|
||||
if ctx.Err() != nil {
|
||||
return nil, status.Errorf(codes.Canceled, "context error: %v", ctx.Err())
|
||||
}
|
||||
switch {
|
||||
case errors.Is(err, transition.ErrAttestationsSignatureInvalid),
|
||||
errors.Is(err, transition.ErrProcessAttestationsFailed):
|
||||
log.WithError(err).Warn("Retrying block construction without attestations")
|
||||
if err := block.SetAttestations([]ethpb.Att{}); err != nil {
|
||||
return nil, errors.Wrap(err, "could not set attestations")
|
||||
}
|
||||
case errors.Is(err, transition.ErrProcessBLSChangesFailed), errors.Is(err, transition.ErrBLSToExecutionChangesSignatureInvalid):
|
||||
log.WithError(err).Warn("Retrying block construction without BLS to execution changes")
|
||||
if err := block.SetBLSToExecutionChanges([]*ethpb.SignedBLSToExecutionChange{}); err != nil {
|
||||
return nil, errors.Wrap(err, "could not set BLS to execution changes")
|
||||
}
|
||||
case errors.Is(err, transition.ErrProcessProposerSlashingsFailed):
|
||||
log.WithError(err).Warn("Retrying block construction without proposer slashings")
|
||||
block.SetProposerSlashings([]*ethpb.ProposerSlashing{})
|
||||
case errors.Is(err, transition.ErrProcessAttesterSlashingsFailed):
|
||||
log.WithError(err).Warn("Retrying block construction without attester slashings")
|
||||
if err := block.SetAttesterSlashings([]ethpb.AttSlashing{}); err != nil {
|
||||
return nil, errors.Wrap(err, "could not set attester slashings")
|
||||
}
|
||||
case errors.Is(err, transition.ErrProcessVoluntaryExitsFailed):
|
||||
log.WithError(err).Warn("Retrying block construction without voluntary exits")
|
||||
block.SetVoluntaryExits([]*ethpb.SignedVoluntaryExit{})
|
||||
case errors.Is(err, transition.ErrProcessSyncAggregateFailed):
|
||||
log.WithError(err).Warn("Retrying block construction without sync aggregate")
|
||||
emptySig := [96]byte{0xC0}
|
||||
emptyAggregate := ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: make([]byte, params.BeaconConfig().SyncCommitteeSize/8),
|
||||
SyncCommitteeSignature: emptySig[:],
|
||||
}
|
||||
if err := block.SetSyncAggregate(emptyAggregate); err != nil {
|
||||
log.WithError(err).Error("Could not set sync aggregate")
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, errors.Wrap(err, "could not compute state root")
|
||||
}
|
||||
// prevent deep recursion by limiting max attempts.
|
||||
if v, ok := ctx.Value(computeStateRootAttemptsKey).(int); !ok {
|
||||
ctx = context.WithValue(ctx, computeStateRootAttemptsKey, int(1))
|
||||
} else if v >= maxComputeStateRootAttempts {
|
||||
return nil, fmt.Errorf("attempted max compute state root attempts %d", maxComputeStateRootAttempts)
|
||||
} else {
|
||||
ctx = context.WithValue(ctx, computeStateRootAttemptsKey, v+1)
|
||||
}
|
||||
// recursive call to compute state root again
|
||||
return vs.computeStateRoot(ctx, block)
|
||||
}
|
||||
|
||||
// Deprecated: The gRPC API will remain the default and fully supported through v8 (expected in 2026) but will be eventually removed in favor of REST API.
|
||||
//
|
||||
// SubmitValidatorRegistrations submits validator registrations.
|
||||
|
||||
@@ -1313,59 +1313,6 @@ func TestProposer_ComputeStateRoot_OK(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestHandleStateRootError_MaxAttemptsReached(t *testing.T) {
|
||||
// Test that handleStateRootError returns an error when max attempts is reached
|
||||
// instead of recursing infinitely.
|
||||
ctx := t.Context()
|
||||
vs := &Server{}
|
||||
|
||||
// Create a minimal block for testing
|
||||
blk := util.NewBeaconBlock()
|
||||
wsb, err := blocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Pre-seed the context with max attempts already reached
|
||||
ctx = context.WithValue(ctx, computeStateRootAttemptsKey, maxComputeStateRootAttempts)
|
||||
|
||||
// Call handleStateRootError with a retryable error
|
||||
_, err = vs.handleStateRootError(ctx, wsb, transition.ErrAttestationsSignatureInvalid)
|
||||
|
||||
// Should return an error about max attempts instead of recursing
|
||||
require.ErrorContains(t, "attempted max compute state root attempts", err)
|
||||
}
|
||||
|
||||
func TestHandleStateRootError_IncrementsAttempts(t *testing.T) {
|
||||
// Test that handleStateRootError properly increments the attempts counter
|
||||
// and eventually fails after max attempts.
|
||||
db := dbutil.SetupDB(t)
|
||||
ctx := t.Context()
|
||||
|
||||
beaconState, parentRoot, _ := util.DeterministicGenesisStateWithGenesisBlock(t, ctx, db, 100)
|
||||
|
||||
stateGen := stategen.New(db, doublylinkedtree.New())
|
||||
vs := &Server{
|
||||
StateGen: stateGen,
|
||||
}
|
||||
|
||||
// Create a block that will trigger retries
|
||||
blk := util.NewBeaconBlock()
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
blk.Block.Slot = 1
|
||||
wsb, err := blocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add a state for the parent root so StateByRoot succeeds
|
||||
require.NoError(t, stateGen.SaveState(ctx, parentRoot, beaconState))
|
||||
|
||||
// Call handleStateRootError with a retryable error - it will recurse
|
||||
// but eventually hit the max attempts limit since CalculateStateRoot
|
||||
// will keep failing (no valid attestations, randao, etc.)
|
||||
_, err = vs.handleStateRootError(ctx, wsb, transition.ErrAttestationsSignatureInvalid)
|
||||
|
||||
// Should eventually fail - either with max attempts or another error
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestProposer_PendingDeposits_Eth1DataVoteOK(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ go_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/state/state-native/custom-types:go_default_library",
|
||||
"//beacon-chain/state/state-native/types:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
"github.com/OffchainLabs/go-bitfield"
|
||||
customtypes "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native/custom-types"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native/types"
|
||||
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
@@ -44,8 +43,6 @@ type Prover interface {
|
||||
FinalizedRootProof(ctx context.Context) ([][]byte, error)
|
||||
CurrentSyncCommitteeProof(ctx context.Context) ([][]byte, error)
|
||||
NextSyncCommitteeProof(ctx context.Context) ([][]byte, error)
|
||||
|
||||
ProofByFieldIndex(ctx context.Context, f types.FieldIndex) ([][]byte, error)
|
||||
}
|
||||
|
||||
// ReadOnlyBeaconState defines a struct which only has read access to beacon state methods.
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native/types"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/container/trie"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
@@ -40,51 +39,33 @@ func (b *BeaconState) NextSyncCommitteeGeneralizedIndex() (uint64, error) {
|
||||
|
||||
// CurrentSyncCommitteeProof from the state's Merkle trie representation.
|
||||
func (b *BeaconState) CurrentSyncCommitteeProof(ctx context.Context) ([][]byte, error) {
|
||||
return b.ProofByFieldIndex(ctx, types.CurrentSyncCommittee)
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
if b.version == version.Phase0 {
|
||||
return nil, errNotSupported("CurrentSyncCommitteeProof", b.version)
|
||||
}
|
||||
|
||||
// In case the Merkle layers of the trie are not populated, we need
|
||||
// to perform some initialization.
|
||||
if err := b.initializeMerkleLayers(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Our beacon state uses a "dirty" fields pattern which requires us to
|
||||
// recompute branches of the Merkle layers that are marked as dirty.
|
||||
if err := b.recomputeDirtyFields(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return trie.ProofFromMerkleLayers(b.merkleLayers, types.CurrentSyncCommittee.RealPosition()), nil
|
||||
}
|
||||
|
||||
// NextSyncCommitteeProof from the state's Merkle trie representation.
|
||||
func (b *BeaconState) NextSyncCommitteeProof(ctx context.Context) ([][]byte, error) {
|
||||
return b.ProofByFieldIndex(ctx, types.NextSyncCommittee)
|
||||
}
|
||||
|
||||
// FinalizedRootProof crafts a Merkle proof for the finalized root
|
||||
// contained within the finalized checkpoint of a beacon state.
|
||||
func (b *BeaconState) FinalizedRootProof(ctx context.Context) ([][]byte, error) {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
branchProof, err := b.proofByFieldIndex(ctx, types.FinalizedCheckpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The epoch field of a finalized checkpoint is the neighbor
|
||||
// index of the finalized root field in its Merkle tree representation
|
||||
// of the checkpoint. This neighbor is the first element added to the proof.
|
||||
epochBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(epochBuf, uint64(b.finalizedCheckpointVal().Epoch))
|
||||
epochRoot := bytesutil.ToBytes32(epochBuf)
|
||||
proof := make([][]byte, 0)
|
||||
proof = append(proof, epochRoot[:])
|
||||
proof = append(proof, branchProof...)
|
||||
return proof, nil
|
||||
}
|
||||
|
||||
// ProofByFieldIndex constructs proofs for given field index with lock acquisition.
|
||||
func (b *BeaconState) ProofByFieldIndex(ctx context.Context, f types.FieldIndex) ([][]byte, error) {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
return b.proofByFieldIndex(ctx, f)
|
||||
}
|
||||
|
||||
// proofByFieldIndex constructs proofs for given field index.
|
||||
// Important: it is assumed that beacon state mutex is locked when calling this method.
|
||||
func (b *BeaconState) proofByFieldIndex(ctx context.Context, f types.FieldIndex) ([][]byte, error) {
|
||||
err := b.validateFieldIndex(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if b.version == version.Phase0 {
|
||||
return nil, errNotSupported("NextSyncCommitteeProof", b.version)
|
||||
}
|
||||
|
||||
if err := b.initializeMerkleLayers(ctx); err != nil {
|
||||
@@ -93,40 +74,35 @@ func (b *BeaconState) proofByFieldIndex(ctx context.Context, f types.FieldIndex)
|
||||
if err := b.recomputeDirtyFields(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return trie.ProofFromMerkleLayers(b.merkleLayers, f.RealPosition()), nil
|
||||
return trie.ProofFromMerkleLayers(b.merkleLayers, types.NextSyncCommittee.RealPosition()), nil
|
||||
}
|
||||
|
||||
func (b *BeaconState) validateFieldIndex(f types.FieldIndex) error {
|
||||
switch b.version {
|
||||
case version.Phase0:
|
||||
if f.RealPosition() > params.BeaconConfig().BeaconStateFieldCount-1 {
|
||||
return errNotSupported(f.String(), b.version)
|
||||
}
|
||||
case version.Altair:
|
||||
if f.RealPosition() > params.BeaconConfig().BeaconStateAltairFieldCount-1 {
|
||||
return errNotSupported(f.String(), b.version)
|
||||
}
|
||||
case version.Bellatrix:
|
||||
if f.RealPosition() > params.BeaconConfig().BeaconStateBellatrixFieldCount-1 {
|
||||
return errNotSupported(f.String(), b.version)
|
||||
}
|
||||
case version.Capella:
|
||||
if f.RealPosition() > params.BeaconConfig().BeaconStateCapellaFieldCount-1 {
|
||||
return errNotSupported(f.String(), b.version)
|
||||
}
|
||||
case version.Deneb:
|
||||
if f.RealPosition() > params.BeaconConfig().BeaconStateDenebFieldCount-1 {
|
||||
return errNotSupported(f.String(), b.version)
|
||||
}
|
||||
case version.Electra:
|
||||
if f.RealPosition() > params.BeaconConfig().BeaconStateElectraFieldCount-1 {
|
||||
return errNotSupported(f.String(), b.version)
|
||||
}
|
||||
case version.Fulu:
|
||||
if f.RealPosition() > params.BeaconConfig().BeaconStateFuluFieldCount-1 {
|
||||
return errNotSupported(f.String(), b.version)
|
||||
}
|
||||
// FinalizedRootProof crafts a Merkle proof for the finalized root
|
||||
// contained within the finalized checkpoint of a beacon state.
|
||||
func (b *BeaconState) FinalizedRootProof(ctx context.Context) ([][]byte, error) {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
if b.version == version.Phase0 {
|
||||
return nil, errNotSupported("FinalizedRootProof", b.version)
|
||||
}
|
||||
|
||||
return nil
|
||||
if err := b.initializeMerkleLayers(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := b.recomputeDirtyFields(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpt := b.finalizedCheckpointVal()
|
||||
// The epoch field of a finalized checkpoint is the neighbor
|
||||
// index of the finalized root field in its Merkle tree representation
|
||||
// of the checkpoint. This neighbor is the first element added to the proof.
|
||||
epochBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(epochBuf, uint64(cpt.Epoch))
|
||||
epochRoot := bytesutil.ToBytes32(epochBuf)
|
||||
proof := make([][]byte, 0)
|
||||
proof = append(proof, epochRoot[:])
|
||||
branch := trie.ProofFromMerkleLayers(b.merkleLayers, types.FinalizedCheckpoint.RealPosition())
|
||||
proof = append(proof, branch...)
|
||||
return proof, nil
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ func TestBeaconStateMerkleProofs_phase0_notsupported(t *testing.T) {
|
||||
_, err := st.NextSyncCommitteeProof(ctx)
|
||||
require.ErrorContains(t, "not supported", err)
|
||||
})
|
||||
t.Run("finalized root", func(t *testing.T) {
|
||||
_, err := st.FinalizedRootProof(ctx)
|
||||
require.ErrorContains(t, "not supported", err)
|
||||
})
|
||||
}
|
||||
func TestBeaconStateMerkleProofs_altair(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
### Added
|
||||
|
||||
- Add feature flag `--enable-proposer-preprocessing` to process the block and verify signatures before proposing.
|
||||
2
changelog/potuz_use_hashtree.md
Normal file
2
changelog/potuz_use_hashtree.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Added
|
||||
- Add feature flag to use hashtree instead of gohashtre.
|
||||
@@ -1,3 +0,0 @@
|
||||
### Added
|
||||
|
||||
- Add `ProofByFieldIndex` to generalize merkle proof generation for `BeaconState`.
|
||||
@@ -70,8 +70,8 @@ type Flags struct {
|
||||
DisableStakinContractCheck bool // Disables check for deposit contract when proposing blocks
|
||||
IgnoreUnviableAttestations bool // Ignore attestations whose target state is not viable (avoids lagging-node DoS).
|
||||
|
||||
EnableHashtree bool // Enables usage of the hashtree library for hashing
|
||||
EnableVerboseSigVerification bool // EnableVerboseSigVerification specifies whether to verify individual signature if batch verification fails
|
||||
EnableProposerPreprocessing bool // EnableProposerPreprocessing enables proposer pre-processing of blocks before proposing.
|
||||
|
||||
PrepareAllPayloads bool // PrepareAllPayloads informs the engine to prepare a block on every slot.
|
||||
// BlobSaveFsync requires blob saving to block on fsync to ensure blobs are durably persisted before passing DA.
|
||||
@@ -238,15 +238,15 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
|
||||
logEnabled(enableFullSSZDataLogging)
|
||||
cfg.EnableFullSSZDataLogging = true
|
||||
}
|
||||
if ctx.IsSet(enableHashtree.Name) {
|
||||
logEnabled(enableHashtree)
|
||||
cfg.EnableHashtree = true
|
||||
}
|
||||
cfg.EnableVerboseSigVerification = true
|
||||
if ctx.IsSet(disableVerboseSigVerification.Name) {
|
||||
logEnabled(disableVerboseSigVerification)
|
||||
cfg.EnableVerboseSigVerification = false
|
||||
}
|
||||
cfg.EnableProposerPreprocessing = ctx.Bool(enableProposerPreprocessing.Name)
|
||||
if cfg.EnableProposerPreprocessing {
|
||||
logEnabled(enableProposerPreprocessing)
|
||||
}
|
||||
if ctx.IsSet(prepareAllPayloads.Name) {
|
||||
logEnabled(prepareAllPayloads)
|
||||
cfg.PrepareAllPayloads = true
|
||||
|
||||
@@ -133,15 +133,14 @@ var (
|
||||
Name: "enable-beacon-rest-api",
|
||||
Usage: "(Experimental): Enables of the beacon REST API when querying a beacon node.",
|
||||
}
|
||||
enableHashtree = &cli.BoolFlag{
|
||||
Name: "enable-hashtree",
|
||||
Usage: "(Experimental): Enables the hashtree hashing library.",
|
||||
}
|
||||
disableVerboseSigVerification = &cli.BoolFlag{
|
||||
Name: "disable-verbose-sig-verification",
|
||||
Usage: "Disables identifying invalid signatures if batch verification fails when processing block.",
|
||||
}
|
||||
enableProposerPreprocessing = &cli.BoolFlag{
|
||||
Name: "enable-proposer-preprocessing",
|
||||
Usage: "Enables proposer pre-processing of blocks before proposing.",
|
||||
Value: false,
|
||||
}
|
||||
prepareAllPayloads = &cli.BoolFlag{
|
||||
Name: "prepare-all-payloads",
|
||||
Usage: "Informs the engine to prepare all local payloads. Useful for relayers and builders.",
|
||||
@@ -271,7 +270,6 @@ var BeaconChainFlags = combinedFlags([]cli.Flag{
|
||||
ignoreUnviableAttestations,
|
||||
enableFullSSZDataLogging,
|
||||
disableVerboseSigVerification,
|
||||
enableProposerPreprocessing,
|
||||
prepareAllPayloads,
|
||||
aggregateFirstInterval,
|
||||
aggregateSecondInterval,
|
||||
@@ -286,6 +284,7 @@ var BeaconChainFlags = combinedFlags([]cli.Flag{
|
||||
forceHeadFlag,
|
||||
blacklistRoots,
|
||||
lowValcountSweep,
|
||||
enableHashtree,
|
||||
}, deprecatedBeaconFlags, deprecatedFlags, upcomingDeprecation)
|
||||
|
||||
func combinedFlags(flags ...[]cli.Flag) []cli.Flag {
|
||||
|
||||
@@ -36,7 +36,6 @@ go_library(
|
||||
"//runtime/version:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_gohashtree//:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -63,6 +62,7 @@ go_test(
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//container/trie:go_default_library",
|
||||
"//crypto/hash/htr:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
@@ -72,6 +72,5 @@ go_test(
|
||||
"//testing/require:go_default_library",
|
||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_prysmaticlabs_gohashtree//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/container/trie"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/hash/htr"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/ssz"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/gohashtree"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -45,7 +45,7 @@ func VerifyKZGInclusionProof(blob ROBlob) error {
|
||||
return errInvalidBodyRoot
|
||||
}
|
||||
chunks := makeChunk(blob.KzgCommitment)
|
||||
gohashtree.HashChunks(chunks, chunks)
|
||||
htr.HashChunks(chunks, chunks)
|
||||
verified := trie.VerifyMerkleProof(root, chunks[0][:], blob.Index+KZGOffset, blob.CommitmentInclusionProof)
|
||||
if !verified {
|
||||
return errInvalidInclusionProof
|
||||
@@ -182,7 +182,7 @@ func LeavesFromCommitments(commitments [][]byte) [][]byte {
|
||||
leaves := make([][]byte, len(commitments))
|
||||
for i, kzg := range commitments {
|
||||
chunk := makeChunk(kzg)
|
||||
gohashtree.HashChunks(chunk, chunk)
|
||||
htr.HashChunks(chunk, chunk)
|
||||
leaves[i] = chunk[0][:]
|
||||
}
|
||||
return leaves
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/container/trie"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/hash/htr"
|
||||
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"github.com/prysmaticlabs/gohashtree"
|
||||
)
|
||||
|
||||
func Test_MerkleProofKZGCommitment_Altair(t *testing.T) {
|
||||
@@ -108,7 +108,7 @@ func Test_MerkleProofKZGCommitment(t *testing.T) {
|
||||
require.Equal(t, true, trie.VerifyMerkleProof(root[:], commitmentsRoot[:], kzgPosition, topProof[:len(topProof)-1]))
|
||||
|
||||
chunk := makeChunk(kzgs[index])
|
||||
gohashtree.HashChunks(chunk, chunk)
|
||||
htr.HashChunks(chunk, chunk)
|
||||
require.Equal(t, true, trie.VerifyMerkleProof(root[:], chunk[0][:], uint64(index+KZGOffset), proof))
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,12 @@ go_library(
|
||||
srcs = ["hashtree.go"],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/crypto/hash/htr",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["@com_github_prysmaticlabs_gohashtree//:go_default_library"],
|
||||
deps = [
|
||||
"//config/features:go_default_library",
|
||||
"@com_github_offchainlabs_hashtree//:go_default_library",
|
||||
"@com_github_prysmaticlabs_gohashtree//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
@@ -13,5 +18,8 @@ go_test(
|
||||
size = "small",
|
||||
srcs = ["hashtree_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//testing/require:go_default_library"],
|
||||
deps = [
|
||||
"//config/features:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -4,14 +4,38 @@ import (
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/OffchainLabs/hashtree"
|
||||
"github.com/OffchainLabs/prysm/v7/config/features"
|
||||
"github.com/prysmaticlabs/gohashtree"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const minSliceSizeToParallelize = 5000
|
||||
|
||||
// Hash hashes chunks pairwise into digests using the configured hashing library.
|
||||
// It performs input validation (odd chunks, digest length).
|
||||
func Hash(digests, chunks [][32]byte) error {
|
||||
if features.Get().EnableHashtree {
|
||||
return hashtree.Hash(digests, chunks)
|
||||
}
|
||||
return gohashtree.Hash(digests, chunks)
|
||||
}
|
||||
|
||||
// HashChunks hashes chunks pairwise into digests without error checking.
|
||||
// The caller must ensure inputs are valid (even chunks, sufficient digest space).
|
||||
func HashChunks(digests, chunks [][32]byte) {
|
||||
if features.Get().EnableHashtree {
|
||||
if err := hashtree.Hash(digests, chunks); err != nil {
|
||||
log.WithError(err).Error("Could not hash chunks")
|
||||
}
|
||||
} else {
|
||||
gohashtree.HashChunks(digests, chunks)
|
||||
}
|
||||
}
|
||||
|
||||
func hashParallel(inputList [][32]byte, outputList [][32]byte, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
err := gohashtree.Hash(outputList, inputList)
|
||||
err := Hash(outputList, inputList)
|
||||
if err != nil {
|
||||
panic(err) // lint:nopanic -- This should never panic.
|
||||
}
|
||||
@@ -25,7 +49,7 @@ func hashParallel(inputList [][32]byte, outputList [][32]byte, wg *sync.WaitGrou
|
||||
func VectorizedSha256(inputList [][32]byte) [][32]byte {
|
||||
outputList := make([][32]byte, len(inputList)/2)
|
||||
if len(inputList) < minSliceSizeToParallelize {
|
||||
err := gohashtree.Hash(outputList, inputList)
|
||||
err := Hash(outputList, inputList)
|
||||
if err != nil {
|
||||
panic(err) // lint:nopanic -- This should never panic.
|
||||
}
|
||||
@@ -38,7 +62,7 @@ func VectorizedSha256(inputList [][32]byte) [][32]byte {
|
||||
for j := range n {
|
||||
go hashParallel(inputList[j*2*groupSize:(j+1)*2*groupSize], outputList[j*groupSize:], &wg)
|
||||
}
|
||||
err := gohashtree.Hash(outputList[n*groupSize:], inputList[n*2*groupSize:])
|
||||
err := Hash(outputList[n*groupSize:], inputList[n*2*groupSize:])
|
||||
if err != nil {
|
||||
panic(err) // lint:nopanic -- This should never panic.
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/config/features"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
)
|
||||
|
||||
@@ -23,3 +24,25 @@ func Test_VectorizedSha256(t *testing.T) {
|
||||
require.Equal(t, r, hash2[i])
|
||||
}
|
||||
}
|
||||
|
||||
func Test_VectorizedSha256_hashtree_enabled(t *testing.T) {
|
||||
resetCfg := features.InitWithReset(&features.Flags{
|
||||
EnableHashtree: true,
|
||||
})
|
||||
defer resetCfg()
|
||||
|
||||
largeSlice := make([][32]byte, 32*minSliceSizeToParallelize)
|
||||
secondLargeSlice := make([][32]byte, 32*minSliceSizeToParallelize)
|
||||
hash1 := make([][32]byte, 16*minSliceSizeToParallelize)
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Go(func() {
|
||||
tempHash := VectorizedSha256(largeSlice)
|
||||
copy(hash1, tempHash)
|
||||
})
|
||||
wg.Wait()
|
||||
hash2 := VectorizedSha256(secondLargeSlice)
|
||||
require.Equal(t, len(hash1), len(hash2))
|
||||
for i, r := range hash1 {
|
||||
require.Equal(t, r, hash2[i])
|
||||
}
|
||||
}
|
||||
|
||||
9
deps.bzl
9
deps.bzl
@@ -2449,6 +2449,15 @@ def prysm_deps():
|
||||
sum = "h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=",
|
||||
version = "v1.4.11",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_offchainlabs_hashtree",
|
||||
build_file_generation = "off",
|
||||
importpath = "github.com/OffchainLabs/hashtree",
|
||||
patch_args = ["-p1"],
|
||||
patches = ["//third_party:com_github_offchainlabs_hashtree.patch"],
|
||||
sum = "h1:R6DAjgAUwwfgji3jEI4WUxtZ3eJ+FbRHjW21UPMBJyo=",
|
||||
version = "v0.2.2",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_oklog_oklog",
|
||||
importpath = "github.com/oklog/oklog",
|
||||
|
||||
@@ -21,7 +21,6 @@ go_library(
|
||||
"@com_github_minio_sha256_simd//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_prysmaticlabs_gohashtree//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/container/trie"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/hash/htr"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/gohashtree"
|
||||
)
|
||||
|
||||
var errInvalidNilSlice = errors.New("invalid empty slice")
|
||||
@@ -182,10 +181,10 @@ func MerkleizeListSSZ[T Hashable](elements []T, limit uint64) ([32]byte, error)
|
||||
chunks := make([][32]byte, 2)
|
||||
chunks[0] = body
|
||||
binary.LittleEndian.PutUint64(chunks[1][:], uint64(len(elements)))
|
||||
if err := gohashtree.Hash(chunks, chunks); err != nil {
|
||||
if err = htr.Hash(chunks, chunks); err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
return chunks[0], err
|
||||
return chunks[0], nil
|
||||
}
|
||||
|
||||
// MerkleizeByteSliceSSZ hashes a byteslice by chunkifying it and returning the
|
||||
|
||||
1
go.mod
1
go.mod
@@ -6,6 +6,7 @@ require (
|
||||
github.com/MariusVanDerWijden/FuzzyVM v0.0.0-20240516070431-7828990cad7d
|
||||
github.com/MariusVanDerWijden/tx-fuzz v1.4.0
|
||||
github.com/OffchainLabs/go-bitfield v0.0.0-20251031151322-f427d04d8506
|
||||
github.com/OffchainLabs/hashtree v0.2.3
|
||||
github.com/aristanetworks/goarista v0.0.0-20200805130819-fd197cf57d96
|
||||
github.com/bazelbuild/rules_go v0.23.2
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4
|
||||
|
||||
2
go.sum
2
go.sum
@@ -59,6 +59,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/OffchainLabs/go-bitfield v0.0.0-20251031151322-f427d04d8506 h1:d/SJkN8/9Ca+1YmuDiUJxAiV4w/a9S8NcsG7GMQSrVI=
|
||||
github.com/OffchainLabs/go-bitfield v0.0.0-20251031151322-f427d04d8506/go.mod h1:6TZI4FU6zT8x6ZfWa1J8YQ2NgW0wLV/W3fHRca8ISBo=
|
||||
github.com/OffchainLabs/hashtree v0.2.3 h1:nM8dBAQZzHLzzM14FaAHXnHTAXZIst69v5xWuS48y/c=
|
||||
github.com/OffchainLabs/hashtree v0.2.3/go.mod h1:b07+cRZs+eAR8TR57CB9TQlt5Gnl/06Xs76xt/1wq0M=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/sarama v1.26.1/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
|
||||
@@ -6272,8 +6272,8 @@
|
||||
|
||||
- name: process_operations#electra
|
||||
sources:
|
||||
- file: beacon-chain/core/transition/electra.go
|
||||
search: func electraOperations(
|
||||
- file: beacon-chain/core/electra/transition_no_verify_sig.go
|
||||
search: func ProcessOperations(
|
||||
spec: |
|
||||
<spec fn="process_operations" fork="electra" hash="643f18b4">
|
||||
def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||
|
||||
90
third_party/com_github_offchainlabs_hashtree.patch
vendored
Normal file
90
third_party/com_github_offchainlabs_hashtree.patch
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
diff -urN a/BUILD.bazel b/BUILD.bazel
|
||||
--- a/BUILD.bazel 1969-12-31 18:00:00.000000000 -0600
|
||||
+++ b/BUILD.bazel 2025-01-05 12:00:00.000000000 -0600
|
||||
@@ -0,0 +1,86 @@
|
||||
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
+
|
||||
+go_library(
|
||||
+ name = "go_default_library",
|
||||
+ srcs = [
|
||||
+ "bindings.go",
|
||||
+ "sha256_1_generic.go",
|
||||
+ ] + select({
|
||||
+ "@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
+ "bindings_amd64.go",
|
||||
+ "wrapper_linux_amd64.s",
|
||||
+ ":hashtree_amd64_syso",
|
||||
+ ],
|
||||
+ "@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
+ "bindings_amd64.go",
|
||||
+ "wrapper_windows_amd64.s",
|
||||
+ ":hashtree_amd64_syso",
|
||||
+ ],
|
||||
+ "@io_bazel_rules_go//go/platform:linux_arm64": [
|
||||
+ "bindings_arm64.go",
|
||||
+ "wrapper_arm64.s",
|
||||
+ ":hashtree_arm64_syso",
|
||||
+ ],
|
||||
+ "@io_bazel_rules_go//go/platform:darwin_arm64": [
|
||||
+ "bindings_arm64.go",
|
||||
+ "wrapper_arm64.s",
|
||||
+ ":hashtree_arm64_syso",
|
||||
+ ],
|
||||
+ "@io_bazel_rules_go//go/platform:darwin_amd64": [
|
||||
+ "bindings_darwin_amd64.go",
|
||||
+ ],
|
||||
+ "//conditions:default": [],
|
||||
+ }),
|
||||
+ importpath = "github.com/OffchainLabs/hashtree",
|
||||
+ visibility = ["//visibility:public"],
|
||||
+ deps = ["@com_github_klauspost_cpuid_v2//:go_default_library"],
|
||||
+)
|
||||
+
|
||||
+genrule(
|
||||
+ name = "hashtree_arm64_syso",
|
||||
+ srcs = [":hashtree_arm64"],
|
||||
+ outs = ["hashtree_arm64.syso"],
|
||||
+ cmd = "cp $(location :hashtree_arm64) $@",
|
||||
+)
|
||||
+
|
||||
+genrule(
|
||||
+ name = "hashtree_amd64_syso",
|
||||
+ srcs = [":hashtree_amd64"],
|
||||
+ outs = ["hashtree_amd64.syso"],
|
||||
+ cmd = "cp $(location :hashtree_amd64) $@",
|
||||
+)
|
||||
+
|
||||
+cc_library(
|
||||
+ name = "hashtree_arm64",
|
||||
+ srcs = [
|
||||
+ "src/hashtree.c",
|
||||
+ "src/sha256_generic.c",
|
||||
+ "src/sha256_armv8_crypto.S",
|
||||
+ "src/sha256_armv8_neon_x1.S",
|
||||
+ "src/sha256_armv8_neon_x4.S",
|
||||
+ ],
|
||||
+ hdrs = ["src/hashtree.h"],
|
||||
+ copts = ["-O3", "-Wall"],
|
||||
+ linkstatic = True,
|
||||
+ strip_include_prefix = "src",
|
||||
+ visibility = ["//visibility:public"],
|
||||
+)
|
||||
+
|
||||
+cc_library(
|
||||
+ name = "hashtree_amd64",
|
||||
+ srcs = [
|
||||
+ "src/hashtree.c",
|
||||
+ "src/sha256_generic.c",
|
||||
+ "src/sha256_avx_x1.S",
|
||||
+ "src/sha256_avx_x4.S",
|
||||
+ "src/sha256_avx_x8.S",
|
||||
+ "src/sha256_avx_x16.S",
|
||||
+ "src/sha256_shani.S",
|
||||
+ "src/sha256_sse_x1.S",
|
||||
+ ],
|
||||
+ hdrs = ["src/hashtree.h"],
|
||||
+ copts = ["-O3", "-Wall", "-fno-integrated-as"],
|
||||
+ linkstatic = True,
|
||||
+ strip_include_prefix = "src",
|
||||
+ visibility = ["//visibility:public"],
|
||||
+)
|
||||
@@ -424,8 +424,7 @@ func debugStateTransition(
|
||||
return st, errors.Wrap(err, "could not process block")
|
||||
}
|
||||
var valid bool
|
||||
sigSet := set.Batch()
|
||||
valid, err = sigSet.VerifyVerbosely()
|
||||
valid, err = set.VerifyVerbosely()
|
||||
if err != nil {
|
||||
return st, errors.Wrap(err, "could not batch verify signature")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user