Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

event visibility config part 2 #2057

Merged
merged 6 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions go/common/tracers/debug_logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -52,6 +50,5 @@ func (l DebugLogs) MarshalJSON() ([]byte, error) {
l.RelAddress1,
l.RelAddress2,
l.RelAddress3,
l.RelAddress4,
})
}
7 changes: 6 additions & 1 deletion go/enclave/core/event_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
97 changes: 73 additions & 24 deletions go/enclave/storage/enclavedb/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ 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 "
)

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)
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
}
Expand All @@ -47,19 +47,21 @@ 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, 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.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
}
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
}
Expand All @@ -70,22 +72,34 @@ 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
}

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
}
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)
Expand Down Expand Up @@ -148,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.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 = ? "

Expand All @@ -172,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 config_public, autoPublic bool
err = rows.Scan(
&relAddress1,
&relAddress2,
&relAddress3,
&l.LifecycleEvent,
&config_public,
&autoPublic,
&t0, &t1, &t2, &t3,
&l.Data,
&l.BlockHash,
Expand All @@ -186,6 +203,7 @@ func DebugGetLogs(ctx context.Context, db *sql.DB, txHash common.TxHash) ([]*tra
&l.Index,
&l.Address,
)
l.LifecycleEvent = config_public || autoPublic
if err != nil {
return nil, fmt.Errorf("could not load log entry from db: %w", err)
}
Expand Down Expand Up @@ -229,13 +247,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...)
Expand Down Expand Up @@ -272,6 +288,39 @@ 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 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=?))) "
visibParams = append(visibParams, acc)
visibParams = append(visibParams, acc)
visibParams = append(visibParams, acc)

// 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.config_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())
Expand Down
27 changes: 25 additions & 2 deletions go/enclave/storage/enclavedb/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package enclavedb
import (
"context"
"database/sql"
"fmt"

gethcommon "github.com/ethereum/go-ethereum/common"

Expand All @@ -27,13 +28,35 @@ 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
AutoPublic *bool // true -when the event is autodetected as public
ConfigPublic bool
Topic1CanView, Topic2CanView, Topic3CanView *bool
SenderCanView *bool
}

func (et EventType) IsPublic() bool {
return (et.Contract.Transparent != nil && *et.Contract.Transparent) || et.ConfigPublic
}

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))
}
Loading
Loading