-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Change Confirmations to Confidence #12987
Conversation
I see you updated files related to
|
d370744
to
41acae7
Compare
41acae7
to
3cbb81a
Compare
07c9165
to
610c769
Compare
25b5a5b
to
a9eb077
Compare
core/chains/evm/logpoller/parser.go
Outdated
return fmt.Sprintf("LIMIT %d", limiter.Limit.Count) | ||
} | ||
|
||
func (v *pgDSLParser) getLastExpression() (string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I think I have mentioned that in a previous PR, but I believe reusing this instance doesn't give us much value, but can lead to major isues. I'm not an expert when it comes to Go GC, but most of the collectors are blazingly fast and optimized for short-living objects, memory footprint shouldn't be the case here. It would be safer to always create a new pgDSLParser
on every query parsing.
For instance, you can have multiple threads (e.g. plugin) running LogPoller read queries, when reusing the same pgDSLParser instance it's not gonna work. I believe you should be able to write a concurrent test that spawns multiple routines calling FilteredLogs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good callout. I'll test concurrency and maybe the best path forward is to benchmark both options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran some quick benchmarks on both options with a query containing nested expressions. The benchmark was run with the command go test -bench=BenchmarkParser -benchtime=10s -benchmem
each time.
wordFilter := NewEventByWordFilter(common.HexToHash("0x42"), 8, []primitives.ValueComparator{
{Value: "a", Operator: primitives.Gt},
{Value: "b", Operator: primitives.Lte},
})
expressions := []query.Expression{
{BoolExpression: query.BoolExpression{
Expressions: []query.Expression{
query.Timestamp(10, primitives.Eq),
{BoolExpression: query.BoolExpression{
Expressions: []query.Expression{
query.TxHash(common.HexToHash("0x84").Hex()),
{BoolExpression: query.BoolExpression{
Expressions: []query.Expression{
query.Confirmation(primitives.Unconfirmed),
wordFilter,
},
BoolOperator: query.AND,
}},
},
BoolOperator: query.OR,
}},
},
BoolOperator: query.AND,
}},
}
No changes to pgDSLParser
. The expression and err are reset for each build of an expression.
goos: darwin
goarch: arm64
pkg: github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller
BenchmarkParser-10 3622035 3270 ns/op 5600 B/op 81 allocs/op
PASS
ok github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller 20.203s
Split pgDSLVistor
from pgDSLParser
and created a new visitor instance for each expression in the build loop.
goos: darwin
goarch: arm64
pkg: github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller
BenchmarkParser-10 3278098 4672 ns/op 5744 B/op 84 allocs/op
PASS
ok github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller 38.635s
I don't see a huge difference between the two, but there does appear to still be some time loss on allocations.
core/chains/evm/logpoller/parser.go
Outdated
v.expression = "" | ||
v.err = nil | ||
|
||
return exp, err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For debugging purposes, it could be worth logging what expression was built. However, maybe in the ORM, not the parser itself
core/chains/evm/logpoller/parser.go
Outdated
} | ||
} | ||
|
||
func valuesFromCursor(cursor string) (int64, string, int, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some godoc or tests showing the expected cursor format would be very helpful here
|
||
func (e *eventBinding) confirmationsFrom(confidence primitives.ConfidenceLevel) int { | ||
// sort highest to lowest on confidence | ||
sort.Slice(e.confidenceSteps, func(i, j int) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to sort that slice on every call? We should sort it on-write, right? When e.confidenceSteps
is initialized you can just sort it once.
} | ||
|
||
// return default of 0 if step doesn't exist | ||
return 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't that be an error? If step doesn't exist then someone is trying to do something that is not supported and might be not aware of that because code silently fallbacks to 0
179ac48
to
197e35b
Compare
610c769
to
947ca18
Compare
39abe02
to
7d4d24a
Compare
3e99497
to
9aae059
Compare
Quality Gate passedIssues Measures |
Confidence
is a different approach to mapping a chain agnostic concept of confidence thatan event or transaction can or should be acted on.
Confidence
is intended to map to definedlevels of confirmations on EVM chains and other states on other chains.
Only two levels of
Confidence
exist by default to define the boundaries:Highest
andLowest
. This creates an inclusive range for all chain configurableConfidence
levels andcan be treated as % confidence that an event or transaction can or should be acted on.