diff --git a/op-batcher/batcher/espresso_service.go b/op-batcher/batcher/espresso_service.go index 3c97679af67..8a4ba01b03f 100644 --- a/op-batcher/batcher/espresso_service.go +++ b/op-batcher/batcher/espresso_service.go @@ -61,19 +61,31 @@ func (bs *BatcherService) EspressoStreamer() *espressoStreamers.Streamer { return bs.driver.espressoStreamer } -// initChainSigner asserts that the configured TxManager implements the -// ChainSigner interface and stores the embedded ChainSigner on the service. -// Espresso uses ChainSigner to sign batch authentication payloads sent to the -// BatchAuthenticator contract; the cast is required by every Espresso path. +// initChainSigner builds the ChainSigner that signs the Espresso transaction +// envelope (see EspressoBatch.ToEspressoTransaction), from the same signing config +// the txmgr uses. Distinct from the enclave key pair, which signs the EIP-712 +// commitment BatchAuthenticator verifies. func (bs *BatcherService) initChainSigner(cfg *CLIConfig) error { - if !cfg.Espresso.Enabled { - return nil + tcfg := cfg.TxMgrConfig + + // Same HD-path resolution as txmgr.NewConfig. + hdPath := tcfg.HDPath + if hdPath == "" && tcfg.SequencerHDPath != "" { + hdPath = tcfg.SequencerHDPath + } else if hdPath == "" && tcfg.L2OutputHDPath != "" { + hdPath = tcfg.L2OutputHDPath } - cast, castOk := bs.TxManager.(opcrypto.ChainSigner) - if !castOk { - return fmt.Errorf("tx manager does not implement ChainSigner") + + factory, from, err := opcrypto.ChainSignerFactoryFromConfig(bs.Log, tcfg.PrivateKey, tcfg.Mnemonic, hdPath, tcfg.SignerCLIConfig) + if err != nil { + return fmt.Errorf("failed to init Espresso chain signer: %w", err) } - bs.ChainSigner = cast + if txFrom := bs.TxManager.From(); from != txFrom { + return fmt.Errorf( + "espresso chain signer resolved to %s but the txmgr sends from %s: the two "+ + "derivations of the same signing config have diverged", from, txFrom) + } + bs.ChainSigner = factory(bs.TxManager.ChainID().ToBig(), from) return nil } @@ -154,6 +166,12 @@ func (bs *BatcherService) initEspresso(ctx context.Context, cfg *CLIConfig) erro } bs.EspressoLightClient = lightClient + // Two distinct signing identities: the L1 batcher key below, and the ephemeral + // enclave key after it. + if err := bs.initChainSigner(cfg); err != nil { + return err + } + if err := bs.initKeyPair(); err != nil { return fmt.Errorf("failed to create key pair for batcher: %w", err) } diff --git a/op-batcher/batcher/service.go b/op-batcher/batcher/service.go index 2a49007388f..4ddec7d05d5 100644 --- a/op-batcher/batcher/service.go +++ b/op-batcher/batcher/service.go @@ -449,9 +449,6 @@ func (bs *BatcherService) initTxManager(_ context.Context, cfg *CLIConfig) error return err } bs.TxManager = txManager - if err := bs.initChainSigner(cfg); err != nil { - return err - } return nil } diff --git a/op-service/crypto/espresso.go b/op-service/crypto/espresso.go index 674e6b19e7d..c25e52c267d 100644 --- a/op-service/crypto/espresso.go +++ b/op-service/crypto/espresso.go @@ -82,6 +82,11 @@ var _ ChainSigner = &privateKeySigner{} // ChainSignerFactoryFromConfig considers three ways that signers are created & then creates single factory from those config options. // It can either take a remote signer (via opsigner.CLIConfig) or it can be provided either a mnemonic + derivation path or a private key. // It prefers the remote signer, then the mnemonic or private key (only one of which can be provided). +// +// Duplicates the key resolution in SignerFactoryFromConfig (signature.go) rather +// than wrapping it: SignerFactory yields a SignerFn, which signs transactions only, +// while ChainSigner also needs Sign over an arbitrary hash. txmgr uses the former, +// Espresso the latter; neither is redundant. func ChainSignerFactoryFromConfig(l log.Logger, privateKey, mnemonic, hdPath string, signerConfig opsigner.CLIConfig) (ChainSignerFactory, common.Address, error) { var signer ChainSignerFactory var fromAddress common.Address diff --git a/op-service/txmgr/cli.go b/op-service/txmgr/cli.go index 6fa048fa72c..054c8f5ba0d 100644 --- a/op-service/txmgr/cli.go +++ b/op-service/txmgr/cli.go @@ -491,7 +491,7 @@ func NewConfig(cfg CLIConfig, l log.Logger) (*Config, error) { hdPath = cfg.L2OutputHDPath } - chainSignerFactory, from, err := opcrypto.ChainSignerFactoryFromConfig(l, cfg.PrivateKey, cfg.Mnemonic, hdPath, cfg.SignerCLIConfig) + signerFactory, from, err := opcrypto.SignerFactoryFromConfig(l, cfg.PrivateKey, cfg.Mnemonic, hdPath, cfg.SignerCLIConfig) if err != nil { return nil, fmt.Errorf("could not init signer: %w", err) } @@ -527,16 +527,13 @@ func NewConfig(cfg CLIConfig, l log.Logger) (*Config, error) { } cellProofTime := fallbackToOsakaCellProofTimeIfKnown(chainID, cfg.CellProofTime) - chainSigner := chainSignerFactory(chainID, from) res := Config{ Backend: l1, ChainID: chainID, - Signer: chainSigner.SignTransaction, + Signer: signerFactory(chainID), From: from, - ChainSigner: chainSigner, - TxSendTimeout: cfg.TxSendTimeout, TxNotInMempoolTimeout: cfg.TxNotInMempoolTimeout, NetworkTimeout: cfg.NetworkTimeout, @@ -667,9 +664,6 @@ type Config struct { Signer opcrypto.SignerFn From common.Address - // ChainSigner is used to allow for easy signing of transactions and arbitrary data. - ChainSigner opcrypto.ChainSigner - // GasPriceEstimatorFn is used to estimate the gas price for a transaction. // If nil, DefaultGasPriceEstimatorFn is used. GasPriceEstimatorFn GasPriceEstimatorFn diff --git a/op-service/txmgr/espresso.go b/op-service/txmgr/espresso.go deleted file mode 100644 index 37bf98190db..00000000000 --- a/op-service/txmgr/espresso.go +++ /dev/null @@ -1,22 +0,0 @@ -package txmgr - -import ( - "context" - - opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" -) - -// SignTransaction is a function that provides the ability to sign a transaction -func (m *SimpleTxManager) SignTransaction(ctx context.Context, address common.Address, tx *types.Transaction) (*types.Transaction, error) { - return m.cfg.ChainSigner.SignTransaction(ctx, address, tx) -} - -// Sign is a function that provides the ability to sign a hash -func (m *SimpleTxManager) Sign(ctx context.Context, hash []byte) ([]byte, error) { - return m.cfg.ChainSigner.Sign(ctx, hash) -} - -// Ensure adherence to the interface -var _ opcrypto.ChainSigner = &SimpleTxManager{}