Skip to content

Commit a34616a

Browse files
chore: backport register signer integration v3.5.6 (#1002)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent b3fe566 commit a34616a

8 files changed

Lines changed: 171 additions & 62 deletions

File tree

arbnode/batch_poster.go

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,8 @@ var (
8080

8181
batchPosterFailureCounter = metrics.NewRegisteredCounter("arb/batchPoster/action/failure", nil)
8282

83-
usableBytesInBlob = big.NewInt(int64(len(kzg4844.Blob{}) * 31 / 32))
84-
blobTxBlobGasPerBlob = big.NewInt(params.BlobTxBlobGasPerBlob)
85-
FatalErrUnableToRegisterSigner = errors.New("unable to register signer")
83+
usableBytesInBlob = big.NewInt(int64(len(kzg4844.Blob{}) * 31 / 32))
84+
blobTxBlobGasPerBlob = big.NewInt(params.BlobTxBlobGasPerBlob)
8685
)
8786

8887
const (
@@ -1633,13 +1632,9 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error)
16331632
return false, fmt.Errorf("batch was reverted, not posting any more batches")
16341633
}
16351634
if espressoSubmitter := b.streamer.espressoSubmitter; espressoSubmitter != nil {
1636-
registered := espressoSubmitter.GetKeyManager().HasRegistered()
1637-
if !registered {
1638-
log.Warn("ephemeral keys are not yet registered in Espresso TEE Contract")
1639-
err := espressoSubmitter.RegisterService()
1640-
if err != nil {
1641-
return false, fmt.Errorf("%w: %w", FatalErrUnableToRegisterSigner, err)
1642-
}
1635+
isRegistered, err := espressoSubmitter.GetKeyManager().CheckRegistration()
1636+
if !isRegistered {
1637+
return false, err
16431638
}
16441639
}
16451640

@@ -2314,7 +2309,7 @@ func (b *BatchPoster) Start(ctxIn context.Context) {
23142309
// Shutting down. No need to print the context canceled error.
23152310
return 0
23162311
}
2317-
if errors.Is(err, FatalErrUnableToRegisterSigner) {
2312+
if errors.Is(err, espresso_key_manager.FatalErrUnableToRegisterSigner) {
23182313
log.Warn(
23192314
"Espresso signer registration failed consecutively. Stopping.",
23202315
"retries", espressotee.EspressoMaxRetries,

arbnode/espresso_caff_node.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,8 +507,13 @@ func (n *EspressoCaffNode) Start(ctx context.Context) error {
507507
}
508508

509509
if n.keyManager != nil {
510-
registered := n.keyManager.HasRegistered()
511-
if !registered {
510+
if err := n.keyManager.Init(); err != nil {
511+
return err
512+
}
513+
if state := n.keyManager.GetKeyManagerState(); state == espresso_key_manager.Registered {
514+
log.Info("Caff node address is already registered on chain!")
515+
} else {
516+
log.Info("caff node completed init, trying to register signer")
512517
if err := n.keyManager.RegisterService(); err != nil {
513518
return err
514519
}

espresso/key-manager/key_manager.go

Lines changed: 97 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package keymanager
33
import (
44
"context"
55
"crypto/ecdsa"
6+
"crypto/rand"
67
"encoding/hex"
78
"errors"
89
"fmt"
@@ -29,20 +30,38 @@ const (
2930
EMPTY = espressotee.EMPTY
3031
)
3132

33+
var FatalErrUnableToRegisterSigner = errors.New("unable to register signer")
34+
35+
type KeyManagerState int
36+
37+
const (
38+
Init KeyManagerState = iota
39+
PendingRegistration
40+
Registered
41+
)
42+
43+
type state struct {
44+
currentState KeyManagerState
45+
attestation []byte
46+
data []byte
47+
}
48+
3249
// This is a private key derived from the test test test ... test junk BIP-39 mnemonic. It is a well known private key, so it should be fine to hardcode for tests.
3350
// I found it here: https://ethereum.stackexchange.com/questions/147078/hardhat-which-file-is-initial-state-in-such-as-the-mnemonic-and-20-accounts
3451
const TEST_PERSISTENT_KEY = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
3552
const quoteFile = "/dev/attestation/quote"
3653
const userDataAttestationFile = "/dev/attestation/user_report_data"
3754

3855
type EspressoKeyManagerInterface interface {
39-
HasRegistered() bool
40-
Register(getAttestationFunc func([]byte) ([]byte, error)) error
4156
RegisterService() error
57+
Init() error
4258
GetCurrentKey() *ecdsa.PublicKey
4359
SignPayload(message []byte) ([]byte, error)
4460
SignMessage(message []byte) ([]byte, error)
4561
TeeType() espressotee.TEE
62+
GetKeyManagerState() KeyManagerState
63+
CheckRegistration() (bool, error)
64+
InitRegistration(getAttestationFunc func([]byte) ([]byte, error)) error
4665
}
4766

4867
var _ EspressoKeyManagerInterface = &EspressoKeyManager{}
@@ -56,8 +75,8 @@ type EspressoKeyManager struct {
5675
teeType espressotee.TEE
5776
serviceType espressotee.ServiceType
5877

59-
hasRegistered bool
6078
espressoNitroAttestationVerifierClient *attestationverifierclient.EspressoAttestationVerifierClient
79+
state state
6180
}
6281

6382
func NewEspressoKeyManager(
@@ -78,7 +97,12 @@ func NewEspressoKeyManager(
7897
// is provided, we use that one. Otherwise, we read the enclave private key from the attestation path.
7998
// Note: The current implementation only supports reading the key during key manager construction
8099
// for the batch poster. Support for reading the caff node key will be added in a later PR.
81-
if keyPairAttestationsPath != "" && chainID != 0 {
100+
if teeType == espressotee.SGX {
101+
privKey, err = ecdsa.GenerateKey(crypto.S256(), rand.Reader)
102+
if err != nil {
103+
panic(err)
104+
}
105+
} else if keyPairAttestationsPath != "" && chainID != 0 {
82106
// Read enclave private key
83107
privKey, err = espresso_tee_utils.ReadEnclavePrivateKey(keyPairAttestationsPath, chainID)
84108
if err != nil {
@@ -120,15 +144,24 @@ func NewEspressoKeyManager(
120144
teeType: teeType,
121145
serviceType: serviceType,
122146
espressoNitroAttestationVerifierClient: espressoNitroAttestationVerifierClient,
147+
state: state{
148+
currentState: Init,
149+
attestation: []byte{},
150+
data: []byte{},
151+
},
123152
}
124153
}
125154

126-
func (k *EspressoKeyManager) HasRegistered() bool {
127-
return k.hasRegistered
155+
func (k *EspressoKeyManager) hasRegistered() bool {
156+
return k.state.currentState == Registered
157+
}
158+
159+
func (k *EspressoKeyManager) GetKeyManagerState() KeyManagerState {
160+
return k.state.currentState
128161
}
129162

130163
func (k *EspressoKeyManager) VerifyRegistered() (bool, error) {
131-
if k.hasRegistered {
164+
if k.hasRegistered() {
132165
return true, nil
133166
}
134167
pubKey, ok := k.privKey.Public().(*ecdsa.PublicKey)
@@ -143,6 +176,30 @@ func (k *EspressoKeyManager) VerifyRegistered() (bool, error) {
143176
return ok, nil
144177
}
145178

179+
func (k *EspressoKeyManager) CheckRegistration() (bool, error) {
180+
state := k.state.currentState
181+
switch state {
182+
case Init:
183+
log.Warn("ephemeral keys are not yet registered in Espresso TEE Contract, KeyManager in Init phase. Waiting for Zk proof to be generated")
184+
err := k.Init()
185+
if err != nil {
186+
return false, fmt.Errorf("unable to init keymanager: %w", err)
187+
}
188+
return false, nil
189+
case PendingRegistration:
190+
log.Warn("ephemeral keys are not yet registered in Espresso TEE Contract, KeyManager in Registration phase")
191+
err := k.RegisterService()
192+
if err != nil {
193+
return false, fmt.Errorf("%w: %w", FatalErrUnableToRegisterSigner, err)
194+
}
195+
return false, nil
196+
case Registered:
197+
return true, nil
198+
default:
199+
return false, fmt.Errorf("key manager in an unknown state: %v", state)
200+
}
201+
}
202+
146203
/*
147204
* This function will get the attestation in order to properly register the signing address on chain for a given TEE type
148205
*/
@@ -201,20 +258,28 @@ func (k *EspressoKeyManager) PrepareRegisterService(getAttestationFunc func([]by
201258
}
202259
}
203260

204-
func (k *EspressoKeyManager) Register(getAttestationFunc func([]byte) ([]byte, error)) error {
205-
if k.hasRegistered {
261+
func (k *EspressoKeyManager) InitRegistration(getAttestationFunc func([]byte) ([]byte, error)) error {
262+
if k.hasRegistered() {
206263
log.Info("EspressoKeyManager already registered")
207264
return nil
208265
}
209266

267+
// In tests we use TESTS tee type but the contract only accepts SGX tee type
268+
if k.teeType == TESTS && k.serviceType != espressotee.Test {
269+
k.teeType = SGX
270+
}
271+
210272
// Check on-chain if we have already registered
211273
hasRegistered, err := k.VerifyRegistered()
212274
if err != nil {
213275
return err
214276
}
215277
if hasRegistered {
216-
k.hasRegistered = true
217-
log.Info("Signer already registered on-chain")
278+
k.state.currentState = Registered
279+
k.state.attestation = []byte{}
280+
k.state.data = []byte{}
281+
signerAddr := crypto.PubkeyToAddress(k.privKey.PublicKey)
282+
log.Info("Signer already registered on-chain", "signer address", signerAddr.Hex())
218283
return nil
219284
}
220285

@@ -223,7 +288,18 @@ func (k *EspressoKeyManager) Register(getAttestationFunc func([]byte) ([]byte, e
223288
if err != nil {
224289
return err
225290
}
226-
err = k.espressoTEEVerifierCaller.RegisterService(k.dataPoster, attestation, data, uint8(k.teeType), k.serviceType)
291+
k.state.currentState = PendingRegistration
292+
k.state.attestation = attestation
293+
k.state.data = data
294+
return nil
295+
}
296+
297+
func (k *EspressoKeyManager) RegisterService() error {
298+
currentState := k.GetKeyManagerState()
299+
if currentState != PendingRegistration {
300+
return fmt.Errorf("invalid state to register signer: got %v, want PendingRegistration", currentState)
301+
}
302+
err := k.espressoTEEVerifierCaller.RegisterService(k.dataPoster, k.state.attestation, k.state.data, uint8(k.teeType), k.serviceType)
227303
if err != nil {
228304
return err
229305
}
@@ -232,18 +308,18 @@ func (k *EspressoKeyManager) Register(getAttestationFunc func([]byte) ([]byte, e
232308
log.Info("Register signer transaction sent", "signer address", signerAddr.Hex())
233309

234310
// Verify our address is actually registered in contract
235-
hasRegistered, err = k.VerifyRegistered()
311+
hasRegistered, err := k.VerifyRegistered()
236312
if err != nil {
237313
return err
238314
}
239315
if !hasRegistered {
240316
return errors.New("address is not registered in contract even after successful transaction and retries")
241317
}
242318

243-
k.hasRegistered = true
244-
if k.teeType == TESTS {
245-
k.teeType = SGX
246-
}
319+
// We are registered free up the memory
320+
k.state.currentState = Registered
321+
k.state.attestation = []byte{}
322+
k.state.data = []byte{}
247323
log.Info("Signer registration confirmed on-chain")
248324
return nil
249325
}
@@ -265,15 +341,15 @@ func (k *EspressoKeyManager) SignMessage(message []byte) ([]byte, error) {
265341
return arbutil.SignMessage(message, k.privKey)
266342
}
267343

268-
func (k *EspressoKeyManager) RegisterService() error {
344+
func (k *EspressoKeyManager) Init() error {
269345
teeType := k.TeeType()
270346
switch teeType {
271347
case SGX:
272-
return k.Register(k.getAttestationQuote)
348+
return k.InitRegistration(k.getAttestationQuote)
273349
case NITRO:
274-
return k.Register(k.getNitroAttestation)
350+
return k.InitRegistration(k.getNitroAttestation)
275351
case TESTS:
276-
return k.Register(k.noOpSignerFunc)
352+
return k.InitRegistration(k.noOpSignerFunc)
277353
default:
278354
return fmt.Errorf("unsupported tee Type: %d", teeType)
279355
}

espresso/key-manager/key_manager_test.go

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ func TestEspressoKeyManager(t *testing.T) {
6767
require.NotNil(t, km, "Key manager should not be nil")
6868
assert.NotEmpty(t, km.GetCurrentKey(), "Public key should be set")
6969
// assert.NotNil(t, km.privKey, "Private key should be set")
70-
registered := km.HasRegistered()
71-
assert.False(t, registered, "Should not be registered initially")
70+
state := km.GetKeyManagerState()
71+
assert.Equal(t, espresso_key_manager.Init, state, "Should not be registered initially")
7272
})
7373

7474
// Test HasRegistered and Registry
@@ -78,8 +78,8 @@ func TestEspressoKeyManager(t *testing.T) {
7878
mockEspressoTEEVerifierClient.On("RegisteredServices", mock.Anything, mock.Anything, mock.Anything).Return(false, nil).Once()
7979
mockEspressoTEEVerifierClient.On("RegisteredServices", mock.Anything, mock.Anything, mock.Anything).Return(true, nil).Once()
8080
km := espresso_key_manager.NewEspressoKeyManager(mockEspressoTEEVerifierClient, dataposter, dataSigner, espresso_key_manager.SGX, espressotee.Test, persistentPrivKey, "", "", 0)
81-
registered := km.HasRegistered()
82-
assert.False(t, registered, "Should start unregistered")
81+
state := km.GetKeyManagerState()
82+
assert.Equal(t, state, espresso_key_manager.Init, "Should start unregistered")
8383

8484
// Mock sign function
8585
called := false
@@ -91,18 +91,18 @@ func TestEspressoKeyManager(t *testing.T) {
9191
return []byte("mock-signature"), nil
9292
}
9393

94-
// First registration
95-
err := km.Register(getAttestationFunc)
94+
// Register: should call sign function
95+
err := km.InitRegistration(getAttestationFunc)
9696
require.NoError(t, err, "Registry should succeed")
9797
assert.True(t, called, "Sign function should be called")
98-
registered = km.HasRegistered()
99-
assert.True(t, registered, "Should be registered after call")
98+
state = km.GetKeyManagerState()
99+
assert.Equal(t, state, espresso_key_manager.PendingRegistration, "Should be pending registration after call")
100100

101101
// Second call (already registered)
102-
called = false
103-
err = km.Register(getAttestationFunc)
104-
require.NoError(t, err, "Registry should succeed when already registered")
105-
assert.False(t, called, "Sign function should not be called again")
102+
err = km.RegisterService()
103+
require.NoError(t, err, "Registry should succeed")
104+
state = km.GetKeyManagerState()
105+
assert.Equal(t, state, espresso_key_manager.Registered, "Should be registered after call")
106106
})
107107

108108
// Test GetCurrentKey
@@ -159,8 +159,8 @@ func TestEspressoKeyManager(t *testing.T) {
159159
mockEspressoTEEVerifierClient.On("RegisteredServices", mock.Anything, mock.Anything, mock.Anything).Return(false, nil).Once()
160160
mockEspressoTEEVerifierClient.On("RegisteredServices", mock.Anything, mock.Anything, mock.Anything).Return(true, nil).Once()
161161
km := espresso_key_manager.NewEspressoKeyManager(mockEspressoTEEVerifierClient, dataposter, dataSigner, espresso_key_manager.TESTS, espressotee.Test, persistentPrivKey, "", "", 0)
162-
registered := km.HasRegistered()
163-
assert.False(t, registered, "Should start unregistered")
162+
state := km.GetKeyManagerState()
163+
assert.Equal(t, state, espresso_key_manager.Init, "Should start unregistered")
164164

165165
// Mock sign function
166166
called := false
@@ -171,20 +171,18 @@ func TestEspressoKeyManager(t *testing.T) {
171171
return []byte{}, nil
172172
}
173173

174-
// First registration
175-
err := km.Register(getAttestationFunc)
174+
// Register: should call sign function
175+
err := km.InitRegistration(getAttestationFunc)
176176
require.NoError(t, err, "Registry should succeed")
177177
assert.True(t, called, "Sign function should be called")
178-
registered = km.HasRegistered()
179-
assert.True(t, registered, "Should be registered after call")
178+
state = km.GetKeyManagerState()
179+
assert.Equal(t, state, espresso_key_manager.PendingRegistration, "Should be pending registration after call")
180180

181181
// Second call (already registered)
182-
called = false
183-
err = km.Register(getAttestationFunc)
184-
require.NoError(t, err, "Registry should succeed when already registered")
185-
assert.False(t, called, "Sign function should not be called again")
186-
registered = km.HasRegistered()
187-
assert.True(t, registered, "Register function should still return true")
182+
err = km.RegisterService()
183+
require.NoError(t, err, "Registry should succeed")
184+
state = km.GetKeyManagerState()
185+
assert.Equal(t, state, espresso_key_manager.Registered, "Should be registered after call")
188186
})
189187

190188
// Test Sign

0 commit comments

Comments
 (0)