Skip to content

Commit

Permalink
complete parser for visit functions
Browse files Browse the repository at this point in the history
  • Loading branch information
EasterTheBunny committed Apr 12, 2024
1 parent 52af0b5 commit 477d6ca
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 10 deletions.
9 changes: 5 additions & 4 deletions core/chains/evm/logpoller/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (w Where) String() (string, map[string]any) {
"WHERE evm_chain_id = %s AND address = %s AND %s",
args.Add("evm_chain_id", w.ChainID.Uint64()),
args.Add("address", w.Address),
makeExpression(w.Op, w.Expressions, args),
makeExpression(w.Op, w.Expressions, args, w.ChainID),
)

if hasCursorLimit(w.Limit) {
Expand Down Expand Up @@ -123,21 +123,22 @@ func orderToString(dir query.SortDirection) string {
}
}

func makeExpression(op query.BoolOperator, expressions []query.Expression, args *namedArgs) string {
func makeExpression(op query.BoolOperator, expressions []query.Expression, args *namedArgs, chainID *big.Int) string {
parts := []string{}

for _, exp := range expressions {
if exp.IsPrimitive() {
v := &PgDSLParser{
args: args,
chainID: chainID,
args: args,
}

// do as primitive
exp.Primitive.Accept(v) // not sure yet what to do with this
parts = append(parts, v.expression)
} else {
// all expressions in this list are combined with BoolOperator.String()
parts = append(parts, makeExpression(exp.BoolExpression.BoolOperator, exp.BoolExpression.Expressions, args))
parts = append(parts, makeExpression(exp.BoolExpression.BoolOperator, exp.BoolExpression.Expressions, args, chainID))
}
}

Expand Down
7 changes: 6 additions & 1 deletion core/chains/evm/logpoller/orm.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package logpoller
import (
"context"
"database/sql"
"errors"
"fmt"
"math/big"
"strings"
Expand Down Expand Up @@ -973,6 +974,10 @@ func (o *DbORM) SelectIndexedLogsWithSigsExcluding(ctx context.Context, sigA, si
}

func (o *DbORM) FilteredLogs(ctx context.Context, filter query.KeyFilter, limit query.LimitAndSort, mapper *EventFilterMapper) ([]Log, error) {
if mapper == nil {
return nil, errors.New("mapper required for setting contract address")
}

if mapper != nil {
newFilter, err := mapper.remap(filter)
if err != nil {
Expand All @@ -984,7 +989,7 @@ func (o *DbORM) FilteredLogs(ctx context.Context, filter query.KeyFilter, limit

where := Where{
ChainID: o.chainID,
Address: common.HexToAddress(filter.Key),
Address: mapper.Address,
Op: query.AND,
Expressions: filter.Expressions,
Limit: limit.Limit,
Expand Down
86 changes: 81 additions & 5 deletions core/chains/evm/logpoller/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package logpoller
import (
"fmt"
"math/big"
"strings"

"github.com/ethereum/go-ethereum/common"
"github.com/smartcontractkit/chainlink-common/pkg/types/query"
)

Expand All @@ -13,11 +15,14 @@ const (
blockFieldName = "block_number"
timestampFieldName = "timestamp"
txHashFieldName = "tx_hash"
eventSigFieldName = "event_sig"
chainIDFieldName = "evm_chain_id"
evmLogsTableName = "evm.logs"
)

// PgDSLParser is a visitor that builds a postgres query and arguments from a commontypes.QueryFilter
type PgDSLParser struct {
chainID *big.Int
expression string
args *namedArgs
}
Expand All @@ -43,8 +48,21 @@ func (v *PgDSLParser) BlockPrimitive(p query.BlockPrimitive) {
)
}

// TODO: need to properly handle unconfirmed level with a fallback option
func (v *PgDSLParser) ConfirmationPrimitive(p query.ConfirmationsPrimitive) {
v.expression = fmt.Sprintf("(%s - %d) >= 0", blockFieldName, p.ConfirmationLevel) // TODO: do some math in the query
if p.ConfirmationLevel == query.Finalized {
nested := fmt.Sprintf(`(SELECT finalized_block_number
FROM evm.log_poller_blocks
WHERE evm_chain_id = :%s
ORDER BY block_number DESC LIMIT 1)`,
v.args.Add(chainIDFieldName, v.chainID),
)

v.expression = fmt.Sprintf("%s <= %s", blockFieldName, nested)
} else {
// TODO: not sure if this is the correct fallback option
v.expression = fmt.Sprintf("(%s - %d) >= 0", blockFieldName, p.ConfirmationLevel)
}
}

func (v *PgDSLParser) TimestampPrimitive(p query.TimestampPrimitive) {
Expand All @@ -64,13 +82,71 @@ func (v *PgDSLParser) TxHashPrimitives(p query.TxHashPrimitive) {
)
}

func (v *PgDSLParser) VisitEventBySigFilter(p *EventBySigFilter) {}
func (v *PgDSLParser) VisitEventBySigFilter(p *EventBySigFilter) {
v.expression = eventSigExpression(p.EventSig, v.args)
}

func (v *PgDSLParser) VisitFinalityFilter(p *FinalityFilter) {
nested := fmt.Sprintf(`(SELECT greatest(block_number - :%s, 0)
FROM evm.log_poller_blocks
WHERE evm_chain_id = :%s
ORDER BY block_number DESC LIMIT 1)`,
v.args.Add("confs", p.Confs),
v.args.Add(chainIDFieldName, v.chainID),
)

v.expression = fmt.Sprintf("%s <= %s", blockFieldName, nested)
}

func (v *PgDSLParser) VisitEventByWordFilter(p *EventByWordFilter) {
v.expression = eventSigExpression(p.EventSig, v.args)

if len(p.ValueComparers) > 0 {
wordIdx := v.args.Add("word_index", p.WordIndex)

func (v *PgDSLParser) VisitFinalityFilter(_ *FinalityFilter) {}
comps := make([]string, len(p.ValueComparers))
for idx, comp := range p.ValueComparers {
placement := v.args.Add("word_value", comp.Value)
comps[idx] = fmt.Sprintf(
"substring(data from 32*:%s+1 for 32) %s :%s",
wordIdx,
cmpOpToString(comp.Operator),
placement,
)
}

func (v *PgDSLParser) VisitEventByWordFilter(_ *EventByWordFilter) {}
v.expression = fmt.Sprintf("%s AND %s", v.expression, strings.Join(comps, " AND "))
}
}

func (v *PgDSLParser) VisitEventTopicsByValueFilter(_ *EventByTopicFilter) {}
func (v *PgDSLParser) VisitEventTopicsByValueFilter(p *EventByTopicFilter) {
v.expression = eventSigExpression(p.EventSig, v.args)

if len(p.ValueComparers) > 0 {
topicIdx := v.args.Add("topic_index", p.Topic)

comps := make([]string, len(p.ValueComparers))
for idx, comp := range p.ValueComparers {
placement := v.args.Add("topic_value", comp.Value)
comps[idx] = fmt.Sprintf(
"topics[:%s] %s :%s",
topicIdx,
cmpOpToString(comp.Operator),
placement,
)
}

v.expression = fmt.Sprintf("%s AND %s", v.expression, strings.Join(comps, " AND "))
}
}

func eventSigExpression(sig common.Hash, args *namedArgs) string {
return fmt.Sprintf(
"%s = :%s",
eventSigFieldName,
args.Add(eventSigFieldName, sig),
)
}

type namedArgs struct {
namedValues map[string]any
Expand Down

0 comments on commit 477d6ca

Please sign in to comment.