2022-06-29 15:44:08 +00:00
|
|
|
# Nimbus
|
2023-12-08 09:35:50 +00:00
|
|
|
# Copyright (c) 2022-2023 Status Research & Development GmbH
|
2022-06-29 15:44:08 +00:00
|
|
|
# Licensed and distributed under either of
|
|
|
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
|
|
|
import
|
|
|
|
std/options,
|
2022-09-03 18:15:35 +00:00
|
|
|
eth/common/[eth_types, eth_types_rlp],
|
2022-06-29 15:44:08 +00:00
|
|
|
eth/bloom as bFilter,
|
|
|
|
stint,
|
2023-12-08 09:35:50 +00:00
|
|
|
../beacon/web3_eth_conv,
|
|
|
|
./rpc_types
|
2022-06-29 15:44:08 +00:00
|
|
|
|
2022-09-03 18:15:35 +00:00
|
|
|
export rpc_types
|
|
|
|
|
2023-12-08 09:35:50 +00:00
|
|
|
type
|
|
|
|
BlockHeader = eth_types.BlockHeader
|
|
|
|
Hash256 = eth_types.Hash256
|
|
|
|
|
2023-01-31 01:32:17 +00:00
|
|
|
{.push raises: [].}
|
|
|
|
|
2023-12-08 09:35:50 +00:00
|
|
|
proc topicToDigest(t: seq[eth_types.Topic]): seq[Web3Topic] =
|
|
|
|
var resSeq: seq[Web3Topic] = @[]
|
2022-06-29 15:44:08 +00:00
|
|
|
for top in t:
|
2023-12-08 09:35:50 +00:00
|
|
|
let ht = Web3Topic(top)
|
2022-06-29 15:44:08 +00:00
|
|
|
resSeq.add(ht)
|
|
|
|
return resSeq
|
|
|
|
|
2023-12-08 09:35:50 +00:00
|
|
|
func ethTopics(topics: openArray[Option[seq[Web3Hash]]]): seq[Option[seq[Hash256]]] =
|
|
|
|
for x in topics:
|
|
|
|
if x.isSome:
|
|
|
|
result.add some(ethHashes(x.get))
|
|
|
|
else:
|
|
|
|
result.add none(seq[Hash256])
|
|
|
|
|
2022-06-29 15:44:08 +00:00
|
|
|
proc deriveLogs*(header: BlockHeader, transactions: seq[Transaction], receipts: seq[Receipt]): seq[FilterLog] =
|
|
|
|
## Derive log fields, does not deal with pending log, only the logs with
|
|
|
|
## full data set
|
|
|
|
doAssert(len(transactions) == len(receipts))
|
|
|
|
|
|
|
|
var resLogs: seq[FilterLog] = @[]
|
|
|
|
var logIndex = 0
|
|
|
|
|
|
|
|
for i, receipt in receipts:
|
|
|
|
for log in receipt.logs:
|
|
|
|
let filterLog = FilterLog(
|
|
|
|
# TODO investigate how to handle this field
|
|
|
|
# - in nimbus info about log removel would need to be kept at synchronization
|
|
|
|
# level, to keep track about potential re-orgs
|
|
|
|
# - in fluffy there is no concept of re-org
|
|
|
|
removed: false,
|
2023-12-08 09:35:50 +00:00
|
|
|
logIndex: some(w3Qty(logIndex)),
|
|
|
|
transactionIndex: some(w3Qty(i)),
|
|
|
|
transactionHash: some(w3Hash transactions[i].rlpHash),
|
|
|
|
blockHash: some(w3Hash header.blockHash),
|
|
|
|
blockNumber: some(w3Qty(header.blockNumber.truncate(uint64))),
|
|
|
|
address: w3Addr log.address,
|
2022-06-29 15:44:08 +00:00
|
|
|
data: log.data,
|
|
|
|
# TODO topics should probably be kept as Hash256 in receipts
|
|
|
|
topics: topicToDigest(log.topics)
|
|
|
|
)
|
|
|
|
|
|
|
|
inc logIndex
|
|
|
|
resLogs.add(filterLog)
|
|
|
|
|
|
|
|
return resLogs
|
|
|
|
|
|
|
|
proc bloomFilter*(
|
|
|
|
bloom: eth_types.BloomFilter,
|
|
|
|
addresses: seq[EthAddress],
|
|
|
|
topics: seq[Option[seq[Hash256]]]): bool =
|
|
|
|
|
|
|
|
let bloomFilter = bFilter.BloomFilter(value: StUint[2048].fromBytesBE(bloom))
|
|
|
|
|
|
|
|
if len(addresses) > 0:
|
|
|
|
var addrIncluded: bool = false
|
|
|
|
for address in addresses:
|
|
|
|
if bloomFilter.contains(address):
|
|
|
|
addrIncluded = true
|
|
|
|
break
|
|
|
|
if not addrIncluded:
|
|
|
|
return false
|
|
|
|
|
|
|
|
for sub in topics:
|
|
|
|
|
|
|
|
if sub.isNone():
|
|
|
|
# catch all wildcard
|
|
|
|
continue
|
|
|
|
|
|
|
|
let subTops = sub.unsafeGet()
|
|
|
|
var topicIncluded = len(subTops) == 0
|
|
|
|
for topic in subTops:
|
|
|
|
# This is is quite not obvious, but passing topic as MDigest256 fails, as
|
|
|
|
# it does not use internal keccak256 hashing. To achieve desired semantics,
|
|
|
|
# we need use digest bare bytes so that they will be properly kec256 hashes
|
|
|
|
if bloomFilter.contains(topic.data):
|
|
|
|
topicIncluded = true
|
|
|
|
break
|
|
|
|
|
|
|
|
if not topicIncluded:
|
|
|
|
return false
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
proc headerBloomFilter*(
|
|
|
|
header: BlockHeader,
|
|
|
|
addresses: seq[EthAddress],
|
|
|
|
topics: seq[Option[seq[Hash256]]]): bool =
|
|
|
|
return bloomFilter(header.bloom, addresses, topics)
|
|
|
|
|
2023-12-08 09:35:50 +00:00
|
|
|
proc headerBloomFilter*(
|
|
|
|
header: BlockHeader,
|
|
|
|
addresses: seq[Web3Address],
|
|
|
|
topics: seq[Option[seq[Web3Hash]]]): bool =
|
|
|
|
headerBloomFilter(header, addresses.ethAddrs, topics.ethTopics)
|
|
|
|
|
2022-06-29 15:44:08 +00:00
|
|
|
proc matchTopics(log: FilterLog, topics: seq[Option[seq[Hash256]]]): bool =
|
|
|
|
for i, sub in topics:
|
|
|
|
|
|
|
|
if sub.isNone():
|
|
|
|
# null subtopic i.e it matches all possible move to nex
|
|
|
|
continue
|
|
|
|
|
|
|
|
let subTops = sub.unsafeGet()
|
|
|
|
|
|
|
|
# treat empty as wildcard, although caller should rather use none kind of
|
|
|
|
# option to indicate that. If nim would have NonEmptySeq type that would be
|
|
|
|
# use case for it.
|
|
|
|
var match = len(subTops) == 0
|
|
|
|
|
|
|
|
for topic in subTops:
|
2023-12-08 09:35:50 +00:00
|
|
|
if log.topics[i].ethHash == topic:
|
2022-06-29 15:44:08 +00:00
|
|
|
match = true
|
|
|
|
break
|
|
|
|
|
|
|
|
if not match:
|
|
|
|
return false
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
proc filterLogs*(
|
|
|
|
logs: openArray[FilterLog],
|
|
|
|
addresses: seq[EthAddress],
|
|
|
|
topics: seq[Option[seq[Hash256]]]): seq[FilterLog] =
|
|
|
|
|
|
|
|
var filteredLogs: seq[FilterLog] = newSeq[FilterLog]()
|
|
|
|
|
|
|
|
for log in logs:
|
2023-12-08 09:35:50 +00:00
|
|
|
if len(addresses) > 0 and (not addresses.contains(log.address.ethAddr)):
|
2022-06-29 15:44:08 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
if len(topics) > len(log.topics):
|
|
|
|
continue
|
|
|
|
|
|
|
|
if not matchTopics(log, topics):
|
|
|
|
continue
|
|
|
|
|
|
|
|
filteredLogs.add(log)
|
|
|
|
|
|
|
|
return filteredLogs
|
2023-12-08 09:35:50 +00:00
|
|
|
|
|
|
|
proc filterLogs*(
|
|
|
|
logs: openArray[FilterLog],
|
|
|
|
addresses: seq[Web3Address],
|
|
|
|
topics: seq[Option[seq[Web3Hash]]]): seq[FilterLog] =
|
|
|
|
filterLogs(logs, addresses.ethAddrs, topics.ethTopics)
|