From 27eeffe2feba0d7335dfbde888b9febe9efecaf4 Mon Sep 17 00:00:00 2001 From: Tudor Malene Date: Fri, 13 Dec 2024 11:58:53 +0200 Subject: [PATCH] caching for event topics and contract address --- go/enclave/storage/cache_service.go | 11 +++++++++++ go/enclave/storage/enclavedb/events.go | 6 +++--- go/enclave/storage/enclavedb/interfaces.go | 6 ++++++ go/enclave/storage/events_storage.go | 23 +++++++++++++++++++--- go/enclave/storage/storage.go | 9 ++------- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/go/enclave/storage/cache_service.go b/go/enclave/storage/cache_service.go index 6bfc24048f..f669bd8a93 100644 --- a/go/enclave/storage/cache_service.go +++ b/go/enclave/storage/cache_service.go @@ -2,6 +2,7 @@ package storage import ( "context" + "encoding/binary" "fmt" "math/big" @@ -34,6 +35,7 @@ const ( receiptCost = 1024 * 50 contractCost = 60 eventTypeCost = 120 + eventTopicCost = 16 enclaveCost = 100 ) @@ -61,6 +63,7 @@ type CacheService struct { // from address ( either eoa or contract) to the id of the db entry eoaCache *cache.Cache[*uint64] contractAddressCache *cache.Cache[*enclavedb.Contract] + eventTopicCache *cache.Cache[*enclavedb.EventTopic] // from contract_address||event_sig to the event_type object eventTypeCache *cache.Cache[*enclavedb.EventType] @@ -110,6 +113,7 @@ func NewCacheService(logger gethlog.Logger, testMode bool) *CacheService { eoaCache: cache.New[*uint64](newCache(logger, nrEOA, idCost)), contractAddressCache: cache.New[*enclavedb.Contract](newCache(logger, nrContractAddresses, contractCost)), eventTypeCache: cache.New[*enclavedb.EventType](newCache(logger, nrEventTypes, eventTypeCost)), + eventTopicCache: cache.New[*enclavedb.EventTopic](newCache(logger, nrEventTypes, eventTopicCost)), receiptCache: cache.New[*CachedReceipt](newCache(logger, nrReceipts, receiptCost)), attestedEnclavesCache: cache.New[*AttestedEnclave](newCache(logger, nrEnclaves, enclaveCost)), @@ -189,6 +193,13 @@ func (cs *CacheService) ReadContractAddr(ctx context.Context, addr gethcommon.Ad return getCachedValue(ctx, cs.contractAddressCache, cs.logger, addr, contractCost, onCacheMiss, true) } +func (cs *CacheService) ReadEventTopic(ctx context.Context, topic []byte, eventTypeId uint64, onCacheMiss func(any) (*enclavedb.EventTopic, error)) (*enclavedb.EventTopic, error) { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, eventTypeId) + key := append(topic, b...) + return getCachedValue(ctx, cs.eventTopicCache, cs.logger, key, eventTopicCost, onCacheMiss, true) +} + type CachedReceipt struct { Receipt *types.Receipt From *gethcommon.Address diff --git a/go/enclave/storage/enclavedb/events.go b/go/enclave/storage/enclavedb/events.go index fde0c96778..29ba9e1064 100644 --- a/go/enclave/storage/enclavedb/events.go +++ b/go/enclave/storage/enclavedb/events.go @@ -80,16 +80,16 @@ func UpdateEventTypeAutoPublic(ctx context.Context, dbTx *sql.Tx, etId uint64, i return err } -func ReadEventTopic(ctx context.Context, dbTX *sql.Tx, topic []byte, eventTypeId uint64) (uint64, *uint64, error) { +func ReadEventTopic(ctx context.Context, dbTX *sql.Tx, topic []byte, eventTypeId uint64) (*EventTopic, error) { var id uint64 var address *uint64 err := dbTX.QueryRowContext(ctx, "select id, rel_address from event_topic where topic=? and event_type=?", topic, eventTypeId).Scan(&id, &address) if errors.Is(err, sql.ErrNoRows) { // make sure the error is converted to obscuro-wide not found error - return 0, nil, errutil.ErrNotFound + return nil, errutil.ErrNotFound } - return id, address, err + return &EventTopic{Id: id, RelevantAddressId: address}, err } func ReadRelevantAddressFromEventTopic(ctx context.Context, dbTX *sql.Tx, id uint64) (*uint64, error) { diff --git a/go/enclave/storage/enclavedb/interfaces.go b/go/enclave/storage/enclavedb/interfaces.go index 8f5dcc7dbb..9081c9f7d7 100644 --- a/go/enclave/storage/enclavedb/interfaces.go +++ b/go/enclave/storage/enclavedb/interfaces.go @@ -61,3 +61,9 @@ func (et EventType) IsTopicRelevant(topicNo int) bool { // this should not happen under any circumstance panic(fmt.Sprintf("unknown topic no: %d", topicNo)) } + +// EventTopic - maps to the "event_topic" table +type EventTopic struct { + Id uint64 + RelevantAddressId *uint64 +} diff --git a/go/enclave/storage/events_storage.go b/go/enclave/storage/events_storage.go index b74b45cfea..484bd296a1 100644 --- a/go/enclave/storage/events_storage.go +++ b/go/enclave/storage/events_storage.go @@ -198,8 +198,9 @@ func (es *eventsStorage) storeTopics(ctx context.Context, dbTX *sql.Tx, eventTyp // if not, discover if there is a relevant externally owned address for i := 1; i < len(l.Topics); i++ { topic := l.Topics[i] + var topicId uint64 // first check if there is an entry already for this topic - topicId, _, err := es.findTopic(ctx, dbTX, topic.Bytes(), eventType.Id) + eventTopic, err := es.findTopic(ctx, dbTX, topic.Bytes(), eventType.Id) if err != nil && !errors.Is(err, errutil.ErrNotFound) { return nil, fmt.Errorf("could not read the event topic. Cause: %w", err) } @@ -209,6 +210,8 @@ func (es *eventsStorage) storeTopics(ctx context.Context, dbTX *sql.Tx, eventTyp if err != nil { return nil, fmt.Errorf("could not store the event topic. Cause: %w", err) } + } else { + topicId = eventTopic.Id } topicIds[i-1] = &topicId } @@ -321,9 +324,23 @@ func (es *eventsStorage) readContract(ctx context.Context, dbTX *sql.Tx, addr ge }) } -func (es *eventsStorage) findTopic(ctx context.Context, dbTX *sql.Tx, topic []byte, eventTypeId uint64) (uint64, *uint64, error) { +func (es *eventsStorage) ReadContract(ctx context.Context, addr gethcommon.Address) (*enclavedb.Contract, error) { + defer es.logDuration("readContract", measure.NewStopwatch()) + return es.cachingService.ReadContractAddr(ctx, addr, func(v any) (*enclavedb.Contract, error) { + dbtx, err := es.db.GetSQLDB().BeginTx(ctx, nil) + if err != nil { + return nil, err + } + defer dbtx.Rollback() + return enclavedb.ReadContractByAddress(ctx, dbtx, addr) + }) +} + +func (es *eventsStorage) findTopic(ctx context.Context, dbTX *sql.Tx, topic []byte, eventTypeId uint64) (*enclavedb.EventTopic, error) { defer es.logDuration("findTopic", measure.NewStopwatch()) - return enclavedb.ReadEventTopic(ctx, dbTX, topic, eventTypeId) + return es.cachingService.ReadEventTopic(ctx, topic, eventTypeId, func(v any) (*enclavedb.EventTopic, error) { + return enclavedb.ReadEventTopic(ctx, dbTX, topic, eventTypeId) + }) } func (es *eventsStorage) readEOA(ctx context.Context, dbTX *sql.Tx, addr gethcommon.Address) (*uint64, error) { diff --git a/go/enclave/storage/storage.go b/go/enclave/storage/storage.go index 03e89b40d5..5849eb599b 100644 --- a/go/enclave/storage/storage.go +++ b/go/enclave/storage/storage.go @@ -621,7 +621,7 @@ func (s *storageImpl) handleTxSendersAndReceivers(ctx context.Context, transacti to := tx.Tx.To() if to != nil { - ctr, err := s.ReadContract(ctx, *to) + ctr, err := s.eventsStorage.ReadContract(ctx, *to) if err != nil && !errors.Is(err, errutil.ErrNotFound) { return nil, nil, fmt.Errorf("could not read contract. cause: %w", err) } @@ -857,12 +857,7 @@ func (s *storageImpl) readOrWriteEOA(ctx context.Context, dbTX *sql.Tx, addr get } func (s *storageImpl) ReadContract(ctx context.Context, address gethcommon.Address) (*enclavedb.Contract, error) { - dbtx, err := s.db.GetSQLDB().BeginTx(ctx, nil) - if err != nil { - return nil, err - } - defer dbtx.Rollback() - return enclavedb.ReadContractByAddress(ctx, dbtx, address) + return s.eventsStorage.ReadContract(ctx, address) } func (s *storageImpl) ReadEventType(ctx context.Context, contractAddress gethcommon.Address, eventSignature gethcommon.Hash) (*enclavedb.EventType, error) {