adding remote singer changes for fulu (#15498)

* adding web 3 signer changes for fulu

* missed adding fulu values

* add accounting for fulu version

* updated web3signer version and fixing linting

* Update validator/keymanager/remote-web3signer/types/requests_test.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update validator/keymanager/remote-web3signer/types/mock/mocks.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* radek suggestions

* removing redundant check and removing old function, changed changelog to reflect

* gaz

* radek's suggestion

* fixing test as v1 proof is no longer used

* fixing more tests

---------

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
james-prysm
2025-09-10 11:58:53 -05:00
committed by GitHub
parent f690af81fa
commit 8136ff7c3a
10 changed files with 142 additions and 97 deletions

View File

@@ -0,0 +1,7 @@
### Added
- Adding Fulu types for web3signer.
### Changed
- changed validatorpb.SignRequest_AggregateAttestationAndProof signing type to use AggregateAttestationAndProofV2 on web3signer.

View File

@@ -6,10 +6,10 @@ lighthouse_archive_name = "lighthouse-%s-x86_64-unknown-linux-gnu.tar.gz" % ligh
def e2e_deps():
http_archive(
name = "web3signer",
urls = ["https://artifacts.consensys.net/public/web3signer/raw/names/web3signer.tar.gz/versions/25.2.0/web3signer-25.2.0.tar.gz"],
sha256 = "2445eaea11755621626a92d18f12c62676eb9f12ee8c8259b222d87d27505578",
urls = ["https://github.com/Consensys/web3signer/releases/download/25.9.0/web3signer-25.9.0.tar.gz"],
sha256 = "4bc95a86e232050ff071279043e1d04616572d551f6f72aee31108f96dc77bd8",
build_file = "@prysm//testing/endtoend:web3signer.BUILD",
strip_prefix = "web3signer-25.2.0",
strip_prefix = "web3signer-25.9.0",
)
http_archive(

View File

@@ -20,7 +20,7 @@ go_library(
"//io/file:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"//validator/accounts/petnames:go_default_library",
"//validator/keymanager:go_default_library",
"//validator/keymanager/remote-web3signer/internal:go_default_library",

View File

@@ -20,7 +20,7 @@ import (
"github.com/OffchainLabs/prysm/v6/io/file"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
validatorpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1/validator-client"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/OffchainLabs/prysm/v6/time/slots"
"github.com/OffchainLabs/prysm/v6/validator/accounts/petnames"
"github.com/OffchainLabs/prysm/v6/validator/keymanager"
"github.com/OffchainLabs/prysm/v6/validator/keymanager/remote-web3signer/internal"
@@ -400,16 +400,14 @@ func getSignRequestJson(ctx context.Context, validator *validator.Validate, requ
if !bytesutil.IsValidRoot(genesisValidatorsRoot) {
return nil, fmt.Errorf("invalid genesis validators root length, genesis root: %v", genesisValidatorsRoot)
}
ver := slots.ToForkVersion(request.SigningSlot)
switch request.Object.(type) {
case *validatorpb.SignRequest_Block:
return handleBlock(ctx, validator, request, genesisValidatorsRoot)
case *validatorpb.SignRequest_AttestationData:
return handleAttestationData(ctx, validator, request, genesisValidatorsRoot)
case *validatorpb.SignRequest_AggregateAttestationAndProof:
// TODO: update to V2 sometime after release
return handleAggregateAttestationAndProof(ctx, validator, request, genesisValidatorsRoot)
case *validatorpb.SignRequest_AggregateAttestationAndProofElectra:
return handleAggregateAttestationAndProofV2(ctx, version.Electra, validator, request, genesisValidatorsRoot)
case *validatorpb.SignRequest_AggregateAttestationAndProof, *validatorpb.SignRequest_AggregateAttestationAndProofElectra:
return handleAggregateAttestationAndProofV2(ctx, ver, validator, request, genesisValidatorsRoot)
case *validatorpb.SignRequest_Slot:
return handleAggregationSlot(ctx, validator, request, genesisValidatorsRoot)
case *validatorpb.SignRequest_BlockAltair:
@@ -430,6 +428,11 @@ func getSignRequestJson(ctx context.Context, validator *validator.Validate, requ
return handleBlockElectra(ctx, validator, request, genesisValidatorsRoot)
case *validatorpb.SignRequest_BlindedBlockElectra:
return handleBlindedBlockElectra(ctx, validator, request, genesisValidatorsRoot)
case *validatorpb.SignRequest_BlockFulu:
return handleBlockFulu(ctx, validator, request, genesisValidatorsRoot)
case *validatorpb.SignRequest_BlindedBlockFulu:
return handleBlindedBlockFulu(ctx, validator, request, genesisValidatorsRoot)
// We do not support "DEPOSIT" type.
/*
case *validatorpb.:
@@ -478,18 +481,6 @@ func handleAttestationData(ctx context.Context, validator *validator.Validate, r
return json.Marshal(attestationSignRequest)
}
func handleAggregateAttestationAndProof(ctx context.Context, validator *validator.Validate, request *validatorpb.SignRequest, genesisValidatorsRoot []byte) ([]byte, error) {
aggregateAndProofSignRequest, err := types.GetAggregateAndProofSignRequest(request, genesisValidatorsRoot)
if err != nil {
return nil, err
}
if err = validator.StructCtx(ctx, aggregateAndProofSignRequest); err != nil {
return nil, err
}
aggregateAndProofSignRequestsTotal.Inc()
return json.Marshal(aggregateAndProofSignRequest)
}
func handleAggregateAttestationAndProofV2(ctx context.Context, fork int, validator *validator.Validate, request *validatorpb.SignRequest, genesisValidatorsRoot []byte) ([]byte, error) {
aggregateAndProofSignRequestV2, err := types.GetAggregateAndProofV2SignRequest(fork, request, genesisValidatorsRoot)
if err != nil {
@@ -622,6 +613,30 @@ func handleBlindedBlockElectra(ctx context.Context, validator *validator.Validat
return json.Marshal(blindedBlockv2ElectraSignRequest)
}
func handleBlockFulu(ctx context.Context, validator *validator.Validate, request *validatorpb.SignRequest, genesisValidatorsRoot []byte) ([]byte, error) {
blockv2FuluSignRequest, err := types.GetBlockV2BlindedSignRequest(request, genesisValidatorsRoot)
if err != nil {
return nil, err
}
if err = validator.StructCtx(ctx, blockv2FuluSignRequest); err != nil {
return nil, err
}
remoteBlockSignRequestsTotal.WithLabelValues("fulu", "false").Inc()
return json.Marshal(blockv2FuluSignRequest)
}
func handleBlindedBlockFulu(ctx context.Context, validator *validator.Validate, request *validatorpb.SignRequest, genesisValidatorsRoot []byte) ([]byte, error) {
blindedBlockv2FuluSignRequest, err := types.GetBlockV2BlindedSignRequest(request, genesisValidatorsRoot)
if err != nil {
return nil, err
}
if err = validator.StructCtx(ctx, blindedBlockv2FuluSignRequest); err != nil {
return nil, err
}
remoteBlockSignRequestsTotal.WithLabelValues("fulu", "true").Inc()
return json.Marshal(blindedBlockv2FuluSignRequest)
}
func handleRandaoReveal(ctx context.Context, validator *validator.Validate, request *validatorpb.SignRequest, genesisValidatorsRoot []byte) ([]byte, error) {
randaoRevealSignRequest, err := types.GetRandaoRevealSignRequest(request, genesisValidatorsRoot)
if err != nil {

View File

@@ -399,14 +399,6 @@ func TestKeymanager_Sign(t *testing.T) {
want: desiredSig,
wantErr: false,
},
{
name: "AGGREGATE_AND_PROOF",
args: args{
request: mock.GetMockSignRequest("AGGREGATE_AND_PROOF"),
},
want: desiredSig,
wantErr: false,
},
{
name: "AGGREGATE_AND_PROOF_V2",
args: args{

View File

@@ -35,6 +35,7 @@ go_test(
"//consensus-types/primitives:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",
"//runtime/version:go_default_library",
"//testing/require:go_default_library",
"//validator/keymanager/remote-web3signer/types/mock:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",

View File

@@ -10,6 +10,7 @@ go_library(
"//config/fieldparams:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",
"//runtime/version:go_default_library",
"//testing/util:go_default_library",
"//validator/keymanager/remote-web3signer/types:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",

View File

@@ -2,10 +2,12 @@ package mock
import (
"fmt"
"strings"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
eth "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
validatorpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1/validator-client"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/OffchainLabs/prysm/v6/testing/util"
"github.com/OffchainLabs/prysm/v6/validator/keymanager/remote-web3signer/types"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -53,33 +55,9 @@ func GetMockSignRequest(t string) *validatorpb.SignRequest {
},
SigningSlot: 0,
}
case "AGGREGATE_AND_PROOF":
return &validatorpb.SignRequest{
PublicKey: make([]byte, fieldparams.BLSPubkeyLength),
SigningRoot: make([]byte, fieldparams.RootLength),
SignatureDomain: make([]byte, 4),
Object: &validatorpb.SignRequest_AggregateAttestationAndProof{
AggregateAttestationAndProof: &eth.AggregateAttestationAndProof{
AggregatorIndex: 0,
Aggregate: &eth.Attestation{
AggregationBits: bitfield.Bitlist{0b1101},
Data: &eth.AttestationData{
BeaconBlockRoot: make([]byte, fieldparams.RootLength),
Source: &eth.Checkpoint{
Root: make([]byte, fieldparams.RootLength),
},
Target: &eth.Checkpoint{
Root: make([]byte, fieldparams.RootLength),
},
},
Signature: make([]byte, 96),
},
SelectionProof: make([]byte, fieldparams.BLSSignatureLength),
},
},
SigningSlot: 0,
}
case "AGGREGATE_AND_PROOF_V2":
committeeBits := bitfield.NewBitvector64()
committeeBits.SetBitAt(0, true)
return &validatorpb.SignRequest{
PublicKey: make([]byte, fieldparams.BLSPubkeyLength),
SigningRoot: make([]byte, fieldparams.RootLength),
@@ -99,7 +77,7 @@ func GetMockSignRequest(t string) *validatorpb.SignRequest {
},
},
Signature: make([]byte, 96),
CommitteeBits: bitfield.Bitvector64{0x01},
CommitteeBits: committeeBits,
},
SelectionProof: make([]byte, fieldparams.BLSSignatureLength),
},
@@ -426,6 +404,24 @@ func GetMockSignRequest(t string) *validatorpb.SignRequest {
BlindedBlockElectra: util.HydrateBlindedBeaconBlockElectra(&eth.BlindedBeaconBlockElectra{}),
},
}
case "BLOCK_V2_FULU":
return &validatorpb.SignRequest{
PublicKey: make([]byte, fieldparams.BLSPubkeyLength),
SigningRoot: make([]byte, fieldparams.RootLength),
SignatureDomain: make([]byte, 4),
Object: &validatorpb.SignRequest_BlockFulu{
BlockFulu: util.HydrateBeaconBlockFulu(&eth.BeaconBlockElectra{}),
},
}
case "BLOCK_V2_BLINDED_FULU":
return &validatorpb.SignRequest{
PublicKey: make([]byte, fieldparams.BLSPubkeyLength),
SigningRoot: make([]byte, fieldparams.RootLength),
SignatureDomain: make([]byte, 4),
Object: &validatorpb.SignRequest_BlindedBlockFulu{
BlindedBlockFulu: util.HydrateBlindedBeaconBlockFulu(&eth.BlindedBeaconBlockFulu{}),
},
}
case "RANDAO_REVEAL":
return &validatorpb.SignRequest{
PublicKey: make([]byte, fieldparams.BLSPubkeyLength),
@@ -523,16 +519,19 @@ func AggregationSlotSignRequest() *types.AggregationSlotSignRequest {
}
}
// AggregateAndProofSignRequest is a mock implementation of the AggregateAndProofSignRequest.
func AggregateAndProofSignRequest() *types.AggregateAndProofSignRequest {
return &types.AggregateAndProofSignRequest{
Type: "AGGREGATE_AND_PROOF",
// AggregateAndProofV2SignRequest is a mock implementation of the AggregateAndProofV2SignRequest.
func AggregateAndProofV2SignRequest(ver int) *types.AggregateAndProofV2SignRequest {
return &types.AggregateAndProofV2SignRequest{
Type: "AGGREGATE_AND_PROOF_V2",
ForkInfo: ForkInfo(),
SigningRoot: make([]byte, fieldparams.RootLength),
AggregateAndProof: &types.AggregateAndProof{
AggregatorIndex: "0",
Aggregate: Attestation(),
SelectionProof: make([]byte, fieldparams.BLSSignatureLength),
AggregateAndProof: &types.AggregateAndProofV2{
Version: strings.ToUpper(version.String(ver)),
Data: &types.AggregateAndProofElectra{
AggregatorIndex: "0",
Aggregate: AttestationElectra(),
SelectionProof: make([]byte, fieldparams.BLSSignatureLength),
},
},
}
}

View File

@@ -65,31 +65,6 @@ func GetAggregationSlotSignRequest(request *validatorpb.SignRequest, genesisVali
}, nil
}
// GetAggregateAndProofSignRequest maps the request for signing type AGGREGATE_AND_PROOF.
func GetAggregateAndProofSignRequest(request *validatorpb.SignRequest, genesisValidatorsRoot []byte) (*AggregateAndProofSignRequest, error) {
aggregateAttestationAndProof, ok := request.Object.(*validatorpb.SignRequest_AggregateAttestationAndProof)
if !ok {
return nil, errors.New("failed to cast request object to aggregate attestation and proof")
}
if aggregateAttestationAndProof == nil {
return nil, errors.New("invalid sign request: AggregateAndProof is nil")
}
fork, err := MapForkInfo(request.SigningSlot, genesisValidatorsRoot)
if err != nil {
return nil, err
}
aggregateAndProof, err := MapAggregateAndProof(aggregateAttestationAndProof.AggregateAttestationAndProof)
if err != nil {
return nil, err
}
return &AggregateAndProofSignRequest{
Type: "AGGREGATE_AND_PROOF",
ForkInfo: fork,
SigningRoot: request.SigningRoot,
AggregateAndProof: aggregateAndProof,
}, nil
}
// GetAggregateAndProofV2SignRequest maps the request for signing type AGGREGATE_AND_PROOF_V2 on Electra changes.
func GetAggregateAndProofV2SignRequest(v int, request *validatorpb.SignRequest, genesisValidatorsRoot []byte) (*AggregateAndProofV2SignRequest, error) {
aggregateAttestationAndProof, ok := request.Object.(*validatorpb.SignRequest_AggregateAttestationAndProofElectra)
@@ -423,6 +398,34 @@ func GetBlockV2BlindedSignRequest(request *validatorpb.SignRequest, genesisValid
return nil, err
}
b = beaconBlock
case *validatorpb.SignRequest_BlockFulu:
version = "FULU"
block, ok := request.Object.(*validatorpb.SignRequest_BlockFulu)
if !ok {
return nil, errors.New("failed to cast request object to fulu block")
}
if block == nil {
return nil, errors.New("invalid sign request: fulu block is nil")
}
beaconBlock, err := blocks.NewBeaconBlock(block.BlockFulu)
if err != nil {
return nil, err
}
b = beaconBlock
case *validatorpb.SignRequest_BlindedBlockFulu:
version = "FULU"
blindedBlock, ok := request.Object.(*validatorpb.SignRequest_BlindedBlockFulu)
if !ok {
return nil, errors.New("failed to cast request object to blinded fulu block")
}
if blindedBlock == nil {
return nil, errors.New("invalid sign request: blinded fulu block is nil")
}
beaconBlock, err := blocks.NewBeaconBlock(blindedBlock.BlindedBlockFulu)
if err != nil {
return nil, err
}
b = beaconBlock
default:
return nil, errors.New("invalid sign request - invalid object type")
}

View File

@@ -6,13 +6,14 @@ import (
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
validatorpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1/validator-client"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/OffchainLabs/prysm/v6/testing/require"
"github.com/OffchainLabs/prysm/v6/validator/keymanager/remote-web3signer/types"
"github.com/OffchainLabs/prysm/v6/validator/keymanager/remote-web3signer/types/mock"
"github.com/ethereum/go-ethereum/common/hexutil"
)
func TestGetAggregateAndProofSignRequest(t *testing.T) {
func TestGetAggregateAndProofV2SignRequest(t *testing.T) {
type args struct {
request *validatorpb.SignRequest
genesisValidatorsRoot []byte
@@ -20,28 +21,28 @@ func TestGetAggregateAndProofSignRequest(t *testing.T) {
tests := []struct {
name string
args args
want *types.AggregateAndProofSignRequest
want *types.AggregateAndProofV2SignRequest
wantErr bool
}{
{
name: "Happy Path Test",
args: args{
request: mock.GetMockSignRequest("AGGREGATE_AND_PROOF"),
request: mock.GetMockSignRequest("AGGREGATE_AND_PROOF_V2"),
genesisValidatorsRoot: make([]byte, fieldparams.RootLength),
},
want: mock.AggregateAndProofSignRequest(),
want: mock.AggregateAndProofV2SignRequest(version.Electra),
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := types.GetAggregateAndProofSignRequest(tt.args.request, tt.args.genesisValidatorsRoot)
got, err := types.GetAggregateAndProofV2SignRequest(version.Electra, tt.args.request, tt.args.genesisValidatorsRoot)
if (err != nil) != tt.wantErr {
t.Errorf("GetAggregateAndProofSignRequest() error = %v, wantErr %v", err, tt.wantErr)
t.Errorf("GetAggregateAndProofV2SignRequest() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetAggregateAndProofSignRequest() got = %v, want %v", got, tt.want)
t.Errorf("GetAggregateAndProofV2SignRequest() got = %v, want %v", got, tt.want)
}
})
}
@@ -476,6 +477,32 @@ func TestGetBlockV2BlindedSignRequest(t *testing.T) {
}(t), "ELECTRA"),
wantErr: false,
},
{
name: "Happy Path Test non blinded Fulu",
args: args{
request: mock.GetMockSignRequest("BLOCK_V2_FULU"),
genesisValidatorsRoot: make([]byte, fieldparams.RootLength),
},
want: mock.BlockV2BlindedSignRequest(func(t *testing.T) []byte {
bytevalue, err := hexutil.Decode("0xca4f98890bc98a59f015d06375a5e00546b8f2ac1e88d31b1774ea28d4b3e7d1")
require.NoError(t, err)
return bytevalue
}(t), "FULU"),
wantErr: false,
},
{
name: "Happy Path Test blinded Fulu",
args: args{
request: mock.GetMockSignRequest("BLOCK_V2_BLINDED_FULU"),
genesisValidatorsRoot: make([]byte, fieldparams.RootLength),
},
want: mock.BlockV2BlindedSignRequest(func(t *testing.T) []byte {
bytevalue, err := hexutil.Decode("0x60cd4e8a557e64d00f63777b53f18c10cc122997c55f40a37cb19dc2edd3b0c7")
require.NoError(t, err)
return bytevalue
}(t), "FULU"),
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {