support null topics and topic position in logs filter (#649)

This commit is contained in:
a10zn8
2025-04-04 17:09:08 +03:00
committed by GitHub
parent 6744e2241c
commit 9ca2c921b5
4 changed files with 55 additions and 20 deletions

View File

@@ -72,7 +72,7 @@ open class EthereumEgressSubscription(
data class LogsRequest(
val address: List<Address>,
val topics: List<Hex32>,
val topics: List<Hex32?>,
)
fun readLogsRequest(params: Map<String, Any?>): LogsRequest {
@@ -98,7 +98,7 @@ open class EthereumEgressSubscription(
} else {
emptyList()
}
val topics: List<Hex32> = if (params.containsKey("topics")) {
val topics: List<Hex32?> = if (params.containsKey("topics")) {
when (val topics = params["topics"]) {
is String -> try {
listOf(Hex32.from(topics))
@@ -106,15 +106,16 @@ open class EthereumEgressSubscription(
log.debug("Ignore invalid topic: $topics with error ${t.message}")
emptyList()
}
is Collection<*> -> topics.mapNotNull { topic ->
is Collection<*> -> topics.map { topic ->
try {
when (topic) {
null -> null
is Collection<*> -> topic.firstOrNull()?.toString()?.let { Hex32.from(it) }
else -> topic?.toString()?.let { Hex32.from(it) }
}
} catch (t: Throwable) {
log.debug("Ignore invalid topic: $topic with error ${t.message}")
null
throw IllegalArgumentException("Invalid topic: $topic")
}
}
null -> emptyList()

View File

@@ -44,7 +44,7 @@ open class ConnectLogs(
return produceLogs.produce(connectBlockUpdates.connect(matcher))
}
open fun create(addresses: List<Address>, topics: List<Hex32>): SubscriptionConnect<LogMessage> {
open fun create(addresses: List<Address>, topics: List<Hex32?>): SubscriptionConnect<LogMessage> {
return object : SubscriptionConnect<LogMessage> {
override fun connect(matcher: Selector.Matcher): Flux<LogMessage> {
// shortcut to the whole output if we don't have any filters
@@ -58,22 +58,17 @@ open class ConnectLogs(
}
}
fun filtered(addresses: List<Address>, topics: List<Hex32>): Function<Flux<LogMessage>, Flux<LogMessage>> {
fun filtered(addresses: List<Address>, selectedTopics: List<Hex32?>): Function<Flux<LogMessage>, Flux<LogMessage>> {
// sort search criteria to use binary search later
val sortedAddresses: List<Address> = addresses.sortedWith(ADDR_COMPARATOR)
val sortedTopics: List<Hex32> = topics.sortedWith(TOPIC_COMPARATOR)
return Function { logs ->
logs.filter {
val goodAddress =
sortedAddresses.isEmpty() || sortedAddresses.binarySearch(it.address, ADDR_COMPARATOR) >= 0
val goodTopic = when {
sortedTopics.isEmpty() -> true
it.topics.size < sortedTopics.size -> false
else -> sortedTopics.indices.all { index ->
it.topics[index].let { logTopic ->
sortedTopics.binarySearch(logTopic, TOPIC_COMPARATOR) >= 0
}
}
selectedTopics.isEmpty() -> true
it.topics.size < selectedTopics.size -> false
else -> selectedTopics.zip(it.topics).all { (selectedTopic, logTopic) -> selectedTopic == null || selectedTopic == logTopic }
}
goodAddress && goodTopic
}