diff --git a/core/signeddata.go b/core/signeddata.go index 4d37357f7..a365b43e7 100644 --- a/core/signeddata.go +++ b/core/signeddata.go @@ -34,6 +34,7 @@ var ( _ SignedData = Signature{} _ SignedData = SignedVoluntaryExit{} _ SignedData = VersionedSignedBlindedBeaconBlock{} + _ SignedData = VersionedSignedValidatorRegistration{} ) // SigFromETH2 returns a new signature from eth2 phase0 BLSSignature. @@ -508,6 +509,107 @@ func (e *SignedVoluntaryExit) UnmarshalJSON(b []byte) error { return e.SignedVoluntaryExit.UnmarshalJSON(b) } +// VersionedSignedValidatorRegistration is a signed versioned validator (builder) registration and implements SignedData. +type VersionedSignedValidatorRegistration struct { + eth2api.VersionedSignedValidatorRegistration +} + +// versionedRawValidatorRegistrationJSON is a custom VersionedSignedValidator serialiser. +type versionedRawValidatorRegistrationJSON struct { + Version int `json:"version"` + Registration json.RawMessage `json:"registration"` +} + +func (r VersionedSignedValidatorRegistration) Clone() (SignedData, error) { + return r.clone() +} + +// clone returns a copy of the VersionedSignedValidatorRegistration. +// It is similar to Clone that returns the SignedData interface. +//nolint:revive // similar method names. +func (r VersionedSignedValidatorRegistration) clone() (VersionedSignedValidatorRegistration, error) { + var resp VersionedSignedValidatorRegistration + err := cloneJSONMarshaler(r, &resp) + if err != nil { + return VersionedSignedValidatorRegistration{}, errors.Wrap(err, "clone registration") + } + + return resp, nil +} + +func (r VersionedSignedValidatorRegistration) Signature() Signature { + switch r.Version { + case spec.BuilderVersionV1: + return SigFromETH2(r.V1.Signature) + default: + panic("unknown version") + } +} + +func (r VersionedSignedValidatorRegistration) SetSignature(sig Signature) (SignedData, error) { + resp, err := r.clone() + if err != nil { + return nil, err + } + + switch resp.Version { + case spec.BuilderVersionV1: + resp.V1.Signature = sig.ToETH2() + default: + return nil, errors.New("unknown type") + } + + return resp, nil +} + +func (r VersionedSignedValidatorRegistration) MarshalJSON() ([]byte, error) { + var marshaller json.Marshaler + switch r.Version { + case spec.BuilderVersionV1: + marshaller = r.VersionedSignedValidatorRegistration.V1 + default: + return nil, errors.New("unknown version") + } + + registration, err := marshaller.MarshalJSON() + if err != nil { + return nil, errors.Wrap(err, "marshal registration") + } + + resp, err := json.Marshal(versionedRawValidatorRegistrationJSON{ + Version: int(r.Version), + Registration: registration, + }) + if err != nil { + return nil, errors.Wrap(err, "marshal wrapper") + } + + return resp, nil +} + +func (r *VersionedSignedValidatorRegistration) UnmarshalJSON(input []byte) error { + var raw versionedRawValidatorRegistrationJSON + if err := json.Unmarshal(input, &raw); err != nil { + return errors.Wrap(err, "unmarshal validator (builder) registration") + } + + resp := eth2api.VersionedSignedValidatorRegistration{Version: spec.BuilderVersion(raw.Version)} + switch resp.Version { + case spec.BuilderVersionV1: + registration := new(eth2v1.SignedValidatorRegistration) + if err := json.Unmarshal(raw.Registration, ®istration); err != nil { + return errors.Wrap(err, "unmarshal V1 registration") + } + resp.V1 = registration + default: + return errors.New("unknown version") + } + + r.VersionedSignedValidatorRegistration = resp + + return nil +} + // cloneJSONMarshaler clones the marshaler by serialising to-from json // since eth2 types contains pointers. The result is stored // in the value pointed to by v. diff --git a/core/signeddata_test.go b/core/signeddata_test.go index e513b82c8..5c742d16a 100644 --- a/core/signeddata_test.go +++ b/core/signeddata_test.go @@ -59,3 +59,11 @@ func TestSetBlindedBlockSig(t *testing.T) { require.NoError(t, err) require.NotEqual(t, clone.Signature(), block.Signature()) } + +func TestSetVersionedValidatorRegistrationSig(t *testing.T) { + registration := testutil.RandomCoreVersionedSignedValidatorRegistration(t) + + clone, err := registration.SetSignature(testutil.RandomCoreSignature()) + require.NoError(t, err) + require.NotEqual(t, clone.Signature(), registration.Signature()) +} diff --git a/go.mod b/go.mod index 21a83edaa..906ba343b 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ go 1.18 replace github.com/grpc-ecosystem/grpc-gateway/v2 => github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1 require ( - github.com/attestantio/go-eth2-client v0.11.7 + github.com/attestantio/go-eth2-client v0.11.8-0.20220725205133-c05328b73d87 github.com/bufbuild/buf v1.6.0 github.com/coinbase/kryptology v1.5.6-0.20220316191335-269410e1b06b github.com/ethereum/go-ethereum v1.10.20 diff --git a/go.sum b/go.sum index 7a2634df6..ae428de30 100644 --- a/go.sum +++ b/go.sum @@ -60,8 +60,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/attestantio/go-eth2-client v0.11.7 h1:mRCtVZYg/Tmp47mNkWKnro/Wj63+jj1vz9BWNQN8MYo= -github.com/attestantio/go-eth2-client v0.11.7/go.mod h1:zXL/BxC0cBBhxj+tP7QG7t9Ufoa8GwQLdlbvZRd9+dM= +github.com/attestantio/go-eth2-client v0.11.8-0.20220725205133-c05328b73d87 h1:rG3xHSJSanANf/oQSc6z7y0UMWdfVP/GZMSyCUAljQY= +github.com/attestantio/go-eth2-client v0.11.8-0.20220725205133-c05328b73d87/go.mod h1:zXL/BxC0cBBhxj+tP7QG7t9Ufoa8GwQLdlbvZRd9+dM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= diff --git a/testutil/random.go b/testutil/random.go index d952cff60..144748d0b 100644 --- a/testutil/random.go +++ b/testutil/random.go @@ -25,6 +25,7 @@ import ( "net" "strings" "testing" + "time" eth2api "github.com/attestantio/go-eth2-client/api" eth2v1 "github.com/attestantio/go-eth2-client/api/v1" @@ -267,6 +268,31 @@ func RandomCoreVersionSignedBlindedBeaconBlock(t *testing.T) core.VersionedSigne } } +func RandomSignedValidatorRegistration(t *testing.T) *eth2v1.SignedValidatorRegistration { + t.Helper() + + return ð2v1.SignedValidatorRegistration{ + Message: ð2v1.ValidatorRegistration{ + FeeRecipient: bellatrix.ExecutionAddress{}, + GasLimit: rand.Uint64(), + Timestamp: time.Time{}, + Pubkey: RandomEth2PubKey(t), + }, + Signature: RandomEth2Signature(), + } +} + +func RandomCoreVersionedSignedValidatorRegistration(t *testing.T) core.VersionedSignedValidatorRegistration { + t.Helper() + + return core.VersionedSignedValidatorRegistration{ + VersionedSignedValidatorRegistration: eth2api.VersionedSignedValidatorRegistration{ + Version: spec.BuilderVersionV1, + V1: RandomSignedValidatorRegistration(t), + }, + } +} + func RandomSyncAggregate(t *testing.T) *altair.SyncAggregate { t.Helper()