Skip to content

Commit 582930d

Browse files
committed
Verify operations on load.
1 parent 5a572ab commit 582930d

File tree

1 file changed

+51
-6
lines changed

1 file changed

+51
-6
lines changed

cmd/validator/credentials/set/process.go

+51-6
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ import (
2929
capella "github.com/attestantio/go-eth2-client/spec/capella"
3030
"github.com/attestantio/go-eth2-client/spec/phase0"
3131
"github.com/pkg/errors"
32+
"github.com/prysmaticlabs/go-ssz"
3233
standardchaintime "github.com/wealdtech/ethdo/services/chaintime/standard"
3334
"github.com/wealdtech/ethdo/signing"
3435
"github.com/wealdtech/ethdo/util"
36+
e2types "github.com/wealdtech/go-eth2-types/v2"
3537
ethutil "github.com/wealdtech/go-eth2-util"
3638
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
3739
)
@@ -256,10 +258,12 @@ func (c *command) dumpRequiredInformation(_ context.Context) error {
256258
func (c *command) generateOperations(ctx context.Context) error {
257259
if c.account == "" && c.mnemonic == "" && c.privateKey == "" && c.validator == "" {
258260
// No input information; fetch the operations from a file.
259-
if err := c.loadOperations(ctx); err == nil {
261+
err := c.loadOperations(ctx)
262+
if err == nil {
263+
// Success.
260264
return nil
261265
}
262-
return fmt.Errorf("no account, mnemonic or private key specified and no %s file found; cannot proceed", changeOperationsFilename)
266+
return fmt.Errorf("no account, mnemonic or private key specified and no %s file loaded: %v", changeOperationsFilename, err)
263267
}
264268

265269
if c.mnemonic != "" {
@@ -330,10 +334,7 @@ func (c *command) loadOperations(ctx context.Context) error {
330334
// If not, read it from the file with the standard name.
331335
_, err := os.Stat(changeOperationsFilename)
332336
if err != nil {
333-
if c.debug {
334-
fmt.Fprintf(os.Stderr, "Failed to read change operations file: %v\n", err)
335-
}
336-
return err
337+
return errors.Wrap(err, "failed to read change operations file")
337338
}
338339
if c.debug {
339340
fmt.Fprintf(os.Stderr, "%s found; loading operations\n", changeOperationsFilename)
@@ -346,6 +347,47 @@ func (c *command) loadOperations(ctx context.Context) error {
346347
return errors.Wrap(err, "failed to parse change operations file")
347348
}
348349

350+
for _, op := range c.signedOperations {
351+
if err := c.verifyOperation(ctx, op); err != nil {
352+
return err
353+
}
354+
}
355+
356+
return nil
357+
}
358+
359+
func (c *command) verifyOperation(ctx context.Context, op *capella.SignedBLSToExecutionChange) error {
360+
root, err := op.Message.HashTreeRoot()
361+
if err != nil {
362+
return errors.Wrap(err, "failed to generate message root")
363+
}
364+
365+
sigBytes := make([]byte, len(op.Signature))
366+
copy(sigBytes, op.Signature[:])
367+
sig, err := e2types.BLSSignatureFromBytes(sigBytes)
368+
if err != nil {
369+
return errors.Wrap(err, "invalid signature")
370+
}
371+
372+
container := &phase0.SigningData{
373+
ObjectRoot: root,
374+
Domain: c.chainInfo.Domain,
375+
}
376+
signingRoot, err := ssz.HashTreeRoot(container)
377+
if err != nil {
378+
return errors.Wrap(err, "failed to generate signing root")
379+
}
380+
381+
pubkeyBytes := make([]byte, len(op.Message.FromBLSPubkey))
382+
copy(pubkeyBytes, op.Message.FromBLSPubkey[:])
383+
pubkey, err := e2types.BLSPublicKeyFromBytes(pubkeyBytes)
384+
if err != nil {
385+
return errors.Wrap(err, "invalid public key")
386+
}
387+
if !sig.Verify(signingRoot[:], pubkey) {
388+
return errors.New("signature does not verify")
389+
}
390+
349391
return nil
350392
}
351393

@@ -567,6 +609,9 @@ func (c *command) createSignedOperation(ctx context.Context,
567609
if err != nil {
568610
return nil, err
569611
}
612+
if c.debug {
613+
fmt.Fprintf(os.Stderr, "Using %#x as best public key for %s\n", pubkey.Marshal(), withdrawalAccount.Name())
614+
}
570615
blsPubkey := phase0.BLSPubKey{}
571616
copy(blsPubkey[:], pubkey.Marshal())
572617

0 commit comments

Comments
 (0)