From b5fb988f80a7a6aaaf24ac9f8c33ee5c4f803fed Mon Sep 17 00:00:00 2001 From: Tudor Malene Date: Mon, 16 Sep 2024 13:13:04 +0100 Subject: [PATCH 1/6] event visibility config part 2 --- go/enclave/storage/enclavedb/events.go | 55 ++++++-- go/enclave/storage/enclavedb/interfaces.go | 28 +++- go/enclave/storage/events_storage.go | 157 ++++++++++++--------- 3 files changed, 159 insertions(+), 81 deletions(-) diff --git a/go/enclave/storage/enclavedb/events.go b/go/enclave/storage/enclavedb/events.go index 14ca92972b..3a5aac5cfd 100644 --- a/go/enclave/storage/enclavedb/events.go +++ b/go/enclave/storage/enclavedb/events.go @@ -36,7 +36,7 @@ const ( func WriteEventType(ctx context.Context, dbTX *sql.Tx, et *EventType) (uint64, error) { res, err := dbTX.ExecContext(ctx, "insert into event_type (contract, event_sig, auto_visibility, public, topic1_can_view, topic2_can_view, topic3_can_view, sender_can_view) values (?, ?, ?, ?, ?, ?, ?, ?)", - et.ContractId, et.EventSignature.Bytes(), et.AutoVisibility, et.Public, et.Topic1CanView, et.Topic2CanView, et.Topic3CanView, et.SenderCanView) + et.Contract.Id, et.EventSignature.Bytes(), et.AutoVisibility, et.Public, et.Topic1CanView, et.Topic2CanView, et.Topic3CanView, et.SenderCanView) if err != nil { return 0, err } @@ -47,10 +47,12 @@ func WriteEventType(ctx context.Context, dbTX *sql.Tx, et *EventType) (uint64, e return uint64(id), nil } -func ReadEventType(ctx context.Context, dbTX *sql.Tx, contractId uint64, eventSignature gethcommon.Hash) (*EventType, error) { - var et EventType - err := dbTX.QueryRowContext(ctx, "select id, contract, event_sig, auto_visibility, public, topic1_can_view, topic2_can_view, topic3_can_view, sender_can_view from event_type where contract=? and event_sig=?", - contractId, eventSignature.Bytes()).Scan(&et.Id, &et.ContractId, &et.EventSignature, &et.AutoVisibility, &et.Public, &et.Topic1CanView, &et.Topic2CanView, &et.Topic3CanView, &et.SenderCanView) +func ReadEventType(ctx context.Context, dbTX *sql.Tx, contract *Contract, eventSignature gethcommon.Hash) (*EventType, error) { + var et EventType = EventType{Contract: contract} + err := dbTX.QueryRowContext(ctx, + "select id, event_sig, auto_visibility, public, topic1_can_view, topic2_can_view, topic3_can_view, sender_can_view from event_type where contract=? and event_sig=?", + contract.Id, eventSignature.Bytes(), + ).Scan(&et.Id, &et.EventSignature, &et.AutoVisibility, &et.Public, &et.Topic1CanView, &et.Topic2CanView, &et.Topic3CanView, &et.SenderCanView) if errors.Is(err, sql.ErrNoRows) { // make sure the error is converted to obscuro-wide not found error return nil, errutil.ErrNotFound @@ -229,13 +231,11 @@ func loadLogs(ctx context.Context, db *sql.DB, requestingAccount *gethcommon.Add query := "select et.event_sig, t1.topic, t2.topic, t3.topic, datablob, b.hash, b.height, tx.hash, tx.idx, log_idx, c.address" + " " + baseEventsJoin var queryParams []any - // Add relevancy rules - // An event is considered relevant to all account owners whose addresses are used as topics in the event. - // In case there are no account addresses in an event's topics, then the event is considered relevant to everyone (known as a "lifecycle event"). - query += " AND (et.public=true OR eoa1.address=? OR eoa2.address=? OR eoa3.address=?) " - queryParams = append(queryParams, requestingAccount.Bytes()) - queryParams = append(queryParams, requestingAccount.Bytes()) - queryParams = append(queryParams, requestingAccount.Bytes()) + // Add visibility rules + visibQuery, visibParams := visibilityQuery(requestingAccount) + + query += visibQuery + queryParams = append(queryParams, visibParams...) query += whereCondition queryParams = append(queryParams, whereParams...) @@ -272,6 +272,37 @@ func loadLogs(ctx context.Context, db *sql.DB, requestingAccount *gethcommon.Add return result, nil } +func visibilityQuery(requestingAccount *gethcommon.Address) (string, []any) { + acc := requestingAccount.Bytes() + + visibQuery := "AND (" + visibParams := make([]any, 0) + + visibQuery += " et.public=true " + + // For auto configs, an event is considered relevant to all account owners whose addresses are used as topics in the event. + visibQuery += " OR (et.auto_visibility=true AND (eoa1.address=? OR eoa2.address=? OR eoa3.address=?))" + visibParams = append(visibParams, acc) + visibParams = append(visibParams, acc) + visibParams = append(visibParams, acc) + + // Configured events + visibQuery += " OR (" + + "et.auto_visibility=false AND et.public=false AND " + + " (" + + " (et.topic1_can_view AND eoa1.address=?) " + + " OR (et.topic2_can_view AND eoa2.address=?) " + + " OR (et.topic3_can_view AND eoa3.address=?)" + + " )" + + ")" + visibParams = append(visibParams, acc) + visibParams = append(visibParams, acc) + visibParams = append(visibParams, acc) + + visibQuery += ") " + return visibQuery, visibParams +} + func WriteEoa(ctx context.Context, dbTX *sql.Tx, sender gethcommon.Address) (uint64, error) { insert := "insert into externally_owned_account (address) values (?)" res, err := dbTX.ExecContext(ctx, insert, sender.Bytes()) diff --git a/go/enclave/storage/enclavedb/interfaces.go b/go/enclave/storage/enclavedb/interfaces.go index 1c252a2aa7..7fa7246dc4 100644 --- a/go/enclave/storage/enclavedb/interfaces.go +++ b/go/enclave/storage/enclavedb/interfaces.go @@ -3,6 +3,7 @@ package enclavedb import ( "context" "database/sql" + "fmt" gethcommon "github.com/ethereum/go-ethereum/common" @@ -27,13 +28,38 @@ type Contract struct { Transparent *bool } +func (contract Contract) IsTransparent() bool { + return contract.Transparent != nil && *contract.Transparent +} + // EventType - maps to the “event_type“ table type EventType struct { Id uint64 - ContractId uint64 + Contract *Contract EventSignature gethcommon.Hash AutoVisibility bool Public bool Topic1CanView, Topic2CanView, Topic3CanView *bool SenderCanView *bool } + +func (et EventType) Auto() bool { + return et.Contract.AutoVisibility && et.AutoVisibility +} + +func (et EventType) IsPublic() bool { + return (et.Contract.Transparent != nil && *et.Contract.Transparent) || et.Public +} + +func (et EventType) IsTopicRelevant(topicNo int) bool { + switch topicNo { + case 1: + return et.Topic1CanView != nil && *et.Topic1CanView + case 2: + return et.Topic2CanView != nil && *et.Topic2CanView + case 3: + return et.Topic3CanView != nil && *et.Topic3CanView + } + // this should not happen under any circumstance + panic(fmt.Sprintf("unknown topic no: %d", topicNo)) +} diff --git a/go/enclave/storage/events_storage.go b/go/enclave/storage/events_storage.go index d572b4f455..fff0a10e26 100644 --- a/go/enclave/storage/events_storage.go +++ b/go/enclave/storage/events_storage.go @@ -35,7 +35,12 @@ func (es *eventsStorage) storeReceiptAndEventLogs(ctx context.Context, dbTX *sql // store the contracts created by this tx for createdContract, cfg := range txExecResult.CreatedContracts { - ctrId, err := es.storeNewContract(ctx, dbTX, createdContract, senderId, cfg) + _, err := es.storeNewContract(ctx, dbTX, createdContract, senderId, cfg) + if err != nil { + return err + } + + c, err := es.readContract(ctx, dbTX, createdContract) if err != nil { return err } @@ -43,7 +48,7 @@ func (es *eventsStorage) storeReceiptAndEventLogs(ctx context.Context, dbTX *sql // create the event types for the events that were configured for eventSig, eventCfg := range cfg.EventConfigs { _, err = enclavedb.WriteEventType(ctx, dbTX, &enclavedb.EventType{ - ContractId: *ctrId, + Contract: c, EventSignature: eventSig, AutoVisibility: eventCfg.AutoConfig, Public: eventCfg.Public, @@ -110,7 +115,7 @@ func (es *eventsStorage) storeEventLog(ctx context.Context, dbTX *sql.Tx, execTx eventType, err := es.readEventType(ctx, dbTX, l.Address, eventSig) if errors.Is(err, errutil.ErrNotFound) { // this is the first type an event of this type is emitted, so we must store it - eventType, err = es.storeEventType(ctx, dbTX, contract, l) + eventType, err = es.storeAutoConfigEventType(ctx, dbTX, contract, l) if err != nil { return fmt.Errorf("could not write event type. cause %w", err) } @@ -119,7 +124,7 @@ func (es *eventsStorage) storeEventLog(ctx context.Context, dbTX *sql.Tx, execTx return fmt.Errorf("could not read event type. Cause: %w", err) } - topicIds, err := es.storeTopics(ctx, dbTX, l) + topicIds, err := es.storeTopics(ctx, dbTX, eventType, l) if err != nil { return fmt.Errorf("could not store topics. cause: %w", err) } @@ -138,27 +143,18 @@ func (es *eventsStorage) storeEventLog(ctx context.Context, dbTX *sql.Tx, execTx } // handles the visibility config detection -func (es *eventsStorage) storeEventType(ctx context.Context, dbTX *sql.Tx, contract *enclavedb.Contract, l *types.Log) (*enclavedb.EventType, error) { - eventType := enclavedb.EventType{ContractId: contract.Id, EventSignature: l.Topics[0], AutoVisibility: contract.AutoVisibility} +func (es *eventsStorage) storeAutoConfigEventType(ctx context.Context, dbTX *sql.Tx, contract *enclavedb.Contract, l *types.Log) (*enclavedb.EventType, error) { + eventType := enclavedb.EventType{ + Contract: contract, + EventSignature: l.Topics[0], + Public: contract.IsTransparent(), + } - // when the contract is transparent, all events are public - switch { - case contract.Transparent != nil && *contract.Transparent: - eventType.Public = true - case contract.AutoVisibility: - // autodetect based on the topics - isPublic, t1, t2, t3, err := es.autodetectVisibility(ctx, dbTX, l) - if err != nil { - return nil, fmt.Errorf("could not auto detect visibility for event type. cause: %w", err) - } - eventType.Public = *isPublic - eventType.Topic1CanView = t1 - eventType.Topic2CanView = t2 - eventType.Topic3CanView = t3 - default: - // todo - return nil, fmt.Errorf("not implemented") + // event types that are not public - will have the default rules + if !eventType.Public { + eventType.AutoVisibility = true } + id, err := enclavedb.WriteEventType(ctx, dbTX, &eventType) if err != nil { return nil, fmt.Errorf("could not write event type. cause: %w", err) @@ -167,75 +163,108 @@ func (es *eventsStorage) storeEventType(ctx context.Context, dbTX *sql.Tx, contr return &eventType, nil } -func (es *eventsStorage) autodetectVisibility(ctx context.Context, dbTX *sql.Tx, l *types.Log) (*bool, *bool, *bool, *bool, error) { - isPublic := true - topicsCanView := make([]bool, 3) +func (es *eventsStorage) storeTopics(ctx context.Context, dbTX *sql.Tx, eventType *enclavedb.EventType, l *types.Log) ([]*uint64, error) { + topicIds := make([]*uint64, 3) + // iterate the topics containing user values + // reuse them if already inserted + // if not, discover if there is a relevant externally owned address for i := 1; i < len(l.Topics); i++ { topic := l.Topics[i] // first check if there is an entry already for this topic - _, relAddressId, err := es.findEventTopic(ctx, dbTX, topic.Bytes()) + eventTopicId, _, err := es.findEventTopic(ctx, dbTX, topic.Bytes()) if err != nil && !errors.Is(err, errutil.ErrNotFound) { - return nil, nil, nil, nil, fmt.Errorf("could not read the event topic. Cause: %w", err) + return nil, fmt.Errorf("could not read the event topic. Cause: %w", err) } if errors.Is(err, errutil.ErrNotFound) { - // check whether the topic is an EOA - relAddressId, err = es.findRelevantAddress(ctx, dbTX, topic) - if err != nil && !errors.Is(err, errutil.ErrNotFound) { - return nil, nil, nil, nil, fmt.Errorf("could not read relevant address. Cause %w", err) + // if no entry was found + eventTopicId, err = es.storeEventTopic(ctx, dbTX, eventType, i, topic) + if err != nil { + return nil, fmt.Errorf("could not read the event topic. Cause: %w", err) } } - if relAddressId != nil { - isPublic = false - topicsCanView[i-1] = true + topicIds[i-1] = &eventTopicId + } + return topicIds, nil +} + +// this function contains visibility logic +func (es *eventsStorage) storeEventTopic(ctx context.Context, dbTX *sql.Tx, eventType *enclavedb.EventType, i int, topic gethcommon.Hash) (uint64, error) { + relevantAddress, err := es.visibililty(ctx, dbTX, eventType, i, topic) + if err != nil && !errors.Is(err, errutil.ErrNotFound) { + return 0, fmt.Errorf("could not determine visibility rules. cause: %w", err) + } + + var relAddressId *uint64 + if relevantAddress != nil { + var err error + relAddressId, err = es.readEOA(ctx, dbTX, *relevantAddress) + if err != nil { + return 0, err } } - return &isPublic, &topicsCanView[0], &topicsCanView[1], &topicsCanView[2], nil + eventTopicId, err := enclavedb.WriteEventTopic(ctx, dbTX, &topic, relAddressId) + if err != nil { + return 0, fmt.Errorf("could not write event topic. Cause: %w", err) + } + return eventTopicId, nil } -func (es *eventsStorage) storeTopics(ctx context.Context, dbTX *sql.Tx, l *types.Log) ([]*uint64, error) { - topicIds := make([]*uint64, 3) - // iterate the topics containing user values - // reuse them if already inserted - // if not, discover if there is a relevant externally owned address - for i := 1; i < len(l.Topics); i++ { - topic := l.Topics[i] - // first check if there is an entry already for this topic - eventTopicId, _, err := es.findEventTopic(ctx, dbTX, topic.Bytes()) +func (es *eventsStorage) visibililty(ctx context.Context, dbTX *sql.Tx, eventType *enclavedb.EventType, i int, topic gethcommon.Hash) (*gethcommon.Address, error) { + var relevantAddress *gethcommon.Address + switch { + case eventType.AutoVisibility: + var err error + // if there is no configuration, we have to autodetect the address + relevantAddress, err = es.autoDetectRelevantAddress(ctx, dbTX, topic) + if err != nil { + return nil, err + } + + // when autodetecting, we assume that any address that is not a contract is an EOA + _, err = es.readEOA(ctx, dbTX, *relevantAddress) if err != nil && !errors.Is(err, errutil.ErrNotFound) { - return nil, fmt.Errorf("could not read the event topic. Cause: %w", err) + return nil, err } if errors.Is(err, errutil.ErrNotFound) { - // check whether the topic is an EOA - relAddressId, err := es.findRelevantAddress(ctx, dbTX, topic) - if err != nil && !errors.Is(err, errutil.ErrNotFound) { - return nil, fmt.Errorf("could not read relevant address. Cause %w", err) - } - eventTopicId, err = enclavedb.WriteEventTopic(ctx, dbTX, &topic, relAddressId) + _, err := enclavedb.WriteEoa(ctx, dbTX, *relevantAddress) if err != nil { - return nil, fmt.Errorf("could not write event topic. Cause: %w", err) + return nil, err } } - topicIds[i-1] = &eventTopicId + + case eventType.IsPublic(): + // for public events, there is no relevant address + relevantAddress = nil + + case eventType.IsTopicRelevant(i): + relevantAddress = common.ExtractPotentialAddress(topic) + if relevantAddress == nil { + return nil, fmt.Errorf("invalid configuration. expected address in topic %d : %s", i, topic.String()) + } + + default: + es.logger.Crit("impossible case. Should not get here") } - return topicIds, nil + + return relevantAddress, nil } // Of the log's topics, returns those that are (potentially) user addresses. A topic is considered a user address if: // - It has at least 12 leading zero bytes (since addresses are 20 bytes long, while hashes are 32) and at most 22 leading zero bytes // - It is not a smart contract address -func (es *eventsStorage) findRelevantAddress(ctx context.Context, dbTX *sql.Tx, topic gethcommon.Hash) (*uint64, error) { +func (es *eventsStorage) autoDetectRelevantAddress(ctx context.Context, dbTX *sql.Tx, topic gethcommon.Hash) (*gethcommon.Address, error) { potentialAddr := common.ExtractPotentialAddress(topic) if potentialAddr == nil { return nil, errutil.ErrNotFound } // first check whether there is already an entry in the EOA table - eoaID, err := es.readEOA(ctx, dbTX, *potentialAddr) + _, err := es.readEOA(ctx, dbTX, *potentialAddr) if err != nil && !errors.Is(err, errutil.ErrNotFound) { return nil, err } if err == nil { - return eoaID, nil + return potentialAddr, nil } // if the address is a contract then it's clearly not an EOA @@ -247,15 +276,7 @@ func (es *eventsStorage) findRelevantAddress(ctx context.Context, dbTX *sql.Tx, return nil, errutil.ErrNotFound } - // when we reach this point, the value looks like an address, but we haven't yet seen it - // for the first iteration, we'll just assume it's an EOA - // we can make this smarter by passing in more information about the event - id, err := enclavedb.WriteEoa(ctx, dbTX, *potentialAddr) - if err != nil { - return nil, err - } - - return &id, nil + return potentialAddr, nil } func (es *eventsStorage) readEventType(ctx context.Context, dbTX *sql.Tx, contractAddress gethcommon.Address, eventSignature gethcommon.Hash) (*enclavedb.EventType, error) { @@ -266,7 +287,7 @@ func (es *eventsStorage) readEventType(ctx context.Context, dbTX *sql.Tx, contra if err != nil { return nil, err } - return enclavedb.ReadEventType(ctx, dbTX, contract.Id, eventSignature) + return enclavedb.ReadEventType(ctx, dbTX, contract, eventSignature) }) } From 70992436ce71d060aadc09f8ff322fc135405925 Mon Sep 17 00:00:00 2001 From: Tudor Malene Date: Tue, 17 Sep 2024 10:56:02 +0100 Subject: [PATCH 2/6] add event_type column and comments --- go/enclave/core/event_types.go | 7 ++++++- go/enclave/storage/enclavedb/events.go | 15 ++++++++------- go/enclave/storage/enclavedb/interfaces.go | 4 ---- go/enclave/storage/events_storage.go | 16 +++++++++------- go/enclave/storage/init/edgelessdb/001_init.sql | 1 + go/enclave/storage/init/sqlite/001_init.sql | 2 ++ 6 files changed, 26 insertions(+), 19 deletions(-) diff --git a/go/enclave/core/event_types.go b/go/enclave/core/event_types.go index 2916ca6588..319bfbd02a 100644 --- a/go/enclave/core/event_types.go +++ b/go/enclave/core/event_types.go @@ -5,7 +5,12 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) -// EventVisibilityConfig - configuration per event by the dApp developer +// EventVisibilityConfig - configuration per event by the dApp developer(DD) +// There are 4 cases: +// 1. DD doesn't configure anything. - ContractVisibilityConfig.AutoConfig=true +// 2. DD configures and specifies the contract as transparent - ContractVisibilityConfig.Transparent=true +// 3. DD configures and specify the contract as non-transparent, but doesn't configure the event - Contract: false/false , EventVisibilityConfig.AutoConfig=true +// DD configures the contract as non-transparent, and also configures the topics for the event type EventVisibilityConfig struct { AutoConfig bool // true for events that have no explicit configuration Public bool // everyone can see and query for this event diff --git a/go/enclave/storage/enclavedb/events.go b/go/enclave/storage/enclavedb/events.go index 3a5aac5cfd..a3a8beae0a 100644 --- a/go/enclave/storage/enclavedb/events.go +++ b/go/enclave/storage/enclavedb/events.go @@ -25,11 +25,11 @@ const ( " join batch b on rec.batch=b.sequence " + "join event_type et on e.event_type=et.id " + " join contract c on et.contract=c.id " + - "left join event_topic t1 on e.topic1=t1.id " + + "left join event_topic t1 on e.topic1=t1.id and et.id=t1.event_type " + " left join externally_owned_account eoa1 on t1.rel_address=eoa1.id " + - "left join event_topic t2 on e.topic2=t2.id " + + "left join event_topic t2 on e.topic2=t2.id and et.id=t2.event_type " + " left join externally_owned_account eoa2 on t2.rel_address=eoa2.id " + - "left join event_topic t3 on e.topic3=t3.id" + + "left join event_topic t3 on e.topic3=t3.id and et.id=t1.event_type " + " left join externally_owned_account eoa3 on t3.rel_address=eoa3.id " + "where b.is_canonical=true " ) @@ -60,8 +60,8 @@ func ReadEventType(ctx context.Context, dbTX *sql.Tx, contract *Contract, eventS return &et, err } -func WriteEventTopic(ctx context.Context, dbTX *sql.Tx, topic *gethcommon.Hash, addressId *uint64) (uint64, error) { - res, err := dbTX.ExecContext(ctx, "insert into event_topic (topic, rel_address) values (?, ?)", topic.Bytes(), addressId) +func WriteEventTopic(ctx context.Context, dbTX *sql.Tx, topic *gethcommon.Hash, addressId *uint64, eventTypeId uint64) (uint64, error) { + res, err := dbTX.ExecContext(ctx, "insert into event_topic (event_type, topic, rel_address) values (?, ?, ?)", eventTypeId, topic.Bytes(), addressId) if err != nil { return 0, err } @@ -77,10 +77,11 @@ func UpdateEventTypeLifecycle(ctx context.Context, dbTx *sql.Tx, etId uint64, is return err } -func ReadEventTopic(ctx context.Context, dbTX *sql.Tx, topic []byte) (uint64, *uint64, error) { +func ReadEventTopic(ctx context.Context, dbTX *sql.Tx, topic []byte, eventTypeId uint64) (uint64, *uint64, error) { var id uint64 var address *uint64 - err := dbTX.QueryRowContext(ctx, "select id, rel_address from event_topic where topic=? ", topic).Scan(&id, &address) + 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 diff --git a/go/enclave/storage/enclavedb/interfaces.go b/go/enclave/storage/enclavedb/interfaces.go index 7fa7246dc4..9c21426737 100644 --- a/go/enclave/storage/enclavedb/interfaces.go +++ b/go/enclave/storage/enclavedb/interfaces.go @@ -43,10 +43,6 @@ type EventType struct { SenderCanView *bool } -func (et EventType) Auto() bool { - return et.Contract.AutoVisibility && et.AutoVisibility -} - func (et EventType) IsPublic() bool { return (et.Contract.Transparent != nil && *et.Contract.Transparent) || et.Public } diff --git a/go/enclave/storage/events_storage.go b/go/enclave/storage/events_storage.go index fff0a10e26..015af17792 100644 --- a/go/enclave/storage/events_storage.go +++ b/go/enclave/storage/events_storage.go @@ -142,7 +142,8 @@ func (es *eventsStorage) storeEventLog(ctx context.Context, dbTX *sql.Tx, execTx return nil } -// handles the visibility config detection +// stores an event type the first time it is emitted +// since it wasn't saved on contract deployment, it means that there is no explicit configuration for it func (es *eventsStorage) storeAutoConfigEventType(ctx context.Context, dbTX *sql.Tx, contract *enclavedb.Contract, l *types.Log) (*enclavedb.EventType, error) { eventType := enclavedb.EventType{ Contract: contract, @@ -171,7 +172,7 @@ func (es *eventsStorage) storeTopics(ctx context.Context, dbTX *sql.Tx, eventTyp for i := 1; i < len(l.Topics); i++ { topic := l.Topics[i] // first check if there is an entry already for this topic - eventTopicId, _, err := es.findEventTopic(ctx, dbTX, topic.Bytes()) + eventTopicId, _, err := es.findEventTopic(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) } @@ -189,7 +190,7 @@ func (es *eventsStorage) storeTopics(ctx context.Context, dbTX *sql.Tx, eventTyp // this function contains visibility logic func (es *eventsStorage) storeEventTopic(ctx context.Context, dbTX *sql.Tx, eventType *enclavedb.EventType, i int, topic gethcommon.Hash) (uint64, error) { - relevantAddress, err := es.visibililty(ctx, dbTX, eventType, i, topic) + relevantAddress, err := es.determineRelevantAddressForTopic(ctx, dbTX, eventType, i, topic) if err != nil && !errors.Is(err, errutil.ErrNotFound) { return 0, fmt.Errorf("could not determine visibility rules. cause: %w", err) } @@ -202,14 +203,15 @@ func (es *eventsStorage) storeEventTopic(ctx context.Context, dbTX *sql.Tx, even return 0, err } } - eventTopicId, err := enclavedb.WriteEventTopic(ctx, dbTX, &topic, relAddressId) + eventTopicId, err := enclavedb.WriteEventTopic(ctx, dbTX, &topic, relAddressId, eventType.Id) if err != nil { return 0, fmt.Errorf("could not write event topic. Cause: %w", err) } return eventTopicId, nil } -func (es *eventsStorage) visibililty(ctx context.Context, dbTX *sql.Tx, eventType *enclavedb.EventType, i int, topic gethcommon.Hash) (*gethcommon.Address, error) { +// based on the eventType configuration, this function determines the address that can view events logs containing this topic +func (es *eventsStorage) determineRelevantAddressForTopic(ctx context.Context, dbTX *sql.Tx, eventType *enclavedb.EventType, i int, topic gethcommon.Hash) (*gethcommon.Address, error) { var relevantAddress *gethcommon.Address switch { case eventType.AutoVisibility: @@ -298,9 +300,9 @@ func (es *eventsStorage) readContract(ctx context.Context, dbTX *sql.Tx, addr ge }) } -func (es *eventsStorage) findEventTopic(ctx context.Context, dbTX *sql.Tx, topic []byte) (uint64, *uint64, error) { +func (es *eventsStorage) findEventTopic(ctx context.Context, dbTX *sql.Tx, topic []byte, eventTypeId uint64) (uint64, *uint64, error) { defer es.logDuration("findEventTopic", measure.NewStopwatch()) - return enclavedb.ReadEventTopic(ctx, dbTX, topic) + 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/init/edgelessdb/001_init.sql b/go/enclave/storage/init/edgelessdb/001_init.sql index 26b33d60fe..ab2fe00cda 100644 --- a/go/enclave/storage/init/edgelessdb/001_init.sql +++ b/go/enclave/storage/init/edgelessdb/001_init.sql @@ -144,6 +144,7 @@ create table if not exists tendb.event_type create table if not exists tendb.event_topic ( id INTEGER AUTO_INCREMENT, + event_type INTEGER, topic binary(32) NOT NULL, rel_address INTEGER, primary key (id), diff --git a/go/enclave/storage/init/sqlite/001_init.sql b/go/enclave/storage/init/sqlite/001_init.sql index 5e3c71701c..3325544e44 100644 --- a/go/enclave/storage/init/sqlite/001_init.sql +++ b/go/enclave/storage/init/sqlite/001_init.sql @@ -138,11 +138,13 @@ create index IDX_EV_CONTRACT on event_type (contract, event_sig); create table if not exists event_topic ( id INTEGER PRIMARY KEY AUTOINCREMENT, + event_type INTEGER references event_type, topic binary(32) NOT NULL, rel_address INTEGER references externally_owned_account -- pos INTEGER NOT NULL -- todo ); create index IDX_TOP on event_topic (topic); +create index IDX_REL_A on event_topic (rel_address); create table if not exists event_log ( From e6e58f4c5d778fbce63735e54f43601804835992 Mon Sep 17 00:00:00 2001 From: Tudor Malene Date: Tue, 17 Sep 2024 15:22:45 +0100 Subject: [PATCH 3/6] fixing autodetect visibility logic --- go/enclave/storage/enclavedb/events.go | 31 ++++-- go/enclave/storage/enclavedb/interfaces.go | 1 + go/enclave/storage/events_storage.go | 101 +++++++++++------- .../storage/init/edgelessdb/001_init.sql | 1 + go/enclave/storage/init/sqlite/001_init.sql | 7 +- 5 files changed, 89 insertions(+), 52 deletions(-) diff --git a/go/enclave/storage/enclavedb/events.go b/go/enclave/storage/enclavedb/events.go index a3a8beae0a..4d3e844b77 100644 --- a/go/enclave/storage/enclavedb/events.go +++ b/go/enclave/storage/enclavedb/events.go @@ -35,8 +35,8 @@ const ( ) func WriteEventType(ctx context.Context, dbTX *sql.Tx, et *EventType) (uint64, error) { - res, err := dbTX.ExecContext(ctx, "insert into event_type (contract, event_sig, auto_visibility, public, topic1_can_view, topic2_can_view, topic3_can_view, sender_can_view) values (?, ?, ?, ?, ?, ?, ?, ?)", - et.Contract.Id, et.EventSignature.Bytes(), et.AutoVisibility, et.Public, et.Topic1CanView, et.Topic2CanView, et.Topic3CanView, et.SenderCanView) + res, err := dbTX.ExecContext(ctx, "insert into event_type (contract, event_sig, auto_visibility,auto_public, public, topic1_can_view, topic2_can_view, topic3_can_view, sender_can_view) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", + et.Contract.Id, et.EventSignature.Bytes(), et.AutoVisibility, et.AutoPublic, et.Public, et.Topic1CanView, et.Topic2CanView, et.Topic3CanView, et.SenderCanView) if err != nil { return 0, err } @@ -50,9 +50,9 @@ func WriteEventType(ctx context.Context, dbTX *sql.Tx, et *EventType) (uint64, e func ReadEventType(ctx context.Context, dbTX *sql.Tx, contract *Contract, eventSignature gethcommon.Hash) (*EventType, error) { var et EventType = EventType{Contract: contract} err := dbTX.QueryRowContext(ctx, - "select id, event_sig, auto_visibility, public, topic1_can_view, topic2_can_view, topic3_can_view, sender_can_view from event_type where contract=? and event_sig=?", + "select id, event_sig, auto_visibility, auto_public, public, topic1_can_view, topic2_can_view, topic3_can_view, sender_can_view from event_type where contract=? and event_sig=?", contract.Id, eventSignature.Bytes(), - ).Scan(&et.Id, &et.EventSignature, &et.AutoVisibility, &et.Public, &et.Topic1CanView, &et.Topic2CanView, &et.Topic3CanView, &et.SenderCanView) + ).Scan(&et.Id, &et.EventSignature, &et.AutoVisibility, &et.AutoPublic, &et.Public, &et.Topic1CanView, &et.Topic2CanView, &et.Topic3CanView, &et.SenderCanView) if errors.Is(err, sql.ErrNoRows) { // make sure the error is converted to obscuro-wide not found error return nil, errutil.ErrNotFound @@ -72,8 +72,8 @@ func WriteEventTopic(ctx context.Context, dbTX *sql.Tx, topic *gethcommon.Hash, return uint64(id), nil } -func UpdateEventTypeLifecycle(ctx context.Context, dbTx *sql.Tx, etId uint64, isLifecycle bool) error { - _, err := dbTx.ExecContext(ctx, "update event_type set public=? where id=?", isLifecycle, etId) +func UpdateEventTypeAutoPublic(ctx context.Context, dbTx *sql.Tx, etId uint64, isPublic bool) error { + _, err := dbTx.ExecContext(ctx, "update event_type set auto_public=? where id=?", isPublic, etId) return err } @@ -89,6 +89,17 @@ func ReadEventTopic(ctx context.Context, dbTX *sql.Tx, topic []byte, eventTypeId return id, address, err } +func ReadRelevantAddressFromEventTopic(ctx context.Context, dbTX *sql.Tx, id uint64) (*uint64, error) { + var address *uint64 + err := dbTX.QueryRowContext(ctx, + "select rel_address from event_topic where id=?", id).Scan(&address) + if errors.Is(err, sql.ErrNoRows) { + // make sure the error is converted to obscuro-wide not found error + return nil, errutil.ErrNotFound + } + return address, err +} + func WriteEventLog(ctx context.Context, dbTX *sql.Tx, eventTypeId uint64, userTopics []*uint64, data []byte, logIdx uint, execTx uint64) error { _, err := dbTX.ExecContext(ctx, "insert into event_log (event_type, topic1, topic2, topic3, datablob, log_idx, receipt) values (?,?,?,?,?,?,?)", eventTypeId, userTopics[0], userTopics[1], userTopics[2], data, logIdx, execTx) @@ -273,21 +284,23 @@ func loadLogs(ctx context.Context, db *sql.DB, requestingAccount *gethcommon.Add return result, nil } +// this function encodes the event log visibility rules func visibilityQuery(requestingAccount *gethcommon.Address) (string, []any) { acc := requestingAccount.Bytes() visibQuery := "AND (" visibParams := make([]any, 0) + // everyone can query public events visibQuery += " et.public=true " - // For auto configs, an event is considered relevant to all account owners whose addresses are used as topics in the event. - visibQuery += " OR (et.auto_visibility=true AND (eoa1.address=? OR eoa2.address=? OR eoa3.address=?))" + // For event logs that have no explicit configuration, an event is visible be all account owners whose addresses are used in any topic + visibQuery += " OR (et.auto_visibility=true AND (et.auto_public=true OR (eoa1.address=? OR eoa2.address=? OR eoa3.address=?))) " visibParams = append(visibParams, acc) visibParams = append(visibParams, acc) visibParams = append(visibParams, acc) - // Configured events + // Configured events that are not public specify explicitly which event topics are addresses empowered to view that event visibQuery += " OR (" + "et.auto_visibility=false AND et.public=false AND " + " (" + diff --git a/go/enclave/storage/enclavedb/interfaces.go b/go/enclave/storage/enclavedb/interfaces.go index 9c21426737..9e5ed4d5fb 100644 --- a/go/enclave/storage/enclavedb/interfaces.go +++ b/go/enclave/storage/enclavedb/interfaces.go @@ -38,6 +38,7 @@ type EventType struct { Contract *Contract EventSignature gethcommon.Hash AutoVisibility bool + AutoPublic *bool // true -when the event is autodetected as public Public bool Topic1CanView, Topic2CanView, Topic3CanView *bool SenderCanView *bool diff --git a/go/enclave/storage/events_storage.go b/go/enclave/storage/events_storage.go index 015af17792..2b8ddb815a 100644 --- a/go/enclave/storage/events_storage.go +++ b/go/enclave/storage/events_storage.go @@ -35,32 +35,10 @@ func (es *eventsStorage) storeReceiptAndEventLogs(ctx context.Context, dbTX *sql // store the contracts created by this tx for createdContract, cfg := range txExecResult.CreatedContracts { - _, err := es.storeNewContract(ctx, dbTX, createdContract, senderId, cfg) + err := es.storeNewContractWithEventTypeConfigs(ctx, dbTX, createdContract, senderId, cfg) if err != nil { return err } - - c, err := es.readContract(ctx, dbTX, createdContract) - if err != nil { - return err - } - - // create the event types for the events that were configured - for eventSig, eventCfg := range cfg.EventConfigs { - _, err = enclavedb.WriteEventType(ctx, dbTX, &enclavedb.EventType{ - Contract: c, - EventSignature: eventSig, - AutoVisibility: eventCfg.AutoConfig, - Public: eventCfg.Public, - Topic1CanView: eventCfg.Topic1CanView, - Topic2CanView: eventCfg.Topic2CanView, - Topic3CanView: eventCfg.Topic3CanView, - SenderCanView: eventCfg.SenderCanView, - }) - if err != nil { - return fmt.Errorf("could not write event type. cause %w", err) - } - } } receiptId, err := es.storeReceipt(ctx, dbTX, batch, txExecResult, txId) @@ -78,6 +56,36 @@ func (es *eventsStorage) storeReceiptAndEventLogs(ctx context.Context, dbTX *sql return nil } +func (es *eventsStorage) storeNewContractWithEventTypeConfigs(ctx context.Context, dbTX *sql.Tx, contractAddr gethcommon.Address, senderId *uint64, cfg *core.ContractVisibilityConfig) error { + _, err := enclavedb.WriteContractConfig(ctx, dbTX, contractAddr, *senderId, cfg) + if err != nil { + return fmt.Errorf("could not write contract address. cause %w", err) + } + + c, err := es.readContract(ctx, dbTX, contractAddr) + if err != nil { + return err + } + + // create the event types for the events that were configured + for eventSig, eventCfg := range cfg.EventConfigs { + _, err = enclavedb.WriteEventType(ctx, dbTX, &enclavedb.EventType{ + Contract: c, + EventSignature: eventSig, + AutoVisibility: eventCfg.AutoConfig, + Public: eventCfg.Public, + Topic1CanView: eventCfg.Topic1CanView, + Topic2CanView: eventCfg.Topic2CanView, + Topic3CanView: eventCfg.Topic3CanView, + SenderCanView: eventCfg.SenderCanView, + }) + if err != nil { + return fmt.Errorf("could not write event type. cause %w", err) + } + } + return nil +} + // Convert the receipt into its storage form and serialize // this removes information that can be recreated // todo - in a future iteration, this can be slimmed down further because we already store the logs separately @@ -95,14 +103,6 @@ func (es *eventsStorage) storeReceipt(ctx context.Context, dbTX *sql.Tx, batch * return execTxId, nil } -func (es *eventsStorage) storeNewContract(ctx context.Context, dbTX *sql.Tx, createdContract gethcommon.Address, senderId *uint64, cfg *core.ContractVisibilityConfig) (*uint64, error) { - ctrId, err := enclavedb.WriteContractConfig(ctx, dbTX, createdContract, *senderId, cfg) - if err != nil { - return nil, fmt.Errorf("could not write contract address. cause %w", err) - } - return ctrId, nil -} - func (es *eventsStorage) storeEventLog(ctx context.Context, dbTX *sql.Tx, execTxId uint64, l *types.Log) error { eventSig := l.Topics[0] @@ -139,6 +139,27 @@ func (es *eventsStorage) storeEventLog(ctx context.Context, dbTX *sql.Tx, execTx return fmt.Errorf("could not write event log. Cause: %w", err) } + if !eventType.Public && eventType.AutoVisibility && eventType.AutoPublic == nil { + isPublic := true + for _, topicId := range topicIds { + if topicId != nil { + addr, err := enclavedb.ReadRelevantAddressFromEventTopic(ctx, dbTX, *topicId) + if err != nil && !errors.Is(err, errutil.ErrNotFound) { + return err + } + if addr != nil { + isPublic = false + break + } + } + } + // for private events with autovisibility, the first time we need to determine whether they are public + err = enclavedb.UpdateEventTypeAutoPublic(ctx, dbTX, eventType.Id, isPublic) + if err != nil { + return fmt.Errorf("could not update event type. cause: %w", err) + } + } + return nil } @@ -172,24 +193,24 @@ func (es *eventsStorage) storeTopics(ctx context.Context, dbTX *sql.Tx, eventTyp for i := 1; i < len(l.Topics); i++ { topic := l.Topics[i] // first check if there is an entry already for this topic - eventTopicId, _, err := es.findEventTopic(ctx, dbTX, topic.Bytes(), eventType.Id) + topicId, _, 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) } if errors.Is(err, errutil.ErrNotFound) { // if no entry was found - eventTopicId, err = es.storeEventTopic(ctx, dbTX, eventType, i, topic) + topicId, err = es.storeTopic(ctx, dbTX, eventType, i, topic) if err != nil { return nil, fmt.Errorf("could not read the event topic. Cause: %w", err) } } - topicIds[i-1] = &eventTopicId + topicIds[i-1] = &topicId } return topicIds, nil } // this function contains visibility logic -func (es *eventsStorage) storeEventTopic(ctx context.Context, dbTX *sql.Tx, eventType *enclavedb.EventType, i int, topic gethcommon.Hash) (uint64, error) { +func (es *eventsStorage) storeTopic(ctx context.Context, dbTX *sql.Tx, eventType *enclavedb.EventType, i int, topic gethcommon.Hash) (uint64, error) { relevantAddress, err := es.determineRelevantAddressForTopic(ctx, dbTX, eventType, i, topic) if err != nil && !errors.Is(err, errutil.ErrNotFound) { return 0, fmt.Errorf("could not determine visibility rules. cause: %w", err) @@ -211,7 +232,7 @@ func (es *eventsStorage) storeEventTopic(ctx context.Context, dbTX *sql.Tx, even } // based on the eventType configuration, this function determines the address that can view events logs containing this topic -func (es *eventsStorage) determineRelevantAddressForTopic(ctx context.Context, dbTX *sql.Tx, eventType *enclavedb.EventType, i int, topic gethcommon.Hash) (*gethcommon.Address, error) { +func (es *eventsStorage) determineRelevantAddressForTopic(ctx context.Context, dbTX *sql.Tx, eventType *enclavedb.EventType, topicNumber int, topic gethcommon.Hash) (*gethcommon.Address, error) { var relevantAddress *gethcommon.Address switch { case eventType.AutoVisibility: @@ -238,10 +259,10 @@ func (es *eventsStorage) determineRelevantAddressForTopic(ctx context.Context, d // for public events, there is no relevant address relevantAddress = nil - case eventType.IsTopicRelevant(i): + case eventType.IsTopicRelevant(topicNumber): relevantAddress = common.ExtractPotentialAddress(topic) if relevantAddress == nil { - return nil, fmt.Errorf("invalid configuration. expected address in topic %d : %s", i, topic.String()) + return nil, fmt.Errorf("invalid configuration. expected address in topic %d : %s", topicNumber, topic.String()) } default: @@ -300,8 +321,8 @@ func (es *eventsStorage) readContract(ctx context.Context, dbTX *sql.Tx, addr ge }) } -func (es *eventsStorage) findEventTopic(ctx context.Context, dbTX *sql.Tx, topic []byte, eventTypeId uint64) (uint64, *uint64, error) { - defer es.logDuration("findEventTopic", measure.NewStopwatch()) +func (es *eventsStorage) findTopic(ctx context.Context, dbTX *sql.Tx, topic []byte, eventTypeId uint64) (uint64, *uint64, error) { + defer es.logDuration("findTopic", measure.NewStopwatch()) return enclavedb.ReadEventTopic(ctx, dbTX, topic, eventTypeId) } diff --git a/go/enclave/storage/init/edgelessdb/001_init.sql b/go/enclave/storage/init/edgelessdb/001_init.sql index ab2fe00cda..18c4aa95eb 100644 --- a/go/enclave/storage/init/edgelessdb/001_init.sql +++ b/go/enclave/storage/init/edgelessdb/001_init.sql @@ -132,6 +132,7 @@ create table if not exists tendb.event_type contract int NOT NULL, event_sig binary(32) NOT NULL, auto_visibility boolean NOT NULL, + auto_public boolean, public boolean NOT NULL, topic1_can_view boolean, topic2_can_view boolean, diff --git a/go/enclave/storage/init/sqlite/001_init.sql b/go/enclave/storage/init/sqlite/001_init.sql index 3325544e44..91270d0d27 100644 --- a/go/enclave/storage/init/sqlite/001_init.sql +++ b/go/enclave/storage/init/sqlite/001_init.sql @@ -124,9 +124,10 @@ create table if not exists event_type ( id INTEGER PRIMARY KEY AUTOINCREMENT, contract INTEGER NOT NULL references contract, - event_sig binary(32) NOT NULL, -- no need to index because there are only a few events for an address - auto_visibility boolean NOT NULL, -- the visibility of this event type was not configured by the contract dev. - public boolean NOT NULL, -- set based on the first event, and then updated to false if it turns out it is true + event_sig binary(32) NOT NULL, + auto_visibility boolean NOT NULL, + auto_public boolean, + public boolean NOT NULL, topic1_can_view boolean, topic2_can_view boolean, topic3_can_view boolean, From dea24a65140993d8bee157f6d79ad2bab535763a Mon Sep 17 00:00:00 2001 From: Tudor Malene Date: Wed, 18 Sep 2024 10:27:35 +0100 Subject: [PATCH 4/6] fix debug endpoint --- go/common/tracers/debug_logs.go | 3 --- go/enclave/storage/enclavedb/events.go | 8 ++++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/go/common/tracers/debug_logs.go b/go/common/tracers/debug_logs.go index 110e1bb828..176a573e6c 100644 --- a/go/common/tracers/debug_logs.go +++ b/go/common/tracers/debug_logs.go @@ -14,7 +14,6 @@ type DebugLogs struct { RelAddress1 *gethcommon.Address `json:"relAddress1"` RelAddress2 *gethcommon.Address `json:"relAddress2"` RelAddress3 *gethcommon.Address `json:"relAddress3"` - RelAddress4 *gethcommon.Address `json:"relAddress4"` LifecycleEvent bool `json:"lifecycleEvent"` gethtypes.Log @@ -37,7 +36,6 @@ func (l DebugLogs) MarshalJSON() ([]byte, error) { RelAddress1 *gethcommon.Address `json:"relAddress1"` RelAddress2 *gethcommon.Address `json:"relAddress2"` RelAddress3 *gethcommon.Address `json:"relAddress3"` - RelAddress4 *gethcommon.Address `json:"relAddress4"` }{ l.Address.Hex(), l.Topics, @@ -52,6 +50,5 @@ func (l DebugLogs) MarshalJSON() ([]byte, error) { l.RelAddress1, l.RelAddress2, l.RelAddress3, - l.RelAddress4, }) } diff --git a/go/enclave/storage/enclavedb/events.go b/go/enclave/storage/enclavedb/events.go index 4d3e844b77..793612f765 100644 --- a/go/enclave/storage/enclavedb/events.go +++ b/go/enclave/storage/enclavedb/events.go @@ -162,7 +162,8 @@ func FilterLogs( func DebugGetLogs(ctx context.Context, db *sql.DB, txHash common.TxHash) ([]*tracers.DebugLogs, error) { var queryParams []any - query := "select eoa1.address, eoa2.address, eoa3.address, et.public, et.event_sig, t1.topic, t2.topic, t3.topic, datablob, b.hash, b.height, tx.hash, tx.idx, log_idx, c.address " + + // todo - should we return the config here? + query := "select eoa1.address, eoa2.address, eoa3.address, et.public, et.auto_public, et.event_sig, t1.topic, t2.topic, t3.topic, datablob, b.hash, b.height, tx.hash, tx.idx, log_idx, c.address " + baseEventsJoin + " AND tx.hash = ? " @@ -186,11 +187,13 @@ func DebugGetLogs(ctx context.Context, db *sql.DB, txHash common.TxHash) ([]*tra var t0, t1, t2, t3 sql.NullString var relAddress1, relAddress2, relAddress3 []byte + var public, autoPublic bool err = rows.Scan( &relAddress1, &relAddress2, &relAddress3, - &l.LifecycleEvent, + &public, + &autoPublic, &t0, &t1, &t2, &t3, &l.Data, &l.BlockHash, @@ -200,6 +203,7 @@ func DebugGetLogs(ctx context.Context, db *sql.DB, txHash common.TxHash) ([]*tra &l.Index, &l.Address, ) + l.LifecycleEvent = public || autoPublic if err != nil { return nil, fmt.Errorf("could not load log entry from db: %w", err) } From d6eeac8683f78c195afbf0ca528d804835d6ad34 Mon Sep 17 00:00:00 2001 From: Tudor Malene Date: Wed, 18 Sep 2024 10:48:52 +0100 Subject: [PATCH 5/6] fix bug --- go/enclave/storage/events_storage.go | 70 ++++++++++++---------------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/go/enclave/storage/events_storage.go b/go/enclave/storage/events_storage.go index 2b8ddb815a..428bf5efcf 100644 --- a/go/enclave/storage/events_storage.go +++ b/go/enclave/storage/events_storage.go @@ -236,23 +236,37 @@ func (es *eventsStorage) determineRelevantAddressForTopic(ctx context.Context, d var relevantAddress *gethcommon.Address switch { case eventType.AutoVisibility: - var err error - // if there is no configuration, we have to autodetect the address - relevantAddress, err = es.autoDetectRelevantAddress(ctx, dbTX, topic) - if err != nil { + extractedAddr := common.ExtractPotentialAddress(topic) + if extractedAddr == nil { + break + } + + // first check whether there is already an entry in the EOA table + _, err := es.readEOA(ctx, dbTX, *extractedAddr) + if err != nil && !errors.Is(err, errutil.ErrNotFound) { return nil, err } + if err == nil { + relevantAddress = extractedAddr + break + } - // when autodetecting, we assume that any address that is not a contract is an EOA - _, err = es.readEOA(ctx, dbTX, *relevantAddress) + // if the address is a contract then it's clearly not an EOA + _, err = es.readContract(ctx, dbTX, *extractedAddr) if err != nil && !errors.Is(err, errutil.ErrNotFound) { return nil, err } - if errors.Is(err, errutil.ErrNotFound) { - _, err := enclavedb.WriteEoa(ctx, dbTX, *relevantAddress) - if err != nil { - return nil, err - } + if err == nil { + // the extracted address is a contract + relevantAddress = nil + break + } + + // save the extracted address to the EOA table + relevantAddress = extractedAddr + _, err = enclavedb.WriteEoa(ctx, dbTX, *relevantAddress) + if err != nil { + return nil, err } case eventType.IsPublic(): @@ -265,6 +279,10 @@ func (es *eventsStorage) determineRelevantAddressForTopic(ctx context.Context, d return nil, fmt.Errorf("invalid configuration. expected address in topic %d : %s", topicNumber, topic.String()) } + case !eventType.IsTopicRelevant(topicNumber): + // no need to do anything because this topic was not configured to be an address + relevantAddress = nil + default: es.logger.Crit("impossible case. Should not get here") } @@ -272,36 +290,6 @@ func (es *eventsStorage) determineRelevantAddressForTopic(ctx context.Context, d return relevantAddress, nil } -// Of the log's topics, returns those that are (potentially) user addresses. A topic is considered a user address if: -// - It has at least 12 leading zero bytes (since addresses are 20 bytes long, while hashes are 32) and at most 22 leading zero bytes -// - It is not a smart contract address -func (es *eventsStorage) autoDetectRelevantAddress(ctx context.Context, dbTX *sql.Tx, topic gethcommon.Hash) (*gethcommon.Address, error) { - potentialAddr := common.ExtractPotentialAddress(topic) - if potentialAddr == nil { - return nil, errutil.ErrNotFound - } - - // first check whether there is already an entry in the EOA table - _, err := es.readEOA(ctx, dbTX, *potentialAddr) - if err != nil && !errors.Is(err, errutil.ErrNotFound) { - return nil, err - } - if err == nil { - return potentialAddr, nil - } - - // if the address is a contract then it's clearly not an EOA - _, err = es.readContract(ctx, dbTX, *potentialAddr) - if err != nil && !errors.Is(err, errutil.ErrNotFound) { - return nil, err - } - if err == nil { - return nil, errutil.ErrNotFound - } - - return potentialAddr, nil -} - func (es *eventsStorage) readEventType(ctx context.Context, dbTX *sql.Tx, contractAddress gethcommon.Address, eventSignature gethcommon.Hash) (*enclavedb.EventType, error) { defer es.logDuration("ReadEventType", measure.NewStopwatch()) From fc5ea8ae70dd4980db9e898f83d012c30a368dab Mon Sep 17 00:00:00 2001 From: Tudor Malene Date: Wed, 18 Sep 2024 12:43:36 +0100 Subject: [PATCH 6/6] clarify naming --- go/enclave/storage/enclavedb/events.go | 22 +++++++++---------- go/enclave/storage/enclavedb/interfaces.go | 4 ++-- go/enclave/storage/events_storage.go | 8 +++---- .../storage/init/edgelessdb/001_init.sql | 2 +- go/enclave/storage/init/sqlite/001_init.sql | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/go/enclave/storage/enclavedb/events.go b/go/enclave/storage/enclavedb/events.go index 793612f765..a471f8f94f 100644 --- a/go/enclave/storage/enclavedb/events.go +++ b/go/enclave/storage/enclavedb/events.go @@ -35,8 +35,8 @@ const ( ) func WriteEventType(ctx context.Context, dbTX *sql.Tx, et *EventType) (uint64, error) { - res, err := dbTX.ExecContext(ctx, "insert into event_type (contract, event_sig, auto_visibility,auto_public, public, topic1_can_view, topic2_can_view, topic3_can_view, sender_can_view) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", - et.Contract.Id, et.EventSignature.Bytes(), et.AutoVisibility, et.AutoPublic, et.Public, et.Topic1CanView, et.Topic2CanView, et.Topic3CanView, et.SenderCanView) + res, err := dbTX.ExecContext(ctx, "insert into event_type (contract, event_sig, auto_visibility,auto_public, config_public, topic1_can_view, topic2_can_view, topic3_can_view, sender_can_view) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", + et.Contract.Id, et.EventSignature.Bytes(), et.AutoVisibility, et.AutoPublic, et.ConfigPublic, et.Topic1CanView, et.Topic2CanView, et.Topic3CanView, et.SenderCanView) if err != nil { return 0, err } @@ -50,9 +50,9 @@ func WriteEventType(ctx context.Context, dbTX *sql.Tx, et *EventType) (uint64, e func ReadEventType(ctx context.Context, dbTX *sql.Tx, contract *Contract, eventSignature gethcommon.Hash) (*EventType, error) { var et EventType = EventType{Contract: contract} err := dbTX.QueryRowContext(ctx, - "select id, event_sig, auto_visibility, auto_public, public, topic1_can_view, topic2_can_view, topic3_can_view, sender_can_view from event_type where contract=? and event_sig=?", + "select id, event_sig, auto_visibility, auto_public, config_public, topic1_can_view, topic2_can_view, topic3_can_view, sender_can_view from event_type where contract=? and event_sig=?", contract.Id, eventSignature.Bytes(), - ).Scan(&et.Id, &et.EventSignature, &et.AutoVisibility, &et.AutoPublic, &et.Public, &et.Topic1CanView, &et.Topic2CanView, &et.Topic3CanView, &et.SenderCanView) + ).Scan(&et.Id, &et.EventSignature, &et.AutoVisibility, &et.AutoPublic, &et.ConfigPublic, &et.Topic1CanView, &et.Topic2CanView, &et.Topic3CanView, &et.SenderCanView) if errors.Is(err, sql.ErrNoRows) { // make sure the error is converted to obscuro-wide not found error return nil, errutil.ErrNotFound @@ -163,7 +163,7 @@ func DebugGetLogs(ctx context.Context, db *sql.DB, txHash common.TxHash) ([]*tra var queryParams []any // todo - should we return the config here? - query := "select eoa1.address, eoa2.address, eoa3.address, et.public, et.auto_public, et.event_sig, t1.topic, t2.topic, t3.topic, datablob, b.hash, b.height, tx.hash, tx.idx, log_idx, c.address " + + query := "select eoa1.address, eoa2.address, eoa3.address, et.config_public, et.auto_public, et.event_sig, t1.topic, t2.topic, t3.topic, datablob, b.hash, b.height, tx.hash, tx.idx, log_idx, c.address " + baseEventsJoin + " AND tx.hash = ? " @@ -187,12 +187,12 @@ func DebugGetLogs(ctx context.Context, db *sql.DB, txHash common.TxHash) ([]*tra var t0, t1, t2, t3 sql.NullString var relAddress1, relAddress2, relAddress3 []byte - var public, autoPublic bool + var config_public, autoPublic bool err = rows.Scan( &relAddress1, &relAddress2, &relAddress3, - &public, + &config_public, &autoPublic, &t0, &t1, &t2, &t3, &l.Data, @@ -203,7 +203,7 @@ func DebugGetLogs(ctx context.Context, db *sql.DB, txHash common.TxHash) ([]*tra &l.Index, &l.Address, ) - l.LifecycleEvent = public || autoPublic + l.LifecycleEvent = config_public || autoPublic if err != nil { return nil, fmt.Errorf("could not load log entry from db: %w", err) } @@ -295,8 +295,8 @@ func visibilityQuery(requestingAccount *gethcommon.Address) (string, []any) { visibQuery := "AND (" visibParams := make([]any, 0) - // everyone can query public events - visibQuery += " et.public=true " + // everyone can query config_public events + visibQuery += " et.config_public=true " // For event logs that have no explicit configuration, an event is visible be all account owners whose addresses are used in any topic visibQuery += " OR (et.auto_visibility=true AND (et.auto_public=true OR (eoa1.address=? OR eoa2.address=? OR eoa3.address=?))) " @@ -306,7 +306,7 @@ func visibilityQuery(requestingAccount *gethcommon.Address) (string, []any) { // Configured events that are not public specify explicitly which event topics are addresses empowered to view that event visibQuery += " OR (" + - "et.auto_visibility=false AND et.public=false AND " + + "et.auto_visibility=false AND et.config_public=false AND " + " (" + " (et.topic1_can_view AND eoa1.address=?) " + " OR (et.topic2_can_view AND eoa2.address=?) " + diff --git a/go/enclave/storage/enclavedb/interfaces.go b/go/enclave/storage/enclavedb/interfaces.go index 9e5ed4d5fb..5d59fef638 100644 --- a/go/enclave/storage/enclavedb/interfaces.go +++ b/go/enclave/storage/enclavedb/interfaces.go @@ -39,13 +39,13 @@ type EventType struct { EventSignature gethcommon.Hash AutoVisibility bool AutoPublic *bool // true -when the event is autodetected as public - Public bool + ConfigPublic bool Topic1CanView, Topic2CanView, Topic3CanView *bool SenderCanView *bool } func (et EventType) IsPublic() bool { - return (et.Contract.Transparent != nil && *et.Contract.Transparent) || et.Public + return (et.Contract.Transparent != nil && *et.Contract.Transparent) || et.ConfigPublic } func (et EventType) IsTopicRelevant(topicNo int) bool { diff --git a/go/enclave/storage/events_storage.go b/go/enclave/storage/events_storage.go index 428bf5efcf..3eaf701a99 100644 --- a/go/enclave/storage/events_storage.go +++ b/go/enclave/storage/events_storage.go @@ -73,7 +73,7 @@ func (es *eventsStorage) storeNewContractWithEventTypeConfigs(ctx context.Contex Contract: c, EventSignature: eventSig, AutoVisibility: eventCfg.AutoConfig, - Public: eventCfg.Public, + ConfigPublic: eventCfg.Public, Topic1CanView: eventCfg.Topic1CanView, Topic2CanView: eventCfg.Topic2CanView, Topic3CanView: eventCfg.Topic3CanView, @@ -139,7 +139,7 @@ func (es *eventsStorage) storeEventLog(ctx context.Context, dbTX *sql.Tx, execTx return fmt.Errorf("could not write event log. Cause: %w", err) } - if !eventType.Public && eventType.AutoVisibility && eventType.AutoPublic == nil { + if !eventType.ConfigPublic && eventType.AutoVisibility && eventType.AutoPublic == nil { isPublic := true for _, topicId := range topicIds { if topicId != nil { @@ -169,11 +169,11 @@ func (es *eventsStorage) storeAutoConfigEventType(ctx context.Context, dbTX *sql eventType := enclavedb.EventType{ Contract: contract, EventSignature: l.Topics[0], - Public: contract.IsTransparent(), + ConfigPublic: contract.IsTransparent(), } // event types that are not public - will have the default rules - if !eventType.Public { + if !eventType.ConfigPublic { eventType.AutoVisibility = true } diff --git a/go/enclave/storage/init/edgelessdb/001_init.sql b/go/enclave/storage/init/edgelessdb/001_init.sql index 18c4aa95eb..72c12ca284 100644 --- a/go/enclave/storage/init/edgelessdb/001_init.sql +++ b/go/enclave/storage/init/edgelessdb/001_init.sql @@ -133,7 +133,7 @@ create table if not exists tendb.event_type event_sig binary(32) NOT NULL, auto_visibility boolean NOT NULL, auto_public boolean, - public boolean NOT NULL, + config_public boolean NOT NULL, topic1_can_view boolean, topic2_can_view boolean, topic3_can_view boolean, diff --git a/go/enclave/storage/init/sqlite/001_init.sql b/go/enclave/storage/init/sqlite/001_init.sql index 91270d0d27..da9ed5b10b 100644 --- a/go/enclave/storage/init/sqlite/001_init.sql +++ b/go/enclave/storage/init/sqlite/001_init.sql @@ -127,7 +127,7 @@ create table if not exists event_type event_sig binary(32) NOT NULL, auto_visibility boolean NOT NULL, auto_public boolean, - public boolean NOT NULL, + config_public boolean NOT NULL, topic1_can_view boolean, topic2_can_view boolean, topic3_can_view boolean,