diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go
index c30927d9ff..95239bd640 100644
--- a/cmd/geth/chaincmd.go
+++ b/cmd/geth/chaincmd.go
@@ -100,6 +100,9 @@ if one is set. Otherwise it prints the genesis from the datadir.`,
utils.VMTraceFlag,
utils.VMTraceJsonConfigFlag,
utils.TransactionHistoryFlag,
+ utils.LogHistoryFlag,
+ utils.LogNoHistoryFlag,
+ utils.LogExportCheckpointsFlag,
utils.StateHistoryFlag,
}, utils.DatabaseFlags),
Description: `
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index fd3f4e1bab..2995d87624 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -87,6 +87,9 @@ var (
utils.TxLookupLimitFlag, // deprecated
utils.TransactionHistoryFlag,
utils.ChainHistoryFlag,
+ utils.LogHistoryFlag,
+ utils.LogNoHistoryFlag,
+ utils.LogExportCheckpointsFlag,
utils.StateHistoryFlag,
utils.LightServeFlag, // deprecated
utils.LightIngressFlag, // deprecated
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 06eabbf313..2e3bb6aead 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -278,6 +278,23 @@ var (
Value: ethconfig.Defaults.HistoryMode.String(),
Category: flags.StateCategory,
}
+ LogHistoryFlag = &cli.Uint64Flag{
+ Name: "history.logs",
+ Usage: "Number of recent blocks to maintain log search index for (default = about one year, 0 = entire chain)",
+ Value: ethconfig.Defaults.LogHistory,
+ Category: flags.StateCategory,
+ }
+ LogNoHistoryFlag = &cli.BoolFlag{
+ Name: "history.logs.disable",
+ Usage: "Do not maintain log search index",
+ Category: flags.StateCategory,
+ }
+ LogExportCheckpointsFlag = &cli.StringFlag{
+ Name: "history.logs.export",
+ Usage: "Export checkpoints to file in go source file format",
+ Category: flags.StateCategory,
+ Value: "",
+ }
// Beacon client light sync settings
BeaconApiFlag = &cli.StringSliceFlag{
Name: "beacon.api",
@@ -1636,6 +1653,15 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
cfg.StateScheme = rawdb.HashScheme
log.Warn("Forcing hash state-scheme for archive mode")
}
+ if ctx.IsSet(LogHistoryFlag.Name) {
+ cfg.LogHistory = ctx.Uint64(LogHistoryFlag.Name)
+ }
+ if ctx.IsSet(LogNoHistoryFlag.Name) {
+ cfg.LogNoHistory = true
+ }
+ if ctx.IsSet(LogExportCheckpointsFlag.Name) {
+ cfg.LogExportCheckpoints = ctx.String(LogExportCheckpointsFlag.Name)
+ }
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) {
cfg.TrieCleanCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100
}
diff --git a/common/range.go b/common/range.go
new file mode 100644
index 0000000000..c3a26ea7f5
--- /dev/null
+++ b/common/range.go
@@ -0,0 +1,115 @@
+// Copyright 2025 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package common
+
+import (
+ "iter"
+)
+
+// Range represents a range of integers.
+type Range[T uint32 | uint64] struct {
+ first, afterLast T
+}
+
+// NewRange creates a new range based of first element and number of elements.
+func NewRange[T uint32 | uint64](first, count T) Range[T] {
+ return Range[T]{first, first + count}
+}
+
+// First returns the first element of the range.
+func (r Range[T]) First() T {
+ return r.first
+}
+
+// Last returns the last element of the range. This panics for empty ranges.
+func (r Range[T]) Last() T {
+ if r.first == r.afterLast {
+ panic("last item of zero length range is not allowed")
+ }
+ return r.afterLast - 1
+}
+
+// AfterLast returns the first element after the range. This allows obtaining
+// information about the end part of zero length ranges.
+func (r Range[T]) AfterLast() T {
+ return r.afterLast
+}
+
+// Count returns the number of elements in the range.
+func (r Range[T]) Count() T {
+ return r.afterLast - r.first
+}
+
+// IsEmpty returns true if the range is empty.
+func (r Range[T]) IsEmpty() bool {
+ return r.first == r.afterLast
+}
+
+// Includes returns true if the given element is inside the range.
+func (r Range[T]) Includes(v T) bool {
+ return v >= r.first && v < r.afterLast
+}
+
+// SetFirst updates the first element of the list.
+func (r *Range[T]) SetFirst(v T) {
+ r.first = v
+ if r.afterLast < r.first {
+ r.afterLast = r.first
+ }
+}
+
+// SetAfterLast updates the end of the range by specifying the first element
+// after the range. This allows setting zero length ranges.
+func (r *Range[T]) SetAfterLast(v T) {
+ r.afterLast = v
+ if r.afterLast < r.first {
+ r.first = r.afterLast
+ }
+}
+
+// SetLast updates last element of the range.
+func (r *Range[T]) SetLast(v T) {
+ r.SetAfterLast(v + 1)
+}
+
+// Intersection returns the intersection of two ranges.
+func (r Range[T]) Intersection(q Range[T]) Range[T] {
+ i := Range[T]{first: max(r.first, q.first), afterLast: min(r.afterLast, q.afterLast)}
+ if i.first > i.afterLast {
+ return Range[T]{}
+ }
+ return i
+}
+
+// Union returns the union of two ranges. Panics for gapped ranges.
+func (r Range[T]) Union(q Range[T]) Range[T] {
+ if max(r.first, q.first) > min(r.afterLast, q.afterLast) {
+ panic("cannot create union; gap between ranges")
+ }
+ return Range[T]{first: min(r.first, q.first), afterLast: max(r.afterLast, q.afterLast)}
+}
+
+// Iter iterates all integers in the range.
+func (r Range[T]) Iter() iter.Seq[T] {
+ return func(yield func(T) bool) {
+ for i := r.first; i < r.afterLast; i++ {
+ if !yield(i) {
+ break
+ }
+ }
+ }
+}
diff --git a/common/range_test.go b/common/range_test.go
new file mode 100644
index 0000000000..878b6d66c8
--- /dev/null
+++ b/common/range_test.go
@@ -0,0 +1,36 @@
+// Copyright 2025 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package common
+
+import (
+ "slices"
+ "testing"
+)
+
+func TestRangeIter(t *testing.T) {
+ r := NewRange[uint32](1, 7)
+ values := slices.Collect(r.Iter())
+ if !slices.Equal(values, []uint32{1, 2, 3, 4, 5, 6, 7}) {
+ t.Fatalf("wrong iter values: %v", values)
+ }
+
+ empty := NewRange[uint32](1, 0)
+ values = slices.Collect(empty.Iter())
+ if !slices.Equal(values, []uint32{}) {
+ t.Fatalf("wrong iter values: %v", values)
+ }
+}
diff --git a/core/filtermaps/checkpoints_holesky.json b/core/filtermaps/checkpoints_holesky.json
index c30856db4f..b8f6be9caf 100644
--- a/core/filtermaps/checkpoints_holesky.json
+++ b/core/filtermaps/checkpoints_holesky.json
@@ -1,20 +1,21 @@
[
-{"blockNumber": 814411, "blockId": "0xf763e96fc3920359c5f706803024b78e83796a3a8563bb5a83c3ddd7cbfde287", "firstIndex": 67107637},
-{"blockNumber": 914278, "blockId": "0x0678cf8d53c0d6d27896df657d98cc73bc63ca468b6295068003938ef9b0f927", "firstIndex": 134217671},
-{"blockNumber": 1048874, "blockId": "0x3620c3d52a40ff4d9fc58c3104cfa2f327f55592caf6a2394c207a5e00b4f740", "firstIndex": 201326382},
-{"blockNumber": 1144441, "blockId": "0x438fb42850f5a0d8e1666de598a4d0106b62da0f7448c62fe029b8cbad35d08d", "firstIndex": 268435440},
-{"blockNumber": 1230411, "blockId": "0xf0ee07e60a93910723b259473a253dd9cf674e8b78c4f153b32ad7032efffeeb", "firstIndex": 335543079},
-{"blockNumber": 1309112, "blockId": "0xc1646e5ef4b4343880a85b1a4111e3321d609a1225e9cebbe10d1c7abf99e58d", "firstIndex": 402653100},
-{"blockNumber": 1380522, "blockId": "0x1617cae91989d97ac6335c4217aa6cc7f7f4c2837e20b3b5211d98d6f9e97e44", "firstIndex": 469761917},
-{"blockNumber": 1476962, "blockId": "0xd978455d2618d093dfc685d7f43f61be6dae0fa8a9cb915ae459aa6e0a5525f0", "firstIndex": 536870773},
-{"blockNumber": 1533518, "blockId": "0xe7d39d71bd9d5f1f3157c35e0329531a7950a19e3042407e38948b89b5384f78", "firstIndex": 603979664},
-{"blockNumber": 1613787, "blockId": "0xa793168d135c075732a618ec367faaed5f359ffa81898c73cb4ec54ec2caa696", "firstIndex": 671088003},
-{"blockNumber": 1719099, "blockId": "0xc4394c71a8a24efe64c5ff2afcdd1594f3708524e6084aa7dadd862bd704ab03", "firstIndex": 738196914},
-{"blockNumber": 1973165, "blockId": "0xee3a9e959a437c707a3036736ec8d42a9261ac6100972c26f65eedcde315a81d", "firstIndex": 805306333},
-{"blockNumber": 2274844, "blockId": "0x76e2d33653ed9282c63ad09d721e1f2e29064aa9c26202e20fc4cc73e8dfe5f6", "firstIndex": 872415141},
-{"blockNumber": 2530503, "blockId": "0x59f4e45345f8b8f848be5004fe75c4a28f651864256c3aa9b2da63369432b718", "firstIndex": 939523693},
-{"blockNumber": 2781903, "blockId": "0xc981e91c6fb69c5e8146ead738fcfc561831f11d7786d39c7fa533966fc37675", "firstIndex": 1006632906},
-{"blockNumber": 3101713, "blockId": "0xc7baa577c91d8439e3fc79002d2113d07ca54a4724bf2f1f5af937b7ba8e1f32", "firstIndex": 1073741382},
-{"blockNumber": 3221770, "blockId": "0xa6b8240b7883fcc71aa5001b5ba66c889975c5217e14c16edebdd6f6e23a9424", "firstIndex": 1140850360}
+{"blockNumber": 814410, "blockId": "0x6c38f0d4ff2c23ae187f581cebb0963c0ec2dbf051b289de1582c369c98a3244", "firstIndex": 67107349},
+{"blockNumber": 914268, "blockId": "0xeff161573a11eb6e2ab930674a5245b2c5ffc5e9e63093503344ec6fa60578a3", "firstIndex": 134216064},
+{"blockNumber": 1048866, "blockId": "0xebd3b95415dad9ab7f2b1d25e48c791e299063c09427bbde54217029c3e215ad", "firstIndex": 201325914},
+{"blockNumber": 1144433, "blockId": "0x0c895438ef12a2c835b4372c209e40a499ba2b18ed0e658846813784de391392", "firstIndex": 268434935},
+{"blockNumber": 1230406, "blockId": "0xd3512e7241efc9853e46b1ad565403d302f62457b6dd84917c31ff375fabf487", "firstIndex": 335544096},
+{"blockNumber": 1309104, "blockId": "0xcf108c6e002e7a5657bf7587adde03edf5f20d03e95b66a194eb8080daaf4f97", "firstIndex": 402653143},
+{"blockNumber": 1380499, "blockId": "0x984b0f8b6bf06f1240bbca8c1df9bef3880bedafd5b5c2a55cbc2f64c9efb974", "firstIndex": 469759822},
+{"blockNumber": 1476950, "blockId": "0x8323b528bb8d80a96b172de92452be0f45078a9ca311cb4be6675f089e25a426", "firstIndex": 536870335},
+{"blockNumber": 1533506, "blockId": "0x737dc416070aa3b522a0c2ab813a70c1820f062c718f27597394f309f0004106", "firstIndex": 603979618},
+{"blockNumber": 1613764, "blockId": "0x9d6a5a505afdda86b1ebcc2b10cb687a1f89c2e2b74315945a3ddc6a0b3c9cd6", "firstIndex": 671088253},
+{"blockNumber": 1719073, "blockId": "0x17bf6a51d9c55a908c3e9e652f80b2aa464b049c697abf3bd5a537e461aff0b9", "firstIndex": 738197366},
+{"blockNumber": 1973133, "blockId": "0x14b288d70e688de3334d09283670301aacfed21c193da8a56fd63767f8177705", "firstIndex": 805305624},
+{"blockNumber": 2274761, "blockId": "0xf02790b273b04219e001d2fcc93e8e47708cb228364e96ad754bc8050d08a9aa", "firstIndex": 872414871},
+{"blockNumber": 2530470, "blockId": "0x157ea98b1a7e66dd3f045da8e25219800671f9a000211d3d94006efd33d89a80", "firstIndex": 939523234},
+{"blockNumber": 2781706, "blockId": "0xa723663a584e280700d2302eba03d1b3b6549333db70c6152576d33e2911f594", "firstIndex": 1006632936},
+{"blockNumber": 3101669, "blockId": "0xa6e66a18fed64d33178c7088f273c404be597662c34f6e6884cf2e24f3ea4ace", "firstIndex": 1073741353},
+{"blockNumber": 3221725, "blockId": "0xe771f897dece48b1583cc1d1d10de8015da57407eb1fdf239fdbe46eaab85143", "firstIndex": 1140850137},
+{"blockNumber": 3357164, "blockId": "0x6252d0aa54c79623b0680069c88d7b5c47983f0d5c4845b6c811b8d9b5e8ff3c", "firstIndex": 1207959453},
+{"blockNumber": 3447019, "blockId": "0xeb7d585e1e063f3cc05ed399fbf6c2df63c271f62f030acb804e9fb1e74b6dc1", "firstIndex": 1275067542}
]
-
diff --git a/core/filtermaps/checkpoints_mainnet.json b/core/filtermaps/checkpoints_mainnet.json
index d2b031a474..ca30280e03 100644
--- a/core/filtermaps/checkpoints_mainnet.json
+++ b/core/filtermaps/checkpoints_mainnet.json
@@ -1,256 +1,264 @@
[
-{"blockNumber": 4166218, "blockId": "0xdd767e0426256179125551e8e40f33565a96d1c94076c7746fa79d767ed4ad65", "firstIndex": 67108680},
-{"blockNumber": 4514014, "blockId": "0x33a0879bdabea4a7a3f2b424388cbcbf2fbd519bddadf13752a259049c78e95d", "firstIndex": 134217343},
-{"blockNumber": 4817415, "blockId": "0x4f0e8c7dd04fbe0985b9394575b19f13ea66a2a628fa5b08178ce4b138c6db80", "firstIndex": 201326352},
-{"blockNumber": 5087733, "blockId": "0xc84cd5e9cda999c919803c7a53a23bb77a18827fbde401d3463f1e9e52536424", "firstIndex": 268435343},
-{"blockNumber": 5306107, "blockId": "0x13f028b5fc055d23f55a92a2eeecfbcfbda8a08e4cd519ce451ba2e70428f5f9", "firstIndex": 335544094},
-{"blockNumber": 5509918, "blockId": "0x1ed770a58a7b4d4a828b7bb44c8820a674d562b23a6a0139981abe4c489d4dad", "firstIndex": 402652853},
-{"blockNumber": 5670390, "blockId": "0x3923ee6a62e6cc5132afdadf1851ae4e73148e6fbe0a8319cafd2a120c98efa3", "firstIndex": 469761897},
-{"blockNumber": 5826139, "blockId": "0xe61bc6ef03c333805f26319e1688f82553f98aa5e902b200e0621a3371b69050", "firstIndex": 536870853},
-{"blockNumber": 5953029, "blockId": "0x43d710b1b7243b848400975048ccefdfaba091c692c7f01c619d988886cc160f", "firstIndex": 603979580},
-{"blockNumber": 6102846, "blockId": "0xa100b2018f6545cc689656b4b846677b138955b7efd30e850cd14c246430ba18", "firstIndex": 671088291},
-{"blockNumber": 6276718, "blockId": "0xb832ac448b06c104ba50faefd58b0b94d53c0fba5cb268086adad4db99c2f35f", "firstIndex": 738197399},
-{"blockNumber": 6448696, "blockId": "0x48e8ae6f729ad6c76b6cf632bd52a6df7886ed55be09d43c5004fcc1463e533b", "firstIndex": 805305988},
-{"blockNumber": 6655974, "blockId": "0xac395971a6ffc30f807848f68b97b2834f8ea13478a7615860b6a69e3d0823ca", "firstIndex": 872415033},
-{"blockNumber": 6873949, "blockId": "0xc522ddb1113b1e9a87b2bdcb11ce78756beba6454a890122f121a032b5769354", "firstIndex": 939523784},
-{"blockNumber": 7080953, "blockId": "0x3606de577d80120d1edbb64bad7fa6795e788bae342866a98cc58ce2f7575045", "firstIndex": 1006632796},
-{"blockNumber": 7267002, "blockId": "0xad770882a69d216e955e34fef84851e56c0de82deacd6187a7a41f6170cd6c6d", "firstIndex": 1073741045},
-{"blockNumber": 7466708, "blockId": "0x17a48817b3a65aba333a5b56f3ff2e86fbcc19e184b046a5305a5182fdd8eb8a", "firstIndex": 1140850680},
-{"blockNumber": 7661807, "blockId": "0xa74731ee775fbd3f4d9313c68562737dd7c8d2c9eb968791d8abe167e16ddc96", "firstIndex": 1207959112},
-{"blockNumber": 7834556, "blockId": "0xe4b4812448075508cb05a0e3257f91b49509dc78cd963676a633864db6e78956", "firstIndex": 1275068095},
-{"blockNumber": 7990068, "blockId": "0x07bd4ca38abb4584a6209e04035646aa545ebbb6c948d438d4c25bfd9cb205fa", "firstIndex": 1342176620},
-{"blockNumber": 8143032, "blockId": "0x0e3149e9637290b044ee693b8fcb66e23d22db3ad0bdda32962138ba18e59f3f", "firstIndex": 1409285949},
-{"blockNumber": 8297660, "blockId": "0x34cd24f80247f7dfaf316b2e637f4b62f72ecc90703014fb25cb98ad044fc2c0", "firstIndex": 1476394911},
-{"blockNumber": 8465137, "blockId": "0x4452fa296498248d7f10c9dc6ec1e4ae7503aa07f491e6d38b21aea5d2c658a8", "firstIndex": 1543503744},
-{"blockNumber": 8655820, "blockId": "0x7bdb9008b30be420f7152cc294ac6e5328eed5b4abd954a34105de3da24f3cc6", "firstIndex": 1610612619},
-{"blockNumber": 8807187, "blockId": "0xde03e3bfddc722c019f0b59bc55efabcd5ab68c6711f4c08d0390a56f396590d", "firstIndex": 1677721589},
-{"blockNumber": 8911171, "blockId": "0xe44f342de74ab05a2a994f8841bdf88f720b9dc260177ba4030d0f7077901324", "firstIndex": 1744830310},
-{"blockNumber": 8960320, "blockId": "0x79764f9ff6e0fe4848eda1805687872021076e4e603112861af84181395ac559", "firstIndex": 1811938893},
-{"blockNumber": 9085994, "blockId": "0x24a101d1c8a63367a0953d10dc79c3b587a93bd7fd382084708adefce0b8363f", "firstIndex": 1879047965},
-{"blockNumber": 9230924, "blockId": "0xb176a98d3acd855cbb75265fb6be955a8d51abc771e021e13275d5b3ecb07eeb", "firstIndex": 1946156668},
-{"blockNumber": 9390535, "blockId": "0x640f5e2d511a5141878d57ae7a619f19b72a2bd3ef019cf0a22d74d93d9acf07", "firstIndex": 2013265733},
-{"blockNumber": 9515674, "blockId": "0xff4a7b6b21aeaeb6e1a75ecd22b1f34c058a0ce1477ce90a8ce78165fd1d0941", "firstIndex": 2080374553},
-{"blockNumber": 9659426, "blockId": "0xc351455249343b41e9171e183612b68c3c895271c62bd2c53d9e3ab1aa865aa1", "firstIndex": 2147483567},
-{"blockNumber": 9794018, "blockId": "0xde98035b4b7f9449c256239b65c7ff2c0330de44dee190106d0a96fb6f683238", "firstIndex": 2214592213},
-{"blockNumber": 9923840, "blockId": "0x881da313a1e2b6fab58a1d6fa65b5dacfdc9d68a3112a647104955b5233f84e3", "firstIndex": 2281701302},
-{"blockNumber": 10042435, "blockId": "0x451f6459640a6f54e2a535cc3a49cfc469861da3ddc101840ab3aef9e17fa424", "firstIndex": 2348810174},
-{"blockNumber": 10168883, "blockId": "0x5d16ff5adf0df1e4dc810da60af37399ef733be7870f21112b8c2cfff4995dd9", "firstIndex": 2415918783},
-{"blockNumber": 10289554, "blockId": "0x85d5690f15a787c43b9a49e8dd6e324f0b3e0c9796d07c0cfb128e5c168f5488", "firstIndex": 2483027930},
-{"blockNumber": 10386676, "blockId": "0x20f675ea72db448024a8a0b8e3ec180cac37a5910575bc32f8d9f5cdfe3c2649", "firstIndex": 2550136212},
-{"blockNumber": 10479675, "blockId": "0x014abb07acf2330cc78800ca1f564928f2daccca4b389bf5c59f4b840d843ec0", "firstIndex": 2617245218},
-{"blockNumber": 10562661, "blockId": "0xd437607a3f81ce8b7c605e167ce5e52bf8a3e02cdc646997bd0ccc57a50ad7d1", "firstIndex": 2684354520},
-{"blockNumber": 10641508, "blockId": "0x2e8ab6470c29f90ac23dcfc58310f0208f5d0e752a0c7982a77a223eca104082", "firstIndex": 2751462730},
-{"blockNumber": 10717156, "blockId": "0x8820447b6429dd12be603c1c130be532e9db065bb4bc6b2a9d4551794d63789a", "firstIndex": 2818571831},
-{"blockNumber": 10784549, "blockId": "0xc557daab80a7cdc963d62aa881faf3ab1baceff8e027046bcd203e432e0983b3", "firstIndex": 2885680800},
-{"blockNumber": 10848651, "blockId": "0xede1b0de5db6685a6f589096ceb8fccb08d3ff60e8b00a93caa4a775b48e07fc", "firstIndex": 2952789740},
-{"blockNumber": 10909166, "blockId": "0x989db675899d13323006a4d6174557e3c5501c672afd60d8bd902fc98d37e92e", "firstIndex": 3019897599},
-{"blockNumber": 10972902, "blockId": "0x5484050cc2c7d774bc5cd6af1c2ef8c19d1de12dabe25867c9b365924ea10434", "firstIndex": 3087007422},
-{"blockNumber": 11036597, "blockId": "0x1e3686e19056587c385262d5b0a07b3ec04e804c2d59e9aaca1e5876e78f69ae", "firstIndex": 3154116231},
-{"blockNumber": 11102520, "blockId": "0x339cf302fe813cce3bb9318b860dfa8be7f688413f38a6ea1987a1b84d742b4b", "firstIndex": 3221224863},
-{"blockNumber": 11168162, "blockId": "0xc0fa21ea090627610bcac4732dff702633f310cabafc42bc500d3d4805198fe0", "firstIndex": 3288334273},
-{"blockNumber": 11233707, "blockId": "0x491c37a479b8cf22eaa3654ae34c5ddc4627df8c58ca8a6979159e1710428576", "firstIndex": 3355442691},
-{"blockNumber": 11300526, "blockId": "0xb7366d2a24df99002cffe0c9a00959c93ef0dcfc3fd17389e2020bf5caa788eb", "firstIndex": 3422551480},
-{"blockNumber": 11367621, "blockId": "0xce53df5080c5b5238bb7717dfbfd88c2f574cfbb3d91f92b57171a00e9776cd2", "firstIndex": 3489660710},
-{"blockNumber": 11431881, "blockId": "0x2a08ff9c4f6fd152166213d902f0870822429f01d5f90e384ac54a3eac0ceb3a", "firstIndex": 3556768626},
-{"blockNumber": 11497107, "blockId": "0x1f99c6b65f2b1cb06ed1786c6a0274ff1b9eacab6cb729fcd386f10ebbd88123", "firstIndex": 3623878389},
-{"blockNumber": 11560104, "blockId": "0xebe6924817bbdfe52af49667da1376bae5a2994b375d4b996e8ff2683744e37a", "firstIndex": 3690986640},
-{"blockNumber": 11625129, "blockId": "0xbe6eee325329ee2fe632d8576864c29dd1c79bab891dc0a22d5b2ac87618d26e", "firstIndex": 3758095773},
-{"blockNumber": 11690397, "blockId": "0xc28bf55f858ddf5b82d1ceb3b5258b90a9ca34df8863a1c652c4d359f5748fdf", "firstIndex": 3825204492},
-{"blockNumber": 11755087, "blockId": "0x0c10cde6ce1bbe24dc57347fe4aaebc17b7d8e8d7d97e3db573133477f494740", "firstIndex": 3892314051},
-{"blockNumber": 11819674, "blockId": "0x36b694a1776c94e4c6ae4a410931b2086de47a83e437517040e3290ce9afff67", "firstIndex": 3959422445},
-{"blockNumber": 11883358, "blockId": "0x21f447aca9ddf94ed71df9fa3648a12acc2ba603f89f24c4784936864c41945f", "firstIndex": 4026531743},
-{"blockNumber": 11948524, "blockId": "0x71a52b6cce80d3a552b0daa18beb952facf81a89bc7ca769d08ac297f317507a", "firstIndex": 4093640009},
-{"blockNumber": 12013168, "blockId": "0x9a7fb369b8d8cd0edd0d890d636096f20c63abb7eb5798ad1e578cac599e3db8", "firstIndex": 4160748475},
-{"blockNumber": 12078711, "blockId": "0x5de09329413b0c2f58d926f225197552a335ba3d5544d7bdb45e7574f78c9b8d", "firstIndex": 4227858275},
-{"blockNumber": 12143640, "blockId": "0xbeafc0e1e0586f5a95f00f2a796d7df122c79c187aa2d917129297f24b8306bd", "firstIndex": 4294967145},
-{"blockNumber": 12208005, "blockId": "0x052487095cdd4a604808e6c14e30fb68b3fa546d35585b315f287219d38ef77c", "firstIndex": 4362075289},
-{"blockNumber": 12272465, "blockId": "0x82c8a50413bd67a0d6f53b085adcd9ae8c25ecc07ed766fa80297a8dcae63b29", "firstIndex": 4429184610},
-{"blockNumber": 12329418, "blockId": "0x294c147e48d32c217ff3f27a3c8c989f15eee57a911408ec4c28d4f13a36bb3b", "firstIndex": 4496292968},
-{"blockNumber": 12382388, "blockId": "0x8c2555965ff735690d2d94ececc48df4700e079c7b21b8e601a30d4e99bc4b5b", "firstIndex": 4563401809},
-{"blockNumber": 12437052, "blockId": "0x2e38362031f36a0f3394da619dcc03be03c19700594cbd1df84c2c476a87de63", "firstIndex": 4630511012},
-{"blockNumber": 12490026, "blockId": "0x122749c02a55c9c2a1e69068f54b6c1d25419eb743e3553aba91acf1daeadc35", "firstIndex": 4697619920},
-{"blockNumber": 12541747, "blockId": "0xfb9f12aa2902da798ac05fab425434f8c7ce98050d67d416dbb32f98c21f66f7", "firstIndex": 4764728267},
-{"blockNumber": 12597413, "blockId": "0x9a7a399c2904ac8d0fec580550525e7e1a73d8f65f739bf7c05d86e389d0d3f7", "firstIndex": 4831837757},
-{"blockNumber": 12651950, "blockId": "0xb78dcb572cdafb9c4e2f3863ef518a3b2df0cd4f76faa26a423b2ca0c1cde734", "firstIndex": 4898946491},
-{"blockNumber": 12706472, "blockId": "0xfd21f41ec6b0c39287d7d48c134d1212a261c53d65db99739994b003150bbad1", "firstIndex": 4966054796},
-{"blockNumber": 12762929, "blockId": "0xc94d994bc40b2ae7dc23cf2b92cc01e84915f090bb57c0d9a67584bd564d3916", "firstIndex": 5033164307},
-{"blockNumber": 12816689, "blockId": "0x7770c72f22cbf6ccf7ab85d203088f7ede89632cf0042c690102f926a90bd09d", "firstIndex": 5100273412},
-{"blockNumber": 12872408, "blockId": "0x2e008b8c952d828875d777f7912f472af96ffc977f2ceae884006682cab6b8ed", "firstIndex": 5167381625},
-{"blockNumber": 12929718, "blockId": "0x85eb0ed3c5910c6a01b65ef0a5b76c59c2cdb5094e6e27eb87c751d77bcc2c88", "firstIndex": 5234491305},
-{"blockNumber": 12988757, "blockId": "0xdf12045bea73af18d4e71f8be8e334160f78b85f96a3535a4056409d8b61355a", "firstIndex": 5301600237},
-{"blockNumber": 13049172, "blockId": "0xf07608d97a101cd9a95fee9d9062a15bcb333263e555f8cfa31da037e0468f30", "firstIndex": 5368709080},
-{"blockNumber": 13108936, "blockId": "0x42739341db582d2f39b91ec9e8cc758777ca3f6ff9f25cd98883619fd5f026a7", "firstIndex": 5435817013},
-{"blockNumber": 13175495, "blockId": "0x564f25eacb229350b7c648b5828169e7a0344ae62e866206828e2cfad8947f10", "firstIndex": 5502926476},
-{"blockNumber": 13237721, "blockId": "0x0973425abec0fa6319701b46e07c2373b0580e3adbed6900aad27d5bf26dcb95", "firstIndex": 5570035419},
-{"blockNumber": 13298771, "blockId": "0xf3a16fec5be808c9f7782fb578dc8cef7f8e2110f7289bd03c0cc13977dd1518", "firstIndex": 5637143840},
-{"blockNumber": 13361281, "blockId": "0x3c0b6364201ca9221b61af3de27a3a87e111870b8c7efc43a6d8496e98c68690", "firstIndex": 5704253046},
-{"blockNumber": 13421819, "blockId": "0x2f472e57997b95558b99e3e5e7e0e8d4dbf8b71c081aac6536c9ff5925dac2ce", "firstIndex": 5771361231},
-{"blockNumber": 13480620, "blockId": "0xc4d689e87464a0c83c661c8e3a0614c370631de857f7e385b161dfe8bacd3e71", "firstIndex": 5838469468},
-{"blockNumber": 13535793, "blockId": "0xe7674bacc8edce9fb3efd59b92c97da48fe7ace1de314b4a67d7d032fc3bb680", "firstIndex": 5905578026},
-{"blockNumber": 13590588, "blockId": "0x6a3e86bdce7dd7d8792e1af9156edd8c3ffee7c20fed97001f58a9a2699f6594", "firstIndex": 5972687757},
-{"blockNumber": 13646707, "blockId": "0xab404a5d3709cf571b04e9493f37116eeb5dd2bc9dc10c48387c1e0199013d69", "firstIndex": 6039797165},
-{"blockNumber": 13703025, "blockId": "0x20e2fde15b8fe56f5dd7ab0f324c552038167ed44864bf3978e531ae68d6d138", "firstIndex": 6106905803},
-{"blockNumber": 13761024, "blockId": "0x2ae49275e13e780f1d29aea8507b2a708ff7bfe977efac93e050273b8b3a8164", "firstIndex": 6174015107},
-{"blockNumber": 13819468, "blockId": "0xb9d19cb31dedb1128b11cad9ffd6e58c70fe7ba65ba68f1ac63668ac5160ad85", "firstIndex": 6241124350},
-{"blockNumber": 13877932, "blockId": "0x80b1ff0bb069a8479360a15eaa84ba30da02cfacadc564837f4b1c90478addb8", "firstIndex": 6308232256},
-{"blockNumber": 13935384, "blockId": "0xe1f5469a559a6114dd469af61b118b9d9551a69bbd49a4e88f2a2d724830c871", "firstIndex": 6375341632},
-{"blockNumber": 13994042, "blockId": "0x25188fb75f2328c870ade7c38ef42ff5fddef9c4e364eebe4c5d8d9cc3ecabab", "firstIndex": 6442449799},
-{"blockNumber": 14051123, "blockId": "0xf4ef2bce9ee9222bdcf6b3a0c204676d9345e211e10c983e523930274e041ef1", "firstIndex": 6509559107},
-{"blockNumber": 14109189, "blockId": "0x80b730c28f75d8cb5ec2fb736341cd87cb4ecb2c9c614e0a4ecc0f9812675d50", "firstIndex": 6576667347},
-{"blockNumber": 14166822, "blockId": "0xf662a24b91684fa8ac462b31071f406de8d6183dba46d30d690f4407bc6af36f", "firstIndex": 6643777079},
-{"blockNumber": 14222488, "blockId": "0x7333e324c96b12f11a38d1fc2ddb4860e018b90f5dc10f3dbe19f7679bb95535", "firstIndex": 6710885890},
-{"blockNumber": 14277180, "blockId": "0x4373c1000e8e10179657689e2f0e42f88bd1601ecb4a5d83970d10287f6654cc", "firstIndex": 6777994595},
-{"blockNumber": 14331080, "blockId": "0x9c708a750a3f284ec0ee950110b36fd488cb1ec24cd0c2ea72c19551ec5c42a5", "firstIndex": 6845103719},
-{"blockNumber": 14384243, "blockId": "0x34ce7503b76335aa18dec880b0cefd388a29e0fcff6f2e1ddda8fb8c0ac1daf0", "firstIndex": 6912212376},
-{"blockNumber": 14437670, "blockId": "0x79842efd3e406b41f51935fe2e6ad20a7dd5a9db2280ebd7f602ed93da1e3c24", "firstIndex": 6979320543},
-{"blockNumber": 14489204, "blockId": "0xcd12addf0afdc229e9fe3bd0a34677a3826c5e78d4baf715f8ed36b736d6627a", "firstIndex": 7046430591},
-{"blockNumber": 14541688, "blockId": "0x55f617abf208a73fc467e8cb5feead586b671dbb0f6281570b3c44b8eabb2b9e", "firstIndex": 7113538755},
-{"blockNumber": 14594551, "blockId": "0xc7211bf772e93c8c2f945fcb6098b47c3455604cb8b94a505cb5cb720914c369", "firstIndex": 7180646025},
-{"blockNumber": 14645065, "blockId": "0x6d5b0326f4b22e2b0196986a514f23ec6e9a62f70f53300a22b21ff661a6ef7e", "firstIndex": 7247756883},
-{"blockNumber": 14695926, "blockId": "0x0a77272250e43b4bb46c02eb76944881a3c6b00a21bb9086a8229199bd62d97a", "firstIndex": 7314865843},
-{"blockNumber": 14746330, "blockId": "0xd677fdbaf8efb1bfdc138ac6b2bd5d0e890a29acb1f52f40169181ad517b0d31", "firstIndex": 7381974956},
-{"blockNumber": 14798546, "blockId": "0xbb277e8623acd2ce2340cf32f6c0ddab70fd95d862287f68a3c37250a70619cd", "firstIndex": 7449082890},
-{"blockNumber": 14848230, "blockId": "0x587b39f11bdaa2091291c7c3947e88df2e91e7997f2375dfd43b6e310a538582", "firstIndex": 7516192636},
-{"blockNumber": 14897646, "blockId": "0xf5b5c9d0c024ca0c0f0c6171871f609687f4ccb064ededbd61176cf23a9011e8", "firstIndex": 7583299602},
-{"blockNumber": 14950782, "blockId": "0x50549486afaf92a4c3520012b325e914ef77a82e4d6530a71f9b1cca31bfae18", "firstIndex": 7650409868},
-{"blockNumber": 15004101, "blockId": "0x7edac55dea3ee4308db60b9bc0524836226fe301e085b3ce39105bd145ba7fc3", "firstIndex": 7717517503},
-{"blockNumber": 15056903, "blockId": "0xb4cfd02d435718598179cdba3f5c11eb8653fe97ec8d89c60673e3e07b8dfc94", "firstIndex": 7784627997},
-{"blockNumber": 15108302, "blockId": "0x53c77a7de4515e9e93467a76f04cc401834bcdd64e9dfa03cf6d2844a6930293", "firstIndex": 7851736988},
-{"blockNumber": 15159526, "blockId": "0x1a31ad84b423254d7ff24e7eca54048ed8cc13cec5eb7289bf3f98ed4de9f724", "firstIndex": 7918844431},
-{"blockNumber": 15211013, "blockId": "0xe5d491e1d6cc5322454143b915c106be1bf28114a41b054ba5e5cfe0abecafba", "firstIndex": 7985953942},
-{"blockNumber": 15264389, "blockId": "0xd9939bb9e58e95d2672c1148b4ec5730204527d3f3fc98ca03a67dc85cf3d710", "firstIndex": 8053063187},
-{"blockNumber": 15315862, "blockId": "0x7254f99c4bb05235d5b437984c9132164e33182d4ce11a3847999da5c28b4092", "firstIndex": 8120172147},
-{"blockNumber": 15364726, "blockId": "0x11b57547579d9009679e327f57e308fe86856391805bc3c86e7b39daae890f52", "firstIndex": 8187281042},
-{"blockNumber": 15412886, "blockId": "0xbe3602b1dbef9015a3ec7968ac7652edf4424934b6bf7b713b99d8556f1d9444", "firstIndex": 8254390023},
-{"blockNumber": 15462792, "blockId": "0x3348ca4e14ac8d3c6ac6df676deaf3e3b5e0a11b599f73bd9739b74ebd693efe", "firstIndex": 8321499024},
-{"blockNumber": 15509914, "blockId": "0xbc98fd6b71438d5a169f9373172fea799fa3d22a8e6fe648d35e1070f2261113", "firstIndex": 8388606521},
-{"blockNumber": 15558748, "blockId": "0x5fa2cf499276ae74a5b8618990e71ed11a063619afe25c01b46e6252eba14c19", "firstIndex": 8455716577},
-{"blockNumber": 15604217, "blockId": "0x78a608e13d2eb3c5fed81a19b829ede88071cf01ea9ff58112a7472435f97c30", "firstIndex": 8522825668},
-{"blockNumber": 15651869, "blockId": "0xd465d861d925d1475440782ff16c2b3361ba3c8e169d7cc90eb8dfc0f31b0aac", "firstIndex": 8589934080},
-{"blockNumber": 15700968, "blockId": "0x71e3def131271e02c06ca945d14a995703a48faac1334a9e2e2321edd0b504d0", "firstIndex": 8657043390},
-{"blockNumber": 15762986, "blockId": "0x9b1b51dca2eae29162ca66968a77b45175f134b44aea3defadcb924f83e0b944", "firstIndex": 8724151376},
-{"blockNumber": 15814455, "blockId": "0x3c04a509cb6304d3df4bef57e0119d9e615ab737ec0b4a7deada6e5f57d9f873", "firstIndex": 8791260562},
-{"blockNumber": 15865639, "blockId": "0x9e9e26148c774518ecf362c0e7c65a5c1b054a8a3e4e36036c70e273fac6147c", "firstIndex": 8858368894},
-{"blockNumber": 15920564, "blockId": "0x9efe1d4dbfd9aa891ac0cffd3e1422a27ba2ea4add211b6900a2242cdb0f0ca0", "firstIndex": 8925477950},
-{"blockNumber": 15974371, "blockId": "0xc63ccef7bc35a0b431a411f99fe581b322d00cfc6422d078696808a5658a32ac", "firstIndex": 8992587107},
-{"blockNumber": 16032913, "blockId": "0x3e60957224964669a8646914e3166553b9f4256d5be160b17995d838af3ef137", "firstIndex": 9059696632},
-{"blockNumber": 16091057, "blockId": "0x12b346047bb49063ab6d9e737775924cf05c52114202ddb1a2bdaf9caabbfe0c", "firstIndex": 9126804912},
-{"blockNumber": 16150977, "blockId": "0x49318a32ff0ce979c4061c1c34db2a94fb06e7669c93742b75aff14a134fa598", "firstIndex": 9193913896},
-{"blockNumber": 16207432, "blockId": "0xf7870865edf81be4389a0be01468da959de703df0d431610814d16ed480176e4", "firstIndex": 9261019778},
-{"blockNumber": 16262582, "blockId": "0x25818e0f4d54af6c44ef7b23add34409a47de3ab1c905889478f3ec8ad173ec3", "firstIndex": 9328131320},
-{"blockNumber": 16319695, "blockId": "0x25de4b1c18cc503f5d12b4fa9072d33a11fa503a3dbeb9ab3d016b57c1e5cd4d", "firstIndex": 9395240790},
-{"blockNumber": 16373605, "blockId": "0x3794a5e0d2aa10baf1e6a5ec623d6089fdd39799eff633017d8df5144526939f", "firstIndex": 9462349509},
-{"blockNumber": 16423494, "blockId": "0xe0217d947ba3865dfc9288e0c890b0996457bb9d18467bd125e86bbb0052b57f", "firstIndex": 9529458033},
-{"blockNumber": 16474853, "blockId": "0xd454f033d190f22f9e56f0209ea1eeb3b6257805d5d88650d2759eb4d24821b7", "firstIndex": 9596567055},
-{"blockNumber": 16525689, "blockId": "0x8a23cbbf3e258e13f5a1ada434366796cb4a3e5b1062455582fb2bc3ab991541", "firstIndex": 9663674943},
-{"blockNumber": 16574203, "blockId": "0xc1a5b7d26e8222bd2d56ef4108f75d69f7c116707d348950834e00962241a4f8", "firstIndex": 9730785112},
-{"blockNumber": 16622622, "blockId": "0x3ddb3ef7a4309bd788258fb0d62613c89a0b4de715f4e12f6017a194d19d6481", "firstIndex": 9797893665},
-{"blockNumber": 16672585, "blockId": "0x8aa5e9f72b261f9e2a9eb768483d1bbd84d3a88fdb1346f6a9a7f262fd28ba41", "firstIndex": 9865002893},
-{"blockNumber": 16720124, "blockId": "0x2128f8baf264166e37554d5c31a06de58d9ccfb663117358251da548a23a060f", "firstIndex": 9932111275},
-{"blockNumber": 16769162, "blockId": "0x6b3e849482d3222032740ad6b8f98e24636c82682a6a3572b1ef76dfebc66821", "firstIndex": 9999217824},
-{"blockNumber": 16818311, "blockId": "0xe45f57381978a2bfc85bd20af1c41e2b630412642ac4f606b477f05f030ef5d9", "firstIndex": 10066328668},
-{"blockNumber": 16869531, "blockId": "0xa154555266d24dc1f4885af5fafcf8cab3de788998cf69e1d28f56aa13a40c43", "firstIndex": 10133437302},
-{"blockNumber": 16921611, "blockId": "0xf1f829b4ab5eec6e243916dd530993fa11eef5510fd730e8d09ead6b380355a1", "firstIndex": 10200547185},
-{"blockNumber": 16974870, "blockId": "0x1a33202b95926ae4cb8e6e99d8d150f3c50d817b3a316452bdf428c971dabde5", "firstIndex": 10267655914},
-{"blockNumber": 17031277, "blockId": "0x706c9dd0dc81e7ac29d2ea0f826e6b8a1dcb5adb1b904ff6e43260729c9fd0a7", "firstIndex": 10334764934},
-{"blockNumber": 17086330, "blockId": "0x085a80cafe96b520105b9a1f8e7a2bbc9474da24da7e6344ca7c4d32db822f92", "firstIndex": 10401871892},
-{"blockNumber": 17141311, "blockId": "0x33ec6513dfa515bc5f6356476b4eb075a8064181d6aaf6aa1a1e18887e342f74", "firstIndex": 10468982364},
-{"blockNumber": 17190907, "blockId": "0x6f41273d3bf30d3347e7eb68872a49b3ac947f314543478be7a28a55e5c41a3c", "firstIndex": 10536090817},
-{"blockNumber": 17237199, "blockId": "0x9a87a14a128c0345a366940f821a14f16719de628658ac0628e410a72d723e90", "firstIndex": 10603200178},
-{"blockNumber": 17287181, "blockId": "0x9c6e78adcf562ac63c103e3e5a02f025023079aca79bdd6ef18f7bd2a6271c29", "firstIndex": 10670309183},
-{"blockNumber": 17338652, "blockId": "0x1b747da97b2397a293602af57514dab4ca1010bb6c601ff05cb2012dd1124ebb", "firstIndex": 10737418023},
-{"blockNumber": 17389337, "blockId": "0xbc3c0ca1e5989605b9b59c94b418562eb17ccbce30e45ac8531cf0b3867a6b2c", "firstIndex": 10804522857},
-{"blockNumber": 17442261, "blockId": "0x1ec341be1cbd09f559bfa3d3e39a341d8e21052eeb7880931d43d086651733b7", "firstIndex": 10871635535},
-{"blockNumber": 17497787, "blockId": "0x6069880d486f2548599df1e14e12752d3eb9bc99843a98cd6631c22be1b58554", "firstIndex": 10938744657},
-{"blockNumber": 17554322, "blockId": "0x69b2564bc00b1f310f6b416912869d7530d7864bf7d70d55c7ace554f129b989", "firstIndex": 11005852829},
-{"blockNumber": 17608492, "blockId": "0x7d590653d5fa52c0d3ee453a77d2088504f57adcef35cd57c567afb554608457", "firstIndex": 11072961972},
-{"blockNumber": 17664272, "blockId": "0xdc16159d3500cdc7410873102f41fc55de2a8a41e3779c4b70e6224a541e2b9e", "firstIndex": 11140070967},
-{"blockNumber": 17715101, "blockId": "0x655e33c4e81182464ea0b0e1fdbc53ce53902431db5107326b816091a4564652", "firstIndex": 11207179487},
-{"blockNumber": 17764042, "blockId": "0x54439184f31cd83ba06b48b6dbfdd744ae7246355be1327b44744058711d05c0", "firstIndex": 11274287303},
-{"blockNumber": 17814383, "blockId": "0xfb453bc951360c76fb09bb1b9a3e39d23ececa0adb93368cc3f41f0457845089", "firstIndex": 11341397984},
-{"blockNumber": 17864648, "blockId": "0x32a68823ef4ec0cbab2fe50c97e3f462b575e8b117da40d00c710b4c66ee1d6d", "firstIndex": 11408505657},
-{"blockNumber": 17913366, "blockId": "0x04b944aab8a4ff91b77c2191817cf051766100c227616a3746af53407e740124", "firstIndex": 11475614351},
-{"blockNumber": 17961690, "blockId": "0x08bee7cc0b764106ca01dd5370b617879487ffb423688c96e948dce125990f45", "firstIndex": 11542723488},
-{"blockNumber": 18011048, "blockId": "0x94c39d3a64f3e9a91b1d98554cd29e1390e30fa61cfa4e909c503eee2fd9f165", "firstIndex": 11609833142},
-{"blockNumber": 18061209, "blockId": "0x2ee9ade68955c030488c8a30537bdf948355f7dd5ae64942b5bfce1be6650e19", "firstIndex": 11676941316},
-{"blockNumber": 18111692, "blockId": "0xd6c4fd0c1cc20ed5e7960bb5043e9e5e9c66a4d2ec5709ac9797fff678435640", "firstIndex": 11744050346},
-{"blockNumber": 18166212, "blockId": "0x3262588c2ef79a3b3f6a3db6435202d22f5667cd48c136b0797404901525c9ff", "firstIndex": 11811159686},
-{"blockNumber": 18218743, "blockId": "0x935bd9a4164ff7ecd09a37b916ce5bf78487bd19377b5b17be153e39318aee74", "firstIndex": 11878268593},
-{"blockNumber": 18271236, "blockId": "0xe58ebb821f27e3665898f390802a3d129d217b3a3ee36d890a85cf22a0a8aa33", "firstIndex": 11945376750},
-{"blockNumber": 18323007, "blockId": "0x3997a841468efa1bc614bfc3de4502274901b04b428f87a1f3086dfd78cda1eb", "firstIndex": 12012485748},
-{"blockNumber": 18372443, "blockId": "0xc44a13a5d02e8dc39f355de5e21ce7bb311ce7f4d9114ff480dce235a169e416", "firstIndex": 12079595370},
-{"blockNumber": 18421829, "blockId": "0x7da63a0b613d8745597b2ac64fd5cc8b2fb14b24d163b12a0a39d7d3d4ff7b5c", "firstIndex": 12146703582},
-{"blockNumber": 18471706, "blockId": "0xd632a1893f415ff618f4b612a7687e6af1f12feeed81f46f0022090829c1eb4c", "firstIndex": 12213812677},
-{"blockNumber": 18522301, "blockId": "0x44fa2cf08145ae40e8e42f4e6b4ab7df360a17c5a065ce45fcc41b51bee011f4", "firstIndex": 12280921639},
-{"blockNumber": 18572935, "blockId": "0x72b8ab4c78c90425ee054b4806a8be703da0febdf1d51866358ec2bd21ba9529", "firstIndex": 12348029751},
-{"blockNumber": 18623431, "blockId": "0x8c4cb2f13501d9788820280c6f16692d0737258c3896f1e4bded32d838febf7f", "firstIndex": 12415138965},
-{"blockNumber": 18675470, "blockId": "0x523b73c19ea8b3ae32ef141a83ef9855e667ebf51443cfcabd1a06659359062a", "firstIndex": 12482247454},
-{"blockNumber": 18725728, "blockId": "0x0cfbd131eb5dad51488238079fba29a63eebb5c32d1a543cb072e48dc2104ef3", "firstIndex": 12549356369},
-{"blockNumber": 18778387, "blockId": "0xc4906c77af8058b9f172a4f0e8788c7887f05caa5ac752b38b5387080f74ae49", "firstIndex": 12616465992},
-{"blockNumber": 18835044, "blockId": "0x49c5e07f409a841dc81f3ef8417f1951f8fcc13c90134f9d2a0cd11938f9fa36", "firstIndex": 12683575082},
-{"blockNumber": 18883308, "blockId": "0x386a58dd5f79a419eeb05075b07b3ff3bc836a265c9688854a504223b1d6a830", "firstIndex": 12750683753},
-{"blockNumber": 18933635, "blockId": "0xd3881292147589bd2e192769e5c9175b5d03a453fe1ef3c4b5b6858ac9402a2f", "firstIndex": 12817792470},
-{"blockNumber": 18988254, "blockId": "0xcbe72dfa15428ac21b9c59c703ceaa0eb4b2205927687261d7aaed3dbb3783ea", "firstIndex": 12884882858},
-{"blockNumber": 19041325, "blockId": "0x92b077e1c2f8819da728f0307c914fdcd57eba14ea07d9a45c28d1ed8ffff576", "firstIndex": 12952010530},
-{"blockNumber": 19089163, "blockId": "0x43f8ab2d3dfc34c8e18cba903074d54e235dc546f19c4eb78245a522c266c84e", "firstIndex": 13019119228},
-{"blockNumber": 19140629, "blockId": "0xab7b7ae5424b18105a13b657fa6099d4ab67fde5baff39fe6e4de707397e995c", "firstIndex": 13086228236},
-{"blockNumber": 19192118, "blockId": "0x451327e6a5cf6ce1c8c14c01687dc5f719f3c2176f46bac4f264616256e30d1c", "firstIndex": 13153337116},
-{"blockNumber": 19237836, "blockId": "0x9b260d6be369557d1dc88aca423e2697e697d941d1b726c183015b5649e248c8", "firstIndex": 13220445421},
-{"blockNumber": 19291271, "blockId": "0x4878c28d79e1f71bc11e062eb61cb52ae6a18b670b0f9bea38b477944615078e", "firstIndex": 13287554254},
-{"blockNumber": 19344448, "blockId": "0x56243b9ad863bf90953fe9aa6e64a426629384db1190e70dce79575d30595f7e", "firstIndex": 13354663659},
-{"blockNumber": 19394948, "blockId": "0x195173b64dda7908d6aa39a63c8bdd29ec181d401e369d513be1308550d0ddcb", "firstIndex": 13421771935},
-{"blockNumber": 19443075, "blockId": "0xd39c1d60996475e65d1ab5b4e755f510ca466564a8155d35db6667988d6c0e44", "firstIndex": 13488880427},
-{"blockNumber": 19488383, "blockId": "0x28956eb8856fa8db59c02585016b8baf43bc44bc35b00bdaf8a6babe51101c5c", "firstIndex": 13555977105},
-{"blockNumber": 19534584, "blockId": "0x2421c97b0f140185d4c20943cd4ed7d7424468482feb76e3003a1cc69da3fd7b", "firstIndex": 13623097580},
-{"blockNumber": 19579602, "blockId": "0x25f96529028e9f51c59aec9ce8de282b7dd67066fd46a1694130698ed0f40d8b", "firstIndex": 13690207623},
-{"blockNumber": 19621517, "blockId": "0x4f6f6e0a0488f3d51823bc4b07c292348c259b1866968f77ee76b66b37101c75", "firstIndex": 13757315529},
-{"blockNumber": 19665085, "blockId": "0x00f9315f89681b44bff46f1bad8894bc6dfae1c459d3d6520f9881861304a496", "firstIndex": 13824425382},
-{"blockNumber": 19709229, "blockId": "0x24e022b21ae1ba8a3e8c87cb9734aa1d1810fc4a69fe147d3ebb1ff0df8bcc15", "firstIndex": 13891534799},
-{"blockNumber": 19755387, "blockId": "0x77f184b7183b1a351760d242041249464b42cfaa6fbc4326f352b06bb3b21a02", "firstIndex": 13958642483},
-{"blockNumber": 19803894, "blockId": "0xf37eb1b054a6d61272940361f386eb744cded84d15c3250a7eabadede257371c", "firstIndex": 14025751618},
-{"blockNumber": 19847885, "blockId": "0x4659649fa8a3b4bbe8978673ba9a22ae20352c7052b676d373b5a51b1967ffa4", "firstIndex": 14092848654},
-{"blockNumber": 19894193, "blockId": "0x15606bdc0f1a710bd69443c7154d4979aece9329977b65990c9b39d6df84ed5c", "firstIndex": 14159970181},
-{"blockNumber": 19938551, "blockId": "0x6a8f4571924ed902bd8e71bf8ed9cc9d72cabeabc410277c8f0fc2b477d00eb7", "firstIndex": 14227077892},
-{"blockNumber": 19985354, "blockId": "0x7b6fb6376410b4d9e5d7ee02f78b2054e005dd2976eea47fc714f66b967dc285", "firstIndex": 14294187965},
-{"blockNumber": 20028440, "blockId": "0x9b37440b71c24756b8855b8012432b84276ae94c80aa1ccc8b70a7705992103c", "firstIndex": 14361296503},
-{"blockNumber": 20071780, "blockId": "0xa2ed129f343f3d60419772ec5635edcd36b8680c9419b6626e2bc84b230c709b", "firstIndex": 14428405230},
-{"blockNumber": 20113832, "blockId": "0xe7a610e8bcbf8ded141ebc7142de03dfc54b1bcc79e3bf8d07fad4e42b665bba", "firstIndex": 14495512019},
-{"blockNumber": 20156854, "blockId": "0xbe09704f65a70ef8843d9c8e511ddc989ea139dbe94cdfe37f52b03620d62385", "firstIndex": 14562622430},
-{"blockNumber": 20200135, "blockId": "0x9a58c34d5f77342e94065d119905c000223cd988c4b11f1539fff20737159630", "firstIndex": 14629731923},
-{"blockNumber": 20244389, "blockId": "0x1e733f0db9ef21183107259b3c2408c78fa5a01469928cd295f3ea7e8eedda45", "firstIndex": 14696840011},
-{"blockNumber": 20288489, "blockId": "0xb5ad7edd86b181226c8c7be0a08069e3955234e797426843fff9de0f57ec59cc", "firstIndex": 14763949714},
-{"blockNumber": 20333582, "blockId": "0x8040c209f5cd1738ee0f85c2f1db7c43a420d148680c7390fd1701b9f0bb671a", "firstIndex": 14831058335},
-{"blockNumber": 20377087, "blockId": "0x08fdc4cd246b6ae9d4a45646b0aed6af3bb330eb6cd4c8b93646157e7b002b84", "firstIndex": 14898167722},
-{"blockNumber": 20421699, "blockId": "0x5a2912b5fc2f02df33b655155990f92dcaacda5b75427fe3d87fb38f36b1c17d", "firstIndex": 14965275691},
-{"blockNumber": 20467194, "blockId": "0x3deaf4325c461004b090b0261996c645ab529c1471feaf7dc2bbe1f128180297", "firstIndex": 15032385211},
-{"blockNumber": 20512397, "blockId": "0x37e39697ec1b7683a6202be250ffaee7a1102e8030f87550b94af05ec66cec83", "firstIndex": 15099493973},
-{"blockNumber": 20557443, "blockId": "0x8e9c04468f3111eab8b1f6a58b277862c624861c237cadecc53ec249bd811bda", "firstIndex": 15166602882},
-{"blockNumber": 20595899, "blockId": "0x9787555fe57e4650002257eb2c88f1ef435b99d406e33fe2f889be180123ef25", "firstIndex": 15233709908},
-{"blockNumber": 20638606, "blockId": "0x70681cffd159ce2e580dbbbe8fa6b5343dbcb081429cdda6c577e615bef4ef05", "firstIndex": 15300820678},
-{"blockNumber": 20683605, "blockId": "0xb32662d5e241132ffe2249caea67f5746a6f4382297b2ac87c81e2794faf1f7a", "firstIndex": 15367929350},
-{"blockNumber": 20728630, "blockId": "0x15a817c846928b673032d5eacd0cff7a04217d268457aa30a322ecca32be4d49", "firstIndex": 15435037830},
-{"blockNumber": 20771519, "blockId": "0x542bc7b9804bbc45f4be470f4dc56f215a4dec71fed71eba2ffc804afd262b95", "firstIndex": 15502145990},
-{"blockNumber": 20815097, "blockId": "0x798cdd51c964fcf18561d70095d9613b84ba836817972799c9dfd0bfbe1e042b", "firstIndex": 15569256033},
-{"blockNumber": 20857859, "blockId": "0xfb5bb066d419a651d8e0186569eb4e8d8bcd5181d8f02e0d578b5dfe2fc738dd", "firstIndex": 15636364671},
-{"blockNumber": 20896890, "blockId": "0x834b8d6fad779e4cf8214128f6c93d7387b6d6279e517f6f0a284b5d831cc3ae", "firstIndex": 15703472902},
-{"blockNumber": 20939387, "blockId": "0x7adee7c78420c711efa216c61e0b561e581d7ff0331efd91ee16a609b34cfdc2", "firstIndex": 15770582325},
-{"blockNumber": 20981303, "blockId": "0x6f5d7b0cc6dad5eb258176e07de21795a8347d68f7303f06934046e0236bea6d", "firstIndex": 15837691713},
-{"blockNumber": 21023216, "blockId": "0x96cfe35a45df1297a36f42c59ebe706ab0473dfbf59ce910b5c5a8dbf696de1c", "firstIndex": 15904799667},
-{"blockNumber": 21068378, "blockId": "0x93753875ff330d922b23f823203198f3b1bb8833367c6b6a8f896ff54be2c12d", "firstIndex": 15971909040},
-{"blockNumber": 21112445, "blockId": "0x6ac02fa6ae486b86aba562eaf6f3d883befaa8ebedcfd8d74bdb7368d42deee3", "firstIndex": 16039003625},
-{"blockNumber": 21155992, "blockId": "0x25f76896b4b693bafb79e9a535e2bf00ed62a577e35209749346e8e79a60bb71", "firstIndex": 16106126344},
-{"blockNumber": 21200962, "blockId": "0x725f2befe913cb2659d262e2d3b6f79a706b31c557d52669471da22347ec8287", "firstIndex": 16173235265},
-{"blockNumber": 21244663, "blockId": "0x6778c4194f54e70939da38853daddb22bfaf160d35617ab05d0f5c476741147b", "firstIndex": 16240344735},
-{"blockNumber": 21290273, "blockId": "0x433ac819c40bd3061205fe0ece0645eec73f54a0a5c1559c981f983345bc0154", "firstIndex": 16307453543},
-{"blockNumber": 21336156, "blockId": "0x261dc8c1639d505624150d2388d15ed10bfb4c3ce9c0c327a4ec26531689a097", "firstIndex": 16374562466},
-{"blockNumber": 21378880, "blockId": "0x5c78b2b70553140dfdfdd4f415b98f88e74f74662315834038fd99042277d917", "firstIndex": 16441671104},
-{"blockNumber": 21421613, "blockId": "0x854532f9d1c77627b763f9cbc7099a653d59554ed57fa763bc218834c82955fe", "firstIndex": 16508780351},
-{"blockNumber": 21466875, "blockId": "0xb8b83cc62084e948235ef4b5973bf7fd988fa28bcaa72f7d38ad8e50de729618", "firstIndex": 16575888599},
-{"blockNumber": 21511942, "blockId": "0xe806a28bc1b7f8cd752c8ceedbe081d49773d4558a9fb95e3357c0c07172522d", "firstIndex": 16642996907},
-{"blockNumber": 21550291, "blockId": "0x1f3e26d303e7a2a9b0614f12f62b189da365b3947c5fe2d99ed2711b37fe7daa", "firstIndex": 16710106826},
-{"blockNumber": 21592690, "blockId": "0xa1408cfbc693faee4425e8fd9e83a181be535c33f874b56c3a7a114404c4f686", "firstIndex": 16777215566},
-{"blockNumber": 21636275, "blockId": "0x704734c2d0351f8ccd38721a9a4b80c063368afaaa857518d98498180a502bba", "firstIndex": 16844323959},
-{"blockNumber": 21681066, "blockId": "0x1e738568ed393395c498b109ad61c0286747318aae0364936f19a7b6aba94aef", "firstIndex": 16911433076},
-{"blockNumber": 21725592, "blockId": "0xee87b7948e25a7498a247c616a0fbaa27f21b004e11fc56f2a20c03791ed8122", "firstIndex": 16978540993}
+{"blockNumber": 4166212, "blockId": "0xd94b724fc1c7dceb3251b51b81f7a0f3220ae5b9add1e62917004f14f2a3532c", "firstIndex": 67108840},
+{"blockNumber": 4513996, "blockId": "0xc0fd25fef5888609d05fa8c5620d8e18c31cdd675dd4ee926ff966668f0e5d76", "firstIndex": 134217480},
+{"blockNumber": 4817399, "blockId": "0x8573c3166fb7f716e97cf6109d382f86441238e0b85828944a072ae8583a6cfa", "firstIndex": 201326547},
+{"blockNumber": 5087706, "blockId": "0xcd2dfae45901e299b25faa04c10df60983d5c0a3d0e478e789c7aeec980cf691", "firstIndex": 268435422},
+{"blockNumber": 5306085, "blockId": "0xe8026984c85873f2b24018a7e0bdf8c2df136b2fc49666b4addf0d2e067890da", "firstIndex": 335544018},
+{"blockNumber": 5509898, "blockId": "0x41bc63dc8184f9a7d4b9a5a554e00eee32fee60ccfa2339264be11270ac28de1", "firstIndex": 402652789},
+{"blockNumber": 5670367, "blockId": "0xe61c2ba463f2f458817ed1bf0ff9fb9d07e9d7354f46b48175b2d784b817bf3b", "firstIndex": 469761896},
+{"blockNumber": 5826113, "blockId": "0xfbbb1fc5e03a5562bf6b7f1799d7a572d9ef66c7fd0e0b9f4fed7262767b5c86", "firstIndex": 536870852},
+{"blockNumber": 5953008, "blockId": "0x6bbdccd094928e846de3c615a33f2952e3259afaa1929f4ee241a56907d0593b", "firstIndex": 603979150},
+{"blockNumber": 6102812, "blockId": "0x2403f2502088a1fa26c1294f5245032fe3b7f3a8bb14c12d0ba8d577156bbc1b", "firstIndex": 671087962},
+{"blockNumber": 6276672, "blockId": "0xeaa05a0e0574fbb164244628a7d14d9d47f1692941098aa737059d44104401df", "firstIndex": 738197399},
+{"blockNumber": 6448662, "blockId": "0xe6f097fa18a2cef425514e863659e42e1aa8d74df49cb0bed5877e82a08d1f84", "firstIndex": 805306056},
+{"blockNumber": 6655925, "blockId": "0xee5c9d87b06dc0c2e850fead07bcd13f85d45ad6b5a6e7ebee53cc8618772786", "firstIndex": 872415229},
+{"blockNumber": 6873878, "blockId": "0x9a0ea103146da21fa1d9cab7ff609ec2c5e7f1856288a1f744239588e33904c2", "firstIndex": 939524080},
+{"blockNumber": 7080893, "blockId": "0x35ad45055d7a1a3ef94efeb05e4122757bcc126ff1bc2b4ac72dc78ab3c0fd75", "firstIndex": 1006632327},
+{"blockNumber": 7266955, "blockId": "0x7b80f70520f2c16eb5890f4963af8f60446f50af82b589ceaf009d09e704b302", "firstIndex": 1073741608},
+{"blockNumber": 7466649, "blockId": "0xea8980b5c692c729013f9cc4c9f66e94d5ef2c5caad23f370be0953b6d85f32c", "firstIndex": 1140850335},
+{"blockNumber": 7661736, "blockId": "0x615cdb03dbf29a22d59bbc769c03f3647c2c9abb7d1767f3f6529708209e7073", "firstIndex": 1207959232},
+{"blockNumber": 7834494, "blockId": "0x05b7dd13e2eb8a833e4b278f9151ca01b294ae5fc5617769422ec85ffb446215", "firstIndex": 1275068098},
+{"blockNumber": 7989998, "blockId": "0x4b5026add7f2fc2c02993b82c61bceba1b75cfcb8a78c5112cc2832bc0413be6", "firstIndex": 1342177025},
+{"blockNumber": 8142950, "blockId": "0x9f56b7753a0e9964973f3e096e1385215e3aef232b448359e5bec05046b016a3", "firstIndex": 1409285545},
+{"blockNumber": 8297598, "blockId": "0x2ddfeb161fe34ff73c4a995bb94256c3b522b39348169edb97bb3d876ccdf77d", "firstIndex": 1476394898},
+{"blockNumber": 8465061, "blockId": "0xfdbe5435da5ae9fb34a9154e5ebe515afac9a128e383f798f1e69952be404fcd", "firstIndex": 1543503805},
+{"blockNumber": 8655740, "blockId": "0x305137325a39a44aba997e214c05f32d965658f7e3fe20322f2e57e72f239977", "firstIndex": 1610612406},
+{"blockNumber": 8807102, "blockId": "0xc32f9fd9a43d2b502dbcc4a683ffe324fca9a871753478bcb1f4fb9573da96a5", "firstIndex": 1677721343},
+{"blockNumber": 8911110, "blockId": "0x806eabee7dc429b57afcb6c0b72b61728b4f13c62ee9942f1813790463f9ab5b", "firstIndex": 1744830172},
+{"blockNumber": 8960262, "blockId": "0xa69f24032e9d5761565e726d484926a0932c6ca7fdb4c04a55bfc5e8f5879c4d", "firstIndex": 1811938729},
+{"blockNumber": 9085906, "blockId": "0x922b4d6aeca64517f5048fa1ffa98d3e813bc415716a1763d07cf2bdea236896", "firstIndex": 1879048062},
+{"blockNumber": 9230838, "blockId": "0xd892f513c48c95a859ae59c4e00ec4be0d684c549456c90e9c36669c11092f50", "firstIndex": 1946156580},
+{"blockNumber": 9390449, "blockId": "0xcc0ced78fa66b570f338d129794d574560a23958e28d0d5288003d4542cec734", "firstIndex": 2013264376},
+{"blockNumber": 9515554, "blockId": "0xc06d04737813c3e2c8e910b2d4543c5c684c7bfe235bb501445f68fd0663f3d9", "firstIndex": 2080374749},
+{"blockNumber": 9659367, "blockId": "0x765fa33d9418b1ed648e88b497b4bf4aa66990e6413dfc155525cda61e3cc813", "firstIndex": 2147483344},
+{"blockNumber": 9793940, "blockId": "0x9527dcbd85a100c51aee4ba90828fee23312f5f041859f3416a54fd87a437ce2", "firstIndex": 2214591669},
+{"blockNumber": 9923756, "blockId": "0xc4da5fdd2de077459fe84f721d7fc01ef69683e03e634b0c5443186486792246", "firstIndex": 2281700949},
+{"blockNumber": 10042325, "blockId": "0x6f554f195d20e4ba1262f73cf2c1cd44b14a71befe5ef0a5318fc309f8cde9fa", "firstIndex": 2348810131},
+{"blockNumber": 10168768, "blockId": "0xdcdf88ec2c197d552343c80d01375a35d6462aff39c5bd976160f7176d2add64", "firstIndex": 2415918723},
+{"blockNumber": 10289467, "blockId": "0x5ece23babcf6b8838695b891b044c3dcf8120cdc15acd83018e96ffc590f6cd0", "firstIndex": 2483027720},
+{"blockNumber": 10386601, "blockId": "0xd398ee129aea1247019fa39dc2f5083819687d8f5ad17ec39ba1803d178fbcda", "firstIndex": 2550136043},
+{"blockNumber": 10479586, "blockId": "0x61c1cccd60a546eacc29f2ae2a6facab402b4f35e2986c6629b302e6b1ebca3e", "firstIndex": 2617245577},
+{"blockNumber": 10562579, "blockId": "0x14fd6a079050e3e110140372605c050945d6db03746fa5b84a8718cb2a0e9b86", "firstIndex": 2684353802},
+{"blockNumber": 10641438, "blockId": "0x1998dcae09111b2c1bf6d0592e2f0b4a0143fe7db7115ff94b2b73b74542cee4", "firstIndex": 2751463334},
+{"blockNumber": 10717094, "blockId": "0x9ce45a150bb6bd13687d0692c86716911ffc6aff5831a03f4015bdffb85f5093", "firstIndex": 2818571144},
+{"blockNumber": 10784494, "blockId": "0xf65c936cf578e673696477f7db7189b47222fdf7ed13096564b9d47b15c86eb9", "firstIndex": 2885680709},
+{"blockNumber": 10848591, "blockId": "0x84ea8e9d5789302ebe88888115488f91cfb75fd89e282dfbd29ba9d6225ab0ca", "firstIndex": 2952789491},
+{"blockNumber": 10909102, "blockId": "0x22275047f643f4a3b82c349274a53d56a00da25beac89655877fb8cbfa3182c8", "firstIndex": 3019898024},
+{"blockNumber": 10972828, "blockId": "0x38e8acfec19bb53ab9fe70dd3577ccd8bd7c41b4d468b8f099a19bf06ce56518", "firstIndex": 3087006561},
+{"blockNumber": 11036532, "blockId": "0x478dac03f520e987a6e845cac1b3a756d69e4f5257f20758b8fc38456e7b6884", "firstIndex": 3154116463},
+{"blockNumber": 11102457, "blockId": "0x1a36616b03351ebe481330fc86578f57d9da5c0dda59f4406d49b53a2fa9b6f6", "firstIndex": 3221224961},
+{"blockNumber": 11168092, "blockId": "0xb23af483ca6dbc2fb8d2fada1f8189de2e155758ed9ecbbb20c234a30c7e093c", "firstIndex": 3288333510},
+{"blockNumber": 11233640, "blockId": "0xdc4c80d8370823773425b31e70b3af59582b556514857d1e9a9b4c53b880a424", "firstIndex": 3355442901},
+{"blockNumber": 11300454, "blockId": "0xdbd4d8e9c1756093037f431330db4604e5a3e67bb74f425f667633d5298fe34c", "firstIndex": 3422551962},
+{"blockNumber": 11367550, "blockId": "0x9e00816bd5b39353657a99421d278091599a39f246bbf8c0898f83e6d70b7c7c", "firstIndex": 3489660743},
+{"blockNumber": 11431820, "blockId": "0xd32d5e5871ce71acc9dcc7cf9d8cb9d964646182529c327a0ddf617814e27d74", "firstIndex": 3556769150},
+{"blockNumber": 11497031, "blockId": "0xed823054d4b293294e3301d3131e2ae9f0ce63c9f07d2d80fc144e42d535d61d", "firstIndex": 3623878513},
+{"blockNumber": 11560027, "blockId": "0x7098177efe77cfb5912dc63069fe366033111041ca5c539907a89e439c861d8f", "firstIndex": 3690987092},
+{"blockNumber": 11625049, "blockId": "0x61fccb47104a076b905d390498a1b38c317348bb1567e69aa1b670bed7a6a13f", "firstIndex": 3758096043},
+{"blockNumber": 11690298, "blockId": "0xaf6f9e9c92db9e155f1ffb35eb68765c09de1206c353c9a56a5d5fa53e2d88d2", "firstIndex": 3825204430},
+{"blockNumber": 11755003, "blockId": "0xf9efb54f08a2b59086a607541005928f1bda54fa2c46fcc48352fa6aa461c03a", "firstIndex": 3892313541},
+{"blockNumber": 11819591, "blockId": "0xa551deb3bd2ec0ca2683cb76adb8fb295d171a3787aa5ff071bd1fa94d3af82e", "firstIndex": 3959422322},
+{"blockNumber": 11883278, "blockId": "0x60c7a359d4aeb09b63b64487fa7794aee87c41b11446f69ba83e24d5bce6947f", "firstIndex": 4026531239},
+{"blockNumber": 11948436, "blockId": "0x1c46fb22653e5f9eb9503fe532151519845d05b121291766715973e027eb9c0c", "firstIndex": 4093639741},
+{"blockNumber": 12013084, "blockId": "0x0b8d1da9e70c4494ba61190390c891230846e69d9b0be605df8b04c4199ffd1b", "firstIndex": 4160749561},
+{"blockNumber": 12078612, "blockId": "0xb049af260be25c6153b67c227689b0556d8fb7d6033c3f61b8218f5c4ac5917a", "firstIndex": 4227857310},
+{"blockNumber": 12143549, "blockId": "0x685dce41efbe2bab0ac9a4b9026d9e5faa3e01ae4637c8181cd2f1eac326fe6a", "firstIndex": 4294966232},
+{"blockNumber": 12207918, "blockId": "0x53644ea8f781c6270f1136ed4bbcb956c98f12a4793c2f56f49b3105282b13ea", "firstIndex": 4362075410},
+{"blockNumber": 12272370, "blockId": "0x503523e1a01cb7d68be0eb22f36280c0ee7a1fc802061a704e326fbb8efcfe27", "firstIndex": 4429184831},
+{"blockNumber": 12329342, "blockId": "0xe6a1bf78dd827def078e23c768cf6e96666ee06b5fdc113380a4769d85f4bd33", "firstIndex": 4496293151},
+{"blockNumber": 12382311, "blockId": "0x352fe793c16b1d8aea195af86ee9aec3dbaa83e7a32872a0d222a77e96fc0e57", "firstIndex": 4563402486},
+{"blockNumber": 12436970, "blockId": "0x90276349edf0941bb3327dc1d749d0371fe550eaddafb5141fcacdd281de0976", "firstIndex": 4630510187},
+{"blockNumber": 12489954, "blockId": "0x71894b1e1608aeba777662a6055e601ce6f17950dbe3844c3601e0f88cbd5848", "firstIndex": 4697619586},
+{"blockNumber": 12541655, "blockId": "0xc34c7299041df72a81c4b86e81639d2dfcebfae603e287fc143881a636ce1188", "firstIndex": 4764728948},
+{"blockNumber": 12597319, "blockId": "0x4c4dc71d8d2f1223ad0469ddfe09fa8934f64e3712ed83708d6e1b9c64eceebb", "firstIndex": 4831837390},
+{"blockNumber": 12651863, "blockId": "0x406a642c8364fb61cbd896512a2d19ecdba3932ab09ac67cf48d91aa1a03f24e", "firstIndex": 4898946362},
+{"blockNumber": 12706391, "blockId": "0xa7fc3739898f7ff5733896313b248fb0b306a132681609b8b9e2671b42dac3a1", "firstIndex": 4966054748},
+{"blockNumber": 12762840, "blockId": "0x5a1048966dfa55a48248517c45683ce342671bf544117d2bac13d8e343563136", "firstIndex": 5033164303},
+{"blockNumber": 12816597, "blockId": "0x97f5b87f422870a8ffeff70c12f4377dde96d248aa912cb64ebfaea51dc086b6", "firstIndex": 5100272541},
+{"blockNumber": 12872315, "blockId": "0x432f7df7973fdea4e5abe2c09b634ca3b724e37a19d5ec23ca5810e4854c6b33", "firstIndex": 5167382243},
+{"blockNumber": 12929620, "blockId": "0xa4524e3b4c5dadac91df2f29696532cfed377f47469fe7cfabf10baac945eea2", "firstIndex": 5234490748},
+{"blockNumber": 12988653, "blockId": "0x9be70e31aeea164c370d8d183a1af45120693b13d360edc78214535c40ef1d63", "firstIndex": 5301600248},
+{"blockNumber": 13049074, "blockId": "0x3076857bd17959c2a3df18357eab3ecbb7ca25457785b07074d2e885eb566fc2", "firstIndex": 5368707746},
+{"blockNumber": 13108823, "blockId": "0x67b2764f6b53779e3d683def2c7659c6d92814152574073d24f10cd67200a22b", "firstIndex": 5435817680},
+{"blockNumber": 13175389, "blockId": "0x0d41e34dbca58dec45e0509b6cbf027b2377220845a85caebbf3a14b8505e8ce", "firstIndex": 5502925085},
+{"blockNumber": 13237624, "blockId": "0x723e0818d54ab1b1c53efc2f2f448c16c1f943af2033575c612c3c71228d4ddf", "firstIndex": 5570034948},
+{"blockNumber": 13298658, "blockId": "0xd7f9f477b20bcf1379ccaaae701c9658a02b177861e0af9e873c63fe8b854f4b", "firstIndex": 5637144562},
+{"blockNumber": 13361166, "blockId": "0x9f9e4130093269d59045f91344a13eb2786023e02099f53dd44854d50a7f5ffb", "firstIndex": 5704253260},
+{"blockNumber": 13421716, "blockId": "0x28752f35ad2adeba342ef6aa51bca1c0abc757c4f712cf620c8a5e6a8576636e", "firstIndex": 5771361775},
+{"blockNumber": 13480516, "blockId": "0x43f4ecf24c17b7a77621e2ca09c88c53b3407fb018f4bb3a032c212015b4e18d", "firstIndex": 5838469616},
+{"blockNumber": 13535688, "blockId": "0x99ffcd9982219a4be45fa5f15622b288afe4f85da536956d39dccac1ec416444", "firstIndex": 5905579739},
+{"blockNumber": 13590487, "blockId": "0xff7b74464a318037e0670c0be7a5b1b79418d1a42c7a3587c46adc1ef720c819", "firstIndex": 5972688013},
+{"blockNumber": 13646596, "blockId": "0xd555ce5f2b65ffeec9b9e3e75a56f5f23d7353a1014bcc861efd7df6e5dc2c92", "firstIndex": 6039797525},
+{"blockNumber": 13702902, "blockId": "0x3e8feab590c6631c63931fee83bf7e10234890bdf377b1b374fb70221b9ac9c0", "firstIndex": 6106905641},
+{"blockNumber": 13760908, "blockId": "0x18e96fa585c57aad1f2a8dc9639d9f4fe53c3f38894862471b7cec17f97f3cb1", "firstIndex": 6174014330},
+{"blockNumber": 13819340, "blockId": "0x25384bf2cef178e30c4d9e0abae59357055241fc715133b2bb078e8278e5296a", "firstIndex": 6241123906},
+{"blockNumber": 13877817, "blockId": "0x4a84a0a7035dbfed0e1281fb1df162a195f2c516686a2e2a6ad605e6f2b3cf57", "firstIndex": 6308232690},
+{"blockNumber": 13935260, "blockId": "0x6c14a8e563614edbad66698ebe911e997e27844f9d33c7069795379540e71a44", "firstIndex": 6375341148},
+{"blockNumber": 13993914, "blockId": "0xc0991d1bc431c5215fb0218b0b541f2b4fae0994775e5eddb016965fe5b4a0c7", "firstIndex": 6442448947},
+{"blockNumber": 14051007, "blockId": "0x854803ce364b6fe4446800e74448a5ee883e7d472e8a0347f1ad13bd347fa69f", "firstIndex": 6509558964},
+{"blockNumber": 14109063, "blockId": "0xa3fadce7ab18a5fedcfed9e3b1f0cf2fb32151172c362327c602343bc26dde8f", "firstIndex": 6576668017},
+{"blockNumber": 14166701, "blockId": "0xaa2443a38e2b0d6b01cf4b73de54d2b7e92c99475bd0802beebd86845c126d1b", "firstIndex": 6643774648},
+{"blockNumber": 14222367, "blockId": "0xa27c78134c1fbf432c8caee7c9d2ef323fdde519a065804c9c8da6ca1615e04f", "firstIndex": 6710886238},
+{"blockNumber": 14277029, "blockId": "0x5d0ed08b65db01e382c339dcb2715b2927fb472b0c1f4256841c386d785c3f3a", "firstIndex": 6777995247},
+{"blockNumber": 14330955, "blockId": "0x3e5014d82c416549acfe2e26b13ff5ddf29ad74943ef5b94a65eca0a4d72d82e", "firstIndex": 6845102969},
+{"blockNumber": 14384139, "blockId": "0x720e1fd687292019c3fa1812c39c73d20fde783c0196f43378a51cb4e0b46d65", "firstIndex": 6912212078},
+{"blockNumber": 14437534, "blockId": "0xe4342ab6f363066d9c2514a870241ceb63df232d33659fdb3928faf433360bb4", "firstIndex": 6979321493},
+{"blockNumber": 14489073, "blockId": "0xeb2f9923d816e773460eccfa42eb4ff2bbfc353b756ba274e98dc85c64ab1536", "firstIndex": 7046428879},
+{"blockNumber": 14541559, "blockId": "0x55cc33721fa9022964f47c30f4146fee7cc80f5b4158d7ecea0ff661cbba3487", "firstIndex": 7113538857},
+{"blockNumber": 14594432, "blockId": "0x676441bdc1ec430a9fbc05e56a0437a475606a253f9fdffc86f5f6286c159b5d", "firstIndex": 7180647956},
+{"blockNumber": 14644942, "blockId": "0x03232a1d3c9b2f1f0c2a4b780c83bce66238d9abdeed71c2a8af9e97a53011b0", "firstIndex": 7247754981},
+{"blockNumber": 14695793, "blockId": "0x6017f6d1d79188692e1a1a18de5f93b83b97905c8ff5bed5cef4b2e9f4d4d41b", "firstIndex": 7314863646},
+{"blockNumber": 14746186, "blockId": "0x332c8ac0b2960fb1627407d45443201a0f6de7421b52af077b32fa6e018e5401", "firstIndex": 7381974499},
+{"blockNumber": 14798403, "blockId": "0x4507ae1d9f27a3eada874dcf04112a5d4ee7155701afd3fb857fe58201a2dede", "firstIndex": 7449082752},
+{"blockNumber": 14848093, "blockId": "0xff98c820c66c3beaaa3b195158c94f099148573a7f032295ba7156c13f78eaa8", "firstIndex": 7516191978},
+{"blockNumber": 14897508, "blockId": "0x49c31d3433b197585f733d7c382ae16d9d78bf59c333a9b76362cc6c5fed270c", "firstIndex": 7583300663},
+{"blockNumber": 14950638, "blockId": "0xf1a1609206788977841927271808fe1c42d059026385d025bf4cea0c0a05966b", "firstIndex": 7650408992},
+{"blockNumber": 15003958, "blockId": "0xf9e6b41108d907672f29ba1df97ed83aca2ba933335e6b5ccfb5d4001807b33f", "firstIndex": 7717519105},
+{"blockNumber": 15056783, "blockId": "0x126a5a5c22e878a4c42bea890d48cfe00edf7fbc27d805c88a5269540bc94a42", "firstIndex": 7784628173},
+{"blockNumber": 15108163, "blockId": "0x5f8494ccacefce9fef8a95a52247f2670ed30bb5a3b3deb85c645e72c115d506", "firstIndex": 7851735261},
+{"blockNumber": 15159385, "blockId": "0x0fed6c5aafb53e9cdb0d8620c3eef9b619fb3ae9559296618f634eddae33f0c6", "firstIndex": 7918844299},
+{"blockNumber": 15210872, "blockId": "0x37bdb94b57044b67fbd9b9a7cdc728fcfd2066cf1904cab478fd42d41ec6e1f0", "firstIndex": 7985954119},
+{"blockNumber": 15264226, "blockId": "0xc173ad8a791e2293efd8e0b2c9f088fac49233aabb1e72db6a045aa9904f4728", "firstIndex": 8053061840},
+{"blockNumber": 15315693, "blockId": "0x985cf97bf28f0becb2b16abfe629a5f520596e45fc23f4936bc2f6298b8145f9", "firstIndex": 8120172048},
+{"blockNumber": 15364606, "blockId": "0x593362ef8a82140f3dd3ff13d0ce50287dcb0b8b3d31ffcc7813c6be16f7438d", "firstIndex": 8187281275},
+{"blockNumber": 15412727, "blockId": "0x5a6ff10acc48e9e8bcf963b042012ea094628b9488b8bf569783b3297c67eedd", "firstIndex": 8254388575},
+{"blockNumber": 15462642, "blockId": "0x137f15c5d112b0fdc6e4c84393032030646122c3b0d86286143a1ab8bfacbac4", "firstIndex": 8321497214},
+{"blockNumber": 15509781, "blockId": "0xe58a8ca223b7c03755d046a6212bc33fa9814f73efe52804d8eea7ae4b4bd7f9", "firstIndex": 8388606496},
+{"blockNumber": 15558625, "blockId": "0x4127d527b58c7685a1237d228508ea77d40f33dbeffb5cc30e47e83a4b6152a5", "firstIndex": 8455714910},
+{"blockNumber": 15604075, "blockId": "0x7d1c1bccfe5c23a1edd81246e6e55277f271cffef30bde22c9d1202f764dd96f", "firstIndex": 8522823324},
+{"blockNumber": 15651742, "blockId": "0x732e5203a504fd97510325c1fb876476ca132831e78182367cd4b4efae1232c3", "firstIndex": 8589934155},
+{"blockNumber": 15700810, "blockId": "0xe031decb5e42a69dafcc814441227085508cf51c9c77f35d06487db19bd05a6a", "firstIndex": 8657041374},
+{"blockNumber": 15762855, "blockId": "0xbdff9b1e193c44f35bf38945d2523c74ef59c4f352efc93fad02ef34eef1c5f0", "firstIndex": 8724150924},
+{"blockNumber": 15814304, "blockId": "0x524a226d9f48e37db00e252c7f6a1350d1829d38fe83c756021cc11c56d3b2dd", "firstIndex": 8791259373},
+{"blockNumber": 15865514, "blockId": "0x4e4ad46f3ae7fb2a2e7cb94aa804929cb7353c79c78cc2cbcee710da5f0ec4b5", "firstIndex": 8858369571},
+{"blockNumber": 15920411, "blockId": "0xa39e4cbd8e84b427e44b8d06b5b1149652f3af5fa88633b802665b8677772bc5", "firstIndex": 8925477782},
+{"blockNumber": 15974193, "blockId": "0x4a3f82935e6fcda6ce7636001989b65b79422d362e60833e01185a7960b2fa55", "firstIndex": 8992587369},
+{"blockNumber": 16032739, "blockId": "0x7f50bb76dfd01125e0a4a7595106e43329eb8bd02e819be2ade4248a403c714a", "firstIndex": 9059696611},
+{"blockNumber": 16090896, "blockId": "0xdc4db130973ef793d2223844e35122a2477e642d86c69616fb3604d2a79805c4", "firstIndex": 9126804425},
+{"blockNumber": 16150783, "blockId": "0xb46294fe1cbcbbdff7309ebf0bf481e78e2589d386b95fa4c781c437e02e0aec", "firstIndex": 9193912139},
+{"blockNumber": 16207278, "blockId": "0x8a3af0387572b56989bb6c98d8860e07b5cdefb2ebe7b1dc58be07c24a53e056", "firstIndex": 9261022215},
+{"blockNumber": 16262389, "blockId": "0xec5a03d88cfc1bf8c278ddce7ace5032c3f7ed5032b4575df54779ec1abca131", "firstIndex": 9328130680},
+{"blockNumber": 16319525, "blockId": "0x74ae702375e242205fe4986448b0ee494d4a38ccc813981489c4b0488e58a949", "firstIndex": 9395240779},
+{"blockNumber": 16373441, "blockId": "0x5f404555cf45c547ef0fc044f2701bc7a28ce1e432de06e0264dbfd1c17447d0", "firstIndex": 9462347671},
+{"blockNumber": 16423343, "blockId": "0xe4af890b6c4dd3b10af2e6c08f14563bd2a3121b22a3cc6a0db29d438c1dcc59", "firstIndex": 9529457704},
+{"blockNumber": 16474687, "blockId": "0x019a8b374cf150fcda1c8af2a3e7ba63603ae81744d6343897c4b17ee58411d5", "firstIndex": 9596566169},
+{"blockNumber": 16525504, "blockId": "0xad394ce7e84e1c904cc5dd6dabd51b1a575c0b2fb006f10f272875b7f921904e", "firstIndex": 9663675287},
+{"blockNumber": 16574051, "blockId": "0x098e2dca2eda0d700aa3127bdfb679ce16e3ca297a305978c6ecfff044269511", "firstIndex": 9730784563},
+{"blockNumber": 16622457, "blockId": "0x8627f1237731c1127116898724f1b6420b8e7bcd8e18a0ea568f192bbd2cd55d", "firstIndex": 9797893241},
+{"blockNumber": 16672410, "blockId": "0x3e32b46faa670b191b89bea84a68022d5ea8b90008b388a948ff27f871d17292", "firstIndex": 9865002964},
+{"blockNumber": 16719964, "blockId": "0x1668c3ea6cb256f306e93851cc2c00612f85df5cf7b5527ffce14c89088d7fdf", "firstIndex": 9932111708},
+{"blockNumber": 16769014, "blockId": "0xed9a6f88e47b5bfe4d5bc92e1c1bfeb252f716f0990ffa1f907655c0f5e3a365", "firstIndex": 9999220312},
+{"blockNumber": 16818134, "blockId": "0x93504ba617500698a1b46f3110cd26827b8efe468190b2a91d3595784e34a1b6", "firstIndex": 10066329167},
+{"blockNumber": 16869369, "blockId": "0x94ca4b395a5c36c4e9d07cbb08271f0680455af4e4659906b647e16abebd7d4e", "firstIndex": 10133438415},
+{"blockNumber": 16921428, "blockId": "0x66650775bff4cb95de56099c10b06f3dfe302a731b391f406d1aa551121308ba", "firstIndex": 10200547148},
+{"blockNumber": 16974677, "blockId": "0x58d5fc4cd45047dac10d55a036e0a4448faacc1041b29c4c7fb41a6e9394c3ff", "firstIndex": 10267655623},
+{"blockNumber": 17031050, "blockId": "0x9d15b831979e95fc4149ecae46478cac1e54470b277d57d7102d19a72f28eeba", "firstIndex": 10334764441},
+{"blockNumber": 17086163, "blockId": "0x978ff48863fcdb50b274ea4220e7635c13c41bae91912db9e24205fb917fde85", "firstIndex": 10401873176},
+{"blockNumber": 17141086, "blockId": "0x4084d442499893361731f17534944d260cccd8e07d41c52d7160910555770b90", "firstIndex": 10468982462},
+{"blockNumber": 17190735, "blockId": "0x42ed86fb42def23870df6ec23204f557669ec7cd8de59c9f3ef9ab90704e4b11", "firstIndex": 10536090726},
+{"blockNumber": 17237026, "blockId": "0x9a49d943f82a7335f8049df4d953080f25920e3b098f6a2d872520166b225961", "firstIndex": 10603199938},
+{"blockNumber": 17287007, "blockId": "0xac3d189676d24eadc62adcf97d8730a001a7766fe3ac27b18e745ca9727f6c46", "firstIndex": 10670308186},
+{"blockNumber": 17338498, "blockId": "0xe50e251aa0a3209fa8a0030b237cf8357b08eeb80492a432c8aa5969a820ee42", "firstIndex": 10737417623},
+{"blockNumber": 17389178, "blockId": "0x1e18cedcfa6c81bc845c9136fc92f9f27ca8fff8847289bb139f374f0f6ba733", "firstIndex": 10804526769},
+{"blockNumber": 17442038, "blockId": "0x07f47ebbee99938fb96beb1ffadf8266f71d0d73f393172f0e24facd40d45c97", "firstIndex": 10871635940},
+{"blockNumber": 17497589, "blockId": "0x247a5e852e36e46f7897ad1875e93d810ff4434bb835b469afae3a3d3d4a9c9a", "firstIndex": 10938744251},
+{"blockNumber": 17554111, "blockId": "0x420e420a1b599e4dc3bd115652b4d6f5eedc391086ef064f97a9cbffc02b62f9", "firstIndex": 11005853686},
+{"blockNumber": 17608282, "blockId": "0xb2ba644d3593d3c832f932f14ffec532e26e9e1cdcd8fbe7477f46e238c6bffd", "firstIndex": 11072962303},
+{"blockNumber": 17664091, "blockId": "0x6d0bfff8145652a617bfe03ab87e3af09219cdb822c9c214b42b16f20742c1eb", "firstIndex": 11140070260},
+{"blockNumber": 17714917, "blockId": "0x61509544b5174d3ff5d48816ff54f2929c8a400ef21454116056baa136b607b6", "firstIndex": 11207179013},
+{"blockNumber": 17763850, "blockId": "0x8da83012621f42670601406c902ce6e48e77c6285dcc6983e108e69b3a8d5d2d", "firstIndex": 11274288732},
+{"blockNumber": 17814186, "blockId": "0xc37bda200856589c220dc206e31186d6c12761fd193f5bc7123cf331fbbed7f5", "firstIndex": 11341397343},
+{"blockNumber": 17864461, "blockId": "0x99af43893dc9f54c55abbdbd7b000e27248145371e9b00db116dfb961b36749c", "firstIndex": 11408506122},
+{"blockNumber": 17913212, "blockId": "0x9b642236d63d756fcd3404713bc6abe97804b46a9e665ae5f1d9aa48e693fe78", "firstIndex": 11475614347},
+{"blockNumber": 17961497, "blockId": "0xaec9b1e851cf51646673ec7698e1d5964d44eb04729ad11385f6ae84d497070a", "firstIndex": 11542723713},
+{"blockNumber": 18010859, "blockId": "0xb15fb7fc308516cad5f1dadfb7dd92fd3fe612308f67154cf2a241990aa15bc4", "firstIndex": 11609833204},
+{"blockNumber": 18061052, "blockId": "0xd8ea94b8b8a7380d21dc433abb69973f3de2eeb339f4aaffdb79f85a5d86929d", "firstIndex": 11676938565},
+{"blockNumber": 18111466, "blockId": "0x5b5cc6d182bffaf06692a7efda8cad5d4742fdbce5c1146b3be3c5be10ea046a", "firstIndex": 11744048539},
+{"blockNumber": 18166001, "blockId": "0x901d8401c795542c75069cd917781fa587ad416da0a5298f144fae2f14305705", "firstIndex": 11811159949},
+{"blockNumber": 18218505, "blockId": "0x5894285023f34ec6fd501cd90b605e118b9688ca7c01082289bf69a6987142bc", "firstIndex": 11878268395},
+{"blockNumber": 18271037, "blockId": "0x3f0fce315fd993d966b6c599ebd360462466e67046d512dc430ac07f75243bae", "firstIndex": 11945377050},
+{"blockNumber": 18322778, "blockId": "0xfa6536b3b06e7b579e53a8d01368182808c950586e39e12485be3145c3acbf43", "firstIndex": 12012486036},
+{"blockNumber": 18372240, "blockId": "0x5531859d5b8a4093020e2fb971808d0eeaddd7d61dc58d70f34923081f97336f", "firstIndex": 12079595358},
+{"blockNumber": 18421630, "blockId": "0xfeadff676fe8f04d0362b77ea2d7c3ea59b05d68cc6b2cc95cfe751558b1bfa7", "firstIndex": 12146703872},
+{"blockNumber": 18471472, "blockId": "0x352b0a17e4160d334b876eb180d686fd67c7ddc40a78219b0bc4b59f5ae5912d", "firstIndex": 12213813174},
+{"blockNumber": 18522088, "blockId": "0xf7d408309246089531b47c787049c7ffd2820c1b87b4804033a458bc193a3432", "firstIndex": 12280921181},
+{"blockNumber": 18572725, "blockId": "0x44126d4a5b43594b09d26e0b0a5dc859c074865cb9b11ab78c80f28406fd0240", "firstIndex": 12348029615},
+{"blockNumber": 18623223, "blockId": "0xd3aec1f98cea30e870d0f530194e9a72e225eb45eefe435e38da5967eb2fa470", "firstIndex": 12415139522},
+{"blockNumber": 18675228, "blockId": "0x24deaef2508038bddf8e9020f95128ae34eb1786f786c3f98df0bdf95f3e97cc", "firstIndex": 12482248123},
+{"blockNumber": 18725495, "blockId": "0x2e5a7edd7337b20e862741e116680a472089426dbc2b0eb5f1c984f8d6da935b", "firstIndex": 12549357121},
+{"blockNumber": 18778174, "blockId": "0xe734a1084fa5eeff427bba8e8d3623181a30dd9bad128fc22de9b15dffd0e549", "firstIndex": 12616466131},
+{"blockNumber": 18834807, "blockId": "0x0924a55ef4f9c2605261433c5b236d47645484efa44b34dc9f15b7c2e6b47a74", "firstIndex": 12683575000},
+{"blockNumber": 18883054, "blockId": "0xef638ec491a1cf685b22bf4072e41710440d6133a53e31250762825247d3eb64", "firstIndex": 12750683712},
+{"blockNumber": 18933405, "blockId": "0x6e9eefc2e121d13e6c04544ea370fe8543afeb36fef3a8e2ea68afb079738c8c", "firstIndex": 12817792510},
+{"blockNumber": 18988033, "blockId": "0x4c98c0dbb6a7217609c4b277fe7ff9e2c32c8d000ee628a3f37b2b296e1ca421", "firstIndex": 12884901389},
+{"blockNumber": 19041096, "blockId": "0x61a219a23d111cd07861ff47b89d4b2840c0ab5421d5d55a6f1fe43da3f33b98", "firstIndex": 12952010147},
+{"blockNumber": 19088914, "blockId": "0xefb26ba58447e50e9b820e0b0d16c08da45793a824af12a2e1f38b6f46b7e36a", "firstIndex": 13019118891},
+{"blockNumber": 19140413, "blockId": "0x91dbb13623fc4d5a4e462dfa0a03c92bf5301948dd4b2c3e5fddd2bc88856d47", "firstIndex": 13086228137},
+{"blockNumber": 19191876, "blockId": "0xdd7f97af7ad206b2636656ed4722fe1c47c6ba9fa5531066785acbe4f8d4c4ad", "firstIndex": 13153336551},
+{"blockNumber": 19237651, "blockId": "0xf1e875f314314abe3654b667c6443c772dd67c525c52877b06515ea8fc5a391b", "firstIndex": 13220444812},
+{"blockNumber": 19291032, "blockId": "0x9eda269ac47957b619d2a8c408b5efc8cfb168a46bfde351f43325fa337fce47", "firstIndex": 13287553967},
+{"blockNumber": 19344225, "blockId": "0x62859b78d45f589f679fc6a3bf266a2e0aa906fd61d787755ec51cfadc05eaf6", "firstIndex": 13354663338},
+{"blockNumber": 19394709, "blockId": "0x7cda3d193bcfe8ddbc89b85e98c814dbbe31a54ccab52ab7738ecd003061f3c8", "firstIndex": 13421772549},
+{"blockNumber": 19442850, "blockId": "0xd95f3f8bab5b91c3e1f848c9455936850bf92cf6a5086b817f6f81031bc0f81e", "firstIndex": 13488880704},
+{"blockNumber": 19488177, "blockId": "0x3a1a9623ee332d6decada9359cf84eeafb81fffa997d6cf4f3efcc92e98e9310", "firstIndex": 13555989570},
+{"blockNumber": 19534365, "blockId": "0x5c7a8ee7cbba4894ea412cc335895a9a7d3369d35779bcdc97a6c24b6a81a7ba", "firstIndex": 13623097446},
+{"blockNumber": 19579409, "blockId": "0x4280f5f76cb0f9947f9da1cb9de6c4b6e65b37b3a3c174f5fb29d360cf389ffb", "firstIndex": 13690206790},
+{"blockNumber": 19621406, "blockId": "0x0a98ca72e97fd295c7c73263b17185d74dbe427f41c616a5d5454faa5a1c63a0", "firstIndex": 13757316653},
+{"blockNumber": 19664868, "blockId": "0xc8c53d89b7a849861f3daaf9503e6397a0340cecb085850c3636bee6ea2b7189", "firstIndex": 13824424608},
+{"blockNumber": 19709011, "blockId": "0xf65babc88ef6a9eb2ffce9a6844adf895995f65a2facd1956f5df17ca68dbf94", "firstIndex": 13891534141},
+{"blockNumber": 19755170, "blockId": "0xf903882449eeb86d69af33b6797099275e82d8787334a02a42a2168dbd739b95", "firstIndex": 13958642627},
+{"blockNumber": 19803666, "blockId": "0xa8a975f570db082a3771790bb1fe405667dde4674ff49e31092687fa92727e36", "firstIndex": 14025752433},
+{"blockNumber": 19847730, "blockId": "0x89d479a4b4d9faa7af3e3f61d13a7a9c80a11c4adf7cd018859eb0ddba30bdd5", "firstIndex": 14092860598},
+{"blockNumber": 19894138, "blockId": "0x740278e6dc79cfd2b030780868a1b8e1520dbae0e8d3ee0a3ef43c84c83c6e0a", "firstIndex": 14159952129},
+{"blockNumber": 19938334, "blockId": "0x05ae7ce9813235c19baa57658bc5c8e160130328a1fd2cc58d2baf2d9a4ae097", "firstIndex": 14227078393},
+{"blockNumber": 19985138, "blockId": "0x511c8876a93a77fa473ae0d29e25d8163162c09b7212f506be0ea73840ea3971", "firstIndex": 14294187397},
+{"blockNumber": 20028221, "blockId": "0x64379baedf429cfa65df076142a7d9909d7e369d6aa6b8e161bb686944d169ff", "firstIndex": 14361296446},
+{"blockNumber": 20071555, "blockId": "0x4f43d8b1091d2bd0c6b080ce51bce08aae6be605e00889be3cdd17cb80614ff8", "firstIndex": 14428405409},
+{"blockNumber": 20113611, "blockId": "0xebbf87409ef6732a53513414926b0aa998a7269f9e9717a3acbe96a33c2de937", "firstIndex": 14495514255},
+{"blockNumber": 20156628, "blockId": "0x70218108c0669f42c4ac1afff80947cf4a0a2fd8e9300b31d45bbe330a5159c9", "firstIndex": 14562622257},
+{"blockNumber": 20199886, "blockId": "0x1d6aaa4b041eb0cc9caed34347bb943e50a139caf8998d781ff4f06d4aa727dc", "firstIndex": 14629732017},
+{"blockNumber": 20244148, "blockId": "0x37fed57b6945a815ec56c84c6261e90cf9f3883d9cbffc62b70d9722c1f0f363", "firstIndex": 14696839730},
+{"blockNumber": 20288249, "blockId": "0x1d9fe664431e093c4ef6139ad35fea767a2e66825e605cfea9e91d1738665619", "firstIndex": 14763948803},
+{"blockNumber": 20333358, "blockId": "0x1ac7c1362791507057b7e87d7118b4f61c2919c8ebdb498ecf7d64a59ba3d2e2", "firstIndex": 14831058814},
+{"blockNumber": 20376855, "blockId": "0xf6a19eac8a402f591079a4aa7ff57349c350ec96d683a031e4d85c05bc0541b2", "firstIndex": 14898167076},
+{"blockNumber": 20421474, "blockId": "0xe8767aa7516b632dc8c0fed3a366273ef14bd7b8c2212998b7105fb80b4c0d9b", "firstIndex": 14965276285},
+{"blockNumber": 20466974, "blockId": "0xafa2d2e6c9594762c163c339069cb15aa9fd27d301268892e12f99a3f2912ade", "firstIndex": 15032384674},
+{"blockNumber": 20512183, "blockId": "0xc1c51f9372d781d7ac0a1a7aa052503bbde3e1706bf65f225b0f6a6eed93d055", "firstIndex": 15099493832},
+{"blockNumber": 20557251, "blockId": "0xa905087c15e2b12b19cd23f20089b471cd9815dcff73842d2043e13a276fcc55", "firstIndex": 15166601921},
+{"blockNumber": 20595654, "blockId": "0x9e7772dd946f65e7569f34f6896d8e597ac8ff88700b871de21ff578c0c995e6", "firstIndex": 15233711474},
+{"blockNumber": 20638340, "blockId": "0xc08b46af83db6f0e5d1acad7020bacd59d0f18df72651d32c9b60edd0351a886", "firstIndex": 15300820584},
+{"blockNumber": 20683359, "blockId": "0x7ec93a1f1d211c24d93ce7e344634efef680a6388374cf3831d250ecd63711f9", "firstIndex": 15367929168},
+{"blockNumber": 20728401, "blockId": "0x4ad4124c2595abcf4477cac4eb70c0c9372bbd48f2066c7ac5b8e9f94817ab48", "firstIndex": 15435038303},
+{"blockNumber": 20771272, "blockId": "0x68fd6b12fdb4add8b2957105a21b571c7dcb114c6c2ca02f5fa40730a108f864", "firstIndex": 15502146509},
+{"blockNumber": 20814862, "blockId": "0x4e7f640bf3c135b2442ca4c744023021af163e8d45e8d776fb7051c49d79fcff", "firstIndex": 15569256173},
+{"blockNumber": 20857627, "blockId": "0x9b023bffed12530b5a68db263bb621a147e0cf02b30ec39a82b82a1fdeb7ca36", "firstIndex": 15636364955},
+{"blockNumber": 20896662, "blockId": "0x8c3adf694b8520ed1edd38282b2f58cf383426176628b5be6330a56882e2a07e", "firstIndex": 15703473445},
+{"blockNumber": 20939156, "blockId": "0x0649e2559f767da945a674c9d6c700628109e18d0757ad33496a228a827413a4", "firstIndex": 15770581979},
+{"blockNumber": 20981054, "blockId": "0xebf0ecca671b833f77df70106cf1171d4dd3fa0f062607e4845569073997f1cd", "firstIndex": 15837691319},
+{"blockNumber": 21022980, "blockId": "0x07479520c08a727c42e3616aca7fc4435773f4ef277d84369190263159606d71", "firstIndex": 15904799391},
+{"blockNumber": 21068139, "blockId": "0x669cfd03b293a61815588cb9cef928a512d328c1fe9191fe6b281573f429f8b8", "firstIndex": 15971908604},
+{"blockNumber": 21112368, "blockId": "0x98957aedaf8b0483be208e8d16a3e6d73ff217e732f3649650671c92c8fb57a5", "firstIndex": 16039007815},
+{"blockNumber": 21155756, "blockId": "0xc301e40988fbe19b1254ab3abe2f78fe0cd35259898be02476179a041926f777", "firstIndex": 16106127130},
+{"blockNumber": 21200717, "blockId": "0x8d35b199ee65c5ccf4ca0fc22b50282850cd88b72580679f1568eea67d3431e8", "firstIndex": 16173235593},
+{"blockNumber": 21244396, "blockId": "0xe7ec084eb8a7125fe26c4ef64fdbb3e0a727b2d882fb1e4fdad1d7fa3dc55fd2", "firstIndex": 16240343803},
+{"blockNumber": 21290031, "blockId": "0x8bb31b883d30875b7ed8a01c35a6f51e603b8d974c4e74af20fb9c723e5ac5df", "firstIndex": 16307452772},
+{"blockNumber": 21335893, "blockId": "0xd0976b7c946a7556e607e47a02d2cfcccd259508e2828b9c4faa5c7105a597a8", "firstIndex": 16374562657},
+{"blockNumber": 21378611, "blockId": "0x72d42953f013aeb7c84bb22c9e07828b92f73885b20c208af612874df8fe85ed", "firstIndex": 16441671192},
+{"blockNumber": 21421343, "blockId": "0x663b3cddcf3f7cfa59ed29b4894e43fa784c07576cfec897ff1a3838235ecb50", "firstIndex": 16508779766},
+{"blockNumber": 21466598, "blockId": "0xe04ebd60289dbcc09a27e053e7b240a59e928e2a76a85a6fa4044ee387c46d18", "firstIndex": 16575888836},
+{"blockNumber": 21511717, "blockId": "0x5ea9863a0b504f381010ff383d60a56390ba9cef162d9d5a077b1884d2adac98", "firstIndex": 16642998234},
+{"blockNumber": 21550050, "blockId": "0x2a7b3e635c80521887ca3ebda04541090ec720dd817cd06fcba61e7ae0f78a4f", "firstIndex": 16710106733},
+{"blockNumber": 21592440, "blockId": "0xc7095268d0d53cb5a069c2ea7107cc42172bb1b817f04154938e6b52bdbb369c", "firstIndex": 16777215261},
+{"blockNumber": 21636007, "blockId": "0x55f463b932053ebfc02728a12c2cdfb2cb4700a115cde686c9ab22bb4c336ecb", "firstIndex": 16844324844},
+{"blockNumber": 21680799, "blockId": "0x4521d473aa7f5150f920c66fe639b20f30cb373b32e425fcb7dcce9803b506be", "firstIndex": 16911431255},
+{"blockNumber": 21725330, "blockId": "0x793876007ce3594df603628766b139a02273ceee43d5b3ca2d0ca2f13a5fc5d9", "firstIndex": 16978541626},
+{"blockNumber": 21771310, "blockId": "0xd0db23bb28d6e39917348b1879dd560c73354ea6d7d0bbee0b7a8fcbcede1091", "firstIndex": 17045650902},
+{"blockNumber": 21811348, "blockId": "0x8165948c08db34aeb8cc2a3e331a00af2d09fbff9c466019fb2f2892ca3f7b71", "firstIndex": 17112760024},
+{"blockNumber": 21851615, "blockId": "0x3083e8f4fbb4d726ef19b1a5bce20e639a0418eac384f9967f24c7697a7e2dfc", "firstIndex": 17179868870},
+{"blockNumber": 21894041, "blockId": "0x9b0776a020374e4985f6a7e1199596bedd387ff085f65224d724ab11955c56fe", "firstIndex": 17246977342},
+{"blockNumber": 21932218, "blockId": "0xe9c50eddc21759d3ab790e2babba56f4b8d38eb739f1b561bc337a1ba6e15393", "firstIndex": 17314085541},
+{"blockNumber": 21959188, "blockId": "0x6b9c482cc4822af2ad62a359b923062556ab6a046d1a39a8243b764848690601", "firstIndex": 17381193886},
+{"blockNumber": 21994911, "blockId": "0x0d99ef9dd42dd1c62fc5249eb4f618e7672ab93fa0ba7545c77360371cf972e5", "firstIndex": 17448302795},
+{"blockNumber": 22026007, "blockId": "0xf7cdc7f6694f2c2ed31fa8a607f65cfa59d0dd7d7424ab5c017f959ae2982c71", "firstIndex": 17515413036},
+{"blockNumber": 22059890, "blockId": "0x82b768a0dddefda2eefd3a33596ea2be075312f1dd4b01f6b0d377faca2af98b", "firstIndex": 17582521768}
]
-
diff --git a/core/filtermaps/checkpoints_sepolia.json b/core/filtermaps/checkpoints_sepolia.json
index 3e3ea23b24..c6d3cd9086 100644
--- a/core/filtermaps/checkpoints_sepolia.json
+++ b/core/filtermaps/checkpoints_sepolia.json
@@ -1,63 +1,68 @@
[
-{"blockNumber": 3246675, "blockId": "0x36bf7de9e1f151963088ca3efa206b6e78411d699d2f64f3bf86895294275e0b", "firstIndex": 67107286},
-{"blockNumber": 3575582, "blockId": "0x08931012467636d3b67ae187790951daed2bb6423f9cd94e166df787b856788d", "firstIndex": 134217672},
-{"blockNumber": 3694264, "blockId": "0x1f35f276a3c78e5942ee285fcbd0c687691853c599a2f5b174ea88f653bc9514", "firstIndex": 201326578},
-{"blockNumber": 3725632, "blockId": "0x3bcb264c56c3eeab6c8588145f09dff3fb5f821d9fc1e7b92264b14314dae553", "firstIndex": 268433636},
-{"blockNumber": 3795390, "blockId": "0x2d1ef2815bb8e018b275fa65540b98265285016aff12596bd89a3b1442d248eb", "firstIndex": 335542953},
-{"blockNumber": 3856683, "blockId": "0x8a9a46d6f53975cd9ec829c3c307a99fb62b8428cefb63ffe06d17143649c3ee", "firstIndex": 402648835},
-{"blockNumber": 3869370, "blockId": "0x2e8c04e7e5e96d09260b65d77b1770b4105b0db2ee7d638c48f086b8afac17db", "firstIndex": 469759276},
-{"blockNumber": 3938357, "blockId": "0xf20f2cdbcc412d5340e31955d14a6526ea748ba99b5ec70b6615bdb18bcd4cfb", "firstIndex": 536868027},
-{"blockNumber": 3984894, "blockId": "0x0bcd886b3cebb884d5beeaf5ad15ee1514968b5ad07177297c7d9c00f27aa406", "firstIndex": 603968430},
-{"blockNumber": 4002664, "blockId": "0x7d3575b6ca685468fa5a5fa9ff9d5fac4415b0a67a3ed87d3530f127db32fff4", "firstIndex": 671088417},
-{"blockNumber": 4113187, "blockId": "0x3a5313ac5b602134bb73535b22801261e891ccb7bd660ab20e0a536dc46d3e13", "firstIndex": 738197016},
-{"blockNumber": 4260758, "blockId": "0xe30fb9a304d3602896a5716d310f67ba34ccef7f809a3ead4b2d991cb9ee4eb0", "firstIndex": 805306270},
-{"blockNumber": 4391131, "blockId": "0x3958478c1c3be9b7caedbcc96230ed446d711e56580e324bc2fcf903fc87c90f", "firstIndex": 872415115},
-{"blockNumber": 4515650, "blockId": "0x46a3a7b97a9dff4ef4dc2c1cc5cd501f2182d9548655b77b5e07a2dbb41071a4", "firstIndex": 939523930},
-{"blockNumber": 4634818, "blockId": "0x2197d0dd3925c1d7ba3e2c4eef20035b68efc0a2506f76ddd9e481e0ce8ca6e1", "firstIndex": 1006628557},
-{"blockNumber": 4718295, "blockId": "0xcce7bb4af1a41e6056ef68192e60c738be01ac3e071ed1ec52cead08a39995ce", "firstIndex": 1073734698},
-{"blockNumber": 4753438, "blockId": "0xa60e043728a369cdf39a399bd7a903085ee9386f38176947578e5692b4b01f65", "firstIndex": 1140843192},
-{"blockNumber": 4786522, "blockId": "0x10629cadc00e65f193fa4d10ecd2bf1855e442814c4a409d19aae9eb895dce13", "firstIndex": 1207956586},
-{"blockNumber": 4811706, "blockId": "0xf1e94111f0086733bdcb4a653486a8b94ec998b61dda0af0fd465c9b4e344f87", "firstIndex": 1275058221},
-{"blockNumber": 4841796, "blockId": "0xa530f7dd72881ac831affdc579c9d75f6d4b6853b1f1894d320bd9047df5f9eb", "firstIndex": 1342177155},
-{"blockNumber": 4914835, "blockId": "0xbd8321e354f72c4190225f8ed63d4aba794b3b568677d985e099cb62d9d36bae", "firstIndex": 1409286143},
-{"blockNumber": 4992519, "blockId": "0x4a06a5a4aa5bc52151937cc1c0f8da691a0282e94aab8b73b9faa87da8d028de", "firstIndex": 1476384367},
-{"blockNumber": 5088668, "blockId": "0xb7d5ee03c08ed3936348eeb3931be8f804e61f2b09debf305967c6a7bbf007e0", "firstIndex": 1543502599},
-{"blockNumber": 5155029, "blockId": "0x84f590dfc2e11f1ca53c1757ac3c508d56f55ee24d6ca5501895974be4250d76", "firstIndex": 1610605837},
-{"blockNumber": 5204413, "blockId": "0xeaf2c3fb6f927c16d38fab08b34303867b87470558612404c7f9e3256b80c5b9", "firstIndex": 1677720841},
-{"blockNumber": 5269957, "blockId": "0x596e0b2e8e4c18c803b61767320fe32c063153d870c94e4a08e9a68cbaa582a9", "firstIndex": 1744825147},
-{"blockNumber": 5337678, "blockId": "0x7b2d54f8af1ecaaaab994e137d4421d8236c1c10d9a7bdcb9e5500db7a3fe9a3", "firstIndex": 1811939316},
-{"blockNumber": 5399058, "blockId": "0xb61ef16d55c96682fb62b0110a2dbc50d8eff2526be4121ece3690700611c71b", "firstIndex": 1879046044},
-{"blockNumber": 5422707, "blockId": "0xdabcab7c0cc9cb9f22f7507a1076c87831cb1afed9d0aa5bcd93f22266720c91", "firstIndex": 1946156915},
-{"blockNumber": 5454264, "blockId": "0xe1bde812906605ce662f5fd9f01b49c7331fb25f52ab5b12d35ea2b4da5458fe", "firstIndex": 2013259168},
-{"blockNumber": 5498898, "blockId": "0x9533d9c5353d22f8a235e95831cfbf4d5a7220a430ca23494526a9d3aa866fe8", "firstIndex": 2080374321},
-{"blockNumber": 5554801, "blockId": "0xe7b320bbecb19f1e99dd6ce4aed1efc754d7b2022e1f80389e8a21413c465f55", "firstIndex": 2147476253},
-{"blockNumber": 5594725, "blockId": "0xce6750be4a5b3e0fe152dd02308e94f7d56b254852a7e9acef6e14105053d7d1", "firstIndex": 2214591591},
-{"blockNumber": 5645198, "blockId": "0x5d42d39999c546f37001d5f613732fb54032384dd71a686d3664d2c8a1337752", "firstIndex": 2281696503},
-{"blockNumber": 5687659, "blockId": "0x3ed941be39a33ffa69cf3531a67f5a25f712ba05db890ff377f60d26842e4b1c", "firstIndex": 2348801751},
-{"blockNumber": 5727823, "blockId": "0xaf699b6c4cd58181bd609a66990b8edb5d1b94d5ff1ab732ded35ce7b8373353", "firstIndex": 2415917178},
-{"blockNumber": 5784505, "blockId": "0x621c740d04ea41f70a2f0537e21e5b96169aea8a8efee0ae5527717e5c40aa64", "firstIndex": 2483024581},
-{"blockNumber": 5843958, "blockId": "0xec122204a4e4698748f55a1c9f8582c46bacda029aee4de1a234e67e3288e6b1", "firstIndex": 2550136761},
-{"blockNumber": 5906359, "blockId": "0x8af5ce73fbd7a6110fb8b19b75a7322456ece88fcfa1614c745f1a65f4e915c1", "firstIndex": 2617245617},
-{"blockNumber": 5977944, "blockId": "0xbc8186258298a4f376124989cfb7b22c2bea6603a5245bb6c505c5fc45844bbd", "firstIndex": 2684350982},
-{"blockNumber": 6051571, "blockId": "0x54f9df9d9d73d1aa1cfcd6f372377c6013ecba2a1ed158d3c304f4fca51dae58", "firstIndex": 2751463209},
-{"blockNumber": 6118461, "blockId": "0xfea757fad3f763c62a514a9c24924934539ca56620bd811f83e9cc2e671f0cf0", "firstIndex": 2818572283},
-{"blockNumber": 6174385, "blockId": "0x2d8d0226e58f7516c13f9e1c9cf3ea65bb520fa1dfd7249dc9ea34a4e1fd430d", "firstIndex": 2885681036},
-{"blockNumber": 6276318, "blockId": "0xa922e9d54fd062b658c4866ed218632ddd51f250d671628a42968bb912d3ed5d", "firstIndex": 2952789983},
-{"blockNumber": 6368452, "blockId": "0x8d3d7466a7c9ca7298f82c37c38b0f64ec04522d2ed2e2349f8edc020c57f2c4", "firstIndex": 3019898695},
-{"blockNumber": 6470810, "blockId": "0x9887c35542835ee81153fa0e4d8a9e6f170b6e14fc78d8c7f3d900d0a70434f1", "firstIndex": 3087007578},
-{"blockNumber": 6553334, "blockId": "0x7b0d89a0282c18785fcc108dbdc9d45dd9d63b7084ddc676df9e9504585a5969", "firstIndex": 3154115987},
-{"blockNumber": 6663825, "blockId": "0xff6cec99324a89d6d36275c17a4569f0cba203fe5b0350f155a7d5445e0ed419", "firstIndex": 3221224775},
-{"blockNumber": 6767082, "blockId": "0xe10a96a7194f98bf262f0cb1cdfb4d3b9a2072139dfcbe3f1eb01419e353044e", "firstIndex": 3288334139},
-{"blockNumber": 6886709, "blockId": "0x20f6a5d986913025ad5b6b6387d818e49a3caf838326f4002c1439ca61313be5", "firstIndex": 3355442979},
-{"blockNumber": 6978948, "blockId": "0xd7c3024765245ec49e6a48b076d540bc91f57f2ccc125e17d60dd37bb669f843", "firstIndex": 3422551908},
-{"blockNumber": 7098891, "blockId": "0x05114c037e1b4d69a46d74a974be9bce45e87ad2226a59b44dd17f98dd2fd0d1", "firstIndex": 3489659530},
-{"blockNumber": 7203157, "blockId": "0xc0f610014fcd9f2850274b58179d474f0947676fd0639b2884316467c631811d", "firstIndex": 3556769512},
-{"blockNumber": 7256735, "blockId": "0x0324c15b3b23fd82c2962dd167618e77e60ebeac5a2c87f672caddc9732337b3", "firstIndex": 3623876508},
-{"blockNumber": 7307851, "blockId": "0x8e23280d1a3aec877d7758413ed20299d381aa43e7e2fc6f381ad96e8ff0acef", "firstIndex": 3690987098},
-{"blockNumber": 7369389, "blockId": "0xbf6436eb2b88539945d6673141a14cb79ffc1e7db2b57176acf8e02ff3b6fcd3", "firstIndex": 3758096287},
-{"blockNumber": 7445220, "blockId": "0x147619f74815283d834ac08ff494fb4791207b3949c64b2623f11ff6141ee7a7", "firstIndex": 3825204992},
-{"blockNumber": 7511632, "blockId": "0x5094d64868f419e6ac3d253d19d5feda76564a0d56d7bbf8a822dff1c2261b30", "firstIndex": 3892314047},
-{"blockNumber": 7557280, "blockId": "0x54aba9351a1ba51873645221aa7c991024da1fe468a600ddb6e2559351d9c28f", "firstIndex": 3959422859},
-{"blockNumber": 7606304, "blockId": "0xbbe2fed08cf0b0ff2cb6ae9fd7257843f77a04a7d4cafb06d7a4bedea6ab0c98", "firstIndex": 4026531690}
+{"blockNumber": 3246675, "blockId": "0x36bf7de9e1f151963088ca3efa206b6e78411d699d2f64f3bf86895294275e0b", "firstIndex": 67108765},
+{"blockNumber": 3575560, "blockId": "0x4652e3bee440f946aeaa3358c9a62b9bc4d41f663737ab00fded00c2662bfa29", "firstIndex": 134217644},
+{"blockNumber": 3694262, "blockId": "0x433573f97e563ca04fa53e0d0eb019d0ffe9dd032a05ee5b33ce7705aedfd34d", "firstIndex": 201316990},
+{"blockNumber": 3725628, "blockId": "0x1e25ebd76b9e2a2007bfdd7c82433cce7dae8beb190d249c82bf83d0cd177735", "firstIndex": 268426577},
+{"blockNumber": 3795378, "blockId": "0xca999083e01d5947212fb878d529abecdd18a6012997b0d5326afcf6908f17e5", "firstIndex": 335543438},
+{"blockNumber": 3856681, "blockId": "0x48148cd35de3de6c626f76ce5d97cfc6acd88772af69c0aef3d640c29ba82096", "firstIndex": 402641717},
+{"blockNumber": 3869367, "blockId": "0x08bafccf9ece7b72e4e069fc3c7493fbf25732881758917df2e8f9a51fc2c75f", "firstIndex": 469761225},
+{"blockNumber": 3938346, "blockId": "0xc638eb890c0e65ce1169ef0bb6b74dede2f4f6144ff8a5739c4894ff41a22fa2", "firstIndex": 536865235},
+{"blockNumber": 3984892, "blockId": "0x6a7782f0765b0f0c406b3cb107fd8bb14c6906293d9bdc5cc00e081bfd1ae59f", "firstIndex": 603972697},
+{"blockNumber": 4002660, "blockId": "0xda473de053602bc42fcbb074a32c908303f7f6db2ed8c38192665dce80276702", "firstIndex": 671087183},
+{"blockNumber": 4113149, "blockId": "0xd1782f677262226194725028858da83e672748e409fe1c21bdd77c07be0662c8", "firstIndex": 738197365},
+{"blockNumber": 4260733, "blockId": "0xc356600819e49d311963312157c481fd9be43a36ad040a0512fd17559c78d394", "firstIndex": 805305957},
+{"blockNumber": 4391073, "blockId": "0x06f903dc765b4b0ca1a40847eb74d30b0b51904a70c46f2e836dc5b3ea3dd8d3", "firstIndex": 872415067},
+{"blockNumber": 4515567, "blockId": "0xe99d3849755a1b4ec9a65d003260c111d4886e29ad6243fc750c72dbc79dbe4c", "firstIndex": 939523746},
+{"blockNumber": 4634815, "blockId": "0x9f281e749b192ef58242ff9fccd496a9075c30bd28c61ed4ce6487fc2d167e5c", "firstIndex": 1006629595},
+{"blockNumber": 4718286, "blockId": "0x23d2a40ec3ae059a45006ba651a70f308b6b282829b9cfdf2534e4311e34050f", "firstIndex": 1073731435},
+{"blockNumber": 4753427, "blockId": "0x6df7295f9ccb45a95e6cc72a8ee56bda992513b3bf4baa3d62219871a0b5a912", "firstIndex": 1140843105},
+{"blockNumber": 4786511, "blockId": "0x705c79435411c1af81385a1eca34343427eceb3f6af72e7f665552d6b0eceb6c", "firstIndex": 1207957185},
+{"blockNumber": 4811696, "blockId": "0x69a6e60d1b958b469feafb1dca97f38f97620a90c21ed92f90080f6443ee6c78", "firstIndex": 1275061401},
+{"blockNumber": 4841770, "blockId": "0x0a0e9d2d3d177601a478428297b5b9a42124166fefe42f2221c7a612c31e7ca1", "firstIndex": 1342174442},
+{"blockNumber": 4914785, "blockId": "0x5ca0e12230aeacbce9064dff15dafb9f24e20b4a737f7d04df8549008b829fa3", "firstIndex": 1409284680},
+{"blockNumber": 4992516, "blockId": "0xb9cb1700d8b65615fc3a019b2e9b2ece3b4f1e0e2fcfc01ff40bcf53e7291b10", "firstIndex": 1476387066},
+{"blockNumber": 5088617, "blockId": "0x33122f693a264fb2ab626232fac5e2714010fd65bdceb772109511f7c9497333", "firstIndex": 1543503849},
+{"blockNumber": 5155024, "blockId": "0x187716822dd6ab9c21138ae5a8e763197a5e7ec48bf0e756c5e6fa2c9f2f24bf", "firstIndex": 1610604247},
+{"blockNumber": 5204373, "blockId": "0x753b6495979ca90a1b915edad6af33c58bbabe68b45f95c7645113ec1d35d0e6", "firstIndex": 1677721200},
+{"blockNumber": 5269952, "blockId": "0xcbb0409ed824631120d6951b55537143d9a1c82ca6dd6255d2eb31c57844685c", "firstIndex": 1744829248},
+{"blockNumber": 5337623, "blockId": "0x0b460658511c4ae5205c038430789f9b31f3c08ba4acc06d273b7a13a149cf8b", "firstIndex": 1811939255},
+{"blockNumber": 5399044, "blockId": "0x9d07e37321e2b019f4837cc4f95f103da87ecdcb77e131e9d42d8643b0446524", "firstIndex": 1879041131},
+{"blockNumber": 5422692, "blockId": "0x9d9e27614635989788e32f15cd7a0abf7470dccf3336b77547baeb3423b629ca", "firstIndex": 1946154968},
+{"blockNumber": 5454259, "blockId": "0x01e694443d471d3411fe0b52720fd4a189e687b14cc8ede116f5e93f0ad96bb6", "firstIndex": 2013265148},
+{"blockNumber": 5498863, "blockId": "0xc4cb906c96d9f80b830b8add25318c38b3ff857c1bd577cd9cae0a324a068ffc", "firstIndex": 2080373677},
+{"blockNumber": 5554788, "blockId": "0x9b934b2d66723559d82e0f4cd49a2497234fe892248cb2f46c13f6a9585cfddd", "firstIndex": 2147475372},
+{"blockNumber": 5594711, "blockId": "0x840c0b7889b8c882cfa0eceb516dd73043b51c0e5a0c1be849a0e2a5dda7e842", "firstIndex": 2214592267},
+{"blockNumber": 5645179, "blockId": "0x188873a43506fee33349bc33df4a55059401e98dc7f0a5d488a0bc5c87dfd431", "firstIndex": 2281695869},
+{"blockNumber": 5687634, "blockId": "0x7ea8d7a2afccf795a2a02eb00746d89db57f13f8936cf7ab0f0a7db1b1ceb341", "firstIndex": 2348806824},
+{"blockNumber": 5727808, "blockId": "0x3f3eaf36c8e0271403737676907eac15312927c1d60ce814337654b7d7f2b2bd", "firstIndex": 2415915517},
+{"blockNumber": 5784480, "blockId": "0x10ec5adf01449c29550f5117f09ecafc49fc614d7da5886cf01619950827f850", "firstIndex": 2483023750},
+{"blockNumber": 5843906, "blockId": "0x9e6e14b3fba395a9ae7b3f1295f33a12d0f8b9f10e1aaab1649a90a56a323676", "firstIndex": 2550136398},
+{"blockNumber": 5906280, "blockId": "0x2188869a164e9c19232f6702a5233dc27a2304839159dd7230cc93ebdfc6c048", "firstIndex": 2617245012},
+{"blockNumber": 5977929, "blockId": "0xb247181ed597d9473c2c6e5762ae45a05f328d8df215fdac83d19ae4c028109a", "firstIndex": 2684347033},
+{"blockNumber": 6051479, "blockId": "0x0e8634c95dac31b7c835b44d0a14290e9212b31b9c3f621997ad1cca2d8ab0ba", "firstIndex": 2751463372},
+{"blockNumber": 6118422, "blockId": "0xa642c4457d4b63d68a5502bdba2355616e34495bf3ab2d8518a45ded54a16be4", "firstIndex": 2818563217},
+{"blockNumber": 6174274, "blockId": "0xbb9808bc56b5f14636e654bdd6d50d35b31345255926341ef3ddb54840095bcc", "firstIndex": 2885680274},
+{"blockNumber": 6276207, "blockId": "0x7ae027a18889e1b60a46ea3e5f2759035f3d9041de68eca0b154068ec533db59", "firstIndex": 2952789656},
+{"blockNumber": 6368344, "blockId": "0x8b4401f89589d9e99259e6c05c18b1780e96b65027caf9d83edf80390d317f66", "firstIndex": 3019898378},
+{"blockNumber": 6470718, "blockId": "0x0e2f8de093392c38750581c41e93c2fb1c0f6676b65c9af52792f3c56e894457", "firstIndex": 3087007589},
+{"blockNumber": 6553237, "blockId": "0xa6c4f3a1fe3b4e116c367fcbb1ae98e0f25570fdb2f1eadee2681deb39462c1e", "firstIndex": 3154116356},
+{"blockNumber": 6663750, "blockId": "0x9049748ddf655c7cc2ccbe2d36010b3a67ae011d114d32b1c812a7a53102f27f", "firstIndex": 3221225375},
+{"blockNumber": 6766894, "blockId": "0xc98188fb313b1beb7fc4f415b4a74c363903b3b5e0172437d79446bc011238b5", "firstIndex": 3288334172},
+{"blockNumber": 6886576, "blockId": "0x4ae8237a94198c82c266f01e472fdcd3ae150c84ecf714205a9be672f1e705b8", "firstIndex": 3355443040},
+{"blockNumber": 6978746, "blockId": "0xb2b69ce29c5c9c46c5cbc6e96260c34313d8b0b4a739cf4091c98f37093aa732", "firstIndex": 3422552017},
+{"blockNumber": 7098871, "blockId": "0x9ab2b681feeb38287a1b689fa64a50efd3407b6331fd6896187cad98a29ce107", "firstIndex": 3489660879},
+{"blockNumber": 7203023, "blockId": "0xdedfff5985c1c93d476120d2afbaa61967bae4edabb9711c7794a1b1cd453aa1", "firstIndex": 3556769365},
+{"blockNumber": 7256709, "blockId": "0xc078041cffc1802b6342fd2ba5a92ff8076ac0f5b72b4a77ba75cd486fe1b3c9", "firstIndex": 3623876563},
+{"blockNumber": 7307744, "blockId": "0xdf8dcdd4af9213a79587eb2f4d91f4111da74f99207ee05e4ae50bcb4f8d5435", "firstIndex": 3690986225},
+{"blockNumber": 7369268, "blockId": "0x62315823621a38a1f138e193b85259988fcc15f4a74d0cf19a412920bcdcad98", "firstIndex": 3758096030},
+{"blockNumber": 7445109, "blockId": "0x8b668ac1274a8dcc9526eb115c2f67bd56f6657b5072c7542da2252daca10fef", "firstIndex": 3825204921},
+{"blockNumber": 7511512, "blockId": "0x056ad7411652aa64849c67705a86e42221cb88f7fb6a7012ab7d3d5b9a30eb76", "firstIndex": 3892313524},
+{"blockNumber": 7557259, "blockId": "0xef660b97661f073b7c7319b69451e16d26ecaed54f9237e209999d137da2bfd4", "firstIndex": 3959415096},
+{"blockNumber": 7606260, "blockId": "0x9f5f06ad381166261780864bf17ad4d3cdd475f87ba51fa7f9ba621bf0ac0acb", "firstIndex": 4026521703},
+{"blockNumber": 7654244, "blockId": "0xefe5b537435001203741bf445ca26466baf7ad3f63c2bba94f0f658aed8c244b", "firstIndex": 4093627258},
+{"blockNumber": 7700433, "blockId": "0x89af6e8c5aa934a9139944b3de7a15232069479dba387e0fdd043ad36156c8bf", "firstIndex": 4160749200},
+{"blockNumber": 7730079, "blockId": "0x08e0d511a93e2a9c004b3456d77d687ae86247417ada1cdd1f85332a62dfed1d", "firstIndex": 4227846795},
+{"blockNumber": 7777515, "blockId": "0xeba8faed2e12bb9ed5e7fad19dd82662f15f6f4f512a0d232eedf1e676712428", "firstIndex": 4294966082},
+{"blockNumber": 7828860, "blockId": "0x62c054bd24be351dc4777460ee922a75fdcea5c9830455cbac6fa29552719c85", "firstIndex": 4362076087},
+{"blockNumber": 7869890, "blockId": "0x5664bcfa6151f798781e22bea4f9a2c796d097402350cb131e4e3c78e13e461a", "firstIndex": 4429183267}
]
-
diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go
index 95dd181551..fe75c1ea7d 100644
--- a/core/filtermaps/filtermaps.go
+++ b/core/filtermaps/filtermaps.go
@@ -95,11 +95,11 @@ type FilterMaps struct {
targetView *ChainView
matcherSyncRequest *FilterMapsMatcherBackend
+ historyCutoff uint64
finalBlock, lastFinal uint64
lastFinalEpoch uint32
stop bool
- targetViewCh chan *ChainView
- finalBlockCh chan uint64
+ targetCh chan targetUpdate
blockProcessingCh chan bool
blockProcessing bool
matcherSyncCh chan *FilterMapsMatcherBackend
@@ -145,24 +145,23 @@ func (a FilterRow) Equal(b FilterRow) bool {
// filterMapsRange describes the rendered range of filter maps and the range
// of fully rendered blocks.
type filterMapsRange struct {
- initialized bool
- headBlockIndexed bool
- headBlockDelimiter uint64 // zero if afterLastIndexedBlock != targetBlockNumber
- // if initialized then all maps are rendered between firstRenderedMap and
- // afterLastRenderedMap-1
- firstRenderedMap, afterLastRenderedMap uint32
+ initialized bool
+ headIndexed bool
+ headDelimiter uint64 // zero if headIndexed is false
+ // if initialized then all maps are rendered in the maps range
+ maps common.Range[uint32]
// if tailPartialEpoch > 0 then maps between firstRenderedMap-mapsPerEpoch and
// firstRenderedMap-mapsPerEpoch+tailPartialEpoch-1 are rendered
tailPartialEpoch uint32
- // if initialized then all log values belonging to blocks between
- // firstIndexedBlock and afterLastIndexedBlock are fully rendered
- // blockLvPointers are available between firstIndexedBlock and afterLastIndexedBlock-1
- firstIndexedBlock, afterLastIndexedBlock uint64
+ // if initialized then all log values in the blocks range are fully
+ // rendered
+ // blockLvPointers are available in the blocks range
+ blocks common.Range[uint64]
}
// hasIndexedBlocks returns true if the range has at least one fully indexed block.
func (fmr *filterMapsRange) hasIndexedBlocks() bool {
- return fmr.initialized && fmr.afterLastIndexedBlock > fmr.firstIndexedBlock
+ return fmr.initialized && !fmr.blocks.IsEmpty() && !fmr.maps.IsEmpty()
}
// lastBlockOfMap is used for caching the (number, id) pairs belonging to the
@@ -183,7 +182,7 @@ type Config struct {
}
// NewFilterMaps creates a new FilterMaps and starts the indexer.
-func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, params Params, config Config) *FilterMaps {
+func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, finalBlock uint64, params Params, config Config) *FilterMaps {
rs, initialized, err := rawdb.ReadFilterMapsRange(db)
if err != nil {
log.Error("Error reading log index range", "error", err)
@@ -193,22 +192,19 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, params Params, c
db: db,
closeCh: make(chan struct{}),
waitIdleCh: make(chan chan bool),
- targetViewCh: make(chan *ChainView, 1),
- finalBlockCh: make(chan uint64, 1),
+ targetCh: make(chan targetUpdate, 1),
blockProcessingCh: make(chan bool, 1),
history: config.History,
disabled: config.Disabled,
exportFileName: config.ExportFileName,
Params: params,
indexedRange: filterMapsRange{
- initialized: initialized,
- headBlockIndexed: rs.HeadBlockIndexed,
- headBlockDelimiter: rs.HeadBlockDelimiter,
- firstIndexedBlock: rs.FirstIndexedBlock,
- afterLastIndexedBlock: rs.AfterLastIndexedBlock,
- firstRenderedMap: rs.FirstRenderedMap,
- afterLastRenderedMap: rs.AfterLastRenderedMap,
- tailPartialEpoch: rs.TailPartialEpoch,
+ initialized: initialized,
+ headIndexed: rs.HeadIndexed,
+ headDelimiter: rs.HeadDelimiter,
+ blocks: common.NewRange(rs.BlocksFirst, rs.BlocksAfterLast-rs.BlocksFirst),
+ maps: common.NewRange(rs.MapsFirst, rs.MapsAfterLast-rs.MapsFirst),
+ tailPartialEpoch: rs.TailPartialEpoch,
},
matcherSyncCh: make(chan *FilterMapsMatcherBackend),
matchers: make(map[*FilterMapsMatcherBackend]struct{}),
@@ -223,24 +219,23 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, params Params, c
f.targetView = initView
if f.indexedRange.initialized {
f.indexedView = f.initChainView(f.targetView)
- f.indexedRange.headBlockIndexed = f.indexedRange.afterLastIndexedBlock == f.indexedView.headNumber+1
- if !f.indexedRange.headBlockIndexed {
- f.indexedRange.headBlockDelimiter = 0
+ f.indexedRange.headIndexed = f.indexedRange.blocks.AfterLast() == f.indexedView.headNumber+1
+ if !f.indexedRange.headIndexed {
+ f.indexedRange.headDelimiter = 0
}
}
if f.indexedRange.hasIndexedBlocks() {
log.Info("Initialized log indexer",
- "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1,
- "first map", f.indexedRange.firstRenderedMap, "last map", f.indexedRange.afterLastRenderedMap-1,
- "head indexed", f.indexedRange.headBlockIndexed)
+ "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(),
+ "first map", f.indexedRange.maps.First(), "last map", f.indexedRange.maps.Last(),
+ "head indexed", f.indexedRange.headIndexed)
}
return f
}
// Start starts the indexer.
func (f *FilterMaps) Start() {
- if !f.testDisableSnapshots && f.indexedRange.initialized && f.indexedRange.headBlockIndexed &&
- f.indexedRange.firstRenderedMap < f.indexedRange.afterLastRenderedMap {
+ if !f.testDisableSnapshots && f.indexedRange.hasIndexedBlocks() && f.indexedRange.headIndexed {
// previous target head rendered; load last map as snapshot
if err := f.loadHeadSnapshot(); err != nil {
log.Error("Could not load head filter map snapshot", "error", err)
@@ -262,7 +257,7 @@ func (f *FilterMaps) Stop() {
// Note that the returned view might be shorter than the existing index if
// the latest maps are not consistent with targetView.
func (f *FilterMaps) initChainView(chainView *ChainView) *ChainView {
- mapIndex := f.indexedRange.afterLastRenderedMap
+ mapIndex := f.indexedRange.maps.AfterLast()
for {
var ok bool
mapIndex, ok = f.lastMapBoundaryBefore(mapIndex)
@@ -332,10 +327,8 @@ func (f *FilterMaps) init() error {
}
if bestLen > 0 {
cp := checkpoints[bestIdx][bestLen-1]
- fmr.firstIndexedBlock = cp.BlockNumber + 1
- fmr.afterLastIndexedBlock = cp.BlockNumber + 1
- fmr.firstRenderedMap = uint32(bestLen) << f.logMapsPerEpoch
- fmr.afterLastRenderedMap = uint32(bestLen) << f.logMapsPerEpoch
+ fmr.blocks = common.NewRange(cp.BlockNumber+1, 0)
+ fmr.maps = common.NewRange(uint32(bestLen)<> f.logValuesPerMap)
- if mapIndex < f.indexedRange.firstRenderedMap || mapIndex >= f.indexedRange.afterLastRenderedMap {
+ if !f.indexedRange.maps.Includes(mapIndex) {
return nil, nil
}
// find possible block range based on map to block pointers
@@ -425,8 +418,8 @@ func (f *FilterMaps) getLogByLvIndex(lvIndex uint64) (*types.Log, error) {
return nil, fmt.Errorf("failed to retrieve last block of map %d before searched log value index %d: %v", mapIndex, lvIndex, err)
}
}
- if firstBlockNumber < f.indexedRange.firstIndexedBlock {
- firstBlockNumber = f.indexedRange.firstIndexedBlock
+ if firstBlockNumber < f.indexedRange.blocks.First() {
+ firstBlockNumber = f.indexedRange.blocks.First()
}
// find block with binary search based on block to log value index pointers
for firstBlockNumber < lastBlockNumber {
@@ -453,6 +446,11 @@ func (f *FilterMaps) getLogByLvIndex(lvIndex uint64) (*types.Log, error) {
// iterate through receipts to find the exact log starting at lvIndex
for _, receipt := range receipts {
for _, log := range receipt.Logs {
+ l := uint64(len(log.Topics) + 1)
+ r := f.valuesPerMap - lvPointer%f.valuesPerMap
+ if l > r {
+ lvPointer += r // skip to map boundary
+ }
if lvPointer > lvIndex {
// lvIndex does not point to the first log value (address value)
// generated by a log as true matches should always do, so it
@@ -462,7 +460,7 @@ func (f *FilterMaps) getLogByLvIndex(lvIndex uint64) (*types.Log, error) {
if lvPointer == lvIndex {
return log, nil // potential match
}
- lvPointer += uint64(len(log.Topics) + 1)
+ lvPointer += l
}
}
return nil, nil
@@ -580,8 +578,8 @@ func (f *FilterMaps) mapRowIndex(mapIndex, rowIndex uint32) uint64 {
// Note that this function assumes that the indexer read lock is being held when
// called from outside the indexerLoop goroutine.
func (f *FilterMaps) getBlockLvPointer(blockNumber uint64) (uint64, error) {
- if blockNumber >= f.indexedRange.afterLastIndexedBlock && f.indexedRange.headBlockIndexed {
- return f.indexedRange.headBlockDelimiter, nil
+ if blockNumber >= f.indexedRange.blocks.AfterLast() && f.indexedRange.headIndexed {
+ return f.indexedRange.headDelimiter, nil
}
if lvPointer, ok := f.lvPointerCache.Get(blockNumber); ok {
return lvPointer, nil
@@ -658,26 +656,28 @@ func (f *FilterMaps) deleteTailEpoch(epoch uint32) error {
firstBlock++
}
fmr := f.indexedRange
- if f.indexedRange.firstRenderedMap == firstMap &&
- f.indexedRange.afterLastRenderedMap > firstMap+f.mapsPerEpoch &&
+ if f.indexedRange.maps.First() == firstMap &&
+ f.indexedRange.maps.AfterLast() > firstMap+f.mapsPerEpoch &&
f.indexedRange.tailPartialEpoch == 0 {
- fmr.firstRenderedMap = firstMap + f.mapsPerEpoch
- fmr.firstIndexedBlock = lastBlock + 1
- } else if f.indexedRange.firstRenderedMap == firstMap+f.mapsPerEpoch {
+ fmr.maps.SetFirst(firstMap + f.mapsPerEpoch)
+ fmr.blocks.SetFirst(lastBlock + 1)
+ } else if f.indexedRange.maps.First() == firstMap+f.mapsPerEpoch {
fmr.tailPartialEpoch = 0
} else {
return errors.New("invalid tail epoch number")
}
f.setRange(f.db, f.indexedView, fmr)
- rawdb.DeleteFilterMapRows(f.db, f.mapRowIndex(firstMap, 0), f.mapRowIndex(firstMap+f.mapsPerEpoch, 0))
+ first := f.mapRowIndex(firstMap, 0)
+ count := f.mapRowIndex(firstMap+f.mapsPerEpoch, 0) - first
+ rawdb.DeleteFilterMapRows(f.db, common.NewRange(first, count))
for mapIndex := firstMap; mapIndex < firstMap+f.mapsPerEpoch; mapIndex++ {
f.filterMapCache.Remove(mapIndex)
}
- rawdb.DeleteFilterMapLastBlocks(f.db, firstMap, firstMap+f.mapsPerEpoch-1) // keep last enrty
+ rawdb.DeleteFilterMapLastBlocks(f.db, common.NewRange(firstMap, f.mapsPerEpoch-1)) // keep last enrty
for mapIndex := firstMap; mapIndex < firstMap+f.mapsPerEpoch-1; mapIndex++ {
f.lastBlockCache.Remove(mapIndex)
}
- rawdb.DeleteBlockLvPointers(f.db, firstBlock, lastBlock) // keep last enrty
+ rawdb.DeleteBlockLvPointers(f.db, common.NewRange(firstBlock, lastBlock-firstBlock)) // keep last enrty
for blockNumber := firstBlock; blockNumber < lastBlock; blockNumber++ {
f.lvPointerCache.Remove(blockNumber)
}
diff --git a/core/filtermaps/indexer.go b/core/filtermaps/indexer.go
index 54a3687648..addda03df4 100644
--- a/core/filtermaps/indexer.go
+++ b/core/filtermaps/indexer.go
@@ -66,28 +66,25 @@ func (f *FilterMaps) indexerLoop() {
}
}
+type targetUpdate struct {
+ targetView *ChainView
+ historyCutoff, finalBlock uint64
+}
+
// SetTargetView sets a new target chain view for the indexer to render.
// Note that SetTargetView never blocks.
-func (f *FilterMaps) SetTargetView(targetView *ChainView) {
+func (f *FilterMaps) SetTarget(targetView *ChainView, historyCutoff, finalBlock uint64) {
if targetView == nil {
panic("nil targetView")
}
for {
select {
- case <-f.targetViewCh:
- case f.targetViewCh <- targetView:
- return
- }
- }
-}
-
-// SetFinalBlock sets the finalized block number used for exporting checkpoints.
-// Note that SetFinalBlock never blocks.
-func (f *FilterMaps) SetFinalBlock(finalBlock uint64) {
- for {
- select {
- case <-f.finalBlockCh:
- case f.finalBlockCh <- finalBlock:
+ case <-f.targetCh:
+ case f.targetCh <- targetUpdate{
+ targetView: targetView,
+ historyCutoff: historyCutoff,
+ finalBlock: finalBlock,
+ }:
return
}
}
@@ -145,26 +142,24 @@ func (f *FilterMaps) processSingleEvent(blocking bool) bool {
}
if blocking {
select {
- case targetView := <-f.targetViewCh:
- f.setTargetView(targetView)
- case f.finalBlock = <-f.finalBlockCh:
+ case target := <-f.targetCh:
+ f.setTarget(target)
case f.matcherSyncRequest = <-f.matcherSyncCh:
case f.blockProcessing = <-f.blockProcessingCh:
case <-f.closeCh:
f.stop = true
case ch := <-f.waitIdleCh:
select {
- case targetView := <-f.targetViewCh:
- f.setTargetView(targetView)
+ case target := <-f.targetCh:
+ f.setTarget(target)
default:
}
ch <- !f.blockProcessing && f.targetHeadIndexed()
}
} else {
select {
- case targetView := <-f.targetViewCh:
- f.setTargetView(targetView)
- case f.finalBlock = <-f.finalBlockCh:
+ case target := <-f.targetCh:
+ f.setTarget(target)
case f.matcherSyncRequest = <-f.matcherSyncCh:
case f.blockProcessing = <-f.blockProcessingCh:
case <-f.closeCh:
@@ -177,8 +172,10 @@ func (f *FilterMaps) processSingleEvent(blocking bool) bool {
}
// setTargetView updates the target chain view of the iterator.
-func (f *FilterMaps) setTargetView(targetView *ChainView) {
- f.targetView = targetView
+func (f *FilterMaps) setTarget(target targetUpdate) {
+ f.targetView = target.targetView
+ f.historyCutoff = target.historyCutoff
+ f.finalBlock = target.finalBlock
}
// tryIndexHead tries to render head maps according to the current targetView
@@ -196,20 +193,20 @@ func (f *FilterMaps) tryIndexHead() bool {
f.lastLogHeadIndex = time.Now()
f.startedHeadIndexAt = f.lastLogHeadIndex
f.startedHeadIndex = true
- f.ptrHeadIndex = f.indexedRange.afterLastIndexedBlock
+ f.ptrHeadIndex = f.indexedRange.blocks.AfterLast()
}
if _, err := headRenderer.run(func() bool {
f.processEvents()
return f.stop
}, func() {
f.tryUnindexTail()
- if f.indexedRange.hasIndexedBlocks() && f.indexedRange.afterLastIndexedBlock >= f.ptrHeadIndex &&
+ if f.indexedRange.hasIndexedBlocks() && f.indexedRange.blocks.AfterLast() >= f.ptrHeadIndex &&
((!f.loggedHeadIndex && time.Since(f.startedHeadIndexAt) > headLogDelay) ||
time.Since(f.lastLogHeadIndex) > logFrequency) {
log.Info("Log index head rendering in progress",
- "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1,
- "processed", f.indexedRange.afterLastIndexedBlock-f.ptrHeadIndex,
- "remaining", f.indexedView.headNumber+1-f.indexedRange.afterLastIndexedBlock,
+ "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(),
+ "processed", f.indexedRange.blocks.AfterLast()-f.ptrHeadIndex,
+ "remaining", f.indexedView.headNumber-f.indexedRange.blocks.Last(),
"elapsed", common.PrettyDuration(time.Since(f.startedHeadIndexAt)))
f.loggedHeadIndex = true
f.lastLogHeadIndex = time.Now()
@@ -218,10 +215,10 @@ func (f *FilterMaps) tryIndexHead() bool {
log.Error("Log index head rendering failed", "error", err)
return false
}
- if f.loggedHeadIndex {
+ if f.loggedHeadIndex && f.indexedRange.hasIndexedBlocks() {
log.Info("Log index head rendering finished",
- "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1,
- "processed", f.indexedRange.afterLastIndexedBlock-f.ptrHeadIndex,
+ "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(),
+ "processed", f.indexedRange.blocks.AfterLast()-f.ptrHeadIndex,
"elapsed", common.PrettyDuration(time.Since(f.startedHeadIndexAt)))
}
f.loggedHeadIndex, f.startedHeadIndex = false, false
@@ -234,7 +231,11 @@ func (f *FilterMaps) tryIndexHead() bool {
// rendered according to targetView and is suspended as soon as the targetView
// is changed.
func (f *FilterMaps) tryIndexTail() bool {
- for firstEpoch := f.indexedRange.firstRenderedMap >> f.logMapsPerEpoch; firstEpoch > 0 && f.needTailEpoch(firstEpoch-1); {
+ for {
+ firstEpoch := f.indexedRange.maps.First() >> f.logMapsPerEpoch
+ if firstEpoch == 0 || !f.needTailEpoch(firstEpoch-1) {
+ break
+ }
f.processEvents()
if f.stop || !f.targetHeadIndexed() {
return false
@@ -242,25 +243,25 @@ func (f *FilterMaps) tryIndexTail() bool {
// resume process if tail rendering was interrupted because of head rendering
tailRenderer := f.tailRenderer
f.tailRenderer = nil
- if tailRenderer != nil && tailRenderer.afterLastMap != f.indexedRange.firstRenderedMap {
+ if tailRenderer != nil && tailRenderer.renderBefore != f.indexedRange.maps.First() {
tailRenderer = nil
}
if tailRenderer == nil {
var err error
- tailRenderer, err = f.renderMapsBefore(f.indexedRange.firstRenderedMap)
+ tailRenderer, err = f.renderMapsBefore(f.indexedRange.maps.First())
if err != nil {
log.Error("Error creating log index tail renderer", "error", err)
return false
}
}
if tailRenderer == nil {
- return true
+ break
}
if !f.startedTailIndex {
f.lastLogTailIndex = time.Now()
f.startedTailIndexAt = f.lastLogTailIndex
f.startedTailIndex = true
- f.ptrTailIndex = f.indexedRange.firstIndexedBlock - f.tailPartialBlocks()
+ f.ptrTailIndex = f.indexedRange.blocks.First() - f.tailPartialBlocks()
}
done, err := tailRenderer.run(func() bool {
f.processEvents()
@@ -268,14 +269,14 @@ func (f *FilterMaps) tryIndexTail() bool {
}, func() {
tpb, ttb := f.tailPartialBlocks(), f.tailTargetBlock()
remaining := uint64(1)
- if f.indexedRange.firstIndexedBlock > ttb+tpb {
- remaining = f.indexedRange.firstIndexedBlock - ttb - tpb
+ if f.indexedRange.blocks.First() > ttb+tpb {
+ remaining = f.indexedRange.blocks.First() - ttb - tpb
}
- if f.indexedRange.hasIndexedBlocks() && f.ptrTailIndex >= f.indexedRange.firstIndexedBlock &&
+ if f.indexedRange.hasIndexedBlocks() && f.ptrTailIndex >= f.indexedRange.blocks.First() &&
(!f.loggedTailIndex || time.Since(f.lastLogTailIndex) > logFrequency) {
log.Info("Log index tail rendering in progress",
- "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1,
- "processed", f.ptrTailIndex-f.indexedRange.firstIndexedBlock+tpb,
+ "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(),
+ "processed", f.ptrTailIndex-f.indexedRange.blocks.First()+tpb,
"remaining", remaining,
"next tail epoch percentage", f.indexedRange.tailPartialEpoch*100/f.mapsPerEpoch,
"elapsed", common.PrettyDuration(time.Since(f.startedTailIndexAt)))
@@ -283,7 +284,8 @@ func (f *FilterMaps) tryIndexTail() bool {
f.lastLogTailIndex = time.Now()
}
})
- if err != nil {
+ if err != nil && f.needTailEpoch(firstEpoch-1) {
+ // stop silently if cutoff point has move beyond epoch boundary while rendering
log.Error("Log index tail rendering failed", "error", err)
}
if !done {
@@ -291,10 +293,10 @@ func (f *FilterMaps) tryIndexTail() bool {
return false
}
}
- if f.loggedTailIndex {
+ if f.loggedTailIndex && f.indexedRange.hasIndexedBlocks() {
log.Info("Log index tail rendering finished",
- "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1,
- "processed", f.ptrTailIndex-f.indexedRange.firstIndexedBlock,
+ "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(),
+ "processed", f.ptrTailIndex-f.indexedRange.blocks.First(),
"elapsed", common.PrettyDuration(time.Since(f.startedTailIndexAt)))
f.loggedTailIndex = false
}
@@ -307,7 +309,7 @@ func (f *FilterMaps) tryIndexTail() bool {
// data from the database and is also called while running head indexing.
func (f *FilterMaps) tryUnindexTail() bool {
for {
- firstEpoch := (f.indexedRange.firstRenderedMap - f.indexedRange.tailPartialEpoch) >> f.logMapsPerEpoch
+ firstEpoch := (f.indexedRange.maps.First() - f.indexedRange.tailPartialEpoch) >> f.logMapsPerEpoch
if f.needTailEpoch(firstEpoch) {
break
}
@@ -318,19 +320,19 @@ func (f *FilterMaps) tryUnindexTail() bool {
if !f.startedTailUnindex {
f.startedTailUnindexAt = time.Now()
f.startedTailUnindex = true
- f.ptrTailUnindexMap = f.indexedRange.firstRenderedMap - f.indexedRange.tailPartialEpoch
- f.ptrTailUnindexBlock = f.indexedRange.firstIndexedBlock - f.tailPartialBlocks()
+ f.ptrTailUnindexMap = f.indexedRange.maps.First() - f.indexedRange.tailPartialEpoch
+ f.ptrTailUnindexBlock = f.indexedRange.blocks.First() - f.tailPartialBlocks()
}
if err := f.deleteTailEpoch(firstEpoch); err != nil {
log.Error("Log index tail epoch unindexing failed", "error", err)
return false
}
}
- if f.startedTailUnindex {
+ if f.startedTailUnindex && f.indexedRange.hasIndexedBlocks() {
log.Info("Log index tail unindexing finished",
- "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1,
- "removed maps", f.indexedRange.firstRenderedMap-f.ptrTailUnindexMap,
- "removed blocks", f.indexedRange.firstIndexedBlock-f.tailPartialBlocks()-f.ptrTailUnindexBlock,
+ "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(),
+ "removed maps", f.indexedRange.maps.First()-f.ptrTailUnindexMap,
+ "removed blocks", f.indexedRange.blocks.First()-f.tailPartialBlocks()-f.ptrTailUnindexBlock,
"elapsed", common.PrettyDuration(time.Since(f.startedTailUnindexAt)))
f.startedTailUnindex = false
}
@@ -340,23 +342,29 @@ func (f *FilterMaps) tryUnindexTail() bool {
// needTailEpoch returns true if the given tail epoch needs to be kept
// according to the current tail target, false if it can be removed.
func (f *FilterMaps) needTailEpoch(epoch uint32) bool {
- firstEpoch := f.indexedRange.firstRenderedMap >> f.logMapsPerEpoch
+ firstEpoch := f.indexedRange.maps.First() >> f.logMapsPerEpoch
if epoch > firstEpoch {
return true
}
if epoch+1 < firstEpoch {
return false
}
- tailTarget := f.tailTargetBlock()
- if tailTarget < f.indexedRange.firstIndexedBlock {
- return true
+ if epoch > 0 {
+ lastBlockOfPrevEpoch, _, err := f.getLastBlockOfMap(epoch<= firstEpoch
+ }
+ if f.historyCutoff > lastBlockOfPrevEpoch {
+ return false
+ }
}
- tailLvIndex, err := f.getBlockLvPointer(tailTarget)
+ lastBlockOfEpoch, _, err := f.getLastBlockOfMap((epoch+1)<= firstEpoch
}
- return uint64(epoch+1)<<(f.logValuesPerMap+f.logMapsPerEpoch) >= tailLvIndex
+ return f.tailTargetBlock() <= lastBlockOfEpoch
}
// tailTargetBlock returns the target value for the tail block number according
@@ -374,15 +382,15 @@ func (f *FilterMaps) tailPartialBlocks() uint64 {
if f.indexedRange.tailPartialEpoch == 0 {
return 0
}
- end, _, err := f.getLastBlockOfMap(f.indexedRange.firstRenderedMap - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch - 1)
+ end, _, err := f.getLastBlockOfMap(f.indexedRange.maps.First() - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch - 1)
if err != nil {
- log.Error("Error fetching last block of map", "mapIndex", f.indexedRange.firstRenderedMap-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch-1, "error", err)
+ log.Error("Error fetching last block of map", "mapIndex", f.indexedRange.maps.First()-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch-1, "error", err)
}
var start uint64
- if f.indexedRange.firstRenderedMap-f.mapsPerEpoch > 0 {
- start, _, err = f.getLastBlockOfMap(f.indexedRange.firstRenderedMap - f.mapsPerEpoch - 1)
+ if f.indexedRange.maps.First()-f.mapsPerEpoch > 0 {
+ start, _, err = f.getLastBlockOfMap(f.indexedRange.maps.First() - f.mapsPerEpoch - 1)
if err != nil {
- log.Error("Error fetching last block of map", "mapIndex", f.indexedRange.firstRenderedMap-f.mapsPerEpoch-1, "error", err)
+ log.Error("Error fetching last block of map", "mapIndex", f.indexedRange.maps.First()-f.mapsPerEpoch-1, "error", err)
}
}
return end - start
@@ -391,5 +399,5 @@ func (f *FilterMaps) tailPartialBlocks() uint64 {
// targetHeadIndexed returns true if the current log index is consistent with
// targetView with its head block fully rendered.
func (f *FilterMaps) targetHeadIndexed() bool {
- return equalViews(f.targetView, f.indexedView) && f.indexedRange.headBlockIndexed
+ return equalViews(f.targetView, f.indexedView) && f.indexedRange.headIndexed
}
diff --git a/core/filtermaps/indexer_test.go b/core/filtermaps/indexer_test.go
index 17ad765e04..a02f8d2459 100644
--- a/core/filtermaps/indexer_test.go
+++ b/core/filtermaps/indexer_test.go
@@ -48,16 +48,35 @@ func TestIndexerRandomRange(t *testing.T) {
defer ts.close()
forks := make([][]common.Hash, 10)
- ts.chain.addBlocks(1000, 5, 2, 4, false) // 51 log values per block
+ ts.chain.addBlocks(1000, 5, 2, 4, false)
for i := range forks {
if i != 0 {
forkBlock := rand.Intn(1000)
ts.chain.setHead(forkBlock)
- ts.chain.addBlocks(1000-forkBlock, 5, 2, 4, false) // 51 log values per block
+ ts.chain.addBlocks(1000-forkBlock, 5, 2, 4, false)
}
forks[i] = ts.chain.getCanonicalChain()
}
- lvPerBlock := uint64(51)
+ expspos := func(block uint64) uint64 { // expected position of block start
+ if block == 0 {
+ return 0
+ }
+ logCount := (block - 1) * 5 * 2
+ mapIndex := logCount / 3
+ spos := mapIndex*16 + (logCount%3)*5
+ if mapIndex == 0 || logCount%3 != 0 {
+ spos++
+ }
+ return spos
+ }
+ expdpos := func(block uint64) uint64 { // expected position of delimiter
+ if block == 0 {
+ return 0
+ }
+ logCount := block * 5 * 2
+ mapIndex := (logCount - 1) / 3
+ return mapIndex*16 + (logCount-mapIndex*3)*5
+ }
ts.setHistory(0, false)
var (
history int
@@ -115,23 +134,26 @@ func TestIndexerRandomRange(t *testing.T) {
}
var tailEpoch uint32
if tailBlock > 0 {
- tailLvPtr := (tailBlock - 1) * lvPerBlock // no logs in genesis block, only delimiter
+ tailLvPtr := expspos(tailBlock) - 1
tailEpoch = uint32(tailLvPtr >> (testParams.logValuesPerMap + testParams.logMapsPerEpoch))
}
+ tailLvPtr := uint64(tailEpoch) << (testParams.logValuesPerMap + testParams.logMapsPerEpoch) // first available lv ptr
var expTailBlock uint64
if tailEpoch > 0 {
- tailLvPtr := uint64(tailEpoch) << (testParams.logValuesPerMap + testParams.logMapsPerEpoch) // first available lv ptr
- // (expTailBlock-1)*lvPerBlock >= tailLvPtr
- expTailBlock = (tailLvPtr + lvPerBlock*2 - 1) / lvPerBlock
+ for expspos(expTailBlock) <= tailLvPtr {
+ expTailBlock++
+ }
}
- if ts.fm.indexedRange.afterLastIndexedBlock != uint64(head+1) {
- ts.t.Fatalf("Invalid index head (expected #%d, got #%d)", head, ts.fm.indexedRange.afterLastIndexedBlock-1)
+ if ts.fm.indexedRange.blocks.Last() != uint64(head) {
+ ts.t.Fatalf("Invalid index head (expected #%d, got #%d)", head, ts.fm.indexedRange.blocks.Last())
}
- if ts.fm.indexedRange.headBlockDelimiter != uint64(head)*lvPerBlock {
- ts.t.Fatalf("Invalid index head delimiter pointer (expected %d, got %d)", uint64(head)*lvPerBlock, ts.fm.indexedRange.headBlockDelimiter)
+ expHeadDelimiter := expdpos(uint64(head))
+ if ts.fm.indexedRange.headDelimiter != expHeadDelimiter {
+ ts.t.Fatalf("Invalid index head delimiter pointer (expected %d, got %d)", expHeadDelimiter, ts.fm.indexedRange.headDelimiter)
}
- if ts.fm.indexedRange.firstIndexedBlock != expTailBlock {
- ts.t.Fatalf("Invalid index tail block (expected #%d, got #%d)", expTailBlock, ts.fm.indexedRange.firstIndexedBlock)
+
+ if ts.fm.indexedRange.blocks.First() != expTailBlock {
+ ts.t.Fatalf("Invalid index tail block (expected #%d, got #%d)", expTailBlock, ts.fm.indexedRange.blocks.First())
}
}
}
@@ -235,7 +257,7 @@ func (ts *testSetup) setHistory(history uint64, noHistory bool) {
History: history,
Disabled: noHistory,
}
- ts.fm = NewFilterMaps(ts.db, view, ts.params, config)
+ ts.fm = NewFilterMaps(ts.db, view, 0, 0, ts.params, config)
ts.fm.testDisableSnapshots = ts.testDisableSnapshots
ts.fm.Start()
}
@@ -420,7 +442,7 @@ func (tc *testChain) setTargetHead() {
if tc.ts.fm != nil {
if !tc.ts.fm.disabled {
//tc.ts.fm.targetViewCh <- NewChainView(tc, head.Number.Uint64(), head.Hash())
- tc.ts.fm.SetTargetView(NewChainView(tc, head.Number.Uint64(), head.Hash()))
+ tc.ts.fm.SetTarget(NewChainView(tc, head.Number.Uint64(), head.Hash()), 0, 0)
}
}
}
diff --git a/core/filtermaps/map_renderer.go b/core/filtermaps/map_renderer.go
index 5bd48a4b23..4f45a7f2b2 100644
--- a/core/filtermaps/map_renderer.go
+++ b/core/filtermaps/map_renderer.go
@@ -46,12 +46,12 @@ var (
// mapRenderer represents a process that renders filter maps in a specified
// range according to the actual targetView.
type mapRenderer struct {
- f *FilterMaps
- afterLastMap uint32
- currentMap *renderedMap
- finishedMaps map[uint32]*renderedMap
- firstFinished, afterLastFinished uint32
- iterator *logIterator
+ f *FilterMaps
+ renderBefore uint32
+ currentMap *renderedMap
+ finishedMaps map[uint32]*renderedMap
+ finished common.Range[uint32]
+ iterator *logIterator
}
// renderedMap represents a single filter map that is being rendered in memory.
@@ -74,22 +74,22 @@ func (r *renderedMap) firstBlock() uint64 {
// specified map index boundary, starting from the latest available starting
// point that is consistent with the current targetView.
// The renderer ensures that filterMapsRange, indexedView and the actual map
-// data are always consistent with each other. If afterLastMap is greater than
+// data are always consistent with each other. If renderBefore is greater than
// the latest existing rendered map then indexedView is updated to targetView,
// otherwise it is checked that the rendered range is consistent with both
// views.
-func (f *FilterMaps) renderMapsBefore(afterLastMap uint32) (*mapRenderer, error) {
- nextMap, startBlock, startLvPtr, err := f.lastCanonicalMapBoundaryBefore(afterLastMap)
+func (f *FilterMaps) renderMapsBefore(renderBefore uint32) (*mapRenderer, error) {
+ nextMap, startBlock, startLvPtr, err := f.lastCanonicalMapBoundaryBefore(renderBefore)
if err != nil {
return nil, err
}
- if snapshot := f.lastCanonicalSnapshotBefore(afterLastMap); snapshot != nil && snapshot.mapIndex >= nextMap {
+ if snapshot := f.lastCanonicalSnapshotBefore(renderBefore); snapshot != nil && snapshot.mapIndex >= nextMap {
return f.renderMapsFromSnapshot(snapshot)
}
- if nextMap >= afterLastMap {
+ if nextMap >= renderBefore {
return nil, nil
}
- return f.renderMapsFromMapBoundary(nextMap, afterLastMap, startBlock, startLvPtr)
+ return f.renderMapsFromMapBoundary(nextMap, renderBefore, startBlock, startLvPtr)
}
// renderMapsFromSnapshot creates a mapRenderer that starts rendering from a
@@ -108,17 +108,16 @@ func (f *FilterMaps) renderMapsFromSnapshot(cp *renderedMap) (*mapRenderer, erro
lastBlock: cp.lastBlock,
blockLvPtrs: cp.blockLvPtrs,
},
- finishedMaps: make(map[uint32]*renderedMap),
- firstFinished: cp.mapIndex,
- afterLastFinished: cp.mapIndex,
- afterLastMap: math.MaxUint32,
- iterator: iter,
+ finishedMaps: make(map[uint32]*renderedMap),
+ finished: common.NewRange(cp.mapIndex, 0),
+ renderBefore: math.MaxUint32,
+ iterator: iter,
}, nil
}
// renderMapsFromMapBoundary creates a mapRenderer that starts rendering at a
// map boundary.
-func (f *FilterMaps) renderMapsFromMapBoundary(firstMap, afterLastMap uint32, startBlock, startLvPtr uint64) (*mapRenderer, error) {
+func (f *FilterMaps) renderMapsFromMapBoundary(firstMap, renderBefore uint32, startBlock, startLvPtr uint64) (*mapRenderer, error) {
iter, err := f.newLogIteratorFromMapBoundary(firstMap, startBlock, startLvPtr)
if err != nil {
return nil, fmt.Errorf("failed to create log iterator from map boundary %d: %v", firstMap, err)
@@ -130,22 +129,21 @@ func (f *FilterMaps) renderMapsFromMapBoundary(firstMap, afterLastMap uint32, st
mapIndex: firstMap,
lastBlock: iter.blockNumber,
},
- finishedMaps: make(map[uint32]*renderedMap),
- firstFinished: firstMap,
- afterLastFinished: firstMap,
- afterLastMap: afterLastMap,
- iterator: iter,
+ finishedMaps: make(map[uint32]*renderedMap),
+ finished: common.NewRange(firstMap, 0),
+ renderBefore: renderBefore,
+ iterator: iter,
}, nil
}
// lastCanonicalSnapshotBefore returns the latest cached snapshot that matches
// the current targetView.
-func (f *FilterMaps) lastCanonicalSnapshotBefore(afterLastMap uint32) *renderedMap {
+func (f *FilterMaps) lastCanonicalSnapshotBefore(renderBefore uint32) *renderedMap {
var best *renderedMap
for _, blockNumber := range f.renderSnapshots.Keys() {
- if cp, _ := f.renderSnapshots.Get(blockNumber); cp != nil && blockNumber < f.indexedRange.afterLastIndexedBlock &&
+ if cp, _ := f.renderSnapshots.Get(blockNumber); cp != nil && blockNumber < f.indexedRange.blocks.AfterLast() &&
blockNumber <= f.targetView.headNumber && f.targetView.getBlockId(blockNumber) == cp.lastBlockId &&
- cp.mapIndex < afterLastMap && (best == nil || blockNumber > best.lastBlock) {
+ cp.mapIndex < renderBefore && (best == nil || blockNumber > best.lastBlock) {
best = cp
}
}
@@ -158,11 +156,11 @@ func (f *FilterMaps) lastCanonicalSnapshotBefore(afterLastMap uint32) *renderedM
// or the boundary of a currently rendered map.
// Along with the next map index where the rendering can be started, the number
// and starting log value pointer of the last block is also returned.
-func (f *FilterMaps) lastCanonicalMapBoundaryBefore(afterLastMap uint32) (nextMap uint32, startBlock, startLvPtr uint64, err error) {
+func (f *FilterMaps) lastCanonicalMapBoundaryBefore(renderBefore uint32) (nextMap uint32, startBlock, startLvPtr uint64, err error) {
if !f.indexedRange.initialized {
return 0, 0, 0, nil
}
- mapIndex := afterLastMap
+ mapIndex := renderBefore
for {
var ok bool
if mapIndex, ok = f.lastMapBoundaryBefore(mapIndex); !ok {
@@ -188,18 +186,18 @@ func (f *FilterMaps) lastCanonicalMapBoundaryBefore(afterLastMap uint32) (nextMa
// lastMapBoundaryBefore returns the latest map boundary before the specified
// map index.
func (f *FilterMaps) lastMapBoundaryBefore(mapIndex uint32) (uint32, bool) {
- if !f.indexedRange.initialized || f.indexedRange.afterLastRenderedMap == 0 {
+ if !f.indexedRange.initialized || f.indexedRange.maps.AfterLast() == 0 {
return 0, false
}
- if mapIndex > f.indexedRange.afterLastRenderedMap {
- mapIndex = f.indexedRange.afterLastRenderedMap
+ if mapIndex > f.indexedRange.maps.AfterLast() {
+ mapIndex = f.indexedRange.maps.AfterLast()
}
- if mapIndex > f.indexedRange.firstRenderedMap {
+ if mapIndex > f.indexedRange.maps.First() {
return mapIndex - 1, true
}
- if mapIndex+f.mapsPerEpoch > f.indexedRange.firstRenderedMap {
- if mapIndex > f.indexedRange.firstRenderedMap-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch {
- mapIndex = f.indexedRange.firstRenderedMap - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch
+ if mapIndex+f.mapsPerEpoch > f.indexedRange.maps.First() {
+ if mapIndex > f.indexedRange.maps.First()-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch {
+ mapIndex = f.indexedRange.maps.First() - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch
}
} else {
mapIndex = (mapIndex >> f.logMapsPerEpoch) << f.logMapsPerEpoch
@@ -218,19 +216,19 @@ func (f *FilterMaps) emptyFilterMap() filterMap {
// loadHeadSnapshot loads the last rendered map from the database and creates
// a snapshot.
func (f *FilterMaps) loadHeadSnapshot() error {
- fm, err := f.getFilterMap(f.indexedRange.afterLastRenderedMap - 1)
+ fm, err := f.getFilterMap(f.indexedRange.maps.Last())
if err != nil {
- return fmt.Errorf("failed to load head snapshot map %d: %v", f.indexedRange.afterLastRenderedMap-1, err)
+ return fmt.Errorf("failed to load head snapshot map %d: %v", f.indexedRange.maps.Last(), err)
}
- lastBlock, _, err := f.getLastBlockOfMap(f.indexedRange.afterLastRenderedMap - 1)
+ lastBlock, _, err := f.getLastBlockOfMap(f.indexedRange.maps.Last())
if err != nil {
- return fmt.Errorf("failed to retrieve last block of head snapshot map %d: %v", f.indexedRange.afterLastRenderedMap-1, err)
+ return fmt.Errorf("failed to retrieve last block of head snapshot map %d: %v", f.indexedRange.maps.Last(), err)
}
var firstBlock uint64
- if f.indexedRange.afterLastRenderedMap > 1 {
- prevLastBlock, _, err := f.getLastBlockOfMap(f.indexedRange.afterLastRenderedMap - 2)
+ if f.indexedRange.maps.AfterLast() > 1 {
+ prevLastBlock, _, err := f.getLastBlockOfMap(f.indexedRange.maps.Last() - 1)
if err != nil {
- return fmt.Errorf("failed to retrieve last block of map %d before head snapshot: %v", f.indexedRange.afterLastRenderedMap-2, err)
+ return fmt.Errorf("failed to retrieve last block of map %d before head snapshot: %v", f.indexedRange.maps.Last()-1, err)
}
firstBlock = prevLastBlock + 1
}
@@ -241,14 +239,14 @@ func (f *FilterMaps) loadHeadSnapshot() error {
return fmt.Errorf("failed to retrieve log value pointer of head snapshot block %d: %v", firstBlock+uint64(i), err)
}
}
- f.renderSnapshots.Add(f.indexedRange.afterLastIndexedBlock-1, &renderedMap{
+ f.renderSnapshots.Add(f.indexedRange.blocks.Last(), &renderedMap{
filterMap: fm,
- mapIndex: f.indexedRange.afterLastRenderedMap - 1,
- lastBlock: f.indexedRange.afterLastIndexedBlock - 1,
- lastBlockId: f.indexedView.getBlockId(f.indexedRange.afterLastIndexedBlock - 1),
+ mapIndex: f.indexedRange.maps.Last(),
+ lastBlock: f.indexedRange.blocks.Last(),
+ lastBlockId: f.indexedView.getBlockId(f.indexedRange.blocks.Last()),
blockLvPtrs: lvPtrs,
finished: true,
- headDelimiter: f.indexedRange.headBlockDelimiter,
+ headDelimiter: f.indexedRange.headDelimiter,
})
return nil
}
@@ -277,14 +275,14 @@ func (r *mapRenderer) run(stopCb func() bool, writeCb func()) (bool, error) {
}
// map finished
r.finishedMaps[r.currentMap.mapIndex] = r.currentMap
- r.afterLastFinished++
- if len(r.finishedMaps) >= maxMapsPerBatch || r.afterLastFinished&(r.f.baseRowGroupLength-1) == 0 {
+ r.finished.SetLast(r.finished.AfterLast())
+ if len(r.finishedMaps) >= maxMapsPerBatch || r.finished.AfterLast()&(r.f.baseRowGroupLength-1) == 0 {
if err := r.writeFinishedMaps(stopCb); err != nil {
return false, err
}
writeCb()
}
- if r.afterLastFinished == r.afterLastMap || r.iterator.finished {
+ if r.finished.AfterLast() == r.renderBefore || r.iterator.finished {
if err := r.writeFinishedMaps(stopCb); err != nil {
return false, err
}
@@ -293,7 +291,7 @@ func (r *mapRenderer) run(stopCb func() bool, writeCb func()) (bool, error) {
}
r.currentMap = &renderedMap{
filterMap: r.f.emptyFilterMap(),
- mapIndex: r.afterLastFinished,
+ mapIndex: r.finished.AfterLast(),
}
}
}
@@ -323,11 +321,6 @@ func (r *mapRenderer) renderCurrentMap(stopCb func() bool) (bool, error) {
}
waitCnt = 0
}
- r.currentMap.lastBlock = r.iterator.blockNumber
- if r.iterator.delimiter {
- r.currentMap.lastBlock++
- r.currentMap.blockLvPtrs = append(r.currentMap.blockLvPtrs, r.iterator.lvIndex+1)
- }
if logValue := r.iterator.getValueHash(); logValue != (common.Hash{}) {
lvp, cached := rowMappingCache.Get(logValue)
if !cached {
@@ -346,9 +339,15 @@ func (r *mapRenderer) renderCurrentMap(stopCb func() bool) (bool, error) {
if err := r.iterator.next(); err != nil {
return false, fmt.Errorf("failed to advance log iterator at %d while rendering map %d: %v", r.iterator.lvIndex, r.currentMap.mapIndex, err)
}
- if !r.f.testDisableSnapshots && r.afterLastMap >= r.f.indexedRange.afterLastRenderedMap &&
- (r.iterator.delimiter || r.iterator.finished) {
- r.makeSnapshot()
+ if !r.iterator.skipToBoundary {
+ r.currentMap.lastBlock = r.iterator.blockNumber
+ if r.iterator.blockStart {
+ r.currentMap.blockLvPtrs = append(r.currentMap.blockLvPtrs, r.iterator.lvIndex)
+ }
+ if !r.f.testDisableSnapshots && r.renderBefore >= r.f.indexedRange.maps.AfterLast() &&
+ (r.iterator.delimiter || r.iterator.finished) {
+ r.makeSnapshot()
+ }
}
}
if r.iterator.finished {
@@ -402,7 +401,7 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error {
mapIndices []uint32
rows []FilterRow
)
- for mapIndex := r.firstFinished; mapIndex < r.afterLastFinished; mapIndex++ {
+ for mapIndex := range r.finished.Iter() {
row := r.finishedMaps[mapIndex].filterMap[rowIndex]
if fm, _ := r.f.filterMapCache.Get(mapIndex); fm != nil && row.Equal(fm[rowIndex]) {
continue
@@ -410,8 +409,8 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error {
mapIndices = append(mapIndices, mapIndex)
rows = append(rows, row)
}
- if newRange.afterLastRenderedMap == r.afterLastFinished { // head updated; remove future entries
- for mapIndex := r.afterLastFinished; mapIndex < oldRange.afterLastRenderedMap; mapIndex++ {
+ if newRange.maps.AfterLast() == r.finished.AfterLast() { // head updated; remove future entries
+ for mapIndex := r.finished.AfterLast(); mapIndex < oldRange.maps.AfterLast(); mapIndex++ {
if fm, _ := r.f.filterMapCache.Get(mapIndex); fm != nil && len(fm[rowIndex]) == 0 {
continue
}
@@ -425,24 +424,24 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error {
checkWriteCnt()
}
// update filter map cache
- if newRange.afterLastRenderedMap == r.afterLastFinished {
+ if newRange.maps.AfterLast() == r.finished.AfterLast() {
// head updated; cache new head maps and remove future entries
- for mapIndex := r.firstFinished; mapIndex < r.afterLastFinished; mapIndex++ {
+ for mapIndex := range r.finished.Iter() {
r.f.filterMapCache.Add(mapIndex, r.finishedMaps[mapIndex].filterMap)
}
- for mapIndex := r.afterLastFinished; mapIndex < oldRange.afterLastRenderedMap; mapIndex++ {
+ for mapIndex := r.finished.AfterLast(); mapIndex < oldRange.maps.AfterLast(); mapIndex++ {
r.f.filterMapCache.Remove(mapIndex)
}
} else {
// head not updated; do not cache maps during tail rendering because we
// need head maps to be available in the cache
- for mapIndex := r.firstFinished; mapIndex < r.afterLastFinished; mapIndex++ {
+ for mapIndex := range r.finished.Iter() {
r.f.filterMapCache.Remove(mapIndex)
}
}
// add or update block pointers
- blockNumber := r.finishedMaps[r.firstFinished].firstBlock()
- for mapIndex := r.firstFinished; mapIndex < r.afterLastFinished; mapIndex++ {
+ blockNumber := r.finishedMaps[r.finished.First()].firstBlock()
+ for mapIndex := range r.finished.Iter() {
renderedMap := r.finishedMaps[mapIndex]
r.f.storeLastBlockOfMap(batch, mapIndex, renderedMap.lastBlock, renderedMap.lastBlockId)
checkWriteCnt()
@@ -455,18 +454,18 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error {
blockNumber++
}
}
- if newRange.afterLastRenderedMap == r.afterLastFinished { // head updated; remove future entries
- for mapIndex := r.afterLastFinished; mapIndex < oldRange.afterLastRenderedMap; mapIndex++ {
+ if newRange.maps.AfterLast() == r.finished.AfterLast() { // head updated; remove future entries
+ for mapIndex := r.finished.AfterLast(); mapIndex < oldRange.maps.AfterLast(); mapIndex++ {
r.f.deleteLastBlockOfMap(batch, mapIndex)
checkWriteCnt()
}
- for ; blockNumber < oldRange.afterLastIndexedBlock; blockNumber++ {
+ for ; blockNumber < oldRange.blocks.AfterLast(); blockNumber++ {
r.f.deleteBlockLvPointer(batch, blockNumber)
checkWriteCnt()
}
}
r.finishedMaps = make(map[uint32]*renderedMap)
- r.firstFinished = r.afterLastFinished
+ r.finished.SetFirst(r.finished.AfterLast())
r.f.setRange(batch, renderedView, newRange)
if err := batch.Write(); err != nil {
log.Crit("Error writing log index update batch", "error", err)
@@ -481,33 +480,33 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error {
// range to the unchanged region until all new map data is committed.
func (r *mapRenderer) getTempRange() (filterMapsRange, error) {
tempRange := r.f.indexedRange
- if err := tempRange.addRenderedRange(r.firstFinished, r.firstFinished, r.afterLastMap, r.f.mapsPerEpoch); err != nil {
+ if err := tempRange.addRenderedRange(r.finished.First(), r.finished.First(), r.renderBefore, r.f.mapsPerEpoch); err != nil {
return filterMapsRange{}, fmt.Errorf("failed to update temporary rendered range: %v", err)
}
- if tempRange.firstRenderedMap != r.f.indexedRange.firstRenderedMap {
+ if tempRange.maps.First() != r.f.indexedRange.maps.First() {
// first rendered map changed; update first indexed block
- if tempRange.firstRenderedMap > 0 {
- lastBlock, _, err := r.f.getLastBlockOfMap(tempRange.firstRenderedMap - 1)
+ if tempRange.maps.First() > 0 {
+ firstBlock, _, err := r.f.getLastBlockOfMap(tempRange.maps.First() - 1)
if err != nil {
- return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d before temporary range: %v", tempRange.firstRenderedMap-1, err)
+ return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d before temporary range: %v", tempRange.maps.First()-1, err)
}
- tempRange.firstIndexedBlock = lastBlock + 1
+ tempRange.blocks.SetFirst(firstBlock + 1) // firstBlock is probably partially rendered
} else {
- tempRange.firstIndexedBlock = 0
+ tempRange.blocks.SetFirst(0)
}
}
- if tempRange.afterLastRenderedMap != r.f.indexedRange.afterLastRenderedMap {
- // first rendered map changed; update first indexed block
- if tempRange.afterLastRenderedMap > 0 {
- lastBlock, _, err := r.f.getLastBlockOfMap(tempRange.afterLastRenderedMap - 1)
+ if tempRange.maps.AfterLast() != r.f.indexedRange.maps.AfterLast() {
+ // last rendered map changed; update last indexed block
+ if !tempRange.maps.IsEmpty() {
+ lastBlock, _, err := r.f.getLastBlockOfMap(tempRange.maps.Last())
if err != nil {
- return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d at the end of temporary range: %v", tempRange.afterLastRenderedMap-1, err)
+ return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d at the end of temporary range: %v", tempRange.maps.Last(), err)
}
- tempRange.afterLastIndexedBlock = lastBlock
+ tempRange.blocks.SetAfterLast(lastBlock) // lastBlock is probably partially rendered
} else {
- tempRange.afterLastIndexedBlock = 0
+ tempRange.blocks.SetAfterLast(0)
}
- tempRange.headBlockDelimiter = 0
+ tempRange.headDelimiter = 0
}
return tempRange, nil
}
@@ -517,39 +516,39 @@ func (r *mapRenderer) getTempRange() (filterMapsRange, error) {
func (r *mapRenderer) getUpdatedRange() (filterMapsRange, error) {
// update filterMapsRange
newRange := r.f.indexedRange
- if err := newRange.addRenderedRange(r.firstFinished, r.afterLastFinished, r.afterLastMap, r.f.mapsPerEpoch); err != nil {
+ if err := newRange.addRenderedRange(r.finished.First(), r.finished.AfterLast(), r.renderBefore, r.f.mapsPerEpoch); err != nil {
return filterMapsRange{}, fmt.Errorf("failed to update rendered range: %v", err)
}
- if newRange.firstRenderedMap != r.f.indexedRange.firstRenderedMap {
+ if newRange.maps.First() != r.f.indexedRange.maps.First() {
// first rendered map changed; update first indexed block
- if newRange.firstRenderedMap > 0 {
- lastBlock, _, err := r.f.getLastBlockOfMap(newRange.firstRenderedMap - 1)
+ if newRange.maps.First() > 0 {
+ firstBlock, _, err := r.f.getLastBlockOfMap(newRange.maps.First() - 1)
if err != nil {
- return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d before rendered range: %v", newRange.firstRenderedMap-1, err)
+ return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d before rendered range: %v", newRange.maps.First()-1, err)
}
- newRange.firstIndexedBlock = lastBlock + 1
+ newRange.blocks.SetFirst(firstBlock + 1) // firstBlock is probably partially rendered
} else {
- newRange.firstIndexedBlock = 0
+ newRange.blocks.SetFirst(0)
}
}
- if newRange.afterLastRenderedMap == r.afterLastFinished {
+ if newRange.maps.AfterLast() == r.finished.AfterLast() {
// last rendered map changed; update last indexed block and head pointers
- lm := r.finishedMaps[r.afterLastFinished-1]
- newRange.headBlockIndexed = lm.finished
+ lm := r.finishedMaps[r.finished.Last()]
+ newRange.headIndexed = lm.finished
if lm.finished {
- newRange.afterLastIndexedBlock = r.f.targetView.headNumber + 1
+ newRange.blocks.SetLast(r.f.targetView.headNumber)
if lm.lastBlock != r.f.targetView.headNumber {
panic("map rendering finished but last block != head block")
}
- newRange.headBlockDelimiter = lm.headDelimiter
+ newRange.headDelimiter = lm.headDelimiter
} else {
- newRange.afterLastIndexedBlock = lm.lastBlock
- newRange.headBlockDelimiter = 0
+ newRange.blocks.SetAfterLast(lm.lastBlock) // lastBlock is probably partially rendered
+ newRange.headDelimiter = 0
}
} else {
// last rendered map not replaced; ensure that target chain view matches
// indexed chain view on the rendered section
- if lastBlock := r.finishedMaps[r.afterLastFinished-1].lastBlock; !matchViews(r.f.indexedView, r.f.targetView, lastBlock) {
+ if lastBlock := r.finishedMaps[r.finished.Last()].lastBlock; !matchViews(r.f.indexedView, r.f.targetView, lastBlock) {
return filterMapsRange{}, errChainUpdate
}
}
@@ -571,9 +570,9 @@ func (fmr *filterMapsRange) addRenderedRange(firstRendered, afterLastRendered, a
m uint32
d int
}
- endpoints := []endpoint{{fmr.firstRenderedMap, 1}, {fmr.afterLastRenderedMap, -1}, {firstRendered, 1}, {afterLastRendered, -101}, {afterLastRemoved, 100}}
+ endpoints := []endpoint{{fmr.maps.First(), 1}, {fmr.maps.AfterLast(), -1}, {firstRendered, 1}, {afterLastRendered, -101}, {afterLastRemoved, 100}}
if fmr.tailPartialEpoch > 0 {
- endpoints = append(endpoints, []endpoint{{fmr.firstRenderedMap - mapsPerEpoch, 1}, {fmr.firstRenderedMap - mapsPerEpoch + fmr.tailPartialEpoch, -1}}...)
+ endpoints = append(endpoints, []endpoint{{fmr.maps.First() - mapsPerEpoch, 1}, {fmr.maps.First() - mapsPerEpoch + fmr.tailPartialEpoch, -1}}...)
}
sort.Slice(endpoints, func(i, j int) bool { return endpoints[i].m < endpoints[j].m })
var (
@@ -596,14 +595,12 @@ func (fmr *filterMapsRange) addRenderedRange(firstRendered, afterLastRendered, a
case 0:
// Initialized database, but no finished maps yet.
fmr.tailPartialEpoch = 0
- fmr.firstRenderedMap = firstRendered
- fmr.afterLastRenderedMap = firstRendered
+ fmr.maps = common.NewRange(firstRendered, 0)
case 2:
// One rendered section (no partial tail epoch).
fmr.tailPartialEpoch = 0
- fmr.firstRenderedMap = merged[0]
- fmr.afterLastRenderedMap = merged[1]
+ fmr.maps = common.NewRange(merged[0], merged[1]-merged[0])
case 4:
// Two rendered sections (with a gap).
@@ -613,8 +610,7 @@ func (fmr *filterMapsRange) addRenderedRange(firstRendered, afterLastRendered, a
return fmt.Errorf("invalid tail partial epoch: %v", merged)
}
fmr.tailPartialEpoch = merged[1] - merged[0]
- fmr.firstRenderedMap = merged[2]
- fmr.afterLastRenderedMap = merged[3]
+ fmr.maps = common.NewRange(merged[2], merged[3]-merged[2])
default:
return fmt.Errorf("invalid number of rendered sections: %v", merged)
@@ -624,12 +620,13 @@ func (fmr *filterMapsRange) addRenderedRange(firstRendered, afterLastRendered, a
// logIterator iterates on the linear log value index range.
type logIterator struct {
- chainView *ChainView
- blockNumber uint64
- receipts types.Receipts
- blockStart, delimiter, finished bool
- txIndex, logIndex, topicIndex int
- lvIndex uint64
+ params *Params
+ chainView *ChainView
+ blockNumber uint64
+ receipts types.Receipts
+ blockStart, delimiter, skipToBoundary, finished bool
+ txIndex, logIndex, topicIndex int
+ lvIndex uint64
}
var errUnindexedRange = errors.New("unindexed range")
@@ -641,12 +638,12 @@ func (f *FilterMaps) newLogIteratorFromBlockDelimiter(blockNumber uint64) (*logI
if blockNumber > f.targetView.headNumber {
return nil, fmt.Errorf("iterator entry point %d after target chain head block %d", blockNumber, f.targetView.headNumber)
}
- if blockNumber < f.indexedRange.firstIndexedBlock || blockNumber >= f.indexedRange.afterLastIndexedBlock {
+ if !f.indexedRange.blocks.Includes(blockNumber) {
return nil, errUnindexedRange
}
var lvIndex uint64
- if f.indexedRange.headBlockIndexed && blockNumber+1 == f.indexedRange.afterLastIndexedBlock {
- lvIndex = f.indexedRange.headBlockDelimiter
+ if f.indexedRange.headIndexed && blockNumber+1 == f.indexedRange.blocks.AfterLast() {
+ lvIndex = f.indexedRange.headDelimiter
} else {
var err error
lvIndex, err = f.getBlockLvPointer(blockNumber + 1)
@@ -656,13 +653,16 @@ func (f *FilterMaps) newLogIteratorFromBlockDelimiter(blockNumber uint64) (*logI
lvIndex--
}
finished := blockNumber == f.targetView.headNumber
- return &logIterator{
+ l := &logIterator{
chainView: f.targetView,
+ params: &f.Params,
blockNumber: blockNumber,
finished: finished,
delimiter: !finished,
lvIndex: lvIndex,
- }, nil
+ }
+ l.enforceValidState()
+ return l, nil
}
// newLogIteratorFromMapBoundary creates a logIterator starting at the given
@@ -679,12 +679,13 @@ func (f *FilterMaps) newLogIteratorFromMapBoundary(mapIndex uint32, startBlock,
// initialize iterator at block start
l := &logIterator{
chainView: f.targetView,
+ params: &f.Params,
blockNumber: startBlock,
receipts: receipts,
blockStart: true,
lvIndex: startLvPtr,
}
- l.nextValid()
+ l.enforceValidState()
targetIndex := uint64(mapIndex) << f.logValuesPerMap
if l.lvIndex > targetIndex {
return nil, fmt.Errorf("log value pointer %d of last block of map is after map boundary %d", l.lvIndex, targetIndex)
@@ -713,7 +714,7 @@ func (l *logIterator) updateChainView(cv *ChainView) bool {
// getValueHash returns the log value hash at the current position.
func (l *logIterator) getValueHash() common.Hash {
- if l.delimiter || l.finished {
+ if l.delimiter || l.finished || l.skipToBoundary {
return common.Hash{}
}
log := l.receipts[l.txIndex].Logs[l.logIndex]
@@ -725,6 +726,13 @@ func (l *logIterator) getValueHash() common.Hash {
// next moves the iterator to the next log value index.
func (l *logIterator) next() error {
+ if l.skipToBoundary {
+ l.lvIndex++
+ if l.lvIndex%l.params.valuesPerMap == 0 {
+ l.skipToBoundary = false
+ }
+ return nil
+ }
if l.finished {
return nil
}
@@ -741,18 +749,26 @@ func (l *logIterator) next() error {
l.blockStart = false
}
l.lvIndex++
- l.nextValid()
+ l.enforceValidState()
return nil
}
-// nextValid updates the internal transaction, log and topic index pointers
+// enforceValidState updates the internal transaction, log and topic index pointers
// to the next existing log value of the given block if necessary.
-// Note that nextValid does not advance the log value index pointer.
-func (l *logIterator) nextValid() {
+// Note that enforceValidState does not advance the log value index pointer.
+func (l *logIterator) enforceValidState() {
+ if l.delimiter || l.finished || l.skipToBoundary {
+ return
+ }
for ; l.txIndex < len(l.receipts); l.txIndex++ {
receipt := l.receipts[l.txIndex]
for ; l.logIndex < len(receipt.Logs); l.logIndex++ {
log := receipt.Logs[l.logIndex]
+ if l.topicIndex == 0 && uint64(len(log.Topics)+1) > l.params.valuesPerMap-l.lvIndex%l.params.valuesPerMap {
+ // next log would be split by map boundary; skip to boundary
+ l.skipToBoundary = true
+ return
+ }
if l.topicIndex <= len(log.Topics) {
return
}
diff --git a/core/filtermaps/matcher.go b/core/filtermaps/matcher.go
index 19acbd762a..6c05672cbc 100644
--- a/core/filtermaps/matcher.go
+++ b/core/filtermaps/matcher.go
@@ -61,11 +61,9 @@ type SyncRange struct {
// block range where the index has not changed since the last matcher sync
// and therefore the set of matches found in this region is guaranteed to
// be valid and complete.
- Valid bool
- FirstValid, LastValid uint64
+ ValidBlocks common.Range[uint64]
// block range indexed according to the given chain head.
- Indexed bool
- FirstIndexed, LastIndexed uint64
+ IndexedBlocks common.Range[uint64]
}
// GetPotentialMatches returns a list of logs that are potential matches for the
@@ -75,7 +73,6 @@ type SyncRange struct {
// Also note that the returned list may contain false positives.
func GetPotentialMatches(ctx context.Context, backend MatcherBackend, firstBlock, lastBlock uint64, addresses []common.Address, topics [][]common.Hash) ([]*types.Log, error) {
params := backend.GetParams()
- var getLogStats runtimeStats
// find the log value index range to search
firstIndex, err := backend.GetBlockLvPointer(ctx, firstBlock)
if err != nil {
@@ -88,8 +85,6 @@ func GetPotentialMatches(ctx context.Context, backend MatcherBackend, firstBlock
if lastIndex > 0 {
lastIndex--
}
- firstMap, lastMap := uint32(firstIndex>>params.logValuesPerMap), uint32(lastIndex>>params.logValuesPerMap)
- firstEpoch, lastEpoch := firstMap>>params.logMapsPerEpoch, lastMap>>params.logMapsPerEpoch
// build matcher according to the given filter criteria
matchers := make([]matcher, len(topics)+1)
@@ -117,45 +112,45 @@ func GetPotentialMatches(ctx context.Context, backend MatcherBackend, firstBlock
// matchers signal a match for consecutive log value indices.
matcher := newMatchSequence(params, matchers)
- // processEpoch returns the potentially matching logs from the given epoch.
- processEpoch := func(epochIndex uint32) ([]*types.Log, error) {
- var logs []*types.Log
- // create a list of map indices to process
- fm, lm := epochIndex< lastMap {
- lm = lastMap
- }
- //
- mapIndices := make([]uint32, lm+1-fm)
- for i := range mapIndices {
- mapIndices[i] = fm + uint32(i)
- }
- // find potential matches
- matches, err := getAllMatches(ctx, matcher, mapIndices)
- if err != nil {
- return logs, err
- }
- // get the actual logs located at the matching log value indices
- var st int
- getLogStats.setState(&st, stGetLog)
- defer getLogStats.setState(&st, stNone)
- for _, m := range matches {
- if m == nil {
- return nil, ErrMatchAll
- }
- mlogs, err := getLogsFromMatches(ctx, backend, firstIndex, lastIndex, m)
- if err != nil {
- return logs, err
- }
- logs = append(logs, mlogs...)
- }
- getLogStats.addAmount(st, int64(len(logs)))
- return logs, nil
+ m := &matcherEnv{
+ ctx: ctx,
+ backend: backend,
+ params: params,
+ matcher: matcher,
+ firstIndex: firstIndex,
+ lastIndex: lastIndex,
+ firstMap: uint32(firstIndex >> params.logValuesPerMap),
+ lastMap: uint32(lastIndex >> params.logValuesPerMap),
}
+ start := time.Now()
+ res, err := m.process()
+
+ if doRuntimeStats {
+ log.Info("Log search finished", "elapsed", time.Since(start))
+ for i, ma := range matchers {
+ for j, m := range ma.(matchAny) {
+ log.Info("Single matcher stats", "matchSequence", i, "matchAny", j)
+ m.(*singleMatcher).stats.print()
+ }
+ }
+ log.Info("Get log stats")
+ m.getLogStats.print()
+ }
+ return res, err
+}
+
+type matcherEnv struct {
+ getLogStats runtimeStats // 64 bit aligned
+ ctx context.Context
+ backend MatcherBackend
+ params *Params
+ matcher matcher
+ firstIndex, lastIndex uint64
+ firstMap, lastMap uint32
+}
+
+func (m *matcherEnv) process() ([]*types.Log, error) {
type task struct {
epochIndex uint32
logs []*types.Log
@@ -175,18 +170,18 @@ func GetPotentialMatches(ctx context.Context, backend MatcherBackend, firstBlock
if task == nil {
break
}
- task.logs, task.err = processEpoch(task.epochIndex)
+ task.logs, task.err = m.processEpoch(task.epochIndex)
close(task.done)
}
wg.Done()
}
- start := time.Now()
- for i := 0; i < 4; i++ {
+ for range 4 {
wg.Add(1)
go worker()
}
+ firstEpoch, lastEpoch := m.firstMap>>m.params.logMapsPerEpoch, m.lastMap>>m.params.logMapsPerEpoch
var logs []*types.Log
// startEpoch is the next task to send whenever a worker can accept it.
// waitEpoch is the next task we are waiting for to finish in order to append
@@ -220,30 +215,58 @@ func GetPotentialMatches(ctx context.Context, backend MatcherBackend, firstBlock
}
}
}
- if doRuntimeStats {
- log.Info("Log search finished", "elapsed", time.Since(start))
- for i, ma := range matchers {
- for j, m := range ma.(matchAny) {
- log.Info("Single matcher stats", "matchSequence", i, "matchAny", j)
- m.(*singleMatcher).stats.print()
- }
- }
- log.Info("Get log stats")
- getLogStats.print()
+ return logs, nil
+}
+
+// processEpoch returns the potentially matching logs from the given epoch.
+func (m *matcherEnv) processEpoch(epochIndex uint32) ([]*types.Log, error) {
+ var logs []*types.Log
+ // create a list of map indices to process
+ fm, lm := epochIndex< m.lastMap {
+ lm = m.lastMap
+ }
+ //
+ mapIndices := make([]uint32, lm+1-fm)
+ for i := range mapIndices {
+ mapIndices[i] = fm + uint32(i)
+ }
+ // find potential matches
+ matches, err := m.getAllMatches(mapIndices)
+ if err != nil {
+ return logs, err
+ }
+ // get the actual logs located at the matching log value indices
+ var st int
+ m.getLogStats.setState(&st, stGetLog)
+ defer m.getLogStats.setState(&st, stNone)
+ for _, match := range matches {
+ if match == nil {
+ return nil, ErrMatchAll
+ }
+ mlogs, err := m.getLogsFromMatches(match)
+ if err != nil {
+ return logs, err
+ }
+ logs = append(logs, mlogs...)
+ }
+ m.getLogStats.addAmount(st, int64(len(logs)))
return logs, nil
}
// getLogsFromMatches returns the list of potentially matching logs located at
// the given list of matching log indices. Matches outside the firstIndex to
// lastIndex range are not returned.
-func getLogsFromMatches(ctx context.Context, backend MatcherBackend, firstIndex, lastIndex uint64, matches potentialMatches) ([]*types.Log, error) {
+func (m *matcherEnv) getLogsFromMatches(matches potentialMatches) ([]*types.Log, error) {
var logs []*types.Log
for _, match := range matches {
- if match < firstIndex || match > lastIndex {
+ if match < m.firstIndex || match > m.lastIndex {
continue
}
- log, err := backend.GetLogByLvIndex(ctx, match)
+ log, err := m.backend.GetLogByLvIndex(m.ctx, match)
if err != nil {
return logs, fmt.Errorf("failed to retrieve log at index %d: %v", match, err)
}
@@ -254,6 +277,28 @@ func getLogsFromMatches(ctx context.Context, backend MatcherBackend, firstIndex,
return logs, nil
}
+// getAllMatches creates an instance for a given matcher and set of map indices,
+// iterates through mapping layers and collects all results, then returns all
+// results in the same order as the map indices were specified.
+func (m *matcherEnv) getAllMatches(mapIndices []uint32) ([]potentialMatches, error) {
+ instance := m.matcher.newInstance(mapIndices)
+ resultsMap := make(map[uint32]potentialMatches)
+ for layerIndex := uint32(0); len(resultsMap) < len(mapIndices); layerIndex++ {
+ results, err := instance.getMatchesForLayer(m.ctx, layerIndex)
+ if err != nil {
+ return nil, err
+ }
+ for _, result := range results {
+ resultsMap[result.mapIndex] = result.matches
+ }
+ }
+ matches := make([]potentialMatches, len(mapIndices))
+ for i, mapIndex := range mapIndices {
+ matches[i] = resultsMap[mapIndex]
+ }
+ return matches, nil
+}
+
// matcher defines a general abstraction for any matcher configuration that
// can instantiate a matcherInstance.
type matcher interface {
@@ -281,28 +326,6 @@ type matcherResult struct {
matches potentialMatches
}
-// getAllMatches creates an instance for a given matcher and set of map indices,
-// iterates through mapping layers and collects all results, then returns all
-// results in the same order as the map indices were specified.
-func getAllMatches(ctx context.Context, matcher matcher, mapIndices []uint32) ([]potentialMatches, error) {
- instance := matcher.newInstance(mapIndices)
- resultsMap := make(map[uint32]potentialMatches)
- for layerIndex := uint32(0); len(resultsMap) < len(mapIndices); layerIndex++ {
- results, err := instance.getMatchesForLayer(ctx, layerIndex)
- if err != nil {
- return nil, err
- }
- for _, result := range results {
- resultsMap[result.mapIndex] = result.matches
- }
- }
- matches := make([]potentialMatches, len(mapIndices))
- for i, mapIndex := range mapIndices {
- matches[i] = resultsMap[mapIndex]
- }
- return matches, nil
-}
-
// singleMatcher implements matcher by returning matches for a single log value hash.
type singleMatcher struct {
backend MatcherBackend
@@ -550,24 +573,18 @@ type matchSequence struct {
// newInstance creates a new instance of matchSequence.
func (m *matchSequence) newInstance(mapIndices []uint32) matcherInstance {
// determine set of indices to request from next matcher
- nextIndices := make([]uint32, 0, len(mapIndices)*3/2)
needMatched := make(map[uint32]struct{})
baseRequested := make(map[uint32]struct{})
nextRequested := make(map[uint32]struct{})
for _, mapIndex := range mapIndices {
needMatched[mapIndex] = struct{}{}
baseRequested[mapIndex] = struct{}{}
- if _, ok := nextRequested[mapIndex]; !ok {
- nextIndices = append(nextIndices, mapIndex)
- nextRequested[mapIndex] = struct{}{}
- }
- nextIndices = append(nextIndices, mapIndex+1)
- nextRequested[mapIndex+1] = struct{}{}
+ nextRequested[mapIndex] = struct{}{}
}
return &matchSequenceInstance{
matchSequence: m,
baseInstance: m.base.newInstance(mapIndices),
- nextInstance: m.next.newInstance(nextIndices),
+ nextInstance: m.next.newInstance(mapIndices),
needMatched: needMatched,
baseRequested: baseRequested,
nextRequested: nextRequested,
@@ -687,12 +704,9 @@ func (m *matchSequenceInstance) getMatchesForLayer(ctx context.Context, layerInd
if _, ok := m.nextRequested[mapIndex]; ok {
continue
}
- if _, ok := m.nextRequested[mapIndex+1]; ok {
- continue
- }
matchedResults = append(matchedResults, matcherResult{
mapIndex: mapIndex,
- matches: m.params.matchResults(mapIndex, m.offset, m.baseResults[mapIndex], m.nextResults[mapIndex], m.nextResults[mapIndex+1]),
+ matches: m.params.matchResults(mapIndex, m.offset, m.baseResults[mapIndex], m.nextResults[mapIndex]),
})
delete(m.needMatched, mapIndex)
}
@@ -715,9 +729,6 @@ func (m *matchSequenceInstance) dropIndices(dropIndices []uint32) {
if m.dropNext(mapIndex) {
dropNext = append(dropNext, mapIndex)
}
- if m.dropNext(mapIndex + 1) {
- dropNext = append(dropNext, mapIndex+1)
- }
}
m.nextInstance.dropIndices(dropNext)
}
@@ -743,9 +754,6 @@ func (m *matchSequenceInstance) evalBase(ctx context.Context, layerIndex uint32)
if m.dropNext(r.mapIndex) {
dropIndices = append(dropIndices, r.mapIndex)
}
- if m.dropNext(r.mapIndex + 1) {
- dropIndices = append(dropIndices, r.mapIndex+1)
- }
}
if len(dropIndices) > 0 {
m.nextInstance.dropIndices(dropIndices)
@@ -771,9 +779,6 @@ func (m *matchSequenceInstance) evalNext(ctx context.Context, layerIndex uint32)
}
m.mergeNextStats(stats)
for _, r := range results {
- if r.mapIndex > 0 && m.dropBase(r.mapIndex-1) {
- dropIndices = append(dropIndices, r.mapIndex-1)
- }
if m.dropBase(r.mapIndex) {
dropIndices = append(dropIndices, r.mapIndex)
}
@@ -792,12 +797,7 @@ func (m *matchSequenceInstance) dropBase(mapIndex uint32) bool {
return false
}
if _, ok := m.needMatched[mapIndex]; ok {
- if next := m.nextResults[mapIndex]; next == nil ||
- (len(next) > 0 && next[len(next)-1] >= (uint64(mapIndex)< 0 && nextNext[0] < (uint64(mapIndex+1)< 0 {
return false
}
}
@@ -812,15 +812,8 @@ func (m *matchSequenceInstance) dropNext(mapIndex uint32) bool {
if _, ok := m.nextRequested[mapIndex]; !ok {
return false
}
- if _, ok := m.needMatched[mapIndex-1]; ok {
- if prevBase := m.baseResults[mapIndex-1]; prevBase == nil ||
- (len(prevBase) > 0 && prevBase[len(prevBase)-1]+m.offset >= (uint64(mapIndex)< 0 && base[0]+m.offset < (uint64(mapIndex+1)< 0 {
return false
}
}
@@ -833,59 +826,39 @@ func (m *matchSequenceInstance) dropNext(mapIndex uint32) bool {
// results at mapIndex and mapIndex+1. Note that acquiring nextNextRes may be
// skipped and it can be substituted with an empty list if baseRes has no potential
// matches that could be sequence matched with anything that could be in nextNextRes.
-func (params *Params) matchResults(mapIndex uint32, offset uint64, baseRes, nextRes, nextNextRes potentialMatches) potentialMatches {
+func (params *Params) matchResults(mapIndex uint32, offset uint64, baseRes, nextRes potentialMatches) potentialMatches {
if nextRes == nil || (baseRes != nil && len(baseRes) == 0) {
// if nextRes is a wild card or baseRes is empty then the sequence matcher
// result equals baseRes.
return baseRes
}
- if len(nextRes) > 0 {
- // discard items from nextRes whose corresponding base matcher results
- // with the negative offset applied would be located at mapIndex-1.
- start := 0
- for start < len(nextRes) && nextRes[start] < uint64(mapIndex)<= min {
+ result = append(result, v-offset)
+ }
}
- nextRes = nextRes[start:]
+ return result
}
- if len(nextNextRes) > 0 {
- // discard items from nextNextRes whose corresponding base matcher results
- // with the negative offset applied would still be located at mapIndex+1.
- stop := 0
- for stop < len(nextNextRes) && nextNextRes[stop] < uint64(mapIndex+1)< 0 && len(baseRes) > 0 {
- if nextRes[0] > baseRes[0]+offset {
- baseRes = baseRes[1:]
- } else if nextRes[0] < baseRes[0]+offset {
- nextRes = nextRes[1:]
- } else {
- matchedRes = append(matchedRes, baseRes[0])
- baseRes = baseRes[1:]
- nextRes = nextRes[1:]
- }
- }
+ for len(nextRes) > 0 && len(baseRes) > 0 {
+ if nextRes[0] > baseRes[0]+offset {
+ baseRes = baseRes[1:]
+ } else if nextRes[0] < baseRes[0]+offset {
+ nextRes = nextRes[1:]
} else {
- // baseRes is a wild card so just return next matcher results with
- // negative offset.
- for len(nextRes) > 0 {
- matchedRes = append(matchedRes, nextRes[0]-offset)
- nextRes = nextRes[1:]
- }
+ matchedRes = append(matchedRes, baseRes[0])
+ baseRes = baseRes[1:]
+ nextRes = nextRes[1:]
}
}
return matchedRes
diff --git a/core/filtermaps/matcher_backend.go b/core/filtermaps/matcher_backend.go
index 66f95f2145..4c4668e321 100644
--- a/core/filtermaps/matcher_backend.go
+++ b/core/filtermaps/matcher_backend.go
@@ -19,6 +19,7 @@ package filtermaps
import (
"context"
+ "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
@@ -27,9 +28,8 @@ type FilterMapsMatcherBackend struct {
f *FilterMaps
// these fields should be accessed under f.matchersLock mutex.
- valid bool
- firstValid, lastValid uint64
- syncCh chan SyncRange
+ validBlocks common.Range[uint64]
+ syncCh chan SyncRange
}
// NewMatcherBackend returns a FilterMapsMatcherBackend after registering it in
@@ -43,11 +43,9 @@ func (f *FilterMaps) NewMatcherBackend() *FilterMapsMatcherBackend {
f.indexLock.RUnlock()
}()
- fm := &FilterMapsMatcherBackend{
- f: f,
- valid: f.indexedRange.initialized && f.indexedRange.afterLastIndexedBlock > f.indexedRange.firstIndexedBlock,
- firstValid: f.indexedRange.firstIndexedBlock,
- lastValid: f.indexedRange.afterLastIndexedBlock - 1,
+ fm := &FilterMapsMatcherBackend{f: f}
+ if f.indexedRange.initialized {
+ fm.validBlocks = f.indexedRange.blocks
}
f.matchers[fm] = struct{}{}
return fm
@@ -122,28 +120,16 @@ func (fm *FilterMapsMatcherBackend) synced() {
fm.f.indexLock.RUnlock()
}()
- var (
- indexed bool
- lastIndexed, subLastIndexed uint64
- )
- if !fm.f.indexedRange.headBlockIndexed {
- subLastIndexed = 1
- }
- if fm.f.indexedRange.afterLastIndexedBlock-subLastIndexed > fm.f.indexedRange.firstIndexedBlock {
- indexed, lastIndexed = true, fm.f.indexedRange.afterLastIndexedBlock-subLastIndexed-1
+ indexedBlocks := fm.f.indexedRange.blocks
+ if !fm.f.indexedRange.headIndexed && !indexedBlocks.IsEmpty() {
+ indexedBlocks.SetAfterLast(indexedBlocks.Last()) // remove partially indexed last block
}
fm.syncCh <- SyncRange{
- HeadNumber: fm.f.indexedView.headNumber,
- Valid: fm.valid,
- FirstValid: fm.firstValid,
- LastValid: fm.lastValid,
- Indexed: indexed,
- FirstIndexed: fm.f.indexedRange.firstIndexedBlock,
- LastIndexed: lastIndexed,
+ HeadNumber: fm.f.indexedView.headNumber,
+ ValidBlocks: fm.validBlocks,
+ IndexedBlocks: indexedBlocks,
}
- fm.valid = indexed
- fm.firstValid = fm.f.indexedRange.firstIndexedBlock
- fm.lastValid = lastIndexed
+ fm.validBlocks = indexedBlocks
fm.syncCh = nil
}
@@ -187,20 +173,10 @@ func (f *FilterMaps) updateMatchersValidRange() {
defer f.matchersLock.Unlock()
for fm := range f.matchers {
- if !f.indexedRange.hasIndexedBlocks() {
- fm.valid = false
- }
- if !fm.valid {
+ if !f.indexedRange.initialized {
+ fm.validBlocks = common.Range[uint64]{}
continue
}
- if fm.firstValid < f.indexedRange.firstIndexedBlock {
- fm.firstValid = f.indexedRange.firstIndexedBlock
- }
- if fm.lastValid >= f.indexedRange.afterLastIndexedBlock {
- fm.lastValid = f.indexedRange.afterLastIndexedBlock - 1
- }
- if fm.firstValid > fm.lastValid {
- fm.valid = false
- }
+ fm.validBlocks = fm.validBlocks.Intersection(f.indexedRange.blocks)
}
}
diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go
index f679c3aeb3..9f3d55aa3f 100644
--- a/core/rawdb/accessors_indexes.go
+++ b/core/rawdb/accessors_indexes.go
@@ -356,8 +356,8 @@ func WriteFilterMapBaseRows(db ethdb.KeyValueWriter, mapRowIndex uint64, rows []
}
}
-func DeleteFilterMapRows(db ethdb.KeyValueRangeDeleter, firstMapRowIndex, afterLastMapRowIndex uint64) {
- if err := db.DeleteRange(filterMapRowKey(firstMapRowIndex, false), filterMapRowKey(afterLastMapRowIndex, false)); err != nil {
+func DeleteFilterMapRows(db ethdb.KeyValueRangeDeleter, mapRows common.Range[uint64]) {
+ if err := db.DeleteRange(filterMapRowKey(mapRows.First(), false), filterMapRowKey(mapRows.AfterLast(), false)); err != nil {
log.Crit("Failed to delete range of filter map rows", "err", err)
}
}
@@ -396,8 +396,8 @@ func DeleteFilterMapLastBlock(db ethdb.KeyValueWriter, mapIndex uint32) {
}
}
-func DeleteFilterMapLastBlocks(db ethdb.KeyValueRangeDeleter, firstMapIndex, afterLastMapIndex uint32) {
- if err := db.DeleteRange(filterMapLastBlockKey(firstMapIndex), filterMapLastBlockKey(afterLastMapIndex)); err != nil {
+func DeleteFilterMapLastBlocks(db ethdb.KeyValueRangeDeleter, maps common.Range[uint32]) {
+ if err := db.DeleteRange(filterMapLastBlockKey(maps.First()), filterMapLastBlockKey(maps.AfterLast())); err != nil {
log.Crit("Failed to delete range of filter map last block pointers", "err", err)
}
}
@@ -433,8 +433,8 @@ func DeleteBlockLvPointer(db ethdb.KeyValueWriter, blockNumber uint64) {
}
}
-func DeleteBlockLvPointers(db ethdb.KeyValueRangeDeleter, firstBlockNumber, afterLastBlockNumber uint64) {
- if err := db.DeleteRange(filterMapBlockLVKey(firstBlockNumber), filterMapBlockLVKey(afterLastBlockNumber)); err != nil {
+func DeleteBlockLvPointers(db ethdb.KeyValueRangeDeleter, blocks common.Range[uint64]) {
+ if err := db.DeleteRange(filterMapBlockLVKey(blocks.First()), filterMapBlockLVKey(blocks.AfterLast())); err != nil {
log.Crit("Failed to delete range of block log value pointers", "err", err)
}
}
@@ -442,10 +442,11 @@ func DeleteBlockLvPointers(db ethdb.KeyValueRangeDeleter, firstBlockNumber, afte
// FilterMapsRange is a storage representation of the block range covered by the
// filter maps structure and the corresponting log value index range.
type FilterMapsRange struct {
- HeadBlockIndexed bool
- HeadBlockDelimiter uint64
- FirstIndexedBlock, AfterLastIndexedBlock uint64
- FirstRenderedMap, AfterLastRenderedMap, TailPartialEpoch uint32
+ HeadIndexed bool
+ HeadDelimiter uint64
+ BlocksFirst, BlocksAfterLast uint64
+ MapsFirst, MapsAfterLast uint32
+ TailPartialEpoch uint32
}
// ReadFilterMapsRange retrieves the filter maps range data. Note that if the
diff --git a/eth/api_backend.go b/eth/api_backend.go
index 75b039dbe1..b4b63556a9 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
+ "github.com/ethereum/go-ethereum/core/filtermaps"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/txpool"
@@ -413,6 +414,10 @@ func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
}
}
+func (b *EthAPIBackend) NewMatcherBackend() filtermaps.MatcherBackend {
+ return b.eth.filterMaps.NewMatcherBackend()
+}
+
func (b *EthAPIBackend) Engine() consensus.Engine {
return b.eth.engine
}
diff --git a/eth/backend.go b/eth/backend.go
index 1790e413fd..99cb3841c3 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
+ "github.com/ethereum/go-ethereum/core/filtermaps"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state/pruner"
"github.com/ethereum/go-ethereum/core/txpool"
@@ -88,6 +89,9 @@ type Ethereum struct {
bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports
closeBloomHandler chan struct{}
+ filterMaps *filtermaps.FilterMaps
+ closeFilterMaps chan chan struct{}
+
APIBackend *EthAPIBackend
miner *miner.Miner
@@ -244,6 +248,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
return nil, err
}
eth.bloomIndexer.Start(eth.blockchain)
+ fmConfig := filtermaps.Config{History: config.LogHistory, Disabled: config.LogNoHistory, ExportFileName: config.LogExportCheckpoints}
+ chainView := eth.newChainView(eth.blockchain.CurrentBlock())
+ eth.filterMaps = filtermaps.NewFilterMaps(chainDb, chainView, 0, 0, filtermaps.DefaultParams, fmConfig)
+ eth.closeFilterMaps = make(chan chan struct{})
if config.BlobPool.Datadir != "" {
config.BlobPool.Datadir = stack.ResolvePath(config.BlobPool.Datadir)
@@ -398,9 +406,71 @@ func (s *Ethereum) Start() error {
// Start the networking layer
s.handler.Start(s.p2pServer.MaxPeers)
+
+ // start log indexer
+ s.filterMaps.Start()
+ go s.updateFilterMapsHeads()
return nil
}
+func (s *Ethereum) newChainView(head *types.Header) *filtermaps.ChainView {
+ if head == nil {
+ return nil
+ }
+ return filtermaps.NewChainView(s.blockchain, head.Number.Uint64(), head.Hash())
+}
+
+func (s *Ethereum) updateFilterMapsHeads() {
+ headEventCh := make(chan core.ChainEvent, 10)
+ blockProcCh := make(chan bool, 10)
+ sub := s.blockchain.SubscribeChainEvent(headEventCh)
+ sub2 := s.blockchain.SubscribeBlockProcessingEvent(blockProcCh)
+ defer func() {
+ sub.Unsubscribe()
+ sub2.Unsubscribe()
+ for {
+ select {
+ case <-headEventCh:
+ case <-blockProcCh:
+ default:
+ return
+ }
+ }
+ }()
+
+ var head *types.Header
+ setHead := func(newHead *types.Header) {
+ if newHead == nil {
+ return
+ }
+ if head == nil || newHead.Hash() != head.Hash() {
+ head = newHead
+ chainView := s.newChainView(head)
+ historyCutoff := s.blockchain.HistoryPruningCutoff()
+ var finalBlock uint64
+ if fb := s.blockchain.CurrentFinalBlock(); fb != nil {
+ finalBlock = fb.Number.Uint64()
+ }
+ s.filterMaps.SetTarget(chainView, historyCutoff, finalBlock)
+ }
+ }
+ setHead(s.blockchain.CurrentBlock())
+
+ for {
+ select {
+ case ev := <-headEventCh:
+ setHead(ev.Header)
+ case blockProc := <-blockProcCh:
+ s.filterMaps.SetBlockProcessing(blockProc)
+ case <-time.After(time.Second * 10):
+ setHead(s.blockchain.CurrentBlock())
+ case ch := <-s.closeFilterMaps:
+ close(ch)
+ return
+ }
+ }
+}
+
func (s *Ethereum) setupDiscovery() error {
eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode())
@@ -443,6 +513,10 @@ func (s *Ethereum) Stop() error {
// Then stop everything else.
s.bloomIndexer.Close()
close(s.closeBloomHandler)
+ ch := make(chan struct{})
+ s.closeFilterMaps <- ch
+ <-ch
+ s.filterMaps.Stop()
s.txPool.Close()
s.blockchain.Stop()
s.engine.Close()
diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go
index ec6de9e663..365857347c 100644
--- a/eth/ethconfig/config.go
+++ b/eth/ethconfig/config.go
@@ -53,6 +53,7 @@ var Defaults = Config{
NetworkId: 0, // enable auto configuration of networkID == chainID
TxLookupLimit: 2350000,
TransactionHistory: 2350000,
+ LogHistory: 2350000,
StateHistory: params.FullImmutabilityThreshold,
DatabaseCache: 512,
TrieCleanCache: 154,
@@ -97,8 +98,11 @@ type Config struct {
// Deprecated: use 'TransactionHistory' instead.
TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved.
- TransactionHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved.
- StateHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose state histories are reserved.
+ TransactionHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved.
+ LogHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head where a log search index is maintained.
+ LogNoHistory bool `toml:",omitempty"` // No log search index is maintained.
+ LogExportCheckpoints string // export log index checkpoints to file
+ StateHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose state histories are reserved.
// State scheme represents the scheme used to store ethereum states and trie
// nodes on top. It can be 'hash', 'path', or none which means use the scheme
diff --git a/eth/filters/filter.go b/eth/filters/filter.go
index 09ccb93907..cedb5b3519 100644
--- a/eth/filters/filter.go
+++ b/eth/filters/filter.go
@@ -19,12 +19,15 @@ package filters
import (
"context"
"errors"
+ "math"
"math/big"
"slices"
+ "time"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/bloombits"
+ "github.com/ethereum/go-ethereum/core/filtermaps"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
)
@@ -38,36 +41,14 @@ type Filter struct {
block *common.Hash // Block hash if filtering a single block
begin, end int64 // Range interval if filtering multiple blocks
- matcher *bloombits.Matcher
+ rangeLogsTestHook chan rangeLogsTestEvent
}
// NewRangeFilter creates a new filter which uses a bloom filter on blocks to
// figure out whether a particular block is interesting or not.
func (sys *FilterSystem) NewRangeFilter(begin, end int64, addresses []common.Address, topics [][]common.Hash) *Filter {
- // Flatten the address and topic filter clauses into a single bloombits filter
- // system. Since the bloombits are not positional, nil topics are permitted,
- // which get flattened into a nil byte slice.
- var filters [][][]byte
- if len(addresses) > 0 {
- filter := make([][]byte, len(addresses))
- for i, address := range addresses {
- filter[i] = address.Bytes()
- }
- filters = append(filters, filter)
- }
- for _, topicList := range topics {
- filter := make([][]byte, len(topicList))
- for i, topic := range topicList {
- filter[i] = topic.Bytes()
- }
- filters = append(filters, filter)
- }
- size, _ := sys.backend.BloomStatus()
-
// Create a generic filter and convert it into a range filter
filter := newFilter(sys, addresses, topics)
-
- filter.matcher = bloombits.NewMatcher(size, filters)
filter.begin = begin
filter.end = end
@@ -113,161 +94,304 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
return nil, errPendingLogsUnsupported
}
- resolveSpecial := func(number int64) (int64, error) {
- var hdr *types.Header
+ resolveSpecial := func(number int64) (uint64, error) {
switch number {
- case rpc.LatestBlockNumber.Int64(), rpc.PendingBlockNumber.Int64():
- // we should return head here since we've already captured
- // that we need to get the pending logs in the pending boolean above
- hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
- if hdr == nil {
- return 0, errors.New("latest header not found")
- }
+ case rpc.LatestBlockNumber.Int64():
+ // when searching from and/or until the current head, we resolve it
+ // to MaxUint64 which is translated by rangeLogs to the actual head
+ // in each iteration, ensuring that the head block will be searched
+ // even if the chain is updated during search.
+ return math.MaxUint64, nil
case rpc.FinalizedBlockNumber.Int64():
- hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
+ hdr, _ := f.sys.backend.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
if hdr == nil {
return 0, errors.New("finalized header not found")
}
+ return hdr.Number.Uint64(), nil
case rpc.SafeBlockNumber.Int64():
- hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.SafeBlockNumber)
+ hdr, _ := f.sys.backend.HeaderByNumber(ctx, rpc.SafeBlockNumber)
if hdr == nil {
return 0, errors.New("safe header not found")
}
- default:
- return number, nil
+ return hdr.Number.Uint64(), nil
}
- return hdr.Number.Int64(), nil
+ if number < 0 {
+ return 0, errors.New("negative block number")
+ }
+ return uint64(number), nil
}
- var err error
// range query need to resolve the special begin/end block number
- if f.begin, err = resolveSpecial(f.begin); err != nil {
+ begin, err := resolveSpecial(f.begin)
+ if err != nil {
return nil, err
}
- if f.end, err = resolveSpecial(f.end); err != nil {
+ end, err := resolveSpecial(f.end)
+ if err != nil {
return nil, err
}
+ return f.rangeLogs(ctx, begin, end)
+}
- logChan, errChan := f.rangeLogsAsync(ctx)
- var logs []*types.Log
- for {
- select {
- case log := <-logChan:
- logs = append(logs, log)
- case err := <-errChan:
- return logs, err
- }
+const (
+ rangeLogsTestSync = iota
+ rangeLogsTestTrimmed
+ rangeLogsTestIndexed
+ rangeLogsTestUnindexed
+ rangeLogsTestDone
+)
+
+type rangeLogsTestEvent struct {
+ event int
+ begin, end uint64
+}
+
+// searchSession represents a single search session.
+type searchSession struct {
+ ctx context.Context
+ filter *Filter
+ mb filtermaps.MatcherBackend
+ syncRange filtermaps.SyncRange // latest synchronized state with the matcher
+ firstBlock, lastBlock uint64 // specified search range; each can be MaxUint64
+ searchRange common.Range[uint64] // actual search range; end trimmed to latest head
+ matchRange common.Range[uint64] // range in which we have results (subset of searchRange)
+ matches []*types.Log // valid set of matches in matchRange
+ forceUnindexed bool // revert to unindexed search
+}
+
+// newSearchSession returns a new searchSession.
+func newSearchSession(ctx context.Context, filter *Filter, mb filtermaps.MatcherBackend, firstBlock, lastBlock uint64) (*searchSession, error) {
+ s := &searchSession{
+ ctx: ctx,
+ filter: filter,
+ mb: mb,
+ firstBlock: firstBlock,
+ lastBlock: lastBlock,
}
+ // enforce a consistent state before starting the search in order to be able
+ // to determine valid range later
+ if err := s.syncMatcher(0); err != nil {
+ return nil, err
+ }
+ return s, nil
}
-// rangeLogsAsync retrieves block-range logs that match the filter criteria asynchronously,
-// it creates and returns two channels: one for delivering log data, and one for reporting errors.
-func (f *Filter) rangeLogsAsync(ctx context.Context) (chan *types.Log, chan error) {
- var (
- logChan = make(chan *types.Log)
- errChan = make(chan error)
- )
-
- go func() {
- defer func() {
- close(errChan)
- close(logChan)
- }()
-
- // Gather all indexed logs, and finish with non indexed ones
- var (
- end = uint64(f.end)
- size, sections = f.sys.backend.BloomStatus()
- err error
- )
- if indexed := sections * size; indexed > uint64(f.begin) {
- if indexed > end {
- indexed = end + 1
- }
- if err = f.indexedLogs(ctx, indexed-1, logChan); err != nil {
- errChan <- err
- return
- }
- }
-
- if err := f.unindexedLogs(ctx, end, logChan); err != nil {
- errChan <- err
- return
- }
-
- errChan <- nil
- }()
-
- return logChan, errChan
-}
-
-// indexedLogs returns the logs matching the filter criteria based on the bloom
-// bits indexed available locally or via the network.
-func (f *Filter) indexedLogs(ctx context.Context, end uint64, logChan chan *types.Log) error {
- // Create a matcher session and request servicing from the backend
- matches := make(chan uint64, 64)
-
- session, err := f.matcher.Start(ctx, uint64(f.begin), end, matches)
+// syncMatcher performs a synchronization step with the matcher. The resulting
+// syncRange structure holds information about the latest range of indexed blocks
+// and the guaranteed valid blocks whose log index have not been changed since
+// the previous synchronization.
+// The function also performs trimming of the match set in order to always keep
+// it consistent with the synced matcher state.
+// Tail trimming is only performed if the first block of the valid log index range
+// is higher than trimTailThreshold. This is useful because unindexed log search
+// is not affected by the valid tail (on the other hand, valid head is taken into
+// account in order to provide reorg safety, even though the log index is not used).
+// In case of indexed search the tail is only trimmed if the first part of the
+// recently obtained results might be invalid. If guaranteed valid new results
+// have been added at the head of previously validated results then there is no
+// need to discard those even if the index tail have been unindexed since that.
+func (s *searchSession) syncMatcher(trimTailThreshold uint64) error {
+ if s.filter.rangeLogsTestHook != nil && !s.matchRange.IsEmpty() {
+ s.filter.rangeLogsTestHook <- rangeLogsTestEvent{event: rangeLogsTestSync, begin: s.matchRange.First(), end: s.matchRange.Last()}
+ }
+ var err error
+ s.syncRange, err = s.mb.SyncLogIndex(s.ctx)
if err != nil {
return err
}
- defer session.Close()
+ // update actual search range based on current head number
+ first := min(s.firstBlock, s.syncRange.HeadNumber)
+ last := min(s.lastBlock, s.syncRange.HeadNumber)
+ s.searchRange = common.NewRange(first, last+1-first)
+ // discard everything that is not needed or might be invalid
+ trimRange := s.syncRange.ValidBlocks
+ if trimRange.First() <= trimTailThreshold {
+ // everything before this point is already known to be valid; if this is
+ // valid then keep everything before
+ trimRange.SetFirst(0)
+ }
+ trimRange = trimRange.Intersection(s.searchRange)
+ s.trimMatches(trimRange)
+ if s.filter.rangeLogsTestHook != nil {
+ if !s.matchRange.IsEmpty() {
+ s.filter.rangeLogsTestHook <- rangeLogsTestEvent{event: rangeLogsTestTrimmed, begin: s.matchRange.First(), end: s.matchRange.Last()}
+ } else {
+ s.filter.rangeLogsTestHook <- rangeLogsTestEvent{event: rangeLogsTestTrimmed, begin: 0, end: 0}
+ }
+ }
+ return nil
+}
- f.sys.backend.ServiceFilter(ctx, session)
+// trimMatches removes any entries from the current set of matches that is outside
+// the given range.
+func (s *searchSession) trimMatches(trimRange common.Range[uint64]) {
+ s.matchRange = s.matchRange.Intersection(trimRange)
+ if s.matchRange.IsEmpty() {
+ s.matches = nil
+ return
+ }
+ for len(s.matches) > 0 && s.matches[0].BlockNumber < s.matchRange.First() {
+ s.matches = s.matches[1:]
+ }
+ for len(s.matches) > 0 && s.matches[len(s.matches)-1].BlockNumber > s.matchRange.Last() {
+ s.matches = s.matches[:len(s.matches)-1]
+ }
+}
- for {
- select {
- case number, ok := <-matches:
- // Abort if all matches have been fulfilled
- if !ok {
- err := session.Error()
- if err == nil {
- f.begin = int64(end) + 1
- }
- return err
- }
- f.begin = int64(number) + 1
+// searchInRange performs a single range search, either indexed or unindexed.
+func (s *searchSession) searchInRange(r common.Range[uint64], indexed bool) ([]*types.Log, error) {
+ first, last := r.First(), r.Last()
+ if indexed {
+ if s.filter.rangeLogsTestHook != nil {
+ s.filter.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestIndexed, first, last}
+ }
+ results, err := s.filter.indexedLogs(s.ctx, s.mb, first, last)
+ if err != filtermaps.ErrMatchAll {
+ return results, err
+ }
+ // "match all" filters are not supported by filtermaps; fall back to
+ // unindexed search which is the most efficient in this case
+ s.forceUnindexed = true
+ // fall through to unindexed case
+ }
+ if s.filter.rangeLogsTestHook != nil {
+ s.filter.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestUnindexed, first, last}
+ }
+ return s.filter.unindexedLogs(s.ctx, first, last)
+}
- // Retrieve the suggested block and pull any truly matching logs
- header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(number))
- if header == nil || err != nil {
- return err
- }
- found, err := f.checkMatches(ctx, header)
+// doSearchIteration performs a search on a range missing from an incomplete set
+// of results, adds the new section and removes invalidated entries.
+func (s *searchSession) doSearchIteration() error {
+ switch {
+ case s.syncRange.IndexedBlocks.IsEmpty():
+ // indexer is not ready; fallback to completely unindexed search, do not check valid range
+ var err error
+ s.matchRange = s.searchRange
+ s.matches, err = s.searchInRange(s.searchRange, false)
+ return err
+
+ case s.matchRange.IsEmpty():
+ // no results yet; try search in entire range
+ indexedSearchRange := s.searchRange.Intersection(s.syncRange.IndexedBlocks)
+ var err error
+ if s.forceUnindexed = indexedSearchRange.IsEmpty(); !s.forceUnindexed {
+ // indexed search on the intersection of indexed and searched range
+ s.matchRange = indexedSearchRange
+ s.matches, err = s.searchInRange(indexedSearchRange, true)
if err != nil {
return err
}
- for _, log := range found {
- logChan <- log
+ return s.syncMatcher(0) // trim everything that the matcher considers potentially invalid
+ } else {
+ // no intersection of indexed and searched range; unindexed search on the whole searched range
+ s.matchRange = s.searchRange
+ s.matches, err = s.searchInRange(s.searchRange, false)
+ if err != nil {
+ return err
}
+ return s.syncMatcher(math.MaxUint64) // unindexed search is not affected by the tail of valid range
+ }
- case <-ctx.Done():
- return ctx.Err()
+ case !s.matchRange.IsEmpty() && s.matchRange.First() > s.searchRange.First():
+ // we have results but tail section is missing; do unindexed search for
+ // the tail part but still allow indexed search for missing head section
+ tailRange := common.NewRange(s.searchRange.First(), s.matchRange.First()-s.searchRange.First())
+ tailMatches, err := s.searchInRange(tailRange, false)
+ if err != nil {
+ return err
+ }
+ s.matches = append(tailMatches, s.matches...)
+ s.matchRange = tailRange.Union(s.matchRange)
+ return s.syncMatcher(math.MaxUint64) // unindexed search is not affected by the tail of valid range
+
+ case !s.matchRange.IsEmpty() && s.matchRange.First() == s.searchRange.First() && s.searchRange.AfterLast() > s.matchRange.AfterLast():
+ // we have results but head section is missing
+ headRange := common.NewRange(s.matchRange.AfterLast(), s.searchRange.AfterLast()-s.matchRange.AfterLast())
+ if !s.forceUnindexed {
+ indexedHeadRange := headRange.Intersection(s.syncRange.IndexedBlocks)
+ if !indexedHeadRange.IsEmpty() && indexedHeadRange.First() == headRange.First() {
+ // indexed head range search is possible
+ headRange = indexedHeadRange
+ } else {
+ s.forceUnindexed = true
+ }
+ }
+ headMatches, err := s.searchInRange(headRange, !s.forceUnindexed)
+ if err != nil {
+ return err
+ }
+ s.matches = append(s.matches, headMatches...)
+ s.matchRange = s.matchRange.Union(headRange)
+ if s.forceUnindexed {
+ return s.syncMatcher(math.MaxUint64) // unindexed search is not affected by the tail of valid range
+ } else {
+ return s.syncMatcher(headRange.First()) // trim if the tail of latest head search results might be invalid
+ }
+
+ default:
+ panic("invalid search session state")
+ }
+}
+
+func (f *Filter) rangeLogs(ctx context.Context, firstBlock, lastBlock uint64) ([]*types.Log, error) {
+ if f.rangeLogsTestHook != nil {
+ defer func() {
+ f.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestDone, 0, 0}
+ close(f.rangeLogsTestHook)
+ }()
+ }
+
+ if firstBlock > lastBlock {
+ return nil, nil
+ }
+ mb := f.sys.backend.NewMatcherBackend()
+ defer mb.Close()
+
+ session, err := newSearchSession(ctx, f, mb, firstBlock, lastBlock)
+ if err != nil {
+ return nil, err
+ }
+ for session.searchRange != session.matchRange {
+ if err := session.doSearchIteration(); err != nil {
+ return session.matches, err
}
}
+ return session.matches, nil
+}
+
+func (f *Filter) indexedLogs(ctx context.Context, mb filtermaps.MatcherBackend, begin, end uint64) ([]*types.Log, error) {
+ start := time.Now()
+ potentialMatches, err := filtermaps.GetPotentialMatches(ctx, mb, begin, end, f.addresses, f.topics)
+ matches := filterLogs(potentialMatches, nil, nil, f.addresses, f.topics)
+ log.Trace("Performed indexed log search", "begin", begin, "end", end, "true matches", len(matches), "false positives", len(potentialMatches)-len(matches), "elapsed", common.PrettyDuration(time.Since(start)))
+ return matches, err
}
// unindexedLogs returns the logs matching the filter criteria based on raw block
// iteration and bloom matching.
-func (f *Filter) unindexedLogs(ctx context.Context, end uint64, logChan chan *types.Log) error {
- for ; f.begin <= int64(end); f.begin++ {
- header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin))
+func (f *Filter) unindexedLogs(ctx context.Context, begin, end uint64) ([]*types.Log, error) {
+ start := time.Now()
+ log.Warn("Performing unindexed log search", "begin", begin, "end", end)
+ var matches []*types.Log
+ for blockNumber := begin; blockNumber <= end; blockNumber++ {
+ select {
+ case <-ctx.Done():
+ return matches, ctx.Err()
+ default:
+ }
+ header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(blockNumber))
if header == nil || err != nil {
- return err
+ return matches, err
}
found, err := f.blockLogs(ctx, header)
if err != nil {
- return err
- }
- for _, log := range found {
- select {
- case logChan <- log:
- case <-ctx.Done():
- return ctx.Err()
- }
+ return matches, err
}
+ matches = append(matches, found...)
}
- return nil
+ log.Trace("Performed unindexed log search", "begin", begin, "end", end, "matches", len(matches), "elapsed", common.PrettyDuration(time.Since(start)))
+ return matches, nil
}
// blockLogs returns the logs matching the filter criteria within a single block.
diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go
index 86012b3f9a..7531a1ecfc 100644
--- a/eth/filters/filter_system.go
+++ b/eth/filters/filter_system.go
@@ -29,7 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/lru"
"github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/bloombits"
+ "github.com/ethereum/go-ethereum/core/filtermaps"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
@@ -69,8 +69,7 @@ type Backend interface {
SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription
- BloomStatus() (uint64, uint64)
- ServiceFilter(ctx context.Context, session *bloombits.MatcherSession)
+ NewMatcherBackend() filtermaps.MatcherBackend
}
// FilterSystem holds resources shared by all filters.
diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go
index aec5ee4166..c35d823f5a 100644
--- a/eth/filters/filter_system_test.go
+++ b/eth/filters/filter_system_test.go
@@ -20,7 +20,6 @@ import (
"context"
"errors"
"math/big"
- "math/rand"
"reflect"
"runtime"
"testing"
@@ -29,7 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/bloombits"
+ "github.com/ethereum/go-ethereum/core/filtermaps"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
@@ -41,7 +40,7 @@ import (
type testBackend struct {
db ethdb.Database
- sections uint64
+ fm *filtermaps.FilterMaps
txFeed event.Feed
logsFeed event.Feed
rmLogsFeed event.Feed
@@ -59,10 +58,28 @@ func (b *testBackend) CurrentHeader() *types.Header {
return hdr
}
+func (b *testBackend) CurrentBlock() *types.Header {
+ return b.CurrentHeader()
+}
+
func (b *testBackend) ChainDb() ethdb.Database {
return b.db
}
+func (b *testBackend) GetCanonicalHash(number uint64) common.Hash {
+ return rawdb.ReadCanonicalHash(b.db, number)
+}
+
+func (b *testBackend) GetHeader(hash common.Hash, number uint64) *types.Header {
+ hdr, _ := b.HeaderByHash(context.Background(), hash)
+ return hdr
+}
+
+func (b *testBackend) GetReceiptsByHash(hash common.Hash) types.Receipts {
+ r, _ := b.GetReceipts(context.Background(), hash)
+ return r
+}
+
func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) {
var (
hash common.Hash
@@ -137,35 +154,26 @@ func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subsc
return b.chainFeed.Subscribe(ch)
}
-func (b *testBackend) BloomStatus() (uint64, uint64) {
- return params.BloomBitsBlocks, b.sections
+func (b *testBackend) NewMatcherBackend() filtermaps.MatcherBackend {
+ return b.fm.NewMatcherBackend()
}
-func (b *testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
- requests := make(chan chan *bloombits.Retrieval)
+func (b *testBackend) startFilterMaps(history uint64, disabled bool, params filtermaps.Params) {
+ head := b.CurrentBlock()
+ chainView := filtermaps.NewChainView(b, head.Number.Uint64(), head.Hash())
+ config := filtermaps.Config{
+ History: history,
+ Disabled: disabled,
+ ExportFileName: "",
+ }
+ b.fm = filtermaps.NewFilterMaps(b.db, chainView, 0, 0, params, config)
+ b.fm.Start()
+ b.fm.WaitIdle()
+}
- go session.Multiplex(16, 0, requests)
- go func() {
- for {
- // Wait for a service request or a shutdown
- select {
- case <-ctx.Done():
- return
-
- case request := <-requests:
- task := <-request
-
- task.Bitsets = make([][]byte, len(task.Sections))
- for i, section := range task.Sections {
- if rand.Int()%4 != 0 { // Handle occasional missing deliveries
- head := rawdb.ReadCanonicalHash(b.db, (section+1)*params.BloomBitsBlocks-1)
- task.Bitsets[i], _ = rawdb.ReadBloomBits(b.db, task.Bit, section, head)
- }
- }
- request <- task
- }
- }
- }()
+func (b *testBackend) stopFilterMaps() {
+ b.fm.Stop()
+ b.fm = nil
}
func (b *testBackend) setPending(block *types.Block, receipts types.Receipts) {
@@ -173,7 +181,7 @@ func (b *testBackend) setPending(block *types.Block, receipts types.Receipts) {
b.pendingReceipts = receipts
}
-func newTestFilterSystem(t testing.TB, db ethdb.Database, cfg Config) (*testBackend, *FilterSystem) {
+func newTestFilterSystem(db ethdb.Database, cfg Config) (*testBackend, *FilterSystem) {
backend := &testBackend{db: db}
sys := NewFilterSystem(backend, cfg)
return backend, sys
@@ -189,7 +197,7 @@ func TestBlockSubscription(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
- backend, sys = newTestFilterSystem(t, db, Config{})
+ backend, sys = newTestFilterSystem(db, Config{})
api = NewFilterAPI(sys)
genesis = &core.Genesis{
Config: params.TestChainConfig,
@@ -244,7 +252,7 @@ func TestPendingTxFilter(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
- backend, sys = newTestFilterSystem(t, db, Config{})
+ backend, sys = newTestFilterSystem(db, Config{})
api = NewFilterAPI(sys)
transactions = []*types.Transaction{
@@ -300,7 +308,7 @@ func TestPendingTxFilterFullTx(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
- backend, sys = newTestFilterSystem(t, db, Config{})
+ backend, sys = newTestFilterSystem(db, Config{})
api = NewFilterAPI(sys)
transactions = []*types.Transaction{
@@ -356,7 +364,7 @@ func TestPendingTxFilterFullTx(t *testing.T) {
func TestLogFilterCreation(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
- _, sys = newTestFilterSystem(t, db, Config{})
+ _, sys = newTestFilterSystem(db, Config{})
api = NewFilterAPI(sys)
testCases = []struct {
@@ -403,7 +411,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
- _, sys = newTestFilterSystem(t, db, Config{})
+ _, sys = newTestFilterSystem(db, Config{})
api = NewFilterAPI(sys)
)
@@ -429,7 +437,7 @@ func TestInvalidGetLogsRequest(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
- _, sys = newTestFilterSystem(t, db, Config{})
+ _, sys = newTestFilterSystem(db, Config{})
api = NewFilterAPI(sys)
blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111")
)
@@ -455,7 +463,7 @@ func TestInvalidGetRangeLogsRequest(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
- _, sys = newTestFilterSystem(t, db, Config{})
+ _, sys = newTestFilterSystem(db, Config{})
api = NewFilterAPI(sys)
)
@@ -470,7 +478,7 @@ func TestLogFilter(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
- backend, sys = newTestFilterSystem(t, db, Config{})
+ backend, sys = newTestFilterSystem(db, Config{})
api = NewFilterAPI(sys)
firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111")
@@ -575,7 +583,7 @@ func TestPendingTxFilterDeadlock(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
- backend, sys = newTestFilterSystem(t, db, Config{Timeout: timeout})
+ backend, sys = newTestFilterSystem(db, Config{Timeout: timeout})
api = NewFilterAPI(sys)
done = make(chan struct{})
)
@@ -599,7 +607,7 @@ func TestPendingTxFilterDeadlock(t *testing.T) {
// Create a bunch of filters that will
// timeout either in 100ms or 200ms
subs := make([]*Subscription, 20)
- for i := 0; i < len(subs); i++ {
+ for i := range subs {
fid := api.NewPendingTransactionFilter(nil)
api.filtersMu.Lock()
f, ok := api.filters[fid]
diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go
index e2790d91eb..4026c03e89 100644
--- a/eth/filters/filter_test.go
+++ b/eth/filters/filter_test.go
@@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/filtermaps"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
@@ -46,15 +47,27 @@ func makeReceipt(addr common.Address) *types.Receipt {
return receipt
}
-func BenchmarkFilters(b *testing.B) {
+func BenchmarkFiltersIndexed(b *testing.B) {
+ benchmarkFilters(b, 0, false)
+}
+
+func BenchmarkFiltersHalfIndexed(b *testing.B) {
+ benchmarkFilters(b, 50000, false)
+}
+
+func BenchmarkFiltersUnindexed(b *testing.B) {
+ benchmarkFilters(b, 0, true)
+}
+
+func benchmarkFilters(b *testing.B, history uint64, noHistory bool) {
var (
- db = rawdb.NewMemoryDatabase()
- _, sys = newTestFilterSystem(b, db, Config{})
- key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
- addr1 = crypto.PubkeyToAddress(key1.PublicKey)
- addr2 = common.BytesToAddress([]byte("jeff"))
- addr3 = common.BytesToAddress([]byte("ethereum"))
- addr4 = common.BytesToAddress([]byte("random addresses please"))
+ db = rawdb.NewMemoryDatabase()
+ backend, sys = newTestFilterSystem(db, Config{})
+ key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ addr1 = crypto.PubkeyToAddress(key1.PublicKey)
+ addr2 = common.BytesToAddress([]byte("jeff"))
+ addr3 = common.BytesToAddress([]byte("ethereum"))
+ addr4 = common.BytesToAddress([]byte("random addresses please"))
gspec = &core.Genesis{
Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}},
@@ -94,9 +107,12 @@ func BenchmarkFilters(b *testing.B) {
rawdb.WriteHeadBlockHash(db, block.Hash())
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i])
}
+ backend.startFilterMaps(history, noHistory, filtermaps.DefaultParams)
+ defer backend.stopFilterMaps()
+
b.ResetTimer()
- filter := sys.NewRangeFilter(0, -1, []common.Address{addr1, addr2, addr3, addr4}, nil)
+ filter := sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{addr1, addr2, addr3, addr4}, nil)
for i := 0; i < b.N; i++ {
filter.begin = 0
@@ -107,10 +123,22 @@ func BenchmarkFilters(b *testing.B) {
}
}
-func TestFilters(t *testing.T) {
+func TestFiltersIndexed(t *testing.T) {
+ testFilters(t, 0, false)
+}
+
+func TestFiltersHalfIndexed(t *testing.T) {
+ testFilters(t, 500, false)
+}
+
+func TestFiltersUnindexed(t *testing.T) {
+ testFilters(t, 0, true)
+}
+
+func testFilters(t *testing.T, history uint64, noHistory bool) {
var (
db = rawdb.NewMemoryDatabase()
- backend, sys = newTestFilterSystem(t, db, Config{})
+ backend, sys = newTestFilterSystem(db, Config{})
// Sender account
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr = crypto.PubkeyToAddress(key1.PublicKey)
@@ -279,6 +307,9 @@ func TestFilters(t *testing.T) {
})
backend.setPending(pchain[0], preceipts[0])
+ backend.startFilterMaps(history, noHistory, filtermaps.DefaultParams)
+ defer backend.stopFilterMaps()
+
for i, tc := range []struct {
f *Filter
want string
@@ -387,3 +418,146 @@ func TestFilters(t *testing.T) {
}
})
}
+
+func TestRangeLogs(t *testing.T) {
+ var (
+ db = rawdb.NewMemoryDatabase()
+ backend, sys = newTestFilterSystem(db, Config{})
+ gspec = &core.Genesis{
+ Config: params.TestChainConfig,
+ Alloc: types.GenesisAlloc{},
+ BaseFee: big.NewInt(params.InitialBaseFee),
+ }
+ )
+ _, err := gspec.Commit(db, triedb.NewDatabase(db, nil))
+ if err != nil {
+ t.Fatal(err)
+ }
+ chain, _ := core.GenerateChain(gspec.Config, gspec.ToBlock(), ethash.NewFaker(), db, 1000, func(i int, gen *core.BlockGen) {})
+ var l uint64
+ bc, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, &l)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = bc.InsertChain(chain[:600])
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ backend.startFilterMaps(200, false, filtermaps.RangeTestParams)
+ defer backend.stopFilterMaps()
+
+ var (
+ testCase, event int
+ filter *Filter
+ addresses = []common.Address{{}}
+ )
+
+ expEvent := func(exp rangeLogsTestEvent) {
+ event++
+ ev := <-filter.rangeLogsTestHook
+ if ev != exp {
+ t.Fatalf("Test case #%d: wrong test event #%d received (got %v, expected %v)", testCase, event, ev, exp)
+ }
+ }
+
+ newFilter := func(begin, end int64) {
+ testCase++
+ event = 0
+ filter = sys.NewRangeFilter(begin, end, addresses, nil)
+ filter.rangeLogsTestHook = make(chan rangeLogsTestEvent)
+ go func(filter *Filter) {
+ filter.Logs(context.Background())
+ // ensure that filter will not be blocked if we exit early
+ for range filter.rangeLogsTestHook {
+ }
+ }(filter)
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 0, 0})
+ }
+
+ updateHead := func() {
+ head := bc.CurrentBlock()
+ backend.fm.SetTarget(filtermaps.NewChainView(backend, head.Number.Uint64(), head.Hash()), 0, 0)
+ backend.fm.WaitIdle()
+ }
+
+ // test case #1
+ newFilter(300, 500)
+ expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 401, 500})
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 401, 500})
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 401, 500})
+ expEvent(rangeLogsTestEvent{rangeLogsTestUnindexed, 300, 400})
+ if _, err := bc.InsertChain(chain[600:700]); err != nil {
+ t.Fatal(err)
+ }
+ updateHead()
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 300, 500})
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 300, 500}) // unindexed search is not affected by trimmed tail
+ expEvent(rangeLogsTestEvent{rangeLogsTestDone, 0, 0})
+
+ // test case #2
+ newFilter(400, int64(rpc.LatestBlockNumber))
+ expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 501, 700})
+ if _, err := bc.InsertChain(chain[700:800]); err != nil {
+ t.Fatal(err)
+ }
+ updateHead()
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 501, 700})
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 601, 698})
+ expEvent(rangeLogsTestEvent{rangeLogsTestUnindexed, 400, 600})
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 698})
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 400, 698})
+ expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 699, 800})
+ if err := bc.SetHead(750); err != nil {
+ t.Fatal(err)
+ }
+ updateHead()
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 800})
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 400, 748})
+ expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 749, 750})
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 750})
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 400, 750})
+ expEvent(rangeLogsTestEvent{rangeLogsTestDone, 0, 0})
+
+ // test case #3
+ newFilter(int64(rpc.LatestBlockNumber), int64(rpc.LatestBlockNumber))
+ expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 750, 750})
+ if err := bc.SetHead(740); err != nil {
+ t.Fatal(err)
+ }
+ updateHead()
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 750, 750})
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 0, 0})
+ expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 740, 740})
+ if _, err := bc.InsertChain(chain[740:750]); err != nil {
+ t.Fatal(err)
+ }
+ updateHead()
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 740, 740})
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 0, 0})
+ expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 750, 750})
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 750, 750})
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 750, 750})
+ expEvent(rangeLogsTestEvent{rangeLogsTestDone, 0, 0})
+
+ // test case #4
+ newFilter(400, int64(rpc.LatestBlockNumber))
+ expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 551, 750})
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 551, 750})
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 551, 750})
+ expEvent(rangeLogsTestEvent{rangeLogsTestUnindexed, 400, 550})
+ if _, err := bc.InsertChain(chain[750:1000]); err != nil {
+ t.Fatal(err)
+ }
+ updateHead()
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 750})
+ // indexed range affected by tail pruning so we have to discard the entire
+ // match set
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 0, 0})
+ expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 801, 1000})
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 801, 1000})
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 801, 1000})
+ expEvent(rangeLogsTestEvent{rangeLogsTestUnindexed, 400, 800})
+ expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 1000})
+ expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 400, 1000})
+}
diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go
index d70cb90ec9..88ff7b8af3 100644
--- a/internal/ethapi/api_test.go
+++ b/internal/ethapi/api_test.go
@@ -46,7 +46,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/beacon"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/bloombits"
+ "github.com/ethereum/go-ethereum/core/filtermaps"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
@@ -615,11 +615,9 @@ func (b testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent)
func (b testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
panic("implement me")
}
-func (b testBackend) BloomStatus() (uint64, uint64) { panic("implement me") }
-func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
+func (b testBackend) NewMatcherBackend() filtermaps.MatcherBackend {
panic("implement me")
}
-
func TestEstimateGas(t *testing.T) {
t.Parallel()
// Initialize test accounts
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index 3d8f7aa700..9e2ea2c876 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -27,7 +27,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/bloombits"
+ "github.com/ethereum/go-ethereum/core/filtermaps"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
@@ -93,8 +93,8 @@ type Backend interface {
GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error)
SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription
- BloomStatus() (uint64, uint64)
- ServiceFilter(ctx context.Context, session *bloombits.MatcherSession)
+
+ NewMatcherBackend() filtermaps.MatcherBackend
}
func GetAPIs(apiBackend Backend) []rpc.API {
diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go
index e017804861..a5fd9bb0d4 100644
--- a/internal/ethapi/transaction_args_test.go
+++ b/internal/ethapi/transaction_args_test.go
@@ -30,7 +30,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/bloombits"
+ "github.com/ethereum/go-ethereum/core/filtermaps"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
@@ -393,12 +393,12 @@ func (b *backendMock) TxPoolContent() (map[common.Address][]*types.Transaction,
func (b *backendMock) TxPoolContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) {
return nil, nil
}
-func (b *backendMock) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription { return nil }
-func (b *backendMock) BloomStatus() (uint64, uint64) { return 0, 0 }
-func (b *backendMock) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {}
-func (b *backendMock) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { return nil }
+func (b *backendMock) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription { return nil }
+func (b *backendMock) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { return nil }
func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
return nil
}
func (b *backendMock) Engine() consensus.Engine { return nil }
+
+func (b *backendMock) NewMatcherBackend() filtermaps.MatcherBackend { return nil }