Skip to content

Commit

Permalink
Change Confirmations to Confidence (#12987)
Browse files Browse the repository at this point in the history
* Change Confirmations to Confidence

`Confidence` is a different approach to mapping a chain agnostic concept of confidence that
an event or transaction can or should be acted on. `Confidence` is intended to map to defined
levels of confirmations on EVM chains and other states on other chains.

Only two levels of `Confidence` exist by default to define the boundaries: `Highest` and
`Lowest`. This creates an inclusive range for all chain configurable `Confidence` levels and
can be treated as % confidence that an event or transaction can or should be acted on.

* go mod tidy

* go tidy

* update latest common

---------

Co-authored-by: Blaž Hrastnik <[email protected]>
  • Loading branch information
EasterTheBunny and archseer authored May 30, 2024
1 parent 732eea0 commit 4c2c6a6
Show file tree
Hide file tree
Showing 15 changed files with 156 additions and 65 deletions.
26 changes: 7 additions & 19 deletions core/chains/evm/logpoller/orm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ func TestORM_IndexedLogs(t *testing.T) {
logpoller.NewAddressFilter(addr),
logpoller.NewEventSigFilter(eventSig),
filtersForTopics(topicIdx, topicValues),
query.Confirmation(primitives.Unconfirmed),
query.Confidence(primitives.Unconfirmed),
},
}
}
Expand Down Expand Up @@ -705,7 +705,7 @@ func TestORM_IndexedLogs(t *testing.T) {
logpoller.NewEventByTopicFilter(1, []primitives.ValueComparator{
{Value: logpoller.EvmWord(2).Hex(), Operator: primitives.Gte},
}),
query.Confirmation(primitives.Unconfirmed),
query.Confidence(primitives.Unconfirmed),
},
}

Expand All @@ -724,7 +724,7 @@ func TestORM_IndexedLogs(t *testing.T) {
logpoller.NewEventByTopicFilter(topicIdx, []primitives.ValueComparator{
{Value: logpoller.EvmWord(max).Hex(), Operator: primitives.Lte},
}),
query.Confirmation(primitives.Unconfirmed),
query.Confidence(primitives.Unconfirmed),
},
}
}
Expand Down Expand Up @@ -885,7 +885,7 @@ func TestORM_DataWords(t *testing.T) {
logpoller.NewEventByWordFilter(eventSig, wordIdx, []primitives.ValueComparator{
{Value: logpoller.EvmWord(word2).Hex(), Operator: primitives.Lte},
}),
query.Confirmation(primitives.Unconfirmed),
query.Confidence(primitives.Unconfirmed),
},
}
}
Expand Down Expand Up @@ -952,7 +952,7 @@ func TestORM_DataWords(t *testing.T) {
logpoller.NewEventByWordFilter(eventSig, 0, []primitives.ValueComparator{
{Value: logpoller.EvmWord(1).Hex(), Operator: primitives.Gte},
}),
query.Confirmation(primitives.Unconfirmed),
query.Confidence(primitives.Unconfirmed),
},
}

Expand Down Expand Up @@ -1668,18 +1668,6 @@ func TestSelectLogsCreatedAfter(t *testing.T) {
}

filter := func(timestamp time.Time, confs evmtypes.Confirmations, topicIdx int, topicVals []common.Hash) query.KeyFilter {
var queryConfs primitives.ConfirmationLevel

switch confs {
case evmtypes.Finalized:
queryConfs = primitives.Finalized
case evmtypes.Unconfirmed:
queryConfs = primitives.Unconfirmed
default:
fmt.Println("default")
queryConfs = primitives.ConfirmationLevel(confs)
}

filters := []query.Expression{
logpoller.NewAddressFilter(address),
logpoller.NewEventSigFilter(event),
Expand All @@ -1703,7 +1691,7 @@ func TestSelectLogsCreatedAfter(t *testing.T) {

filters = append(filters, []query.Expression{
query.Timestamp(uint64(timestamp.Unix()), primitives.Gt),
query.Confirmation(queryConfs),
logpoller.NewConfirmationsFilter(confs),
}...)

return query.KeyFilter{
Expand Down Expand Up @@ -1982,7 +1970,7 @@ func TestSelectLogsDataWordBetween(t *testing.T) {
logpoller.NewEventByWordFilter(eventSig, 1, []primitives.ValueComparator{
{Value: logpoller.EvmWord(word).Hex(), Operator: primitives.Gte},
}),
query.Confirmation(primitives.Unconfirmed),
query.Confidence(primitives.Unconfirmed),
},
}
}
Expand Down
44 changes: 34 additions & 10 deletions core/chains/evm/logpoller/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (

"github.com/smartcontractkit/chainlink-common/pkg/types/query"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"

evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
)

Expand Down Expand Up @@ -58,19 +57,17 @@ func (v *pgDSLParser) Block(p primitives.Block) {
)
}

func (v *pgDSLParser) Confirmations(p primitives.Confirmations) {
switch p.ConfirmationLevel {
func (v *pgDSLParser) Confidence(p primitives.Confidence) {
switch p.ConfidenceLevel {
case primitives.Finalized:
// the highest level of confidence maps to finalized
v.expression = v.nestedConfQuery(true, 0)
case primitives.Unconfirmed:
// Unconfirmed in the evm relayer is an alias to the case of 0 confirmations
// set the level to the number 0 and fallthrough to the default case
p.ConfirmationLevel = primitives.ConfirmationLevel(0)

fallthrough
v.expression = v.nestedConfQuery(false, 0)
default:
// the default case passes the confirmation level as a number directly to a subquery
v.expression = v.nestedConfQuery(false, uint64(evmtypes.Confirmations(p.ConfirmationLevel)))
v.err = errors.New("unrecognized confidence level; use confidence to confirmations mappings instead")

return
}
}

Expand Down Expand Up @@ -191,6 +188,16 @@ func (v *pgDSLParser) VisitEventTopicsByValueFilter(p *eventByTopicFilter) {
}
}

func (v *pgDSLParser) VisitConfirmationsFilter(p *confirmationsFilter) {
switch p.Confirmations {
case evmtypes.Finalized:
// the highest level of confidence maps to finalized
v.expression = v.nestedConfQuery(true, 0)
default:
v.expression = v.nestedConfQuery(false, uint64(p.Confirmations))
}
}

func makeComp(comp primitives.ValueComparator, args *queryArgs, field, subfield, pattern string) (string, error) {
cmp, err := cmpOpToString(comp.Operator)
if err != nil {
Expand Down Expand Up @@ -500,3 +507,20 @@ func (f *eventByTopicFilter) Accept(visitor primitives.Visitor) {
v.VisitEventTopicsByValueFilter(f)
}
}

type confirmationsFilter struct {
Confirmations evmtypes.Confirmations
}

func NewConfirmationsFilter(confirmations evmtypes.Confirmations) query.Expression {
return query.Expression{Primitive: &confirmationsFilter{
Confirmations: confirmations,
}}
}

func (f *confirmationsFilter) Accept(visitor primitives.Visitor) {
switch v := visitor.(type) {
case *pgDSLParser:
v.VisitConfirmationsFilter(f)
}
}
40 changes: 34 additions & 6 deletions core/chains/evm/logpoller/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ func TestDSLParser(t *testing.T) {
query.Timestamp(10, primitives.Eq),
query.TxHash(common.HexToHash("0x84").String()),
query.Block(99, primitives.Neq),
query.Confirmation(primitives.Finalized),
query.Confirmation(primitives.Unconfirmed),
query.Confidence(primitives.Finalized),
query.Confidence(primitives.Unconfirmed),
}
limiter := query.NewLimitAndSort(query.CursorLimit("10-0x42-20", query.CursorPrevious, 20))

Expand Down Expand Up @@ -167,7 +167,8 @@ func TestDSLParser(t *testing.T) {
t.Run("finalized", func(t *testing.T) {
parser := &pgDSLParser{}
chainID := big.NewInt(1)
expressions := []query.Expression{query.Confirmation(primitives.Finalized)}

expressions := []query.Expression{query.Confidence(primitives.Finalized)}
limiter := query.LimitAndSort{}

result, args, err := parser.buildQuery(chainID, expressions, limiter)
Expand All @@ -185,7 +186,8 @@ func TestDSLParser(t *testing.T) {
t.Run("unconfirmed", func(t *testing.T) {
parser := &pgDSLParser{}
chainID := big.NewInt(1)
expressions := []query.Expression{query.Confirmation(primitives.Unconfirmed)}

expressions := []query.Expression{query.Confidence(primitives.Unconfirmed)}
limiter := query.LimitAndSort{}

result, args, err := parser.buildQuery(chainID, expressions, limiter)
Expand All @@ -199,6 +201,30 @@ func TestDSLParser(t *testing.T) {

assertArgs(t, args, 2)
})

t.Run("exact confirmations", func(t *testing.T) {
parser := &pgDSLParser{}
chainID := big.NewInt(1)

expressions := []query.Expression{NewConfirmationsFilter(25)}
limiter := query.LimitAndSort{}

result, args, err := parser.buildQuery(chainID, expressions, limiter)
expected := "SELECT evm.logs.* " +
"FROM evm.logs " +
"WHERE evm_chain_id = :evm_chain_id " +
"AND block_number <= (SELECT greatest(block_number - :confs_0, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = :evm_chain_id ORDER BY block_number DESC LIMIT 1)"

require.NoError(t, err)
assert.Equal(t, expected, result)

confirmations, ok := args.args["confs_0"]

require.True(t, ok)
require.Equal(t, uint64(25), confirmations)

assertArgs(t, args, 2)
})
})

t.Run("query for event by word", func(t *testing.T) {
Expand Down Expand Up @@ -256,14 +282,15 @@ func TestDSLParser(t *testing.T) {

parser := &pgDSLParser{}
chainID := big.NewInt(1)

expressions := []query.Expression{
{BoolExpression: query.BoolExpression{
Expressions: []query.Expression{
query.Timestamp(10, primitives.Gte),
{BoolExpression: query.BoolExpression{
Expressions: []query.Expression{
query.TxHash(common.HexToHash("0x84").Hex()),
query.Confirmation(primitives.Unconfirmed),
query.Confidence(primitives.Unconfirmed),
},
BoolOperator: query.OR,
}},
Expand Down Expand Up @@ -298,6 +325,7 @@ func TestDSLParser(t *testing.T) {

parser := &pgDSLParser{}
chainID := big.NewInt(1)

expressions := []query.Expression{
{BoolExpression: query.BoolExpression{
Expressions: []query.Expression{
Expand All @@ -307,7 +335,7 @@ func TestDSLParser(t *testing.T) {
query.TxHash(common.HexToHash("0x84").Hex()),
{BoolExpression: query.BoolExpression{
Expressions: []query.Expression{
query.Confirmation(primitives.Unconfirmed),
query.Confidence(primitives.Unconfirmed),
wordFilter,
},
BoolOperator: query.AND,
Expand Down
2 changes: 1 addition & 1 deletion core/scripts/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
github.com/prometheus/client_golang v1.17.0
github.com/shopspring/decimal v1.3.1
github.com/smartcontractkit/chainlink-automation v1.0.3
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240528141639-92c521695f6f
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240528165711-19b9064a1d7e
github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772
github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000
github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c
Expand Down
4 changes: 2 additions & 2 deletions core/scripts/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1185,8 +1185,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq
github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE=
github.com/smartcontractkit/chainlink-automation v1.0.3 h1:h/ijT0NiyV06VxYVgcNfsE3+8OEzT3Q0Z9au0z1BPWs=
github.com/smartcontractkit/chainlink-automation v1.0.3/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240528141639-92c521695f6f h1:k9F/a9kF1kknZ04mYTMstHHZ9DgOIifGRkRgm2T+sEc=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240528141639-92c521695f6f/go.mod h1:DUZccDEW98n+J1mhdWGO7wr/Njad9p9Fzks839JN7Rs=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240528165711-19b9064a1d7e h1:+lMjCyABWYAEr0ueTKheYHe9YbUx27UP+zpUOi+7Jz4=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240528165711-19b9064a1d7e/go.mod h1:DUZccDEW98n+J1mhdWGO7wr/Njad9p9Fzks839JN7Rs=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d h1:5tgMC5Gi2UAOKZ+m28W8ubjLeR0pQCAcrz6eQ0rW510=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d/go.mod h1:0UNuO3nDt9MFsZPaHJBEUolxVkN0iC69j1ccDp95e8k=
github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo=
Expand Down
51 changes: 41 additions & 10 deletions core/services/relay/evm/chain_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package evm

import (
"context"
"errors"
"fmt"
"reflect"
"strings"
Expand All @@ -12,12 +13,14 @@ import (

"github.com/smartcontractkit/chainlink-common/pkg/codec"
"github.com/smartcontractkit/chainlink-common/pkg/types/query"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"

commonservices "github.com/smartcontractkit/chainlink-common/pkg/services"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"

evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
Expand Down Expand Up @@ -207,17 +210,23 @@ func (cr *chainReader) addEvent(contractName, eventName string, a abi.ABI, chain
return err
}

confirmations, err := confirmationsFromConfig(chainReaderDefinition.ConfidenceConfirmations)
if err != nil {
return err
}

eb := &eventBinding{
contractName: contractName,
eventName: eventName,
lp: cr.lp,
hash: event.ID,
inputInfo: inputInfo,
inputModifier: inputModifier,
codecTopicInfo: codecTopicInfo,
topics: make(map[string]topicDetail),
eventDataWords: chainReaderDefinition.GenericDataWordNames,
id: wrapItemType(contractName, eventName, false) + uuid.NewString(),
contractName: contractName,
eventName: eventName,
lp: cr.lp,
hash: event.ID,
inputInfo: inputInfo,
inputModifier: inputModifier,
codecTopicInfo: codecTopicInfo,
topics: make(map[string]topicDetail),
eventDataWords: chainReaderDefinition.GenericDataWordNames,
id: wrapItemType(contractName, eventName, false) + uuid.NewString(),
confirmationsMapping: confirmations,
}

cr.contractBindings.AddReadBinding(contractName, eventName, eb)
Expand Down Expand Up @@ -328,3 +337,25 @@ func setupEventInput(event abi.Event, def types.ChainReaderDefinition) ([]abi.Ar

return filterArgs, types.NewCodecEntry(inputArgs, nil, nil), indexArgNames
}

func confirmationsFromConfig(values map[string]int) (map[primitives.ConfidenceLevel]evmtypes.Confirmations, error) {
mappings := map[primitives.ConfidenceLevel]evmtypes.Confirmations{
primitives.Unconfirmed: evmtypes.Unconfirmed,
primitives.Finalized: evmtypes.Finalized,
}

if values == nil {
return mappings, nil
}

for key, mapped := range values {
mappings[primitives.ConfidenceLevel(key)] = evmtypes.Confirmations(mapped)
}

if mappings[primitives.Finalized] != evmtypes.Finalized &&
mappings[primitives.Finalized] > mappings[primitives.Unconfirmed] {
return nil, errors.New("finalized confidence level should map to -1 or a higher value than 0")
}

return mappings, nil
}
16 changes: 10 additions & 6 deletions core/services/relay/evm/chain_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,13 @@ func (it *chainReaderInterfaceTester) Setup(t *testing.T) {
OutputModifications: codec.ModifiersConfig{
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}},
},
ConfidenceConfirmations: map[string]int{"0.0": 0, "1.0": -1},
},
EventWithFilterName: {
ChainSpecificName: "Triggered",
ReadType: types.Event,
EventInputFields: []string{"Field"},
ChainSpecificName: "Triggered",
ReadType: types.Event,
EventInputFields: []string{"Field"},
ConfidenceConfirmations: map[string]int{"0.0": 0, "1.0": -1},
},
triggerWithDynamicTopic: {
ChainSpecificName: triggerWithDynamicTopic,
Expand All @@ -205,11 +207,13 @@ func (it *chainReaderInterfaceTester) Setup(t *testing.T) {
InputModifications: codec.ModifiersConfig{
&codec.RenameModifierConfig{Fields: map[string]string{"FieldHash": "Field"}},
},
ConfidenceConfirmations: map[string]int{"0.0": 0, "1.0": -1},
},
triggerWithAllTopics: {
ChainSpecificName: triggerWithAllTopics,
ReadType: types.Event,
EventInputFields: []string{"Field1", "Field2", "Field3"},
ChainSpecificName: triggerWithAllTopics,
ReadType: types.Event,
EventInputFields: []string{"Field1", "Field2", "Field3"},
ConfidenceConfirmations: map[string]int{"0.0": 0, "1.0": -1},
},
MethodReturningSeenStruct: {
ChainSpecificName: "returnSeen",
Expand Down
Loading

0 comments on commit 4c2c6a6

Please sign in to comment.