mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 07:37:20 +00:00
eth/filters: implement log filter using new log index (#31080)
This PR is #2 of a 3-part series that implements the new log index intended to replace core/bloombits. Based on https://github.com/ethereum/go-ethereum/pull/31079 Replaces https://github.com/ethereum/go-ethereum/pull/30370 This part replaces the old bloombits based log search logic in `eth/filters` to use the new `core/filtermaps` logic. FilterMaps data structure explanation: https://gist.github.com/zsfelfoldi/a60795f9da7ae6422f28c7a34e02a07e Log index generator code overview: https://gist.github.com/zsfelfoldi/97105dff0b1a4f5ed557924a24b9b9e7 Search pattern matcher code overview: https://gist.github.com/zsfelfoldi/5981735641c956afb18065e84f8aff34 Note that the possibility of a tree hashing scheme and remote proof protocol are mentioned in the documents above but they are not exactly specified yet. These specs are WIP and will be finalized after the local log indexer/filter code is finalized and merged. --------- Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
parent
0f06e35115
commit
d85f796356
25 changed files with 1593 additions and 1014 deletions
|
|
@ -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: `
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
115
common/range.go
Normal file
115
common/range.go
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
common/range_test.go
Normal file
36
common/range_test.go
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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}
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -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.logMapsPerEpoch, 0)
|
||||
}
|
||||
f.setRange(batch, f.targetView, fmr)
|
||||
return batch.Write()
|
||||
|
|
@ -386,13 +379,13 @@ func (f *FilterMaps) setRange(batch ethdb.KeyValueWriter, newView *ChainView, ne
|
|||
f.updateMatchersValidRange()
|
||||
if newRange.initialized {
|
||||
rs := rawdb.FilterMapsRange{
|
||||
HeadBlockIndexed: newRange.headBlockIndexed,
|
||||
HeadBlockDelimiter: newRange.headBlockDelimiter,
|
||||
FirstIndexedBlock: newRange.firstIndexedBlock,
|
||||
AfterLastIndexedBlock: newRange.afterLastIndexedBlock,
|
||||
FirstRenderedMap: newRange.firstRenderedMap,
|
||||
AfterLastRenderedMap: newRange.afterLastRenderedMap,
|
||||
TailPartialEpoch: newRange.tailPartialEpoch,
|
||||
HeadIndexed: newRange.headIndexed,
|
||||
HeadDelimiter: newRange.headDelimiter,
|
||||
BlocksFirst: newRange.blocks.First(),
|
||||
BlocksAfterLast: newRange.blocks.AfterLast(),
|
||||
MapsFirst: newRange.maps.First(),
|
||||
MapsAfterLast: newRange.maps.AfterLast(),
|
||||
TailPartialEpoch: newRange.tailPartialEpoch,
|
||||
}
|
||||
rawdb.WriteFilterMapsRange(batch, rs)
|
||||
} else {
|
||||
|
|
@ -410,7 +403,7 @@ func (f *FilterMaps) setRange(batch ethdb.KeyValueWriter, newView *ChainView, ne
|
|||
// called from outside the indexerLoop goroutine.
|
||||
func (f *FilterMaps) getLogByLvIndex(lvIndex uint64) (*types.Log, error) {
|
||||
mapIndex := uint32(lvIndex >> 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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<<f.logMapsPerEpoch - 1)
|
||||
if err != nil {
|
||||
log.Error("Could not get last block of previous epoch", "epoch", epoch-1, "error", err)
|
||||
return epoch >= firstEpoch
|
||||
}
|
||||
if f.historyCutoff > lastBlockOfPrevEpoch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
tailLvIndex, err := f.getBlockLvPointer(tailTarget)
|
||||
lastBlockOfEpoch, _, err := f.getLastBlockOfMap((epoch+1)<<f.logMapsPerEpoch - 1)
|
||||
if err != nil {
|
||||
log.Error("Could not get log value index of tail block", "error", err)
|
||||
return true
|
||||
log.Error("Could not get last block of epoch", "epoch", epoch, "error", err)
|
||||
return epoch >= 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<<params.logMapsPerEpoch, (epochIndex+1)<<params.logMapsPerEpoch-1
|
||||
if fm < firstMap {
|
||||
fm = firstMap
|
||||
}
|
||||
if lm > 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.params.logMapsPerEpoch, (epochIndex+1)<<m.params.logMapsPerEpoch-1
|
||||
if fm < m.firstMap {
|
||||
fm = m.firstMap
|
||||
}
|
||||
if lm > 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)<<m.params.logValuesPerMap)+m.offset) {
|
||||
return false
|
||||
}
|
||||
if nextNext := m.nextResults[mapIndex+1]; nextNext == nil ||
|
||||
(len(nextNext) > 0 && nextNext[0] < (uint64(mapIndex+1)<<m.params.logValuesPerMap)+m.offset) {
|
||||
if next := m.nextResults[mapIndex]; next == nil || len(next) > 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)<<m.params.logValuesPerMap)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if _, ok := m.needMatched[mapIndex]; ok {
|
||||
if base := m.baseResults[mapIndex]; base == nil ||
|
||||
(len(base) > 0 && base[0]+m.offset < (uint64(mapIndex+1)<<m.params.logValuesPerMap)) {
|
||||
if base := m.baseResults[mapIndex]; base == nil || len(base) > 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)<<params.logValuesPerMap+offset {
|
||||
start++
|
||||
if baseRes == nil || len(nextRes) == 0 {
|
||||
// if baseRes is a wild card or nextRes is empty then the sequence matcher
|
||||
// result is the items of nextRes with a negative offset applied.
|
||||
result := make(potentialMatches, 0, len(nextRes))
|
||||
min := (uint64(mapIndex) << params.logValuesPerMap) + offset
|
||||
for _, v := range nextRes {
|
||||
if v >= 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)<<params.logValuesPerMap+offset {
|
||||
stop++
|
||||
}
|
||||
nextNextRes = nextNextRes[:stop]
|
||||
// iterate through baseRes and nextRes in parallel and collect matching results.
|
||||
maxLen := len(baseRes)
|
||||
if l := len(nextRes); l < maxLen {
|
||||
maxLen = l
|
||||
}
|
||||
maxLen := len(nextRes) + len(nextNextRes)
|
||||
if maxLen == 0 {
|
||||
return nextRes
|
||||
}
|
||||
if len(baseRes) < maxLen {
|
||||
maxLen = len(baseRes)
|
||||
}
|
||||
// iterate through baseRes, nextRes and nextNextRes and collect matching results.
|
||||
matchedRes := make(potentialMatches, 0, maxLen)
|
||||
for _, nextRes := range []potentialMatches{nextRes, nextNextRes} {
|
||||
if baseRes != nil {
|
||||
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 {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
Loading…
Reference in a new issue