diff --git a/changelog/james-prysm_fulu-web3signer.md b/changelog/james-prysm_fulu-web3signer.md new file mode 100644 index 0000000000..699abb4150 --- /dev/null +++ b/changelog/james-prysm_fulu-web3signer.md @@ -0,0 +1,7 @@ +### Added + +- Adding Fulu types for web3signer. + +### Changed + +- changed validatorpb.SignRequest_AggregateAttestationAndProof signing type to use AggregateAttestationAndProofV2 on web3signer. \ No newline at end of file diff --git a/testing/endtoend/deps.bzl b/testing/endtoend/deps.bzl index 313c7f5e7f..33f424a369 100644 --- a/testing/endtoend/deps.bzl +++ b/testing/endtoend/deps.bzl @@ -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( diff --git a/validator/keymanager/remote-web3signer/BUILD.bazel b/validator/keymanager/remote-web3signer/BUILD.bazel index c86f63453e..46119f746e 100644 --- a/validator/keymanager/remote-web3signer/BUILD.bazel +++ b/validator/keymanager/remote-web3signer/BUILD.bazel @@ -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", diff --git a/validator/keymanager/remote-web3signer/keymanager.go b/validator/keymanager/remote-web3signer/keymanager.go index 3768f2f870..ca6a7cbfde 100644 --- a/validator/keymanager/remote-web3signer/keymanager.go +++ b/validator/keymanager/remote-web3signer/keymanager.go @@ -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 { diff --git a/validator/keymanager/remote-web3signer/keymanager_test.go b/validator/keymanager/remote-web3signer/keymanager_test.go index 4eeef835ec..8b55890188 100644 --- a/validator/keymanager/remote-web3signer/keymanager_test.go +++ b/validator/keymanager/remote-web3signer/keymanager_test.go @@ -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{ diff --git a/validator/keymanager/remote-web3signer/types/BUILD.bazel b/validator/keymanager/remote-web3signer/types/BUILD.bazel index 69c5463dac..79cffaca88 100644 --- a/validator/keymanager/remote-web3signer/types/BUILD.bazel +++ b/validator/keymanager/remote-web3signer/types/BUILD.bazel @@ -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", diff --git a/validator/keymanager/remote-web3signer/types/mock/BUILD.bazel b/validator/keymanager/remote-web3signer/types/mock/BUILD.bazel index 671786065b..a9a32929c2 100644 --- a/validator/keymanager/remote-web3signer/types/mock/BUILD.bazel +++ b/validator/keymanager/remote-web3signer/types/mock/BUILD.bazel @@ -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", diff --git a/validator/keymanager/remote-web3signer/types/mock/mocks.go b/validator/keymanager/remote-web3signer/types/mock/mocks.go index 081818c2a6..5d4d4b164b 100644 --- a/validator/keymanager/remote-web3signer/types/mock/mocks.go +++ b/validator/keymanager/remote-web3signer/types/mock/mocks.go @@ -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: ð.AggregateAttestationAndProof{ - AggregatorIndex: 0, - Aggregate: ð.Attestation{ - AggregationBits: bitfield.Bitlist{0b1101}, - Data: ð.AttestationData{ - BeaconBlockRoot: make([]byte, fieldparams.RootLength), - Source: ð.Checkpoint{ - Root: make([]byte, fieldparams.RootLength), - }, - Target: ð.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(ð.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(ð.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(ð.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), + }, }, } } diff --git a/validator/keymanager/remote-web3signer/types/requests.go b/validator/keymanager/remote-web3signer/types/requests.go index 48495ae435..c458c6c7f0 100644 --- a/validator/keymanager/remote-web3signer/types/requests.go +++ b/validator/keymanager/remote-web3signer/types/requests.go @@ -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") } diff --git a/validator/keymanager/remote-web3signer/types/requests_test.go b/validator/keymanager/remote-web3signer/types/requests_test.go index 523f89079b..32a678bf00 100644 --- a/validator/keymanager/remote-web3signer/types/requests_test.go +++ b/validator/keymanager/remote-web3signer/types/requests_test.go @@ -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) {