From e65987996186fec78aedaa664afd10eaf1ea4c24 Mon Sep 17 00:00:00 2001 From: Joel Date: Tue, 22 Nov 2022 19:10:03 +0000 Subject: [PATCH] Return errors from enclave DB, instead of ignoring or using a critical log message (#863) --- go/enclave/db/interfaces.go | 26 +++--- go/enclave/db/rawdb/accessors_attestation.go | 17 ++-- go/enclave/db/rawdb/accessors_chain.go | 31 +++++--- go/enclave/db/rawdb/accessors_metadata.go | 19 +++-- go/enclave/db/rawdb/accessors_receipts.go | 7 +- go/enclave/db/storage.go | 83 +++++++++++--------- go/enclave/enclave.go | 58 ++++++++++---- go/enclave/events/subscription_manager.go | 28 ++++--- go/enclave/rollupchain/rollup_chain.go | 59 ++++++++++---- 9 files changed, 208 insertions(+), 120 deletions(-) diff --git a/go/enclave/db/interfaces.go b/go/enclave/db/interfaces.go index 724c88352d..0028de402e 100644 --- a/go/enclave/db/interfaces.go +++ b/go/enclave/db/interfaces.go @@ -40,7 +40,7 @@ type RollupResolver interface { // FetchRollupByHeight returns the rollup with the given height and true, or (nil, false) if no such rollup is stored. FetchRollupByHeight(height uint64) (*core.Rollup, bool) // FetchRollups returns all the proposed rollups with the given height - FetchRollups(height uint64) []*core.Rollup + FetchRollups(height uint64) ([]*core.Rollup, error) // StoreRollup persists the rollup StoreRollup(rollup *core.Rollup) // ParentRollup returns the rollup's parent rollup, or (nil, false) if no such rollup was found. @@ -58,21 +58,21 @@ type BlockStateStorage interface { FetchBlockState(blockHash common.L1RootHash) (*core.BlockState, bool) // FetchLogs returns the block's logs, or (nil, false) if no such block was found. FetchLogs(blockHash common.L1RootHash) ([]*types.Log, bool) - // FetchHeadState returns the head block state. Returns nil if nothing recorded yet - FetchHeadState() *core.BlockState + // FetchHeadState returns the head block state. + FetchHeadState() (*core.BlockState, error) // StoreNewHead saves the block state alongside its rollup, receipts and logs. - StoreNewHead(state *core.BlockState, rollup *core.Rollup, receipts []*types.Receipt, logs []*types.Log) + StoreNewHead(state *core.BlockState, rollup *core.Rollup, receipts []*types.Receipt, logs []*types.Log) error // CreateStateDB creates a database that can be used to execute transactions - CreateStateDB(hash common.L2RootHash) *state.StateDB + CreateStateDB(hash common.L2RootHash) (*state.StateDB, error) // EmptyStateDB creates the original empty StateDB EmptyStateDB() *state.StateDB } type SharedSecretStorage interface { - // FetchSecret returns the enclave's secret, returns (nil, false) if not found - FetchSecret() (*crypto.SharedEnclaveSecret, bool) + // FetchSecret returns the enclave's secret. + FetchSecret() (*crypto.SharedEnclaveSecret, error) // StoreSecret stores a secret in the enclave - StoreSecret(secret crypto.SharedEnclaveSecret) + StoreSecret(secret crypto.SharedEnclaveSecret) error } type TransactionStorage interface { @@ -81,18 +81,18 @@ type TransactionStorage interface { // GetTransactionReceipt - returns the receipt of a tx by tx hash GetTransactionReceipt(txHash gethcommon.Hash) (*types.Receipt, error) // GetReceiptsByHash retrieves the receipts for all transactions in a given rollup. - GetReceiptsByHash(hash gethcommon.Hash) types.Receipts + GetReceiptsByHash(hash gethcommon.Hash) (types.Receipts, error) // GetSender returns the sender of the tx by hash GetSender(txHash gethcommon.Hash) (gethcommon.Address, error) // GetContractCreationTx returns the hash of the tx that created a contract - GetContractCreationTx(address gethcommon.Address) (gethcommon.Hash, error) + GetContractCreationTx(address gethcommon.Address) (*gethcommon.Hash, error) } type AttestationStorage interface { - // FetchAttestedKey returns the public key of an attested aggregator, returns nil if not found - FetchAttestedKey(aggregator gethcommon.Address) *ecdsa.PublicKey + // FetchAttestedKey returns the public key of an attested aggregator + FetchAttestedKey(aggregator gethcommon.Address) (*ecdsa.PublicKey, error) // StoreAttestedKey - store the public key of an attested aggregator - StoreAttestedKey(aggregator gethcommon.Address, key *ecdsa.PublicKey) + StoreAttestedKey(aggregator gethcommon.Address, key *ecdsa.PublicKey) error } // Storage is the enclave's interface for interacting with the enclave's datastore diff --git a/go/enclave/db/rawdb/accessors_attestation.go b/go/enclave/db/rawdb/accessors_attestation.go index c590ee7137..aacf770e4a 100644 --- a/go/enclave/db/rawdb/accessors_attestation.go +++ b/go/enclave/db/rawdb/accessors_attestation.go @@ -2,29 +2,32 @@ package rawdb import ( "crypto/ecdsa" + "fmt" gethlog "github.com/ethereum/go-ethereum/log" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" - "github.com/obscuronet/go-obscuro/go/common/log" ) -func ReadAttestationKey(db ethdb.KeyValueReader, address gethcommon.Address, logger gethlog.Logger) *ecdsa.PublicKey { +func ReadAttestationKey(db ethdb.KeyValueReader, address gethcommon.Address) (*ecdsa.PublicKey, error) { key, err := db.Get(attestationPkKey(address)) if err != nil { - logger.Crit("Could not read key from db. ", log.ErrKey, err) + return nil, fmt.Errorf("could not retrieve attestation key for address %s. Cause: %w", address, err) } + publicKey, err := crypto.DecompressPubkey(key) if err != nil { - logger.Crit("Could not parse key from db.", log.ErrKey, err) + return nil, fmt.Errorf("could not parse key from db. Cause: %w", err) } - return publicKey + + return publicKey, nil } -func WriteAttestationKey(db ethdb.KeyValueWriter, address gethcommon.Address, key *ecdsa.PublicKey, logger gethlog.Logger) { +func WriteAttestationKey(db ethdb.KeyValueWriter, address gethcommon.Address, key *ecdsa.PublicKey, logger gethlog.Logger) error { if err := db.Put(attestationPkKey(address), crypto.CompressPubkey(key)); err != nil { - logger.Crit("Failed to store the attested key. ", log.ErrKey, err) + return fmt.Errorf("could not write attestation key. Cause: %w", err) } + return nil } diff --git a/go/enclave/db/rawdb/accessors_chain.go b/go/enclave/db/rawdb/accessors_chain.go index 51ec6b7394..75718655cd 100644 --- a/go/enclave/db/rawdb/accessors_chain.go +++ b/go/enclave/db/rawdb/accessors_chain.go @@ -21,25 +21,28 @@ import ( // todo - all the function in this file should return an error, which must be handled by the caller // once that is done, the logger parameter should be removed -func ReadRollup(db ethdb.KeyValueReader, hash gethcommon.Hash, logger gethlog.Logger) *core.Rollup { - height := ReadHeaderNumber(db, hash) - if height == nil { - return nil +func ReadRollup(db ethdb.KeyValueReader, hash gethcommon.Hash, logger gethlog.Logger) (*core.Rollup, error) { + height, err := ReadHeaderNumber(db, hash) + if err != nil { + return nil, err } return &core.Rollup{ Header: ReadHeader(db, hash, *height, logger), Transactions: ReadBody(db, hash, *height, logger), - } + }, nil } // ReadHeaderNumber returns the header number assigned to a hash. -func ReadHeaderNumber(db ethdb.KeyValueReader, hash gethcommon.Hash) *uint64 { - data, _ := db.Get(headerNumberKey(hash)) +func ReadHeaderNumber(db ethdb.KeyValueReader, hash gethcommon.Hash) (*uint64, error) { + data, err := db.Get(headerNumberKey(hash)) + if err != nil { + return nil, err + } if len(data) != 8 { - return nil + return nil, fmt.Errorf("header number bytes had wrong length") } number := binary.BigEndian.Uint64(data) - return &number + return &number, nil } func WriteRollup(db ethdb.KeyValueWriter, rollup *core.Rollup, logger gethlog.Logger) { @@ -136,13 +139,17 @@ func ReadBodyRLP(db ethdb.KeyValueReader, hash gethcommon.Hash, number uint64, l return data } -func ReadRollupsForHeight(db ethdb.Database, number uint64, logger gethlog.Logger) []*core.Rollup { +func ReadRollupsForHeight(db ethdb.Database, number uint64, logger gethlog.Logger) ([]*core.Rollup, error) { hashes := ReadAllHashes(db, number) rollups := make([]*core.Rollup, len(hashes)) for i, hash := range hashes { - rollups[i] = ReadRollup(db, hash, logger) + rollup, err := ReadRollup(db, hash, logger) + if err != nil { + return nil, err + } + rollups[i] = rollup } - return rollups + return rollups, nil } // ReadAllHashes retrieves all the hashes assigned to blocks at a certain heights, diff --git a/go/enclave/db/rawdb/accessors_metadata.go b/go/enclave/db/rawdb/accessors_metadata.go index 932d5f9698..f38478e1d6 100644 --- a/go/enclave/db/rawdb/accessors_metadata.go +++ b/go/enclave/db/rawdb/accessors_metadata.go @@ -1,36 +1,41 @@ package rawdb import ( + "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb" gethlog "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" + "github.com/obscuronet/go-obscuro/go/common/errutil" "github.com/obscuronet/go-obscuro/go/common/log" "github.com/obscuronet/go-obscuro/go/enclave/crypto" ) -func ReadSharedSecret(db ethdb.KeyValueReader) (*crypto.SharedEnclaveSecret, bool) { +func ReadSharedSecret(db ethdb.KeyValueReader) (*crypto.SharedEnclaveSecret, error) { var ss crypto.SharedEnclaveSecret + // TODO - Handle error. enc, _ := db.Get(sharedSecret) if len(enc) == 0 { - return nil, false + return nil, errutil.ErrNotFound } if err := rlp.DecodeBytes(enc, &ss); err != nil { - return nil, false + return nil, fmt.Errorf("could not decode shared secret") } - return &ss, true + return &ss, nil } -func WriteSharedSecret(db ethdb.KeyValueWriter, ss crypto.SharedEnclaveSecret, logger gethlog.Logger) { +func WriteSharedSecret(db ethdb.KeyValueWriter, ss crypto.SharedEnclaveSecret) error { enc, err := rlp.EncodeToBytes(ss) if err != nil { - logger.Crit("could not encode shared secret. ", log.ErrKey, err) + return fmt.Errorf("could not encode shared secret. Cause: %w", err) } if err = db.Put(sharedSecret, enc); err != nil { - logger.Crit("could not put shared secret in DB. ", log.ErrKey, err) + return fmt.Errorf("could not shared secret in DB. Cause: %w", err) } + return nil } func ReadGenesisHash(db ethdb.KeyValueReader) (*common.Hash, bool) { diff --git a/go/enclave/db/rawdb/accessors_receipts.go b/go/enclave/db/rawdb/accessors_receipts.go index 6057e9bdbd..090d77b6d0 100644 --- a/go/enclave/db/rawdb/accessors_receipts.go +++ b/go/enclave/db/rawdb/accessors_receipts.go @@ -112,12 +112,13 @@ func WriteContractCreationTx(db ethdb.KeyValueWriter, receipts types.Receipts, l } // ReadContractTransaction - returns the tx that created a contract -func ReadContractTransaction(db ethdb.Reader, address common.Address, logger gethlog.Logger) common.Hash { +func ReadContractTransaction(db ethdb.Reader, address common.Address) (*common.Hash, error) { value, err := db.Get(contractReceiptKey(address)) if err != nil { - logger.Error("failed to read the contract receipt.", log.ErrKey, err) + return nil, err } - return common.BytesToHash(value) + hash := common.BytesToHash(value) + return &hash, nil } // DeleteReceipts removes all receipt data associated with a block hash. diff --git a/go/enclave/db/storage.go b/go/enclave/db/storage.go index 0c3fbefabc..d8e3ce1d4d 100644 --- a/go/enclave/db/storage.go +++ b/go/enclave/db/storage.go @@ -3,10 +3,11 @@ package db import ( "bytes" "crypto/ecdsa" - "errors" "fmt" "math/big" + "github.com/obscuronet/go-obscuro/go/common/errutil" + gethlog "github.com/ethereum/go-ethereum/log" "github.com/obscuronet/go-obscuro/go/enclave/crypto" @@ -33,9 +34,6 @@ type storageImpl struct { logger gethlog.Logger } -// ErrTxNotFound indicates that a transaction could not be found. -var ErrTxNotFound = errors.New("transaction not found") - func NewStorage(backingDB ethdb.Database, chainConfig *params.ChainConfig, logger gethlog.Logger) Storage { return &storageImpl{ db: backingDB, @@ -79,11 +77,12 @@ func (s *storageImpl) StoreRollup(rollup *core.Rollup) { func (s *storageImpl) FetchRollup(hash common.L2RootHash) (*core.Rollup, bool) { s.assertSecretAvailable() - r := obscurorawdb.ReadRollup(s.db, hash, s.logger) - if r != nil { - return r, true + rollup, err := obscurorawdb.ReadRollup(s.db, hash, s.logger) + if err != nil { + // TODO - Return this error. + return nil, false } - return nil, false + return rollup, true } func (s *storageImpl) FetchRollupByHeight(height uint64) (*core.Rollup, bool) { @@ -98,7 +97,7 @@ func (s *storageImpl) FetchRollupByHeight(height uint64) (*core.Rollup, bool) { return s.FetchRollup(hash) } -func (s *storageImpl) FetchRollups(height uint64) []*core.Rollup { +func (s *storageImpl) FetchRollups(height uint64) ([]*core.Rollup, error) { s.assertSecretAvailable() return obscurorawdb.ReadRollupsForHeight(s.db, height, s.logger) } @@ -127,11 +126,11 @@ func (s *storageImpl) FetchHeadBlock() (*types.Block, bool) { return s.FetchBlock(rawdb.ReadHeadHeaderHash(s.db)) } -func (s *storageImpl) StoreSecret(secret crypto.SharedEnclaveSecret) { - obscurorawdb.WriteSharedSecret(s.db, secret, s.logger) +func (s *storageImpl) StoreSecret(secret crypto.SharedEnclaveSecret) error { + return obscurorawdb.WriteSharedSecret(s.db, secret) } -func (s *storageImpl) FetchSecret() (*crypto.SharedEnclaveSecret, bool) { +func (s *storageImpl) FetchSecret() (*crypto.SharedEnclaveSecret, error) { return obscurorawdb.ReadSharedSecret(s.db) } @@ -242,7 +241,7 @@ func (s *storageImpl) FetchLogs(hash common.L1RootHash) ([]*types.Log, bool) { return nil, false } -func (s *storageImpl) StoreNewHead(state *core.BlockState, rollup *core.Rollup, receipts []*types.Receipt, logs []*types.Log) { +func (s *storageImpl) StoreNewHead(state *core.BlockState, rollup *core.Rollup, receipts []*types.Receipt, logs []*types.Log) error { batch := s.db.NewBatch() if state.FoundNewRollup { @@ -261,21 +260,24 @@ func (s *storageImpl) StoreNewHead(state *core.BlockState, rollup *core.Rollup, rawdb.WriteHeadHeaderHash(batch, state.Block) if err := batch.Write(); err != nil { - s.logger.Crit("could not save new head. ", log.ErrKey, err) + return fmt.Errorf("could not save new head. Cause: %w", err) } + return nil } -func (s *storageImpl) CreateStateDB(hash common.L2RootHash) *state.StateDB { +func (s *storageImpl) CreateStateDB(hash common.L2RootHash) (*state.StateDB, error) { rollup, f := s.FetchRollup(hash) if !f { - s.logger.Crit("could not retrieve rollup for hash %s", hash.String()) + return nil, errutil.ErrNotFound } + // todo - snapshots? statedb, err := state.New(rollup.Header.Root, s.stateDB, nil) if err != nil { - s.logger.Crit("could not create state DB. ", log.ErrKey, err) + return nil, fmt.Errorf("could not create state DB. Cause: %w", err) } - return statedb + + return statedb, nil } func (s *storageImpl) EmptyStateDB() *state.StateDB { @@ -286,29 +288,33 @@ func (s *storageImpl) EmptyStateDB() *state.StateDB { return statedb } -func (s *storageImpl) FetchHeadState() *core.BlockState { +func (s *storageImpl) FetchHeadState() (*core.BlockState, error) { h := rawdb.ReadHeadHeaderHash(s.db) if (bytes.Equal(h.Bytes(), gethcommon.Hash{}.Bytes())) { - s.logger.Error("could not read head header hash from storage") - return nil + return nil, errutil.ErrNotFound } - return obscurorawdb.ReadBlockState(s.db, h, s.logger) + + blockState := obscurorawdb.ReadBlockState(s.db, h, s.logger) + if blockState == nil { + return nil, fmt.Errorf("could not retrieve block state for head") + } + + return obscurorawdb.ReadBlockState(s.db, h, s.logger), nil } // GetReceiptsByHash retrieves the receipts for all transactions in a given rollup. -func (s *storageImpl) GetReceiptsByHash(hash gethcommon.Hash) types.Receipts { - number := obscurorawdb.ReadHeaderNumber(s.db, hash) - if number == nil { - return nil +func (s *storageImpl) GetReceiptsByHash(hash gethcommon.Hash) (types.Receipts, error) { + number, err := obscurorawdb.ReadHeaderNumber(s.db, hash) + if err != nil { + return nil, err } - receipts := obscurorawdb.ReadReceipts(s.db, hash, *number, s.chainConfig, s.logger) - return receipts + return obscurorawdb.ReadReceipts(s.db, hash, *number, s.chainConfig, s.logger), nil } func (s *storageImpl) GetTransaction(txHash gethcommon.Hash) (*types.Transaction, gethcommon.Hash, uint64, uint64, error) { tx, blockHash, blockNumber, index := obscurorawdb.ReadTransaction(s.db, txHash, s.logger) if tx == nil { - return nil, gethcommon.Hash{}, 0, 0, ErrTxNotFound + return nil, gethcommon.Hash{}, 0, 0, errutil.ErrNotFound } return tx, blockHash, blockNumber, index, nil } @@ -326,9 +332,8 @@ func (s *storageImpl) GetSender(txHash gethcommon.Hash) (gethcommon.Address, err return msg.From(), nil } -func (s *storageImpl) GetContractCreationTx(address gethcommon.Address) (gethcommon.Hash, error) { - tx := obscurorawdb.ReadContractTransaction(s.db, address, s.logger) - return tx, nil +func (s *storageImpl) GetContractCreationTx(address gethcommon.Address) (*gethcommon.Hash, error) { + return obscurorawdb.ReadContractTransaction(s.db, address) } func (s *storageImpl) GetTransactionReceipt(txHash gethcommon.Hash) (*types.Receipt, error) { @@ -337,7 +342,11 @@ func (s *storageImpl) GetTransactionReceipt(txHash gethcommon.Hash) (*types.Rece return nil, err } - receipts := s.GetReceiptsByHash(blockHash) + receipts, err := s.GetReceiptsByHash(blockHash) + if err != nil { + return nil, fmt.Errorf("could not retrieve receipts for transaction. Cause: %w", err) + } + if len(receipts) <= int(index) { return nil, fmt.Errorf("receipt index not matching the transactions in block: %s", blockHash.Hex()) } @@ -346,10 +355,10 @@ func (s *storageImpl) GetTransactionReceipt(txHash gethcommon.Hash) (*types.Rece return receipt, nil } -func (s *storageImpl) FetchAttestedKey(aggregator gethcommon.Address) *ecdsa.PublicKey { - return obscurorawdb.ReadAttestationKey(s.db, aggregator, s.logger) +func (s *storageImpl) FetchAttestedKey(aggregator gethcommon.Address) (*ecdsa.PublicKey, error) { + return obscurorawdb.ReadAttestationKey(s.db, aggregator) } -func (s *storageImpl) StoreAttestedKey(aggregator gethcommon.Address, key *ecdsa.PublicKey) { - obscurorawdb.WriteAttestationKey(s.db, aggregator, key, s.logger) +func (s *storageImpl) StoreAttestedKey(aggregator gethcommon.Address, key *ecdsa.PublicKey) error { + return obscurorawdb.WriteAttestationKey(s.db, aggregator, key, s.logger) } diff --git a/go/enclave/enclave.go b/go/enclave/enclave.go index 4e220d80a0..e529ed25cb 100644 --- a/go/enclave/enclave.go +++ b/go/enclave/enclave.go @@ -8,6 +8,8 @@ import ( "fmt" "math/big" + "github.com/obscuronet/go-obscuro/go/common/errutil" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/core/vm" "github.com/obscuronet/go-obscuro/go/common/gethapi" @@ -197,9 +199,12 @@ func NewEnclave(config config.EnclaveConfig, mgmtContractLib mgmtcontractlib.Mgm // Status is only implemented by the RPC wrapper func (e *enclaveImpl) Status() (common.Status, error) { - _, found := e.storage.FetchSecret() - if !found { - return common.AwaitingSecret, nil + _, err := e.storage.FetchSecret() + if err != nil { + if errors.Is(err, errutil.ErrNotFound) { + return common.AwaitingSecret, nil + } + return common.Unavailable, err } return common.Running, nil // The enclave is local so it is always ready } @@ -309,11 +314,14 @@ func (e *enclaveImpl) GetTransactionCount(encryptedParams common.EncryptedParams if err != nil { return nil, err } - hs := e.storage.FetchHeadState() - if hs != nil { + hs, err := e.storage.FetchHeadState() + if err == nil { // todo: we should return an error when head state is not available, but for current test situations with race // conditions we allow it to return zero while head state is uninitialized - s := e.storage.CreateStateDB(hs.HeadRollup) + s, err := e.storage.CreateStateDB(hs.HeadRollup) + if err != nil { + return nil, fmt.Errorf("could not create stateDB. Cause: %w", err) + } nonce = s.GetNonce(address) } @@ -342,7 +350,7 @@ func (e *enclaveImpl) GetTransaction(encryptedParams common.EncryptedParamsGetTx // Unlike in the Geth impl, we do not try and retrieve unconfirmed transactions from the mempool. tx, blockHash, blockNumber, index, err := e.storage.GetTransaction(txHash) if err != nil { - if errors.Is(err, db.ErrTxNotFound) { + if errors.Is(err, errutil.ErrNotFound) { return nil, nil } return nil, err @@ -379,7 +387,7 @@ func (e *enclaveImpl) GetTransactionReceipt(encryptedParams common.EncryptedPara // We retrieve the transaction. tx, txRollupHash, txRollupHeight, _, err := e.storage.GetTransaction(txHash) if err != nil { - if errors.Is(err, db.ErrTxNotFound) { + if errors.Is(err, errutil.ErrNotFound) { return nil, nil } return nil, err @@ -397,7 +405,7 @@ func (e *enclaveImpl) GetTransactionReceipt(encryptedParams common.EncryptedPara // We retrieve the transaction receipt. txReceipt, err := e.storage.GetTransactionReceipt(txHash) if err != nil { - if errors.Is(err, db.ErrTxNotFound) { + if errors.Is(err, errutil.ErrNotFound) { return nil, nil } return nil, fmt.Errorf("could not retrieve transaction receipt in eth_getTransactionReceipt request. Cause: %w", err) @@ -410,7 +418,10 @@ func (e *enclaveImpl) GetTransactionReceipt(encryptedParams common.EncryptedPara } // We filter out irrelevant logs. - txReceipt.Logs = e.subscriptionManager.FilterLogs(txReceipt.Logs, txRollupHash, &sender, &filters.FilterCriteria{}) + txReceipt.Logs, err = e.subscriptionManager.FilterLogs(txReceipt.Logs, txRollupHash, &sender, &filters.FilterCriteria{}) + if err != nil { + return nil, fmt.Errorf("could not filter logs. Cause: %w", err) + } // We marshal the receipt to JSON. txReceiptBytes, err := txReceipt.MarshalJSON() @@ -452,7 +463,10 @@ func (e *enclaveImpl) Attestation() (*common.AttestationReport, error) { // GenerateSecret - the genesis enclave is responsible with generating the secret entropy func (e *enclaveImpl) GenerateSecret() (common.EncryptedSharedEnclaveSecret, error) { secret := crypto.GenerateEntropy(e.logger) - e.storage.StoreSecret(secret) + err := e.storage.StoreSecret(secret) + if err != nil { + return nil, fmt.Errorf("could not store secret. Cause: %w", err) + } encSec, err := crypto.EncryptSecret(e.enclavePubKey, secret, e.logger) if err != nil { e.logger.Error("failed to encrypt secret.", log.ErrKey, err) @@ -467,7 +481,10 @@ func (e *enclaveImpl) InitEnclave(s common.EncryptedSharedEnclaveSecret) error { if err != nil { return err } - e.storage.StoreSecret(*secret) + err = e.storage.StoreSecret(*secret) + if err != nil { + return fmt.Errorf("could not store secret. Cause: %w", err) + } e.logger.Trace(fmt.Sprintf("Secret decrypted and stored. Secret: %v", secret)) return nil } @@ -485,9 +502,9 @@ func (e *enclaveImpl) verifyAttestationAndEncryptSecret(att *common.AttestationR } e.logger.Info(fmt.Sprintf("Successfully verified attestation and identity. Owner: %s", att.Owner)) - secret, found := e.storage.FetchSecret() - if !found { - return nil, errors.New("secret was nil, no secret to share - this shouldn't happen") + secret, err := e.storage.FetchSecret() + if err != nil { + return nil, fmt.Errorf("could not retrieve secret; this should not happen. Cause: %w", err) } return crypto.EncryptSecret(att.PubKey, *secret, e.logger) } @@ -504,7 +521,10 @@ func (e *enclaveImpl) storeAttestation(att *common.AttestationReport) error { if err != nil { return fmt.Errorf("failed to parse public key %w", err) } - e.storage.StoreAttestedKey(att.Owner, key) + err = e.storage.StoreAttestedKey(att.Owner, key) + if err != nil { + return fmt.Errorf("could not store attested key. Cause: %w", err) + } return nil } @@ -513,7 +533,11 @@ func (e *enclaveImpl) GetBalance(encryptedParams common.EncryptedParamsGetBalanc } func (e *enclaveImpl) GetCode(address gethcommon.Address, rollupHash *gethcommon.Hash) ([]byte, error) { - return e.storage.CreateStateDB(*rollupHash).GetCode(address), nil + stateDB, err := e.storage.CreateStateDB(*rollupHash) + if err != nil { + return nil, fmt.Errorf("could not create stateDB. Cause: %w", err) + } + return stateDB.GetCode(address), nil } func (e *enclaveImpl) Subscribe(id gethrpc.ID, encryptedSubscription common.EncryptedParamsLogSubscription) error { diff --git a/go/enclave/events/subscription_manager.go b/go/enclave/events/subscription_manager.go index 5d7f9c7bce..6cfd0d049c 100644 --- a/go/enclave/events/subscription_manager.go +++ b/go/enclave/events/subscription_manager.go @@ -142,14 +142,17 @@ func (s *SubscriptionManager) GetFilteredLogs(account *gethcommon.Address, filte if !found { return nil, fmt.Errorf("could not filter logs as block state for head block could not be found") } - return s.FilterLogs(logs, headBlockState.HeadRollup, account, filter), nil + return s.FilterLogs(logs, headBlockState.HeadRollup, account, filter) } // FilterLogs takes a list of logs and the hash of the rollup to use to create the state DB. It returns the logs // filtered based on the provided account and filter. -func (s *SubscriptionManager) FilterLogs(logs []*types.Log, rollupHash common.L2RootHash, account *gethcommon.Address, filter *filters.FilterCriteria) []*types.Log { +func (s *SubscriptionManager) FilterLogs(logs []*types.Log, rollupHash common.L2RootHash, account *gethcommon.Address, filter *filters.FilterCriteria) ([]*types.Log, error) { filteredLogs := []*types.Log{} - stateDB := s.storage.CreateStateDB(rollupHash) + stateDB, err := s.storage.CreateStateDB(rollupHash) + if err != nil { + return nil, fmt.Errorf("could not create state DB to filter logs. Cause: %w", err) + } for _, logItem := range logs { userAddrs := getUserAddrsFromLogTopics(logItem, stateDB) @@ -158,33 +161,40 @@ func (s *SubscriptionManager) FilterLogs(logs []*types.Log, rollupHash common.L2 } } - return filteredLogs + return filteredLogs, nil } // GetSubscribedLogsEncrypted returns, for each subscription, the logs filtered and encrypted with the appropriate // viewing key. func (s *SubscriptionManager) GetSubscribedLogsEncrypted(logs []*types.Log, rollupHash common.L2RootHash) (map[gethrpc.ID][]byte, error) { - filteredLogs := s.getSubscribedLogs(logs, rollupHash) + filteredLogs, err := s.getSubscribedLogs(logs, rollupHash) + if err != nil { + return nil, fmt.Errorf("could not get subscribed logs. Cause: %w", err) + } return s.encryptLogs(filteredLogs) } // Filters out irrelevant logs, those that are not subscribed to, and those the subscription has seen before, and // organises them by their subscribing ID. -func (s *SubscriptionManager) getSubscribedLogs(logs []*types.Log, rollupHash common.L2RootHash) map[gethrpc.ID][]*types.Log { +func (s *SubscriptionManager) getSubscribedLogs(logs []*types.Log, rollupHash common.L2RootHash) (map[gethrpc.ID][]*types.Log, error) { relevantLogsByID := map[gethrpc.ID][]*types.Log{} // If there are no subscriptions, we return early, to avoid the overhead of creating the state DB. if s.getNumberOfSubsThreadsafe() == 0 { - return map[gethrpc.ID][]*types.Log{} + return map[gethrpc.ID][]*types.Log{}, nil + } + + stateDB, err := s.storage.CreateStateDB(rollupHash) + if err != nil { + return nil, fmt.Errorf("could not create stateDB to extract user addresses. Cause: %w", err) } - stateDB := s.storage.CreateStateDB(rollupHash) for _, logItem := range logs { userAddrs := getUserAddrsFromLogTopics(logItem, stateDB) s.updateRelevantLogs(logItem, userAddrs, relevantLogsByID) } - return relevantLogsByID + return relevantLogsByID, nil } // Encrypts each log with the appropriate viewing key. diff --git a/go/enclave/rollupchain/rollup_chain.go b/go/enclave/rollupchain/rollup_chain.go index 24ae73a707..fc91e2cd8f 100644 --- a/go/enclave/rollupchain/rollup_chain.go +++ b/go/enclave/rollupchain/rollup_chain.go @@ -253,7 +253,10 @@ func (rc *RollupChain) updateState(b *types.Block) *obscurocore.BlockState { for _, receipt := range receipts { logs = append(logs, receipt.Logs...) } - rc.storage.StoreNewHead(blockState, head, receipts, logs) + err := rc.storage.StoreNewHead(blockState, head, receipts, logs) + if err != nil { + rc.logger.Crit("Could not store new head.", log.ErrKey, err) + } return blockState } @@ -274,8 +277,12 @@ func (rc *RollupChain) handleGenesisRollup(b *types.Block, rollups []*obscurocor HeadRollup: genesis.Hash(), FoundNewRollup: true, } - rc.storage.StoreNewHead(&bs, genesis, nil, []*types.Log{}) - err := rc.faucet.CalculateGenesisState(rc.storage) + err := rc.storage.StoreNewHead(&bs, genesis, nil, []*types.Log{}) + if err != nil { + return nil, false + } + + err = rc.faucet.CalculateGenesisState(rc.storage) if err != nil { return nil, false } @@ -427,7 +434,11 @@ func (rc *RollupChain) calculateBlockState(b *types.Block, parentState *obscuroc // verifies that the headers of the rollup match the results of executing the transactions func (rc *RollupChain) checkRollup(r *obscurocore.Rollup) ([]*types.Receipt, []*types.Receipt, error) { //nolint - stateDB := rc.storage.CreateStateDB(r.Header.ParentHash) + stateDB, err := rc.storage.CreateStateDB(r.Header.ParentHash) + if err != nil { + return nil, nil, fmt.Errorf("could not create stateDB. Cause: %w", err) + } + // calculate the state to compare with what is in the Rollup rootHash, successfulTxs, txReceipts, depositReceipts := rc.processState(r, r.Transactions, stateDB) if len(successfulTxs) != len(r.Transactions) { @@ -582,7 +593,11 @@ func (rc *RollupChain) produceRollup(b *types.Block, bs *obscurocore.BlockState) } newRollupTxs = rc.mempool.CurrentTxs(headRollup, rc.storage) - newRollupState = rc.storage.CreateStateDB(r.Header.ParentHash) + newRollupState, err = rc.storage.CreateStateDB(r.Header.ParentHash) + if err != nil { + rc.logger.Crit("could not create stateDB", log.ErrKey, err) + return nil + } rootHash, successfulTxs, txReceipts, depositReceipts := rc.processState(r, newRollupTxs, newRollupState) @@ -709,7 +724,7 @@ func (rc *RollupChain) GetBalance(encryptedParams common.EncryptedParamsGetBalan if err != nil { return nil, fmt.Errorf("failed to retrieve tx that created contract %s. Cause %w", accountAddress.Hex(), err) } - transaction, _, _, _, err := rc.storage.GetTransaction(txHash) + transaction, _, _, _, err := rc.storage.GetTransaction(*txHash) if err != nil { return nil, fmt.Errorf("failed to retrieve tx that created contract %s. Cause %w", accountAddress.Hex(), err) } @@ -739,10 +754,11 @@ func (rc *RollupChain) GetChainStateAtBlock(blockNumber gethrpc.BlockNumber) (*s } // We get that of the chain at that height - blockchainState := rc.storage.CreateStateDB(rollup.Hash()) + blockchainState, err := rc.storage.CreateStateDB(rollup.Hash()) if err != nil { - return nil, err + return nil, fmt.Errorf("could not create stateDB. Cause: %w", err) } + if blockchainState == nil { return nil, fmt.Errorf("unable to fetch chain state for rollup %s", rollup.Hash().Hex()) } @@ -777,9 +793,9 @@ func (rc *RollupChain) ExecuteOffChainTransactionAtBlock(apiArgs *gethapi.Transa return nil, fmt.Errorf("unable to convert TransactionArgs to Message - %w", err) } - hs := rc.storage.FetchHeadState() - if hs == nil { - return nil, fmt.Errorf("unable to fetch head state") + hs, err := rc.storage.FetchHeadState() + if err != nil { + return nil, fmt.Errorf("unable to fetch head state. Cause: %w", err) } // todo - get the parent r, f := rc.storage.FetchRollup(hs.HeadRollup) @@ -788,7 +804,11 @@ func (rc *RollupChain) ExecuteOffChainTransactionAtBlock(apiArgs *gethapi.Transa } rc.logger.Trace(fmt.Sprintf("!OffChain call: contractAddress=%s, from=%s, data=%s, rollup=r_%d, state=%s", callMsg.To(), callMsg.From(), hexutils.BytesToHex(callMsg.Data()), common.ShortHash(r.Hash()), r.Header.Root.Hex())) - s := rc.storage.CreateStateDB(hs.HeadRollup) + s, err := rc.storage.CreateStateDB(hs.HeadRollup) + if err != nil { + return nil, fmt.Errorf("could not create stateDB. Cause: %w", err) + } + result, err := evm.ExecuteOffChainCall(&callMsg, s, r.Header, rc.storage, rc.chainConfig, rc.logger) if err != nil { // also return the result as the result can be evaluated on some errors like ErrIntrinsicGas @@ -825,7 +845,13 @@ func (rc *RollupChain) verifySig(r *obscurocore.Rollup) bool { rc.logger.Error("Missing signature on rollup") return false } - pubKey := rc.storage.FetchAttestedKey(r.Header.Agg) + + pubKey, err := rc.storage.FetchAttestedKey(r.Header.Agg) + if err != nil { + rc.logger.Error("Could not retrieve attested key for aggregator %s. Cause: %w", r.Header.Agg, err) + return false + } + return ecdsa.Verify(pubKey, h[:], r.Header.R, r.Header.S) } @@ -843,9 +869,12 @@ func (rc *RollupChain) getRollup(height gethrpc.BlockNumber) (*obscurocore.Rollu // TODO - Depends on the current pending rollup; leaving it for a different iteration as it will need more thought. return nil, fmt.Errorf("requested balance for pending block. This is not handled currently") case gethrpc.LatestBlockNumber: - rollupHash := rc.storage.FetchHeadState().HeadRollup + headState, err := rc.storage.FetchHeadState() + if err != nil { + return nil, fmt.Errorf("could not retrieve head state. Cause: %w", err) + } var found bool - rollup, found = rc.storage.FetchRollup(rollupHash) + rollup, found = rc.storage.FetchRollup(headState.HeadRollup) if !found { return nil, fmt.Errorf("rollup with requested height %d was not found", height) }