From 7ecb5785641385ca24dc6ab71c792e16d23afd85 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 21 Mar 2023 09:04:26 +0100 Subject: [PATCH 001/988] params: begin v1.11.6 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 2ac4a554b1..7df3a82b3d 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 5 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 6 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 2ed8013f08757a914c04e3fe9ae7c5023609d07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 21 Mar 2023 11:52:29 +0200 Subject: [PATCH 002/988] build: allow building nightly archives via cron jobs (#26938) --- build/ci.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build/ci.go b/build/ci.go index 49926621bd..3e145b20b0 100644 --- a/build/ci.go +++ b/build/ci.go @@ -465,10 +465,6 @@ func maybeSkipArchive(env build.Environment) { log.Printf("skipping archive creation because this is a PR build") os.Exit(0) } - if env.IsCronJob { - log.Printf("skipping archive creation because this is a cron job") - os.Exit(0) - } if env.Branch != "master" && !strings.HasPrefix(env.Tag, "v1.") { log.Printf("skipping archive creation because branch %q, tag %q is not on the inclusion list", env.Branch, env.Tag) os.Exit(0) From 8a9a73c99b292bfcb832342877be48856397ee2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 21 Mar 2023 12:01:43 +0200 Subject: [PATCH 003/988] log: add special casing of uint256 into the logger (#26936) --- go.mod | 2 +- go.sum | 4 ++++ log/format.go | 42 +++++++++++++++++++++++++++++++++++++++++- log/format_test.go | 20 ++++++++++++++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 21325d5669..26519b8048 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ require ( github.com/graph-gophers/graphql-go v1.3.0 github.com/hashicorp/go-bexpr v0.1.10 github.com/holiman/bloomfilter/v2 v2.0.3 - github.com/holiman/uint256 v1.2.0 + github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c github.com/huin/goupnp v1.0.3 github.com/influxdata/influxdb v1.8.3 github.com/influxdata/influxdb-client-go/v2 v2.4.0 diff --git a/go.sum b/go.sum index 51beb15cd2..4491e01891 100644 --- a/go.sum +++ b/go.sum @@ -297,6 +297,10 @@ github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o= +github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8= +github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= diff --git a/log/format.go b/log/format.go index d7e2f820af..b10786efa0 100644 --- a/log/format.go +++ b/log/format.go @@ -12,6 +12,8 @@ import ( "sync/atomic" "time" "unicode/utf8" + + "github.com/holiman/uint256" ) const ( @@ -339,12 +341,20 @@ func formatLogfmtValue(value interface{}, term bool) string { return v.Format(timeFormat) case *big.Int: - // Big ints get consumed by the Stringer clause so we need to handle + // Big ints get consumed by the Stringer clause, so we need to handle // them earlier on. if v == nil { return "" } return formatLogfmtBigInt(v) + + case *uint256.Int: + // Uint256s get consumed by the Stringer clause, so we need to handle + // them earlier on. + if v == nil { + return "" + } + return formatLogfmtUint256(v) } if term { if s, ok := value.(TerminalStringer); ok { @@ -469,6 +479,36 @@ func formatLogfmtBigInt(n *big.Int) string { return string(buf[i+1:]) } +// formatLogfmtUint256 formats n with thousand separators. +func formatLogfmtUint256(n *uint256.Int) string { + if n.IsUint64() { + return FormatLogfmtUint64(n.Uint64()) + } + var ( + text = n.Dec() + buf = make([]byte, len(text)+len(text)/3) + comma = 0 + i = len(buf) - 1 + ) + for j := len(text) - 1; j >= 0; j, i = j-1, i-1 { + c := text[j] + + switch { + case c == '-': + buf[i] = c + case comma == 3: + buf[i] = ',' + i-- + comma = 0 + fallthrough + default: + buf[i] = c + comma++ + } + } + return string(buf[i+1:]) +} + // escapeString checks if the provided string needs escaping/quoting, and // calls strconv.Quote if needed func escapeString(s string) string { diff --git a/log/format_test.go b/log/format_test.go index cfcfe85802..e08c1d1a4a 100644 --- a/log/format_test.go +++ b/log/format_test.go @@ -7,6 +7,8 @@ import ( "math/rand" "strings" "testing" + + "github.com/holiman/uint256" ) func TestPrettyInt64(t *testing.T) { @@ -80,6 +82,24 @@ func TestPrettyBigInt(t *testing.T) { } } +func TestPrettyUint256(t *testing.T) { + tests := []struct { + int string + s string + }{ + {"111222333444555678999", "111,222,333,444,555,678,999"}, + {"11122233344455567899900", "11,122,233,344,455,567,899,900"}, + } + + for _, tt := range tests { + v := new(uint256.Int) + v.SetFromDecimal(tt.int) + if have := formatLogfmtUint256(v); have != tt.s { + t.Errorf("invalid output %s, want %s", have, tt.s) + } + } +} + var sink string func BenchmarkPrettyInt64Logfmt(b *testing.B) { From 905a723fae3df9cc9280e539989db21c1b80d5b6 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 21 Mar 2023 19:10:23 +0800 Subject: [PATCH 004/988] core/rawdb: use atomic int added in go1.19 (#26935) --- core/rawdb/chain_freezer.go | 24 +++++++-------- core/rawdb/chain_iterator.go | 5 +-- core/rawdb/database.go | 7 ++--- core/rawdb/freezer.go | 53 +++++++++++++++----------------- core/rawdb/freezer_batch.go | 5 ++- core/rawdb/freezer_table.go | 53 +++++++++++++++----------------- core/rawdb/freezer_table_test.go | 39 ++++++++++++----------- core/rawdb/freezer_test.go | 4 +-- 8 files changed, 90 insertions(+), 100 deletions(-) diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 167afc3889..22dbda4a21 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -43,10 +43,7 @@ const ( // The background thread will keep moving ancient chain segments from key-value // database to flat files for saving space on live database. type chainFreezer struct { - // WARNING: The `threshold` field is accessed atomically. On 32 bit platforms, only - // 64-bit aligned fields can be atomic. The struct is guaranteed to be so aligned, - // so take advantage of that (https://golang.org/pkg/sync/atomic/#pkg-note-BUG). - threshold uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests) + threshold atomic.Uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests) *Freezer quit chan struct{} @@ -60,12 +57,13 @@ func newChainFreezer(datadir string, namespace string, readonly bool) (*chainFre if err != nil { return nil, err } - return &chainFreezer{ - Freezer: freezer, - threshold: params.FullImmutabilityThreshold, - quit: make(chan struct{}), - trigger: make(chan chan struct{}), - }, nil + cf := chainFreezer{ + Freezer: freezer, + quit: make(chan struct{}), + trigger: make(chan chan struct{}), + } + cf.threshold.Store(params.FullImmutabilityThreshold) + return &cf, nil } // Close closes the chain freezer instance and terminates the background thread. @@ -124,8 +122,8 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { continue } number := ReadHeaderNumber(nfdb, hash) - threshold := atomic.LoadUint64(&f.threshold) - frozen := atomic.LoadUint64(&f.frozen) + threshold := f.threshold.Load() + frozen := f.frozen.Load() switch { case number == nil: log.Error("Current full block number unavailable", "hash", hash) @@ -186,7 +184,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { // Wipe out side chains also and track dangling side chains var dangling []common.Hash - frozen = atomic.LoadUint64(&f.frozen) // Needs reload after during freezeRange + frozen = f.frozen.Load() // Needs reload after during freezeRange for number := first; number < frozen; number++ { // Always keep the genesis block in active database if number != 0 { diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index 102943516e..56bb15b718 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -132,11 +132,12 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool } } // process runs in parallel - nThreadsAlive := int32(threads) + var nThreadsAlive atomic.Int32 + nThreadsAlive.Store(int32(threads)) process := func() { defer func() { // Last processor closes the result channel - if atomic.AddInt32(&nThreadsAlive, -1) == 0 { + if nThreadsAlive.Add(-1) == 0 { close(hashesCh) } }() diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 6c545032f9..b8cc36a811 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -24,7 +24,6 @@ import ( "path" "path/filepath" "strings" - "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -72,9 +71,9 @@ func (frdb *freezerdb) Freeze(threshold uint64) error { } // Set the freezer threshold to a temporary value defer func(old uint64) { - atomic.StoreUint64(&frdb.AncientStore.(*chainFreezer).threshold, old) - }(atomic.LoadUint64(&frdb.AncientStore.(*chainFreezer).threshold)) - atomic.StoreUint64(&frdb.AncientStore.(*chainFreezer).threshold, threshold) + frdb.AncientStore.(*chainFreezer).threshold.Store(old) + }(frdb.AncientStore.(*chainFreezer).threshold.Load()) + frdb.AncientStore.(*chainFreezer).threshold.Store(threshold) // Trigger a freeze cycle and block until it's done trigger := make(chan struct{}, 1) diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 60e2c56e0f..323dc1ddb3 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -62,11 +62,8 @@ const freezerTableSize = 2 * 1000 * 1000 * 1000 // reserving it for go-ethereum. This would also reduce the memory requirements // of Geth, and thus also GC overhead. type Freezer struct { - // WARNING: The `frozen` and `tail` fields are accessed atomically. On 32 bit platforms, only - // 64-bit aligned fields can be atomic. The struct is guaranteed to be so aligned, - // so take advantage of that (https://golang.org/pkg/sync/atomic/#pkg-note-BUG). - frozen uint64 // Number of blocks already frozen - tail uint64 // Number of the first stored item in the freezer + frozen atomic.Uint64 // Number of blocks already frozen + tail atomic.Uint64 // Number of the first stored item in the freezer // This lock synchronizes writers and the truncate operation, as well as // the "atomic" (batched) read operations. @@ -212,12 +209,12 @@ func (f *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][] // Ancients returns the length of the frozen items. func (f *Freezer) Ancients() (uint64, error) { - return atomic.LoadUint64(&f.frozen), nil + return f.frozen.Load(), nil } // Tail returns the number of first stored item in the freezer. func (f *Freezer) Tail() (uint64, error) { - return atomic.LoadUint64(&f.tail), nil + return f.tail.Load(), nil } // AncientSize returns the ancient size of the specified category. @@ -251,7 +248,7 @@ func (f *Freezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize defer f.writeLock.Unlock() // Roll back all tables to the starting position in case of error. - prevItem := atomic.LoadUint64(&f.frozen) + prevItem := f.frozen.Load() defer func() { if err != nil { // The write operation has failed. Go back to the previous item position. @@ -272,7 +269,7 @@ func (f *Freezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize if err != nil { return 0, err } - atomic.StoreUint64(&f.frozen, item) + f.frozen.Store(item) return writeSize, nil } @@ -284,7 +281,7 @@ func (f *Freezer) TruncateHead(items uint64) error { f.writeLock.Lock() defer f.writeLock.Unlock() - if atomic.LoadUint64(&f.frozen) <= items { + if f.frozen.Load() <= items { return nil } for _, table := range f.tables { @@ -292,7 +289,7 @@ func (f *Freezer) TruncateHead(items uint64) error { return err } } - atomic.StoreUint64(&f.frozen, items) + f.frozen.Store(items) return nil } @@ -304,7 +301,7 @@ func (f *Freezer) TruncateTail(tail uint64) error { f.writeLock.Lock() defer f.writeLock.Unlock() - if atomic.LoadUint64(&f.tail) >= tail { + if f.tail.Load() >= tail { return nil } for _, table := range f.tables { @@ -312,7 +309,7 @@ func (f *Freezer) TruncateTail(tail uint64) error { return err } } - atomic.StoreUint64(&f.tail, tail) + f.tail.Store(tail) return nil } @@ -343,22 +340,22 @@ func (f *Freezer) validate() error { ) // Hack to get boundary of any table for kind, table := range f.tables { - head = atomic.LoadUint64(&table.items) - tail = atomic.LoadUint64(&table.itemHidden) + head = table.items.Load() + tail = table.itemHidden.Load() name = kind break } // Now check every table against those boundaries. for kind, table := range f.tables { - if head != atomic.LoadUint64(&table.items) { - return fmt.Errorf("freezer tables %s and %s have differing head: %d != %d", kind, name, atomic.LoadUint64(&table.items), head) + if head != table.items.Load() { + return fmt.Errorf("freezer tables %s and %s have differing head: %d != %d", kind, name, table.items.Load(), head) } - if tail != atomic.LoadUint64(&table.itemHidden) { - return fmt.Errorf("freezer tables %s and %s have differing tail: %d != %d", kind, name, atomic.LoadUint64(&table.itemHidden), tail) + if tail != table.itemHidden.Load() { + return fmt.Errorf("freezer tables %s and %s have differing tail: %d != %d", kind, name, table.itemHidden.Load(), tail) } } - atomic.StoreUint64(&f.frozen, head) - atomic.StoreUint64(&f.tail, tail) + f.frozen.Store(head) + f.tail.Store(tail) return nil } @@ -369,11 +366,11 @@ func (f *Freezer) repair() error { tail = uint64(0) ) for _, table := range f.tables { - items := atomic.LoadUint64(&table.items) + items := table.items.Load() if head > items { head = items } - hidden := atomic.LoadUint64(&table.itemHidden) + hidden := table.itemHidden.Load() if hidden > tail { tail = hidden } @@ -386,8 +383,8 @@ func (f *Freezer) repair() error { return err } } - atomic.StoreUint64(&f.frozen, head) - atomic.StoreUint64(&f.tail, tail) + f.frozen.Store(head) + f.tail.Store(tail) return nil } @@ -413,7 +410,7 @@ func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error { // and that error will be returned. forEach := func(t *freezerTable, offset uint64, fn func(uint64, []byte) error) error { var ( - items = atomic.LoadUint64(&t.items) + items = t.items.Load() batchSize = uint64(1024) maxBytes = uint64(1024 * 1024) ) @@ -436,7 +433,7 @@ func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error { } // TODO(s1na): This is a sanity-check since as of now no process does tail-deletion. But the migration // process assumes no deletion at tail and needs to be modified to account for that. - if table.itemOffset > 0 || table.itemHidden > 0 { + if table.itemOffset.Load() > 0 || table.itemHidden.Load() > 0 { return fmt.Errorf("migration not supported for tail-deleted freezers") } ancientsPath := filepath.Dir(table.index.Name()) @@ -452,7 +449,7 @@ func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error { out []byte start = time.Now() logged = time.Now() - offset = newTable.items + offset = newTable.items.Load() ) if offset > 0 { log.Info("found previous migration attempt", "migrated", offset) diff --git a/core/rawdb/freezer_batch.go b/core/rawdb/freezer_batch.go index 54c98cee08..3cc7d84f4e 100644 --- a/core/rawdb/freezer_batch.go +++ b/core/rawdb/freezer_batch.go @@ -18,7 +18,6 @@ package rawdb import ( "fmt" - "sync/atomic" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/rlp" @@ -107,7 +106,7 @@ func (t *freezerTable) newBatch() *freezerTableBatch { func (batch *freezerTableBatch) reset() { batch.dataBuffer = batch.dataBuffer[:0] batch.indexBuffer = batch.indexBuffer[:0] - batch.curItem = atomic.LoadUint64(&batch.t.items) + batch.curItem = batch.t.items.Load() batch.totalBytes = 0 } @@ -201,7 +200,7 @@ func (batch *freezerTableBatch) commit() error { // Update headBytes of table. batch.t.headBytes += dataSize - atomic.StoreUint64(&batch.t.items, batch.curItem) + batch.t.items.Store(batch.curItem) // Update metrics. batch.t.sizeGauge.Inc(dataSize + indexSize) diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index b111797d52..10dfb90ea7 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -88,18 +88,15 @@ func (i *indexEntry) bounds(end *indexEntry) (startOffset, endOffset, fileId uin // It consists of a data file (snappy encoded arbitrary data blobs) and an indexEntry // file (uncompressed 64 bit indices into the data file). type freezerTable struct { - // WARNING: The `items` field is accessed atomically. On 32 bit platforms, only - // 64-bit aligned fields can be atomic. The struct is guaranteed to be so aligned, - // so take advantage of that (https://golang.org/pkg/sync/atomic/#pkg-note-BUG). - items uint64 // Number of items stored in the table (including items removed from tail) - itemOffset uint64 // Number of items removed from the table + items atomic.Uint64 // Number of items stored in the table (including items removed from tail) + itemOffset atomic.Uint64 // Number of items removed from the table // itemHidden is the number of items marked as deleted. Tail deletion is // only supported at file level which means the actual deletion will be // delayed until the entire data file is marked as deleted. Before that // these items will be hidden to prevent being visited again. The value // should never be lower than itemOffset. - itemHidden uint64 + itemHidden atomic.Uint64 noCompression bool // if true, disables snappy compression. Note: does not work retroactively readonly bool @@ -241,14 +238,14 @@ func (t *freezerTable) repair() error { // which is not enough in theory but enough in practice. // TODO: use uint64 to represent total removed items. t.tailId = firstIndex.filenum - t.itemOffset = uint64(firstIndex.offset) + t.itemOffset.Store(uint64(firstIndex.offset)) // Load metadata from the file - meta, err := loadMetadata(t.meta, t.itemOffset) + meta, err := loadMetadata(t.meta, t.itemOffset.Load()) if err != nil { return err } - t.itemHidden = meta.VirtualTail + t.itemHidden.Store(meta.VirtualTail) // Read the last index, use the default value in case the freezer is empty if offsetsSize == indexEntrySize { @@ -331,7 +328,7 @@ func (t *freezerTable) repair() error { } } // Update the item and byte counters and return - t.items = t.itemOffset + uint64(offsetsSize/indexEntrySize-1) // last indexEntry points to the end of the data file + t.items.Store(t.itemOffset.Load() + uint64(offsetsSize/indexEntrySize-1)) // last indexEntry points to the end of the data file t.headBytes = contentSize t.headId = lastIndex.filenum @@ -346,9 +343,9 @@ func (t *freezerTable) repair() error { return err } if verbose { - t.logger.Info("Chain freezer table opened", "items", t.items, "size", t.headBytes) + t.logger.Info("Chain freezer table opened", "items", t.items.Load(), "size", t.headBytes) } else { - t.logger.Debug("Chain freezer table opened", "items", t.items, "size", common.StorageSize(t.headBytes)) + t.logger.Debug("Chain freezer table opened", "items", t.items.Load(), "size", common.StorageSize(t.headBytes)) } return nil } @@ -382,11 +379,11 @@ func (t *freezerTable) truncateHead(items uint64) error { defer t.lock.Unlock() // Ensure the given truncate target falls in the correct range - existing := atomic.LoadUint64(&t.items) + existing := t.items.Load() if existing <= items { return nil } - if items < atomic.LoadUint64(&t.itemHidden) { + if items < t.itemHidden.Load() { return errors.New("truncation below tail") } // We need to truncate, save the old size for metrics tracking @@ -403,7 +400,7 @@ func (t *freezerTable) truncateHead(items uint64) error { // Truncate the index file first, the tail position is also considered // when calculating the new freezer table length. - length := items - atomic.LoadUint64(&t.itemOffset) + length := items - t.itemOffset.Load() if err := truncateFreezerFile(t.index, int64(length+1)*indexEntrySize); err != nil { return err } @@ -438,7 +435,7 @@ func (t *freezerTable) truncateHead(items uint64) error { } // All data files truncated, set internal counters and return t.headBytes = int64(expected.offset) - atomic.StoreUint64(&t.items, items) + t.items.Store(items) // Retrieve the new size and update the total size counter newSize, err := t.sizeNolock() @@ -455,10 +452,10 @@ func (t *freezerTable) truncateTail(items uint64) error { defer t.lock.Unlock() // Ensure the given truncate target falls in the correct range - if atomic.LoadUint64(&t.itemHidden) >= items { + if t.itemHidden.Load() >= items { return nil } - if atomic.LoadUint64(&t.items) < items { + if t.items.Load() < items { return errors.New("truncation above head") } // Load the new tail index by the given new tail position @@ -466,10 +463,10 @@ func (t *freezerTable) truncateTail(items uint64) error { newTailId uint32 buffer = make([]byte, indexEntrySize) ) - if atomic.LoadUint64(&t.items) == items { + if t.items.Load() == items { newTailId = t.headId } else { - offset := items - atomic.LoadUint64(&t.itemOffset) + offset := items - t.itemOffset.Load() if _, err := t.index.ReadAt(buffer, int64((offset+1)*indexEntrySize)); err != nil { return err } @@ -478,7 +475,7 @@ func (t *freezerTable) truncateTail(items uint64) error { newTailId = newTail.filenum } // Update the virtual tail marker and hidden these entries in table. - atomic.StoreUint64(&t.itemHidden, items) + t.itemHidden.Store(items) if err := writeMetadata(t.meta, newMetadata(items)); err != nil { return err } @@ -501,7 +498,7 @@ func (t *freezerTable) truncateTail(items uint64) error { // Count how many items can be deleted from the file. var ( newDeleted = items - deleted = atomic.LoadUint64(&t.itemOffset) + deleted = t.itemOffset.Load() ) for current := items - 1; current >= deleted; current -= 1 { if _, err := t.index.ReadAt(buffer, int64((current-deleted+1)*indexEntrySize)); err != nil { @@ -541,7 +538,7 @@ func (t *freezerTable) truncateTail(items uint64) error { } // Release any files before the current tail t.tailId = newTailId - atomic.StoreUint64(&t.itemOffset, newDeleted) + t.itemOffset.Store(newDeleted) t.releaseFilesBefore(t.tailId, true) // Retrieve the new size and update the total size counter @@ -654,7 +651,7 @@ func (t *freezerTable) releaseFilesBefore(num uint32, remove bool) { // it will return error. func (t *freezerTable) getIndices(from, count uint64) ([]*indexEntry, error) { // Apply the table-offset - from = from - t.itemOffset + from = from - t.itemOffset.Load() // For reading N items, we need N+1 indices. buffer := make([]byte, (count+1)*indexEntrySize) if _, err := t.index.ReadAt(buffer, int64(from*indexEntrySize)); err != nil { @@ -744,8 +741,8 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i return nil, nil, errClosed } var ( - items = atomic.LoadUint64(&t.items) // the total items(head + 1) - hidden = atomic.LoadUint64(&t.itemHidden) // the number of hidden items + items = t.items.Load() // the total items(head + 1) + hidden = t.itemHidden.Load() // the number of hidden items ) // Ensure the start is written, not deleted from the tail, and that the // caller actually wants something @@ -832,7 +829,7 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i // has returns an indicator whether the specified number data is still accessible // in the freezer table. func (t *freezerTable) has(number uint64) bool { - return atomic.LoadUint64(&t.items) > number && atomic.LoadUint64(&t.itemHidden) <= number + return t.items.Load() > number && t.itemHidden.Load() <= number } // size returns the total data size in the freezer table. @@ -922,7 +919,7 @@ func (t *freezerTable) dumpIndex(w io.Writer, start, stop int64) { return } fmt.Fprintf(w, "Version %d count %d, deleted %d, hidden %d\n", meta.Version, - atomic.LoadUint64(&t.items), atomic.LoadUint64(&t.itemOffset), atomic.LoadUint64(&t.itemHidden)) + t.items.Load(), t.itemOffset.Load(), t.itemHidden.Load()) buf := make([]byte, indexEntrySize) diff --git a/core/rawdb/freezer_table_test.go b/core/rawdb/freezer_table_test.go index 6181d4d72c..5c4cc40edd 100644 --- a/core/rawdb/freezer_table_test.go +++ b/core/rawdb/freezer_table_test.go @@ -24,7 +24,6 @@ import ( "os" "path/filepath" "reflect" - "sync/atomic" "testing" "testing/quick" @@ -191,7 +190,7 @@ func TestFreezerRepairDanglingHeadLarge(t *testing.T) { writeChunks(t, f, 255, 15) // The last item should be there - if _, err = f.Retrieve(f.items - 1); err != nil { + if _, err = f.Retrieve(f.items.Load() - 1); err != nil { t.Fatal(err) } f.Close() @@ -317,7 +316,7 @@ func TestFreezerRepairDanglingIndex(t *testing.T) { writeChunks(t, f, 9, 15) // The last item should be there - if _, err = f.Retrieve(f.items - 1); err != nil { + if _, err = f.Retrieve(f.items.Load() - 1); err != nil { f.Close() t.Fatal(err) } @@ -350,8 +349,8 @@ func TestFreezerRepairDanglingIndex(t *testing.T) { t.Fatal(err) } defer f.Close() - if f.items != 7 { - t.Fatalf("expected %d items, got %d", 7, f.items) + if f.items.Load() != 7 { + t.Fatalf("expected %d items, got %d", 7, f.items.Load()) } if err := assertFileSize(fileToCrop, 15); err != nil { t.Fatal(err) @@ -374,7 +373,7 @@ func TestFreezerTruncate(t *testing.T) { writeChunks(t, f, 30, 15) // The last item should be there - if _, err = f.Retrieve(f.items - 1); err != nil { + if _, err = f.Retrieve(f.items.Load() - 1); err != nil { t.Fatal(err) } f.Close() @@ -388,8 +387,8 @@ func TestFreezerTruncate(t *testing.T) { } defer f.Close() f.truncateHead(10) // 150 bytes - if f.items != 10 { - t.Fatalf("expected %d items, got %d", 10, f.items) + if f.items.Load() != 10 { + t.Fatalf("expected %d items, got %d", 10, f.items.Load()) } // 45, 45, 45, 15 -- bytes should be 15 if f.headBytes != 15 { @@ -444,9 +443,9 @@ func TestFreezerRepairFirstFile(t *testing.T) { if err != nil { t.Fatal(err) } - if f.items != 1 { + if f.items.Load() != 1 { f.Close() - t.Fatalf("expected %d items, got %d", 0, f.items) + t.Fatalf("expected %d items, got %d", 0, f.items.Load()) } // Write 40 bytes @@ -483,7 +482,7 @@ func TestFreezerReadAndTruncate(t *testing.T) { writeChunks(t, f, 30, 15) // The last item should be there - if _, err = f.Retrieve(f.items - 1); err != nil { + if _, err = f.Retrieve(f.items.Load() - 1); err != nil { t.Fatal(err) } f.Close() @@ -495,9 +494,9 @@ func TestFreezerReadAndTruncate(t *testing.T) { if err != nil { t.Fatal(err) } - if f.items != 30 { + if f.items.Load() != 30 { f.Close() - t.Fatalf("expected %d items, got %d", 0, f.items) + t.Fatalf("expected %d items, got %d", 0, f.items.Load()) } for y := byte(0); y < 30; y++ { f.Retrieve(uint64(y)) @@ -1210,13 +1209,13 @@ func runRandTest(rt randTest) bool { rt[i].err = fmt.Errorf("failed to reload table %v", err) } case opCheckAll: - tail := atomic.LoadUint64(&f.itemHidden) - head := atomic.LoadUint64(&f.items) + tail := f.itemHidden.Load() + head := f.items.Load() if tail == head { continue } - got, err := f.RetrieveItems(atomic.LoadUint64(&f.itemHidden), head-tail, 100000) + got, err := f.RetrieveItems(f.itemHidden.Load(), head-tail, 100000) if err != nil { rt[i].err = err } else { @@ -1238,7 +1237,7 @@ func runRandTest(rt randTest) bool { if len(step.items) == 0 { continue } - tail := atomic.LoadUint64(&f.itemHidden) + tail := f.itemHidden.Load() for i := 0; i < len(step.items); i++ { blobs = append(blobs, values[step.items[i]-tail]) } @@ -1254,7 +1253,7 @@ func runRandTest(rt randTest) bool { case opTruncateHead: f.truncateHead(step.target) - length := atomic.LoadUint64(&f.items) - atomic.LoadUint64(&f.itemHidden) + length := f.items.Load() - f.itemHidden.Load() values = values[:length] case opTruncateHeadAll: @@ -1262,10 +1261,10 @@ func runRandTest(rt randTest) bool { values = nil case opTruncateTail: - prev := atomic.LoadUint64(&f.itemHidden) + prev := f.itemHidden.Load() f.truncateTail(step.target) - truncated := atomic.LoadUint64(&f.itemHidden) - prev + truncated := f.itemHidden.Load() - prev values = values[truncated:] case opTruncateTailAll: diff --git a/core/rawdb/freezer_test.go b/core/rawdb/freezer_test.go index 5896e43ce2..630c9029b0 100644 --- a/core/rawdb/freezer_test.go +++ b/core/rawdb/freezer_test.go @@ -267,10 +267,10 @@ func TestFreezerReadonlyValidate(t *testing.T) { bBatch := f.tables["b"].newBatch() require.NoError(t, bBatch.AppendRaw(0, item)) require.NoError(t, bBatch.commit()) - if f.tables["a"].items != 3 { + if f.tables["a"].items.Load() != 3 { t.Fatalf("unexpected number of items in table") } - if f.tables["b"].items != 1 { + if f.tables["b"].items.Load() != 1 { t.Fatalf("unexpected number of items in table") } require.NoError(t, f.Close()) From b3f43c89b3b884d5d0b8e1a239847f54a291a19b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 21 Mar 2023 07:14:47 -0400 Subject: [PATCH 005/988] core/vm: expose jumptable constructors (#26880) When interacting with geth as a library to e.g. produce state tests, it is desirable to obtain the consensus-correct jumptable definition for a given fork. This changes adds accessors so the instructionset can be obtained and characteristics about opcodes can be inspected. --- core/vm/jump_table_export.go | 74 ++++++++++++++++++++++++++++++++++++ params/config.go | 6 +-- 2 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 core/vm/jump_table_export.go diff --git a/core/vm/jump_table_export.go b/core/vm/jump_table_export.go new file mode 100644 index 0000000000..0d61b00ede --- /dev/null +++ b/core/vm/jump_table_export.go @@ -0,0 +1,74 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "errors" + + "github.com/ethereum/go-ethereum/params" +) + +// LookupInstructionSet returns the instructionset for the fork configured by +// the rules. +func LookupInstructionSet(rules params.Rules) (JumpTable, error) { + switch { + case rules.IsPrague: + return newShanghaiInstructionSet(), errors.New("prague-fork not defined yet") + case rules.IsCancun: + return newShanghaiInstructionSet(), errors.New("cancun-fork not defined yet") + case rules.IsShanghai: + return newShanghaiInstructionSet(), nil + case rules.IsMerge: + return newMergeInstructionSet(), nil + case rules.IsLondon: + return newLondonInstructionSet(), nil + case rules.IsBerlin: + return newBerlinInstructionSet(), nil + case rules.IsIstanbul: + return newIstanbulInstructionSet(), nil + case rules.IsConstantinople: + return newConstantinopleInstructionSet(), nil + case rules.IsByzantium: + return newByzantiumInstructionSet(), nil + case rules.IsEIP158: + return newSpuriousDragonInstructionSet(), nil + case rules.IsEIP150: + return newTangerineWhistleInstructionSet(), nil + case rules.IsHomestead: + return newHomesteadInstructionSet(), nil + } + return newFrontierInstructionSet(), nil +} + +// Stack returns the mininum and maximum stack requirements. +func (op *operation) Stack() (int, int) { + return op.minStack, op.maxStack +} + +// HasCost returns true if the opcode has a cost. Opcodes which do _not_ have +// a cost assigned are one of two things: +// - undefined, a.k.a invalid opcodes, +// - the STOP opcode. +// This method can thus be used to check if an opcode is "Invalid (or STOP)". +func (op *operation) HasCost() bool { + // Ideally, we'd check this: + // return op.execute == opUndefined + // However, go-lang does now allow that. So we'll just check some other + // 'indicators' that this is an invalid op. Alas, STOP is impossible to + // filter out + return op.dynamicGas != nil || op.constantGas != 0 +} diff --git a/params/config.go b/params/config.go index e04b16673c..190eb737c4 100644 --- a/params/config.go +++ b/params/config.go @@ -956,7 +956,7 @@ type Rules struct { IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsBerlin, IsLondon bool - IsMerge, IsShanghai, isCancun, isPrague bool + IsMerge, IsShanghai, IsCancun, IsPrague bool } // Rules ensures c's ChainID is not nil. @@ -979,7 +979,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules IsLondon: c.IsLondon(num), IsMerge: isMerge, IsShanghai: c.IsShanghai(timestamp), - isCancun: c.IsCancun(timestamp), - isPrague: c.IsPrague(timestamp), + IsCancun: c.IsCancun(timestamp), + IsPrague: c.IsPrague(timestamp), } } From 20f8eb756bdbfa6dbd94374bbad15883e23ab150 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 22 Mar 2023 18:36:26 +0100 Subject: [PATCH 006/988] eth/catalyst: fix races (#26950) --- eth/catalyst/api_test.go | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index fb6e6935ee..f381222002 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -879,15 +879,10 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { genesis, preMergeBlocks := generateMergeChain(100, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() - - ethservice.BlockChain().Config().TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty()) - - var ( - api = NewConsensusAPI(ethservice) - parent = preMergeBlocks[len(preMergeBlocks)-1] - ) + api := NewConsensusAPI(ethservice) // Test parent already post TTD in FCU + parent := preMergeBlocks[len(preMergeBlocks)-2] fcState := engine.ForkchoiceStateV1{ HeadBlockHash: parent.Hash(), SafeBlockHash: common.Hash{}, @@ -913,6 +908,28 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { t.Fatalf("error preparing payload, err=%v", err) } data := *payload.Resolve().ExecutionPayload + // We need to recompute the blockhash, since the miner computes a wrong (correct) blockhash + txs, _ := decodeTransactions(data.Transactions) + header := &types.Header{ + ParentHash: data.ParentHash, + UncleHash: types.EmptyUncleHash, + Coinbase: data.FeeRecipient, + Root: data.StateRoot, + TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), + ReceiptHash: data.ReceiptsRoot, + Bloom: types.BytesToBloom(data.LogsBloom), + Difficulty: common.Big0, + Number: new(big.Int).SetUint64(data.Number), + GasLimit: data.GasLimit, + GasUsed: data.GasUsed, + Time: data.Timestamp, + BaseFee: data.BaseFeePerGas, + Extra: data.ExtraData, + MixDigest: data.Random, + } + block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */) + data.BlockHash = block.Hash() + // Send the new payload resp2, err := api.NewPayloadV1(data) if err != nil { t.Fatalf("error sending NewPayload, err=%v", err) @@ -1240,9 +1257,10 @@ func TestNilWithdrawals(t *testing.T) { func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { genesis, blocks := generateMergeChain(10, true) - n, ethservice := startEthService(t, genesis, blocks) // enable shanghai on the last block - ethservice.BlockChain().Config().ShanghaiTime = &blocks[len(blocks)-1].Header().Time + time := blocks[len(blocks)-1].Header().Time + 1 + genesis.Config.ShanghaiTime = &time + n, ethservice := startEthService(t, genesis, blocks) var ( parent = ethservice.BlockChain().CurrentBlock() From 7f3fc15a8bea47831c6058047967cabf17ce0fed Mon Sep 17 00:00:00 2001 From: Delweng Date: Thu, 23 Mar 2023 15:34:40 +0800 Subject: [PATCH 007/988] core/rawdb: update freezertable read meter (#26946) The meter for "for measuring the effective amount of data read" within the freezertable was never updated. This change remedies that. --------- Signed-off-by: jsvisa --- core/rawdb/freezer_table.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 10dfb90ea7..928b37d70b 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -823,6 +823,9 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i break } } + + // Update metrics. + t.readMeter.Mark(int64(totalSize)) return output[:outputSize], sizes, nil } From 37ecff0967bec978e0723f4861803943bd6d0e17 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 23 Mar 2023 03:15:40 -0600 Subject: [PATCH 008/988] cmd/evm, tests: record preimages if dump is expected (#26955) With #25287 we made it so that preimages were not recorded by default. This had the side effect that the evm command is no longer able to dump state since it does a preimage lookup to determine the address represented by a key. This change enables the recording of preimages when the dump command is given. --- cmd/evm/runner.go | 8 ++++++-- tests/state_test_util.go | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 3a010da9f2..d6ec8ae752 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -40,6 +40,7 @@ import ( "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie" "github.com/urfave/cli/v2" ) @@ -125,6 +126,7 @@ func runCmd(ctx *cli.Context) error { sender = common.BytesToAddress([]byte("sender")) receiver = common.BytesToAddress([]byte("receiver")) genesisConfig *core.Genesis + preimages = ctx.Bool(DumpFlag.Name) ) if ctx.Bool(MachineFlag.Name) { tracer = logger.NewJSONLogger(logconfig, os.Stdout) @@ -139,10 +141,12 @@ func runCmd(ctx *cli.Context) error { genesisConfig = gen db := rawdb.NewMemoryDatabase() genesis := gen.MustCommit(db) - statedb, _ = state.New(genesis.Root(), state.NewDatabase(db), nil) + sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: preimages}) + statedb, _ = state.New(genesis.Root(), sdb, nil) chainConfig = gen.Config } else { - statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + sdb := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: preimages}) + statedb, _ = state.New(common.Hash{}, sdb, nil) genesisConfig = new(core.Genesis) } if ctx.String(SenderFlag.Name) != "" { diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 98acc468a1..14b6fe5341 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie" "golang.org/x/crypto/sha3" ) @@ -284,7 +285,7 @@ func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { } func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter bool) (*snapshot.Tree, *state.StateDB) { - sdb := state.NewDatabase(db) + sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) statedb, _ := state.New(common.Hash{}, sdb, nil) for addr, a := range accounts { statedb.SetCode(addr, a.Code) From 8990c92aea01ca07801597b00c0d83d4e2d9b811 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 23 Mar 2023 11:52:22 +0100 Subject: [PATCH 009/988] core/state: add account address to Trie slot accessors (#26934) This changes the Trie interface to add the plain account address as a parameter to all storage-related methods. After the introduction of the TryAccount* functions, TryGet, TryUpdate and TryDelete are now only meant to read an account's storage. In their current form, they assume that an account storage is stored in a separate trie, and that the hashing of the slot is independent of its account's address. The proposed structure for a stateless storage breaks these two assumptions: the hashing of a slot key requires the address and all slots and accounts are stored in a single trie. This PR therefore adds an address parameter to the interface. It is ignored in the MPT version, so this change has no functional impact, however it will reduce the diff size when merging verkle trees. --- core/state/database.go | 20 ++++++++++---------- core/state/state_object.go | 8 ++++---- core/state/statedb.go | 2 +- core/state/trie_prefetcher.go | 24 +++++++++++++++--------- core/state/trie_prefetcher_test.go | 16 ++++++++-------- light/trie.go | 6 +++--- trie/secure_trie.go | 12 ++++++------ 7 files changed, 47 insertions(+), 41 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index d3c36c10ac..a67c414d93 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -68,10 +68,10 @@ type Trie interface { // TODO(fjl): remove this when StateTrie is removed GetKey([]byte) []byte - // TryGet returns the value for key stored in the trie. The value bytes must - // not be modified by the caller. If a node was not found in the database, a - // trie.MissingNodeError is returned. - TryGet(key []byte) ([]byte, error) + // TryGetStorage returns the value for key stored in the trie. The value bytes + // must not be modified by the caller. If a node was not found in the database, + // a trie.MissingNodeError is returned. + TryGetStorage(addr common.Address, key []byte) ([]byte, error) // TryGetAccount abstracts an account read from the trie. It retrieves the // account blob from the trie with provided account address and decodes it @@ -81,20 +81,20 @@ type Trie interface { // be returned. TryGetAccount(address common.Address) (*types.StateAccount, error) - // TryUpdate associates key with value in the trie. If value has length zero, any - // existing value is deleted from the trie. The value bytes must not be modified + // TryUpdateStorage associates key with value in the trie. If value has length zero, + // any existing value is deleted from the trie. The value bytes must not be modified // by the caller while they are stored in the trie. If a node was not found in the // database, a trie.MissingNodeError is returned. - TryUpdate(key, value []byte) error + TryUpdateStorage(addr common.Address, key, value []byte) error // TryUpdateAccount abstracts an account write to the trie. It encodes the // provided account object with associated algorithm and then updates it // in the trie with provided address. TryUpdateAccount(address common.Address, account *types.StateAccount) error - // TryDelete removes any existing value for key from the trie. If a node was not - // found in the database, a trie.MissingNodeError is returned. - TryDelete(key []byte) error + // TryDeleteStorage removes any existing value for key from the trie. If a node + // was not found in the database, a trie.MissingNodeError is returned. + TryDeleteStorage(addr common.Address, key []byte) error // TryDeleteAccount abstracts an account deletion from the trie. TryDeleteAccount(address common.Address) error diff --git a/core/state/state_object.go b/core/state/state_object.go index 7e34cba44a..936f6dae2f 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -201,7 +201,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has s.db.setError(err) return common.Hash{} } - enc, err = tr.TryGet(key.Bytes()) + enc, err = tr.TryGetStorage(s.address, key.Bytes()) if metrics.EnabledExpensive { s.db.StorageReads += time.Since(start) } @@ -253,7 +253,7 @@ func (s *stateObject) finalise(prefetch bool) { } } if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { - s.db.prefetcher.prefetch(s.addrHash, s.data.Root, slotsToPrefetch) + s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch) } if len(s.dirtyStorage) > 0 { s.dirtyStorage = make(Storage) @@ -294,7 +294,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { var v []byte if (value == common.Hash{}) { - if err := tr.TryDelete(key[:]); err != nil { + if err := tr.TryDeleteStorage(s.address, key[:]); err != nil { s.db.setError(err) return nil, err } @@ -302,7 +302,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { } else { // Encoding []byte cannot fail, ok to ignore the error. v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) - if err := tr.TryUpdate(key[:], v); err != nil { + if err := tr.TryUpdateStorage(s.address, key[:], v); err != nil { s.db.setError(err) return nil, err } diff --git a/core/state/statedb.go b/core/state/statedb.go index 54d5040451..38583f51db 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -871,7 +871,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure } if s.prefetcher != nil && len(addressesToPrefetch) > 0 { - s.prefetcher.prefetch(common.Hash{}, s.originalRoot, addressesToPrefetch) + s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch) } // Invalidate journal because reverting across transactions is not allowed. s.clearJournalAndRefund() diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index f142c86bbf..edd370fbdb 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -141,7 +141,7 @@ func (p *triePrefetcher) copy() *triePrefetcher { } // prefetch schedules a batch of trie items to prefetch. -func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, keys [][]byte) { +func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) { // If the prefetcher is an inactive one, bail out if p.fetches != nil { return @@ -150,7 +150,7 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, keys [][] id := p.trieID(owner, root) fetcher := p.fetchers[id] if fetcher == nil { - fetcher = newSubfetcher(p.db, p.root, owner, root) + fetcher = newSubfetcher(p.db, p.root, owner, root, addr) p.fetchers[id] = fetcher } fetcher.schedule(keys) @@ -205,11 +205,12 @@ func (p *triePrefetcher) trieID(owner common.Hash, root common.Hash) string { // main prefetcher is paused and either all requested items are processed or if // the trie being worked on is retrieved from the prefetcher. type subfetcher struct { - db Database // Database to load trie nodes through - state common.Hash // Root hash of the state to prefetch - owner common.Hash // Owner of the trie, usually account hash - root common.Hash // Root hash of the trie to prefetch - trie Trie // Trie being populated with nodes + db Database // Database to load trie nodes through + state common.Hash // Root hash of the state to prefetch + owner common.Hash // Owner of the trie, usually account hash + root common.Hash // Root hash of the trie to prefetch + addr common.Address // Address of the account that the trie belongs to + trie Trie // Trie being populated with nodes tasks [][]byte // Items queued up for retrieval lock sync.Mutex // Lock protecting the task queue @@ -226,12 +227,13 @@ type subfetcher struct { // newSubfetcher creates a goroutine to prefetch state items belonging to a // particular root hash. -func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash) *subfetcher { +func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash, addr common.Address) *subfetcher { sf := &subfetcher{ db: db, state: state, owner: owner, root: root, + addr: addr, wake: make(chan struct{}, 1), stop: make(chan struct{}), term: make(chan struct{}), @@ -336,7 +338,11 @@ func (sf *subfetcher) loop() { if _, ok := sf.seen[string(task)]; ok { sf.dups++ } else { - sf.trie.TryGet(task) + if len(task) == common.AddressLength { + sf.trie.TryGetAccount(common.BytesToAddress(task)) + } else { + sf.trie.TryGetStorage(sf.addr, task) + } sf.seen[string(task)] = struct{}{} } } diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index cb0b67d7ea..501bb70840 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -47,19 +47,19 @@ func TestCopyAndClose(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) time.Sleep(1 * time.Second) a := prefetcher.trie(common.Hash{}, db.originalRoot) - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) b := prefetcher.trie(common.Hash{}, db.originalRoot) cpy := prefetcher.copy() - cpy.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) - cpy.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + cpy.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) + cpy.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) c := cpy.trie(common.Hash{}, db.originalRoot) prefetcher.close() cpy2 := cpy.copy() - cpy2.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + cpy2.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) d := cpy2.trie(common.Hash{}, db.originalRoot) cpy.close() cpy2.close() @@ -72,7 +72,7 @@ func TestUseAfterClose(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) a := prefetcher.trie(common.Hash{}, db.originalRoot) prefetcher.close() b := prefetcher.trie(common.Hash{}, db.originalRoot) @@ -88,7 +88,7 @@ func TestCopyClose(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) cpy := prefetcher.copy() a := prefetcher.trie(common.Hash{}, db.originalRoot) b := cpy.trie(common.Hash{}, db.originalRoot) diff --git a/light/trie.go b/light/trie.go index 0ccab1588d..0f05a80004 100644 --- a/light/trie.go +++ b/light/trie.go @@ -105,7 +105,7 @@ type odrTrie struct { trie *trie.Trie } -func (t *odrTrie) TryGet(key []byte) ([]byte, error) { +func (t *odrTrie) TryGetStorage(_ common.Address, key []byte) ([]byte, error) { key = crypto.Keccak256(key) var res []byte err := t.do(key, func() (err error) { @@ -142,14 +142,14 @@ func (t *odrTrie) TryUpdateAccount(address common.Address, acc *types.StateAccou }) } -func (t *odrTrie) TryUpdate(key, value []byte) error { +func (t *odrTrie) TryUpdateStorage(_ common.Address, key, value []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { return t.trie.TryUpdate(key, value) }) } -func (t *odrTrie) TryDelete(key []byte) error { +func (t *odrTrie) TryDeleteStorage(_ common.Address, key []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { return t.trie.TryDelete(key) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 83b92cebd2..01e004d02e 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -75,7 +75,7 @@ func NewStateTrie(id *ID, db *Database) (*StateTrie, error) { // Get returns the value for key stored in the trie. // The value bytes must not be modified by the caller. func (t *StateTrie) Get(key []byte) []byte { - res, err := t.TryGet(key) + res, err := t.TryGetStorage(common.Address{}, key) if err != nil { log.Error("Unhandled trie error in StateTrie.Get", "err", err) } @@ -86,7 +86,7 @@ func (t *StateTrie) Get(key []byte) []byte { // The value bytes must not be modified by the caller. // If the specified node is not in the trie, nil will be returned. // If a trie node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryGet(key []byte) ([]byte, error) { +func (t *StateTrie) TryGetStorage(_ common.Address, key []byte) ([]byte, error) { return t.trie.TryGet(t.hashKey(key)) } @@ -131,7 +131,7 @@ func (t *StateTrie) TryGetNode(path []byte) ([]byte, int, error) { // The value bytes must not be modified by the caller while they are // stored in the trie. func (t *StateTrie) Update(key, value []byte) { - if err := t.TryUpdate(key, value); err != nil { + if err := t.TryUpdateStorage(common.Address{}, key, value); err != nil { log.Error("Unhandled trie error in StateTrie.Update", "err", err) } } @@ -144,7 +144,7 @@ func (t *StateTrie) Update(key, value []byte) { // stored in the trie. // // If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryUpdate(key, value []byte) error { +func (t *StateTrie) TryUpdateStorage(_ common.Address, key, value []byte) error { hk := t.hashKey(key) err := t.trie.TryUpdate(hk, value) if err != nil { @@ -171,7 +171,7 @@ func (t *StateTrie) TryUpdateAccount(address common.Address, acc *types.StateAcc // Delete removes any existing value for key from the trie. func (t *StateTrie) Delete(key []byte) { - if err := t.TryDelete(key); err != nil { + if err := t.TryDeleteStorage(common.Address{}, key); err != nil { log.Error("Unhandled trie error in StateTrie.Delete", "err", err) } } @@ -179,7 +179,7 @@ func (t *StateTrie) Delete(key []byte) { // TryDelete removes any existing value for key from the trie. // If the specified trie node is not in the trie, nothing will be changed. // If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryDelete(key []byte) error { +func (t *StateTrie) TryDeleteStorage(_ common.Address, key []byte) error { hk := t.hashKey(key) delete(t.getSecKeyCache(), string(hk)) return t.trie.TryDelete(hk) From 7dc100714d5477296fbeef1f4f58b788d6bab738 Mon Sep 17 00:00:00 2001 From: turboboost55 <7891737+turboboost55@users.noreply.github.com> Date: Thu, 23 Mar 2023 06:13:50 -0700 Subject: [PATCH 010/988] metrics: add cpu counters (#26796) This PR adds counter metrics for the CPU system and the Geth process. Currently the only metrics available for these items are gauges. Gauges are fine when the consumer scrapes metrics data at the same interval as Geth produces new values (every 3 seconds), but it is likely that most consumers will not scrape that often. Intervals of 10, 15, or maybe even 30 seconds are probably more common. So the problem is, how does the consumer estimate what the CPU was doing in between scrapes. With a counter, it's easy ... you just subtract two successive values and divide by the time to get a nice, accurate average. But with a gauge, you can't do that. A gauge reading is an instantaneous picture of what was happening at that moment, but it gives you no idea about what was going on between scrapes. Taking an average of values is meaningless. --- metrics/counter_float64.go | 153 +++++++++++++++++++++++++++ metrics/counter_float_64_test.go | 77 ++++++++++++++ metrics/exp/exp.go | 7 ++ metrics/graphite.go | 2 + metrics/influxdb/influxdb.go | 10 ++ metrics/influxdb/influxdbv2.go | 17 +-- metrics/librato/librato.go | 11 ++ metrics/log.go | 3 + metrics/metrics.go | 19 ++-- metrics/metrics_test.go | 2 + metrics/opentsdb.go | 2 + metrics/prometheus/collector.go | 4 + metrics/prometheus/collector_test.go | 7 ++ metrics/prometheus/prometheus.go | 2 + metrics/registry.go | 4 +- metrics/syslog.go | 2 + metrics/writer.go | 3 + 17 files changed, 312 insertions(+), 13 deletions(-) create mode 100644 metrics/counter_float64.go create mode 100644 metrics/counter_float_64_test.go diff --git a/metrics/counter_float64.go b/metrics/counter_float64.go new file mode 100644 index 0000000000..f05f62fed6 --- /dev/null +++ b/metrics/counter_float64.go @@ -0,0 +1,153 @@ +package metrics + +import ( + "sync" +) + +// CounterFloat64 holds a float64 value that can be incremented and decremented. +type CounterFloat64 interface { + Clear() + Count() float64 + Dec(float64) + Inc(float64) + Snapshot() CounterFloat64 +} + +// GetOrRegisterCounterFloat64 returns an existing CounterFloat64 or constructs and registers +// a new StandardCounterFloat64. +func GetOrRegisterCounterFloat64(name string, r Registry) CounterFloat64 { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, NewCounterFloat64).(CounterFloat64) +} + +// GetOrRegisterCounterFloat64Forced returns an existing CounterFloat64 or constructs and registers a +// new CounterFloat64 no matter the global switch is enabled or not. +// Be sure to unregister the counter from the registry once it is of no use to +// allow for garbage collection. +func GetOrRegisterCounterFloat64Forced(name string, r Registry) CounterFloat64 { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, NewCounterFloat64Forced).(CounterFloat64) +} + +// NewCounterFloat64 constructs a new StandardCounterFloat64. +func NewCounterFloat64() CounterFloat64 { + if !Enabled { + return NilCounterFloat64{} + } + return &StandardCounterFloat64{count: 0.0} +} + +// NewCounterFloat64Forced constructs a new StandardCounterFloat64 and returns it no matter if +// the global switch is enabled or not. +func NewCounterFloat64Forced() CounterFloat64 { + return &StandardCounterFloat64{count: 0.0} +} + +// NewRegisteredCounterFloat64 constructs and registers a new StandardCounterFloat64. +func NewRegisteredCounterFloat64(name string, r Registry) CounterFloat64 { + c := NewCounterFloat64() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + +// NewRegisteredCounterFloat64Forced constructs and registers a new StandardCounterFloat64 +// and launches a goroutine no matter the global switch is enabled or not. +// Be sure to unregister the counter from the registry once it is of no use to +// allow for garbage collection. +func NewRegisteredCounterFloat64Forced(name string, r Registry) CounterFloat64 { + c := NewCounterFloat64Forced() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + +// CounterFloat64Snapshot is a read-only copy of another CounterFloat64. +type CounterFloat64Snapshot float64 + +// Clear panics. +func (CounterFloat64Snapshot) Clear() { + panic("Clear called on a CounterFloat64Snapshot") +} + +// Count returns the value at the time the snapshot was taken. +func (c CounterFloat64Snapshot) Count() float64 { return float64(c) } + +// Dec panics. +func (CounterFloat64Snapshot) Dec(float64) { + panic("Dec called on a CounterFloat64Snapshot") +} + +// Inc panics. +func (CounterFloat64Snapshot) Inc(float64) { + panic("Inc called on a CounterFloat64Snapshot") +} + +// Snapshot returns the snapshot. +func (c CounterFloat64Snapshot) Snapshot() CounterFloat64 { return c } + +// NilCounterFloat64 is a no-op CounterFloat64. +type NilCounterFloat64 struct{} + +// Clear is a no-op. +func (NilCounterFloat64) Clear() {} + +// Count is a no-op. +func (NilCounterFloat64) Count() float64 { return 0.0 } + +// Dec is a no-op. +func (NilCounterFloat64) Dec(i float64) {} + +// Inc is a no-op. +func (NilCounterFloat64) Inc(i float64) {} + +// Snapshot is a no-op. +func (NilCounterFloat64) Snapshot() CounterFloat64 { return NilCounterFloat64{} } + +// StandardCounterFloat64 is the standard implementation of a CounterFloat64 and uses the +// sync.Mutex package to manage a single float64 value. +type StandardCounterFloat64 struct { + mutex sync.Mutex + count float64 +} + +// Clear sets the counter to zero. +func (c *StandardCounterFloat64) Clear() { + c.mutex.Lock() + defer c.mutex.Unlock() + c.count = 0.0 +} + +// Count returns the current value. +func (c *StandardCounterFloat64) Count() float64 { + c.mutex.Lock() + defer c.mutex.Unlock() + return c.count +} + +// Dec decrements the counter by the given amount. +func (c *StandardCounterFloat64) Dec(v float64) { + c.mutex.Lock() + defer c.mutex.Unlock() + c.count -= v +} + +// Inc increments the counter by the given amount. +func (c *StandardCounterFloat64) Inc(v float64) { + c.mutex.Lock() + defer c.mutex.Unlock() + c.count += v +} + +// Snapshot returns a read-only copy of the counter. +func (c *StandardCounterFloat64) Snapshot() CounterFloat64 { + return CounterFloat64Snapshot(c.Count()) +} diff --git a/metrics/counter_float_64_test.go b/metrics/counter_float_64_test.go new file mode 100644 index 0000000000..44d9b4c20c --- /dev/null +++ b/metrics/counter_float_64_test.go @@ -0,0 +1,77 @@ +package metrics + +import "testing" + +func BenchmarkCounterFloat64(b *testing.B) { + c := NewCounterFloat64() + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.Inc(1.0) + } +} + +func TestCounterFloat64Clear(t *testing.T) { + c := NewCounterFloat64() + c.Inc(1.0) + c.Clear() + if count := c.Count(); count != 0 { + t.Errorf("c.Count(): 0 != %v\n", count) + } +} + +func TestCounterFloat64Dec1(t *testing.T) { + c := NewCounterFloat64() + c.Dec(1.0) + if count := c.Count(); count != -1.0 { + t.Errorf("c.Count(): -1.0 != %v\n", count) + } +} + +func TestCounterFloat64Dec2(t *testing.T) { + c := NewCounterFloat64() + c.Dec(2.0) + if count := c.Count(); count != -2.0 { + t.Errorf("c.Count(): -2.0 != %v\n", count) + } +} + +func TestCounterFloat64Inc1(t *testing.T) { + c := NewCounterFloat64() + c.Inc(1.0) + if count := c.Count(); count != 1.0 { + t.Errorf("c.Count(): 1.0 != %v\n", count) + } +} + +func TestCounterFloat64Inc2(t *testing.T) { + c := NewCounterFloat64() + c.Inc(2.0) + if count := c.Count(); count != 2.0 { + t.Errorf("c.Count(): 2.0 != %v\n", count) + } +} + +func TestCounterFloat64Snapshot(t *testing.T) { + c := NewCounterFloat64() + c.Inc(1.0) + snapshot := c.Snapshot() + c.Inc(1.0) + if count := snapshot.Count(); count != 1.0 { + t.Errorf("c.Count(): 1.0 != %v\n", count) + } +} + +func TestCounterFloat64Zero(t *testing.T) { + c := NewCounterFloat64() + if count := c.Count(); count != 0 { + t.Errorf("c.Count(): 0 != %v\n", count) + } +} + +func TestGetOrRegisterCounterFloat64(t *testing.T) { + r := NewRegistry() + NewRegisteredCounterFloat64("foo", r).Inc(47.0) + if c := GetOrRegisterCounterFloat64("foo", r); c.Count() != 47.0 { + t.Fatal(c) + } +} diff --git a/metrics/exp/exp.go b/metrics/exp/exp.go index 3ebe8cc68a..2b04eeab27 100644 --- a/metrics/exp/exp.go +++ b/metrics/exp/exp.go @@ -100,6 +100,11 @@ func (exp *exp) publishCounter(name string, metric metrics.Counter) { v.Set(metric.Count()) } +func (exp *exp) publishCounterFloat64(name string, metric metrics.CounterFloat64) { + v := exp.getFloat(name) + v.Set(metric.Count()) +} + func (exp *exp) publishGauge(name string, metric metrics.Gauge) { v := exp.getInt(name) v.Set(metric.Value()) @@ -167,6 +172,8 @@ func (exp *exp) syncToExpvar() { switch i := i.(type) { case metrics.Counter: exp.publishCounter(name, i) + case metrics.CounterFloat64: + exp.publishCounterFloat64(name, i) case metrics.Gauge: exp.publishGauge(name, i) case metrics.GaugeFloat64: diff --git a/metrics/graphite.go b/metrics/graphite.go index 142eec86be..29f72b0c41 100644 --- a/metrics/graphite.go +++ b/metrics/graphite.go @@ -67,6 +67,8 @@ func graphite(c *GraphiteConfig) error { switch metric := i.(type) { case Counter: fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, metric.Count(), now) + case CounterFloat64: + fmt.Fprintf(w, "%s.%s.count %f %d\n", c.Prefix, name, metric.Count(), now) case Gauge: fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Value(), now) case GaugeFloat64: diff --git a/metrics/influxdb/influxdb.go b/metrics/influxdb/influxdb.go index 748c692e13..ea6c3d9dff 100644 --- a/metrics/influxdb/influxdb.go +++ b/metrics/influxdb/influxdb.go @@ -141,6 +141,16 @@ func (r *reporter) send() error { }, Time: now, }) + case metrics.CounterFloat64: + count := metric.Count() + pts = append(pts, client.Point{ + Measurement: fmt.Sprintf("%s%s.count", namespace, name), + Tags: r.tags, + Fields: map[string]interface{}{ + "value": count, + }, + Time: now, + }) case metrics.Gauge: ms := metric.Snapshot() pts = append(pts, client.Point{ diff --git a/metrics/influxdb/influxdbv2.go b/metrics/influxdb/influxdbv2.go index bfb762196c..dc8a42cd5a 100644 --- a/metrics/influxdb/influxdbv2.go +++ b/metrics/influxdb/influxdbv2.go @@ -24,8 +24,6 @@ type v2Reporter struct { client influxdb2.Client write api.WriteAPI - - cache map[string]int64 } // InfluxDBWithTags starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval with the specified tags @@ -39,7 +37,6 @@ func InfluxDBV2WithTags(r metrics.Registry, d time.Duration, endpoint string, to organization: organization, namespace: namespace, tags: tags, - cache: make(map[string]int64), } rep.client = influxdb2.NewClient(rep.endpoint, rep.token) @@ -86,17 +83,25 @@ func (r *v2Reporter) send() { switch metric := i.(type) { case metrics.Counter: v := metric.Count() - l := r.cache[name] measurement := fmt.Sprintf("%s%s.count", namespace, name) fields := map[string]interface{}{ - "value": v - l, + "value": v, } pt := influxdb2.NewPoint(measurement, r.tags, fields, now) r.write.WritePoint(pt) - r.cache[name] = v + case metrics.CounterFloat64: + v := metric.Count() + + measurement := fmt.Sprintf("%s%s.count", namespace, name) + fields := map[string]interface{}{ + "value": v, + } + + pt := influxdb2.NewPoint(measurement, r.tags, fields, now) + r.write.WritePoint(pt) case metrics.Gauge: ms := metric.Snapshot() diff --git a/metrics/librato/librato.go b/metrics/librato/librato.go index b16493413e..3d45f4c7be 100644 --- a/metrics/librato/librato.go +++ b/metrics/librato/librato.go @@ -107,6 +107,17 @@ func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot B } snapshot.Counters = append(snapshot.Counters, measurement) } + case metrics.CounterFloat64: + if m.Count() > 0 { + measurement[Name] = fmt.Sprintf("%s.%s", name, "count") + measurement[Value] = m.Count() + measurement[Attributes] = map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + } + snapshot.Counters = append(snapshot.Counters, measurement) + } case metrics.Gauge: measurement[Name] = name measurement[Value] = float64(m.Value()) diff --git a/metrics/log.go b/metrics/log.go index 0c8ea7c971..d1ce627a83 100644 --- a/metrics/log.go +++ b/metrics/log.go @@ -24,6 +24,9 @@ func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) { case Counter: l.Printf("counter %s\n", name) l.Printf(" count: %9d\n", metric.Count()) + case CounterFloat64: + l.Printf("counter %s\n", name) + l.Printf(" count: %f\n", metric.Count()) case Gauge: l.Printf("gauge %s\n", name) l.Printf(" value: %9d\n", metric.Value()) diff --git a/metrics/metrics.go b/metrics/metrics.go index ff7196b564..c206f16924 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -144,6 +144,9 @@ func CollectProcessMetrics(refresh time.Duration) { cpuSysLoad = GetOrRegisterGauge("system/cpu/sysload", DefaultRegistry) cpuSysWait = GetOrRegisterGauge("system/cpu/syswait", DefaultRegistry) cpuProcLoad = GetOrRegisterGauge("system/cpu/procload", DefaultRegistry) + cpuSysLoadTotal = GetOrRegisterCounterFloat64("system/cpu/sysload/total", DefaultRegistry) + cpuSysWaitTotal = GetOrRegisterCounterFloat64("system/cpu/syswait/total", DefaultRegistry) + cpuProcLoadTotal = GetOrRegisterCounterFloat64("system/cpu/procload/total", DefaultRegistry) cpuThreads = GetOrRegisterGauge("system/cpu/threads", DefaultRegistry) cpuGoroutines = GetOrRegisterGauge("system/cpu/goroutines", DefaultRegistry) cpuSchedLatency = getOrRegisterRuntimeHistogram("system/cpu/schedlatency", secondsToNs, nil) @@ -172,13 +175,17 @@ func CollectProcessMetrics(refresh time.Duration) { secondsSinceLastCollect := collectTime.Sub(lastCollectTime).Seconds() lastCollectTime = collectTime if secondsSinceLastCollect > 0 { - sysLoad := (cpustats[now].GlobalTime - cpustats[prev].GlobalTime) / secondsSinceLastCollect - sysWait := (cpustats[now].GlobalWait - cpustats[prev].GlobalWait) / secondsSinceLastCollect - procLoad := (cpustats[now].LocalTime - cpustats[prev].LocalTime) / secondsSinceLastCollect + sysLoad := cpustats[now].GlobalTime - cpustats[prev].GlobalTime + sysWait := cpustats[now].GlobalWait - cpustats[prev].GlobalWait + procLoad := cpustats[now].LocalTime - cpustats[prev].LocalTime // Convert to integer percentage. - cpuSysLoad.Update(int64(sysLoad * 100)) - cpuSysWait.Update(int64(sysWait * 100)) - cpuProcLoad.Update(int64(procLoad * 100)) + cpuSysLoad.Update(int64(sysLoad / secondsSinceLastCollect * 100)) + cpuSysWait.Update(int64(sysWait / secondsSinceLastCollect * 100)) + cpuProcLoad.Update(int64(procLoad / secondsSinceLastCollect * 100)) + // increment counters (ms) + cpuSysLoadTotal.Inc(sysLoad) + cpuSysWaitTotal.Inc(sysWait) + cpuProcLoadTotal.Inc(procLoad) } // Threads diff --git a/metrics/metrics_test.go b/metrics/metrics_test.go index e3fde1ea62..534c44139b 100644 --- a/metrics/metrics_test.go +++ b/metrics/metrics_test.go @@ -18,6 +18,7 @@ func TestReadRuntimeValues(t *testing.T) { func BenchmarkMetrics(b *testing.B) { r := NewRegistry() c := NewRegisteredCounter("counter", r) + cf := NewRegisteredCounterFloat64("counterfloat64", r) g := NewRegisteredGauge("gauge", r) gf := NewRegisteredGaugeFloat64("gaugefloat64", r) h := NewRegisteredHistogram("histogram", r, NewUniformSample(100)) @@ -71,6 +72,7 @@ func BenchmarkMetrics(b *testing.B) { //log.Println("go", i) for i := 0; i < b.N; i++ { c.Inc(1) + cf.Inc(1.0) g.Update(int64(i)) gf.Update(float64(i)) h.Update(int64(i)) diff --git a/metrics/opentsdb.go b/metrics/opentsdb.go index 3fde55454b..c9fd2e75d5 100644 --- a/metrics/opentsdb.go +++ b/metrics/opentsdb.go @@ -71,6 +71,8 @@ func openTSDB(c *OpenTSDBConfig) error { switch metric := i.(type) { case Counter: fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, metric.Count(), shortHostname) + case CounterFloat64: + fmt.Fprintf(w, "put %s.%s.count %d %f host=%s\n", c.Prefix, name, now, metric.Count(), shortHostname) case Gauge: fmt.Fprintf(w, "put %s.%s.value %d %d host=%s\n", c.Prefix, name, now, metric.Value(), shortHostname) case GaugeFloat64: diff --git a/metrics/prometheus/collector.go b/metrics/prometheus/collector.go index e8d5e4f5d1..2bd9bf22cc 100644 --- a/metrics/prometheus/collector.go +++ b/metrics/prometheus/collector.go @@ -50,6 +50,10 @@ func (c *collector) addCounter(name string, m metrics.Counter) { c.writeGaugeCounter(name, m.Count()) } +func (c *collector) addCounterFloat64(name string, m metrics.CounterFloat64) { + c.writeGaugeCounter(name, m.Count()) +} + func (c *collector) addGauge(name string, m metrics.Gauge) { c.writeGaugeCounter(name, m.Value()) } diff --git a/metrics/prometheus/collector_test.go b/metrics/prometheus/collector_test.go index 43f2f804d3..ff87c8e765 100644 --- a/metrics/prometheus/collector_test.go +++ b/metrics/prometheus/collector_test.go @@ -20,6 +20,10 @@ func TestCollector(t *testing.T) { counter.Inc(12345) c.addCounter("test/counter", counter) + counterfloat64 := metrics.NewCounterFloat64() + counterfloat64.Inc(54321.98) + c.addCounterFloat64("test/counter_float64", counterfloat64) + gauge := metrics.NewGauge() gauge.Update(23456) c.addGauge("test/gauge", gauge) @@ -61,6 +65,9 @@ func TestCollector(t *testing.T) { const expectedOutput = `# TYPE test_counter gauge test_counter 12345 +# TYPE test_counter_float64 gauge +test_counter_float64 54321.98 + # TYPE test_gauge gauge test_gauge 23456 diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index c8408d8cab..d966fa9a86 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -45,6 +45,8 @@ func Handler(reg metrics.Registry) http.Handler { switch m := i.(type) { case metrics.Counter: c.addCounter(name, m.Snapshot()) + case metrics.CounterFloat64: + c.addCounterFloat64(name, m.Snapshot()) case metrics.Gauge: c.addGauge(name, m.Snapshot()) case metrics.GaugeFloat64: diff --git a/metrics/registry.go b/metrics/registry.go index c5435adf24..4c62248351 100644 --- a/metrics/registry.go +++ b/metrics/registry.go @@ -120,6 +120,8 @@ func (r *StandardRegistry) GetAll() map[string]map[string]interface{} { switch metric := i.(type) { case Counter: values["count"] = metric.Count() + case CounterFloat64: + values["count"] = metric.Count() case Gauge: values["value"] = metric.Value() case GaugeFloat64: @@ -196,7 +198,7 @@ func (r *StandardRegistry) register(name string, i interface{}) error { return DuplicateMetric(name) } switch i.(type) { - case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer: + case Counter, CounterFloat64, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer: r.metrics[name] = i } return nil diff --git a/metrics/syslog.go b/metrics/syslog.go index 551a2bd0f0..f23b07e199 100644 --- a/metrics/syslog.go +++ b/metrics/syslog.go @@ -17,6 +17,8 @@ func Syslog(r Registry, d time.Duration, w *syslog.Writer) { switch metric := i.(type) { case Counter: w.Info(fmt.Sprintf("counter %s: count: %d", name, metric.Count())) + case CounterFloat64: + w.Info(fmt.Sprintf("counter %s: count: %f", name, metric.Count())) case Gauge: w.Info(fmt.Sprintf("gauge %s: value: %d", name, metric.Value())) case GaugeFloat64: diff --git a/metrics/writer.go b/metrics/writer.go index 88521a80d9..256fbd14c9 100644 --- a/metrics/writer.go +++ b/metrics/writer.go @@ -29,6 +29,9 @@ func WriteOnce(r Registry, w io.Writer) { case Counter: fmt.Fprintf(w, "counter %s\n", namedMetric.name) fmt.Fprintf(w, " count: %9d\n", metric.Count()) + case CounterFloat64: + fmt.Fprintf(w, "counter %s\n", namedMetric.name) + fmt.Fprintf(w, " count: %f\n", metric.Count()) case Gauge: fmt.Fprintf(w, "gauge %s\n", namedMetric.name) fmt.Fprintf(w, " value: %9d\n", metric.Value()) From f6c3a534a49f6ba0f8abc6b6a7de8d2d9a6ed555 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 23 Mar 2023 15:12:32 -0400 Subject: [PATCH 011/988] metrics/influxdb: use smaller dependency and reuse code between v1 and v2 reporters (#26963) This change switches to use the smaller influxdata/influxdb1-client package instead of depending on the whole infuxdb package. The new smaller client is very similar to the influxdb-v2 client, which made it possible to refactor the two reporters to reuse code a lot more. --- go.mod | 2 +- go.sum | 241 +--------------------- metrics/influxdb/influxdb.go | 360 +++++++++------------------------ metrics/influxdb/influxdbv1.go | 145 +++++++++++++ metrics/influxdb/influxdbv2.go | 142 +------------ 5 files changed, 254 insertions(+), 636 deletions(-) create mode 100644 metrics/influxdb/influxdbv1.go diff --git a/go.mod b/go.mod index 26519b8048..29e8c22723 100644 --- a/go.mod +++ b/go.mod @@ -38,8 +38,8 @@ require ( github.com/holiman/bloomfilter/v2 v2.0.3 github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c github.com/huin/goupnp v1.0.3 - github.com/influxdata/influxdb v1.8.3 github.com/influxdata/influxdb-client-go/v2 v2.4.0 + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e github.com/julienschmidt/httprouter v1.3.0 diff --git a/go.sum b/go.sum index 4491e01891..229ecef206 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,4 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 h1:qoVeMsc9/fh/yhxVaA0obYjVH/oI/ihrOoMwsLS9KSA= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= @@ -26,27 +7,19 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= -github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go-v2 v1.2.0 h1:BS+UYpbsElC82gB+2E2jiCBg36i8HlubTB/dO/moQ9c= github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= @@ -67,26 +40,17 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxq github.com/aws/smithy-go v1.1.0 h1:D6CSsM3gdxaGaqXnPgOBCeL6Mophqzu7KJOu7zW78sU= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= -github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0 h1:gFqGlGl/5f9UGXAaKapCGUfaTCgRKKnzu2VvzMZlOFA= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= @@ -118,7 +82,6 @@ github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 h1:6IrxszG5G+O github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= -github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -133,7 +96,6 @@ github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbz github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= @@ -149,7 +111,6 @@ github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7/go.mod h1:yRkwfj0CBpOG github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= @@ -166,7 +127,6 @@ github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= @@ -186,17 +146,10 @@ github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnR github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= -github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= @@ -204,8 +157,6 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= @@ -213,26 +164,17 @@ github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -247,15 +189,11 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -269,17 +207,10 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -290,8 +221,6 @@ github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLt github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= @@ -306,23 +235,15 @@ github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= -github.com/influxdata/influxdb v1.8.3 h1:WEypI1BQFTT4teLM+1qkEcvUi0dAvopAI/ir0vAiBg8= -github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= -github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= -github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 h1:vilfsDSy7TDxedi9gyBkMvAirat/oRcL0lFdJBf6tdM= github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= -github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= -github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= -github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= @@ -336,15 +257,9 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= @@ -353,20 +268,13 @@ github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYb github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= -github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= -github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= @@ -383,19 +291,16 @@ github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awS github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= @@ -406,10 +311,7 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= @@ -429,8 +331,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0= @@ -451,46 +351,28 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= -github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= @@ -503,19 +385,14 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= -github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -523,9 +400,7 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -538,7 +413,6 @@ github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCA github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= @@ -558,11 +432,9 @@ github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBn github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= @@ -573,17 +445,8 @@ github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -595,34 +458,13 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg= golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -632,19 +474,13 @@ golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -663,10 +499,6 @@ golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -678,28 +510,17 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -728,7 +549,6 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -737,40 +557,20 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -783,48 +583,17 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= -gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -840,7 +609,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -870,11 +638,6 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/metrics/influxdb/influxdb.go b/metrics/influxdb/influxdb.go index ea6c3d9dff..5dfbbab3ed 100644 --- a/metrics/influxdb/influxdb.go +++ b/metrics/influxdb/influxdb.go @@ -2,270 +2,112 @@ package influxdb import ( "fmt" - uurl "net/url" - "time" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" - "github.com/influxdata/influxdb/client" ) -type reporter struct { - reg metrics.Registry - interval time.Duration - - url uurl.URL - database string - username string - password string - namespace string - tags map[string]string - - client *client.Client - - cache map[string]int64 -} - -// InfluxDB starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval. -func InfluxDB(r metrics.Registry, d time.Duration, url, database, username, password, namespace string) { - InfluxDBWithTags(r, d, url, database, username, password, namespace, nil) -} - -// InfluxDBWithTags starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval with the specified tags -func InfluxDBWithTags(r metrics.Registry, d time.Duration, url, database, username, password, namespace string, tags map[string]string) { - u, err := uurl.Parse(url) - if err != nil { - log.Warn("Unable to parse InfluxDB", "url", url, "err", err) - return - } - - rep := &reporter{ - reg: r, - interval: d, - url: *u, - database: database, - username: username, - password: password, - namespace: namespace, - tags: tags, - cache: make(map[string]int64), - } - if err := rep.makeClient(); err != nil { - log.Warn("Unable to make InfluxDB client", "err", err) - return - } - - rep.run() -} - -// InfluxDBWithTagsOnce runs once an InfluxDB reporter and post the given metrics.Registry with the specified tags -func InfluxDBWithTagsOnce(r metrics.Registry, url, database, username, password, namespace string, tags map[string]string) error { - u, err := uurl.Parse(url) - if err != nil { - return fmt.Errorf("unable to parse InfluxDB. url: %s, err: %v", url, err) - } - - rep := &reporter{ - reg: r, - url: *u, - database: database, - username: username, - password: password, - namespace: namespace, - tags: tags, - cache: make(map[string]int64), - } - if err := rep.makeClient(); err != nil { - return fmt.Errorf("unable to make InfluxDB client. err: %v", err) - } - - if err := rep.send(); err != nil { - return fmt.Errorf("unable to send to InfluxDB. err: %v", err) - } - - return nil -} - -func (r *reporter) makeClient() (err error) { - r.client, err = client.NewClient(client.Config{ - URL: r.url, - Username: r.username, - Password: r.password, - Timeout: 10 * time.Second, - }) - - return -} - -func (r *reporter) run() { - intervalTicker := time.NewTicker(r.interval) - pingTicker := time.NewTicker(time.Second * 5) - - defer intervalTicker.Stop() - defer pingTicker.Stop() - - for { - select { - case <-intervalTicker.C: - if err := r.send(); err != nil { - log.Warn("Unable to send to InfluxDB", "err", err) - } - case <-pingTicker.C: - _, _, err := r.client.Ping() - if err != nil { - log.Warn("Got error while sending a ping to InfluxDB, trying to recreate client", "err", err) - - if err = r.makeClient(); err != nil { - log.Warn("Unable to make InfluxDB client", "err", err) - } - } +func readMeter(namespace, name string, i interface{}) (string, map[string]interface{}) { + switch metric := i.(type) { + case metrics.Counter: + measurement := fmt.Sprintf("%s%s.count", namespace, name) + fields := map[string]interface{}{ + "value": metric.Count(), } - } -} - -func (r *reporter) send() error { - var pts []client.Point - - r.reg.Each(func(name string, i interface{}) { - now := time.Now() - namespace := r.namespace - - switch metric := i.(type) { - case metrics.Counter: - count := metric.Count() - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.count", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "value": count, - }, - Time: now, - }) - case metrics.CounterFloat64: - count := metric.Count() - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.count", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "value": count, - }, - Time: now, - }) - case metrics.Gauge: - ms := metric.Snapshot() - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.gauge", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "value": ms.Value(), - }, - Time: now, - }) - case metrics.GaugeFloat64: - ms := metric.Snapshot() - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.gauge", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "value": ms.Value(), - }, - Time: now, - }) - case metrics.Histogram: - ms := metric.Snapshot() - if ms.Count() > 0 { - ps := ms.Percentiles([]float64{0.25, 0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) - fields := map[string]interface{}{ - "count": ms.Count(), - "max": ms.Max(), - "mean": ms.Mean(), - "min": ms.Min(), - "stddev": ms.StdDev(), - "variance": ms.Variance(), - "p25": ps[0], - "p50": ps[1], - "p75": ps[2], - "p95": ps[3], - "p99": ps[4], - "p999": ps[5], - "p9999": ps[6], - } - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.histogram", namespace, name), - Tags: r.tags, - Fields: fields, - Time: now, - }) - } - case metrics.Meter: - ms := metric.Snapshot() - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.meter", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "count": ms.Count(), - "m1": ms.Rate1(), - "m5": ms.Rate5(), - "m15": ms.Rate15(), - "mean": ms.RateMean(), - }, - Time: now, - }) - case metrics.Timer: - ms := metric.Snapshot() - ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.timer", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "count": ms.Count(), - "max": ms.Max(), - "mean": ms.Mean(), - "min": ms.Min(), - "stddev": ms.StdDev(), - "variance": ms.Variance(), - "p50": ps[0], - "p75": ps[1], - "p95": ps[2], - "p99": ps[3], - "p999": ps[4], - "p9999": ps[5], - "m1": ms.Rate1(), - "m5": ms.Rate5(), - "m15": ms.Rate15(), - "meanrate": ms.RateMean(), - }, - Time: now, - }) - case metrics.ResettingTimer: - t := metric.Snapshot() - - if len(t.Values()) > 0 { - ps := t.Percentiles([]float64{50, 95, 99}) - val := t.Values() - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.span", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "count": len(val), - "max": val[len(val)-1], - "mean": t.Mean(), - "min": val[0], - "p50": ps[0], - "p95": ps[1], - "p99": ps[2], - }, - Time: now, - }) - } + return measurement, fields + case metrics.CounterFloat64: + measurement := fmt.Sprintf("%s%s.count", namespace, name) + fields := map[string]interface{}{ + "value": metric.Count(), } - }) - - bps := client.BatchPoints{ - Points: pts, - Database: r.database, + return measurement, fields + case metrics.Gauge: + measurement := fmt.Sprintf("%s%s.gauge", namespace, name) + fields := map[string]interface{}{ + "value": metric.Snapshot().Value(), + } + return measurement, fields + case metrics.GaugeFloat64: + measurement := fmt.Sprintf("%s%s.gauge", namespace, name) + fields := map[string]interface{}{ + "value": metric.Snapshot().Value(), + } + return measurement, fields + case metrics.Histogram: + ms := metric.Snapshot() + if ms.Count() <= 0 { + break + } + ps := ms.Percentiles([]float64{0.25, 0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) + measurement := fmt.Sprintf("%s%s.histogram", namespace, name) + fields := map[string]interface{}{ + "count": ms.Count(), + "max": ms.Max(), + "mean": ms.Mean(), + "min": ms.Min(), + "stddev": ms.StdDev(), + "variance": ms.Variance(), + "p25": ps[0], + "p50": ps[1], + "p75": ps[2], + "p95": ps[3], + "p99": ps[4], + "p999": ps[5], + "p9999": ps[6], + } + return measurement, fields + case metrics.Meter: + ms := metric.Snapshot() + measurement := fmt.Sprintf("%s%s.meter", namespace, name) + fields := map[string]interface{}{ + "count": ms.Count(), + "m1": ms.Rate1(), + "m5": ms.Rate5(), + "m15": ms.Rate15(), + "mean": ms.RateMean(), + } + return measurement, fields + case metrics.Timer: + ms := metric.Snapshot() + ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) + + measurement := fmt.Sprintf("%s%s.timer", namespace, name) + fields := map[string]interface{}{ + "count": ms.Count(), + "max": ms.Max(), + "mean": ms.Mean(), + "min": ms.Min(), + "stddev": ms.StdDev(), + "variance": ms.Variance(), + "p50": ps[0], + "p75": ps[1], + "p95": ps[2], + "p99": ps[3], + "p999": ps[4], + "p9999": ps[5], + "m1": ms.Rate1(), + "m5": ms.Rate5(), + "m15": ms.Rate15(), + "meanrate": ms.RateMean(), + } + return measurement, fields + case metrics.ResettingTimer: + t := metric.Snapshot() + if len(t.Values()) == 0 { + break + } + ps := t.Percentiles([]float64{50, 95, 99}) + val := t.Values() + measurement := fmt.Sprintf("%s%s.span", namespace, name) + fields := map[string]interface{}{ + "count": len(val), + "max": val[len(val)-1], + "mean": t.Mean(), + "min": val[0], + "p50": ps[0], + "p95": ps[1], + "p99": ps[2], + } + return measurement, fields } - - _, err := r.client.Write(bps) - return err + return "", nil } diff --git a/metrics/influxdb/influxdbv1.go b/metrics/influxdb/influxdbv1.go new file mode 100644 index 0000000000..f65d30ef95 --- /dev/null +++ b/metrics/influxdb/influxdbv1.go @@ -0,0 +1,145 @@ +package influxdb + +import ( + "fmt" + uurl "net/url" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + client "github.com/influxdata/influxdb1-client/v2" +) + +type reporter struct { + reg metrics.Registry + interval time.Duration + + url uurl.URL + database string + username string + password string + namespace string + tags map[string]string + + client client.Client + + cache map[string]int64 +} + +// InfluxDB starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval. +func InfluxDB(r metrics.Registry, d time.Duration, url, database, username, password, namespace string) { + InfluxDBWithTags(r, d, url, database, username, password, namespace, nil) +} + +// InfluxDBWithTags starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval with the specified tags +func InfluxDBWithTags(r metrics.Registry, d time.Duration, url, database, username, password, namespace string, tags map[string]string) { + u, err := uurl.Parse(url) + if err != nil { + log.Warn("Unable to parse InfluxDB", "url", url, "err", err) + return + } + + rep := &reporter{ + reg: r, + interval: d, + url: *u, + database: database, + username: username, + password: password, + namespace: namespace, + tags: tags, + cache: make(map[string]int64), + } + if err := rep.makeClient(); err != nil { + log.Warn("Unable to make InfluxDB client", "err", err) + return + } + + rep.run() +} + +// InfluxDBWithTagsOnce runs once an InfluxDB reporter and post the given metrics.Registry with the specified tags +func InfluxDBWithTagsOnce(r metrics.Registry, url, database, username, password, namespace string, tags map[string]string) error { + u, err := uurl.Parse(url) + if err != nil { + return fmt.Errorf("unable to parse InfluxDB. url: %s, err: %v", url, err) + } + + rep := &reporter{ + reg: r, + url: *u, + database: database, + username: username, + password: password, + namespace: namespace, + tags: tags, + cache: make(map[string]int64), + } + if err := rep.makeClient(); err != nil { + return fmt.Errorf("unable to make InfluxDB client. err: %v", err) + } + + if err := rep.send(); err != nil { + return fmt.Errorf("unable to send to InfluxDB. err: %v", err) + } + + return nil +} + +func (r *reporter) makeClient() (err error) { + r.client, err = client.NewHTTPClient(client.HTTPConfig{ + Addr: r.url.String(), + Username: r.username, + Password: r.password, + Timeout: 10 * time.Second, + }) + + return +} + +func (r *reporter) run() { + intervalTicker := time.NewTicker(r.interval) + pingTicker := time.NewTicker(time.Second * 5) + + defer intervalTicker.Stop() + defer pingTicker.Stop() + + for { + select { + case <-intervalTicker.C: + if err := r.send(); err != nil { + log.Warn("Unable to send to InfluxDB", "err", err) + } + case <-pingTicker.C: + _, _, err := r.client.Ping(0) + if err != nil { + log.Warn("Got error while sending a ping to InfluxDB, trying to recreate client", "err", err) + + if err = r.makeClient(); err != nil { + log.Warn("Unable to make InfluxDB client", "err", err) + } + } + } + } +} + +func (r *reporter) send() error { + bps, err := client.NewBatchPoints( + client.BatchPointsConfig{ + Database: r.database, + }) + if err != nil { + return err + } + r.reg.Each(func(name string, i interface{}) { + now := time.Now() + measurement, fields := readMeter(r.namespace, name, i) + if fields == nil { + return + } + if p, err := client.NewPoint(measurement, r.tags, fields, now); err == nil { + bps.AddPoint(p) + } + }) + return r.client.Write(bps) +} diff --git a/metrics/influxdb/influxdbv2.go b/metrics/influxdb/influxdbv2.go index dc8a42cd5a..7984898f32 100644 --- a/metrics/influxdb/influxdbv2.go +++ b/metrics/influxdb/influxdbv2.go @@ -2,7 +2,6 @@ package influxdb import ( "context" - "fmt" "time" "github.com/ethereum/go-ethereum/log" @@ -78,144 +77,13 @@ func (r *v2Reporter) run() { func (r *v2Reporter) send() { r.reg.Each(func(name string, i interface{}) { now := time.Now() - namespace := r.namespace - - switch metric := i.(type) { - case metrics.Counter: - v := metric.Count() - - measurement := fmt.Sprintf("%s%s.count", namespace, name) - fields := map[string]interface{}{ - "value": v, - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - - case metrics.CounterFloat64: - v := metric.Count() - - measurement := fmt.Sprintf("%s%s.count", namespace, name) - fields := map[string]interface{}{ - "value": v, - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - - case metrics.Gauge: - ms := metric.Snapshot() - - measurement := fmt.Sprintf("%s%s.gauge", namespace, name) - fields := map[string]interface{}{ - "value": ms.Value(), - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - - case metrics.GaugeFloat64: - ms := metric.Snapshot() - - measurement := fmt.Sprintf("%s%s.gauge", namespace, name) - fields := map[string]interface{}{ - "value": ms.Value(), - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - - case metrics.Histogram: - ms := metric.Snapshot() - - if ms.Count() > 0 { - ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) - measurement := fmt.Sprintf("%s%s.histogram", namespace, name) - fields := map[string]interface{}{ - "count": ms.Count(), - "max": ms.Max(), - "mean": ms.Mean(), - "min": ms.Min(), - "stddev": ms.StdDev(), - "variance": ms.Variance(), - "p50": ps[0], - "p75": ps[1], - "p95": ps[2], - "p99": ps[3], - "p999": ps[4], - "p9999": ps[5], - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - } - - case metrics.Meter: - ms := metric.Snapshot() - - measurement := fmt.Sprintf("%s%s.meter", namespace, name) - fields := map[string]interface{}{ - "count": ms.Count(), - "m1": ms.Rate1(), - "m5": ms.Rate5(), - "m15": ms.Rate15(), - "mean": ms.RateMean(), - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - - case metrics.Timer: - ms := metric.Snapshot() - ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) - - measurement := fmt.Sprintf("%s%s.timer", namespace, name) - fields := map[string]interface{}{ - "count": ms.Count(), - "max": ms.Max(), - "mean": ms.Mean(), - "min": ms.Min(), - "stddev": ms.StdDev(), - "variance": ms.Variance(), - "p50": ps[0], - "p75": ps[1], - "p95": ps[2], - "p99": ps[3], - "p999": ps[4], - "p9999": ps[5], - "m1": ms.Rate1(), - "m5": ms.Rate5(), - "m15": ms.Rate15(), - "meanrate": ms.RateMean(), - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - - case metrics.ResettingTimer: - t := metric.Snapshot() - - if len(t.Values()) > 0 { - ps := t.Percentiles([]float64{50, 95, 99}) - val := t.Values() - - measurement := fmt.Sprintf("%s%s.span", namespace, name) - fields := map[string]interface{}{ - "count": len(val), - "max": val[len(val)-1], - "mean": t.Mean(), - "min": val[0], - "p50": ps[0], - "p95": ps[1], - "p99": ps[2], - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - } + measurement, fields := readMeter(r.namespace, name, i) + if fields == nil { + return } + pt := influxdb2.NewPoint(measurement, r.tags, fields, now) + r.write.WritePoint(pt) }) - // Force all unwritten data to be sent r.write.Flush() } From b1acaf47aa3cbd91241605850381bb4dadecfbea Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Thu, 23 Mar 2023 16:12:37 -0400 Subject: [PATCH 012/988] eth/gasprice: change feehistory input type from int to uint64 (#26922) Change input param type from int to uint64 --- eth/api_backend.go | 2 +- eth/gasprice/feehistory.go | 14 +++++++------- eth/gasprice/feehistory_test.go | 4 ++-- eth/gasprice/gasprice.go | 6 +++--- internal/ethapi/api.go | 2 +- internal/ethapi/backend.go | 2 +- internal/ethapi/transaction_args_test.go | 2 +- les/api_backend.go | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index 643f6369df..ac160b0736 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -327,7 +327,7 @@ func (b *EthAPIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) return b.gpo.SuggestTipCap(ctx) } -func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) { +func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) { return b.gpo.FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles) } diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 47cc31999e..82edf9a7fb 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -142,7 +142,7 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) { // also returned if requested and available. // Note: an error is only returned if retrieving the head header has failed. If there are no // retrievable blocks in the specified range then zero block count is returned with no error. -func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNumber, blocks int) (*types.Block, []*types.Receipt, uint64, int, error) { +func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNumber, blocks uint64) (*types.Block, []*types.Receipt, uint64, uint64, error) { var ( headBlock *types.Header pendingBlock *types.Block @@ -200,8 +200,8 @@ func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNum return nil, nil, 0, 0, nil } // Ensure not trying to retrieve before genesis. - if int(reqEnd+1) < blocks { - blocks = int(reqEnd + 1) + if uint64(reqEnd+1) < blocks { + blocks = uint64(reqEnd + 1) } return pendingBlock, pendingReceipts, uint64(reqEnd), blocks, nil } @@ -220,7 +220,7 @@ func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNum // // Note: baseFee includes the next block after the newest of the returned range, because this // value can be derived from the newest block. -func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { +func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedLastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { if blocks < 1 { return common.Big0, nil, nil, nil, nil // returning with no data and no error means there are no retrievable blocks } @@ -249,7 +249,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast if err != nil || blocks == 0 { return common.Big0, nil, nil, nil, err } - oldestBlock := lastBlock + 1 - uint64(blocks) + oldestBlock := lastBlock + 1 - blocks var ( next = oldestBlock @@ -259,7 +259,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast for i, p := range rewardPercentiles { binary.LittleEndian.PutUint64(percentileKey[i*8:(i+1)*8], math.Float64bits(p)) } - for i := 0; i < maxBlockFetchers && i < blocks; i++ { + for i := 0; i < maxBlockFetchers && i < int(blocks); i++ { go func() { for { // Retrieve the next block number to fetch with this goroutine @@ -314,7 +314,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast if fees.err != nil { return common.Big0, nil, nil, nil, fees.err } - i := int(fees.blockNumber - oldestBlock) + i := fees.blockNumber - oldestBlock if fees.results.baseFee != nil { reward[i], baseFee[i], baseFee[i+1], gasUsedRatio[i] = fees.results.reward, fees.results.baseFee, fees.results.nextBaseFee, fees.results.gasUsedRatio } else { diff --git a/eth/gasprice/feehistory_test.go b/eth/gasprice/feehistory_test.go index b54874d688..1bcfb287a5 100644 --- a/eth/gasprice/feehistory_test.go +++ b/eth/gasprice/feehistory_test.go @@ -28,8 +28,8 @@ import ( func TestFeeHistory(t *testing.T) { var cases = []struct { pending bool - maxHeader, maxBlock int - count int + maxHeader, maxBlock uint64 + count uint64 last rpc.BlockNumber percent []float64 expFirst uint64 diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index 604ad5e104..8e98a3409b 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -42,8 +42,8 @@ var ( type Config struct { Blocks int Percentile int - MaxHeaderHistory int - MaxBlockHistory int + MaxHeaderHistory uint64 + MaxBlockHistory uint64 Default *big.Int `toml:",omitempty"` MaxPrice *big.Int `toml:",omitempty"` IgnorePrice *big.Int `toml:",omitempty"` @@ -71,7 +71,7 @@ type Oracle struct { fetchLock sync.Mutex checkBlocks, percentile int - maxHeaderHistory, maxBlockHistory int + maxHeaderHistory, maxBlockHistory uint64 historyCache *lru.Cache[cacheKey, processedFees] } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 0cf29e5fe6..4e39855309 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -89,7 +89,7 @@ type feeHistoryResult struct { // FeeHistory returns the fee market history. func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecimal64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { - oldest, reward, baseFee, gasUsed, err := s.b.FeeHistory(ctx, int(blockCount), lastBlock, rewardPercentiles) + oldest, reward, baseFee, gasUsed, err := s.b.FeeHistory(ctx, uint64(blockCount), lastBlock, rewardPercentiles) if err != nil { return nil, err } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 98887afc80..0249c8664d 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -44,7 +44,7 @@ type Backend interface { SyncProgress() ethereum.SyncProgress SuggestGasTipCap(ctx context.Context) (*big.Int, error) - FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) + FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) ChainDb() ethdb.Database AccountManager() *accounts.Manager ExtRPCEnabled() bool diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 1b533861d5..24c15b7775 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -258,7 +258,7 @@ func (b *backendMock) ChainConfig() *params.ChainConfig { return b.config } // Other methods needed to implement Backend interface. func (b *backendMock) SyncProgress() ethereum.SyncProgress { return ethereum.SyncProgress{} } -func (b *backendMock) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { +func (b *backendMock) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { return nil, nil, nil, nil, nil } func (b *backendMock) ChainDb() ethdb.Database { return nil } diff --git a/les/api_backend.go b/les/api_backend.go index 4b0369845a..2d1fccd9ad 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -272,7 +272,7 @@ func (b *LesApiBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) return b.gpo.SuggestTipCap(ctx) } -func (b *LesApiBackend) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) { +func (b *LesApiBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) { return b.gpo.FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles) } From 0137bd69c55ca1edd42c533e543297493d3182ff Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 24 Mar 2023 07:39:20 -0400 Subject: [PATCH 013/988] go.mod: update golang.org/x/tools (#26960) --- go.mod | 10 +++++----- go.sum | 24 ++++++++++-------------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 29e8c22723..95c80c6fd8 100644 --- a/go.mod +++ b/go.mod @@ -61,10 +61,10 @@ require ( golang.org/x/crypto v0.1.0 golang.org/x/exp v0.0.0-20230206171751-46f607a40771 golang.org/x/sync v0.1.0 - golang.org/x/sys v0.5.0 - golang.org/x/text v0.7.0 + golang.org/x/sys v0.6.0 + golang.org/x/text v0.8.0 golang.org/x/time v0.0.0-20220922220347-f3bd1da661af - golang.org/x/tools v0.2.0 + golang.org/x/tools v0.7.0 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce ) @@ -116,8 +116,8 @@ require ( github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/mod v0.6.0 // indirect - golang.org/x/net v0.4.0 // indirect + golang.org/x/mod v0.9.0 // indirect + golang.org/x/net v0.8.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 229ecef206..4c134a2772 100644 --- a/go.sum +++ b/go.sum @@ -224,10 +224,6 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= -github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= -github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o= -github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8= github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -469,8 +465,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -496,8 +492,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -544,8 +540,8 @@ golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -555,8 +551,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= @@ -575,8 +571,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 792d893ed01cd70f3253fa3f6834e1fbf7bee13c Mon Sep 17 00:00:00 2001 From: ucwong Date: Fri, 24 Mar 2023 07:17:39 -0600 Subject: [PATCH 014/988] rlp/rlpgen: print want/expect output string if mismatch (#26932) Co-authored-by: Marius van der Wijden --- rlp/rlpgen/gen_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rlp/rlpgen/gen_test.go b/rlp/rlpgen/gen_test.go index ff3b8385ae..3b4f5df287 100644 --- a/rlp/rlpgen/gen_test.go +++ b/rlp/rlpgen/gen_test.go @@ -75,7 +75,7 @@ func TestOutput(t *testing.T) { t.Fatal("error loading expected test output:", err) } if !bytes.Equal(output, wantOutput) { - t.Fatal("output mismatch:\n", string(output)) + t.Fatalf("output mismatch, want: %v got %v", string(wantOutput), string(output)) } }) } From df383addee1df80d899b9dc32e3761ce68228606 Mon Sep 17 00:00:00 2001 From: norwnd <112318969+norwnd@users.noreply.github.com> Date: Sun, 26 Mar 2023 00:38:43 +0300 Subject: [PATCH 015/988] ethclient: ensure returned subscription is nil on error (#26976) --- ethclient/ethclient.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index c8353b25ae..47beaf63cc 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -320,7 +320,14 @@ func (ec *Client) SyncProgress(ctx context.Context) (*ethereum.SyncProgress, err // SubscribeNewHead subscribes to notifications about the current blockchain head // on the given channel. func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) { - return ec.c.EthSubscribe(ctx, ch, "newHeads") + sub, err := ec.c.EthSubscribe(ctx, ch, "newHeads") + if err != nil { + // Defensively prefer returning nil interface explicitly on error-path, instead + // of letting default golang behavior wrap it with non-nil interface that stores + // nil concrete type value. + return nil, err + } + return sub, nil } // State Access @@ -389,7 +396,14 @@ func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuer if err != nil { return nil, err } - return ec.c.EthSubscribe(ctx, ch, "logs", arg) + sub, err := ec.c.EthSubscribe(ctx, ch, "logs", arg) + if err != nil { + // Defensively prefer returning nil interface explicitly on error-path, instead + // of letting default golang behavior wrap it with non-nil interface that stores + // nil concrete type value. + return nil, err + } + return sub, nil } func toFilterArg(q ethereum.FilterQuery) (interface{}, error) { From 41f89ca94423fad523a4427c9af2c327fe344fe2 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:48:46 +0200 Subject: [PATCH 016/988] core/state, trie: remove Try prefix in Trie accessors (#26975) This change renames StateTrie methods to remove the Try* prefix. We added the Trie methods with prefix 'Try' a long time ago, working around the problem that most existing methods of Trie did not return the database error. This weird naming convention has persisted until now. Co-authored-by: Gary Rong --- core/state/database.go | 24 +++++++++--------- core/state/state_object.go | 6 ++--- core/state/statedb.go | 6 ++--- core/state/trie_prefetcher.go | 4 +-- eth/protocols/snap/handler.go | 8 +++--- light/trie.go | 12 ++++----- trie/secure_trie.go | 47 +++++++++++++++++------------------ trie/sync_test.go | 2 +- 8 files changed, 54 insertions(+), 55 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index a67c414d93..82f620b460 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -68,36 +68,36 @@ type Trie interface { // TODO(fjl): remove this when StateTrie is removed GetKey([]byte) []byte - // TryGetStorage returns the value for key stored in the trie. The value bytes + // GetStorage returns the value for key stored in the trie. The value bytes // must not be modified by the caller. If a node was not found in the database, // a trie.MissingNodeError is returned. - TryGetStorage(addr common.Address, key []byte) ([]byte, error) + GetStorage(addr common.Address, key []byte) ([]byte, error) - // TryGetAccount abstracts an account read from the trie. It retrieves the + // GetAccount abstracts an account read from the trie. It retrieves the // account blob from the trie with provided account address and decodes it // with associated decoding algorithm. If the specified account is not in // the trie, nil will be returned. If the trie is corrupted(e.g. some nodes // are missing or the account blob is incorrect for decoding), an error will // be returned. - TryGetAccount(address common.Address) (*types.StateAccount, error) + GetAccount(address common.Address) (*types.StateAccount, error) - // TryUpdateStorage associates key with value in the trie. If value has length zero, + // UpdateStorage associates key with value in the trie. If value has length zero, // any existing value is deleted from the trie. The value bytes must not be modified // by the caller while they are stored in the trie. If a node was not found in the // database, a trie.MissingNodeError is returned. - TryUpdateStorage(addr common.Address, key, value []byte) error + UpdateStorage(addr common.Address, key, value []byte) error - // TryUpdateAccount abstracts an account write to the trie. It encodes the + // UpdateAccount abstracts an account write to the trie. It encodes the // provided account object with associated algorithm and then updates it // in the trie with provided address. - TryUpdateAccount(address common.Address, account *types.StateAccount) error + UpdateAccount(address common.Address, account *types.StateAccount) error - // TryDeleteStorage removes any existing value for key from the trie. If a node + // DeleteStorage removes any existing value for key from the trie. If a node // was not found in the database, a trie.MissingNodeError is returned. - TryDeleteStorage(addr common.Address, key []byte) error + DeleteStorage(addr common.Address, key []byte) error - // TryDeleteAccount abstracts an account deletion from the trie. - TryDeleteAccount(address common.Address) error + // DeleteAccount abstracts an account deletion from the trie. + DeleteAccount(address common.Address) error // Hash returns the root hash of the trie. It does not write to the database and // can be used even if the trie doesn't have one. diff --git a/core/state/state_object.go b/core/state/state_object.go index 936f6dae2f..95fe6f52fa 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -201,7 +201,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has s.db.setError(err) return common.Hash{} } - enc, err = tr.TryGetStorage(s.address, key.Bytes()) + enc, err = tr.GetStorage(s.address, key.Bytes()) if metrics.EnabledExpensive { s.db.StorageReads += time.Since(start) } @@ -294,7 +294,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { var v []byte if (value == common.Hash{}) { - if err := tr.TryDeleteStorage(s.address, key[:]); err != nil { + if err := tr.DeleteStorage(s.address, key[:]); err != nil { s.db.setError(err) return nil, err } @@ -302,7 +302,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { } else { // Encoding []byte cannot fail, ok to ignore the error. v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) - if err := tr.TryUpdateStorage(s.address, key[:], v); err != nil { + if err := tr.UpdateStorage(s.address, key[:], v); err != nil { s.db.setError(err) return nil, err } diff --git a/core/state/statedb.go b/core/state/statedb.go index 38583f51db..b89f4bfd8c 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -512,7 +512,7 @@ func (s *StateDB) updateStateObject(obj *stateObject) { } // Encode the account and update the account trie addr := obj.Address() - if err := s.trie.TryUpdateAccount(addr, &obj.data); err != nil { + if err := s.trie.UpdateAccount(addr, &obj.data); err != nil { s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err)) } @@ -533,7 +533,7 @@ func (s *StateDB) deleteStateObject(obj *stateObject) { } // Delete the account from the trie addr := obj.Address() - if err := s.trie.TryDeleteAccount(addr); err != nil { + if err := s.trie.DeleteAccount(addr); err != nil { s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err)) } } @@ -587,7 +587,7 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { if data == nil { start := time.Now() var err error - data, err = s.trie.TryGetAccount(addr) + data, err = s.trie.GetAccount(addr) if metrics.EnabledExpensive { s.AccountReads += time.Since(start) } diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index edd370fbdb..844f72fc10 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -339,9 +339,9 @@ func (sf *subfetcher) loop() { sf.dups++ } else { if len(task) == common.AddressLength { - sf.trie.TryGetAccount(common.BytesToAddress(task)) + sf.trie.GetAccount(common.BytesToAddress(task)) } else { - sf.trie.TryGetStorage(sf.addr, task) + sf.trie.GetStorage(sf.addr, task) } sf.seen[string(task)] = struct{}{} } diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index d7c9400440..55781ac54b 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -418,7 +418,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP if err != nil { return nil, nil } - acc, err := accTrie.TryGetAccountByHash(account) + acc, err := accTrie.GetAccountByHash(account) if err != nil || acc == nil { return nil, nil } @@ -510,7 +510,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s case 1: // If we're only retrieving an account trie node, fetch it directly - blob, resolved, err := accTrie.TryGetNode(pathset[0]) + blob, resolved, err := accTrie.GetNode(pathset[0]) loads += resolved // always account database reads, even for failures if err != nil { break @@ -524,7 +524,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s if snap == nil { // We don't have the requested state snapshotted yet (or it is stale), // but can look up the account via the trie instead. - account, err := accTrie.TryGetAccountByHash(common.BytesToHash(pathset[0])) + account, err := accTrie.GetAccountByHash(common.BytesToHash(pathset[0])) loads += 8 // We don't know the exact cost of lookup, this is an estimate if err != nil || account == nil { break @@ -545,7 +545,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s break } for _, path := range pathset[1:] { - blob, resolved, err := stTrie.TryGetNode(path) + blob, resolved, err := stTrie.GetNode(path) loads += resolved // always account database reads, even for failures if err != nil { break diff --git a/light/trie.go b/light/trie.go index 0f05a80004..2f8f71c61e 100644 --- a/light/trie.go +++ b/light/trie.go @@ -105,7 +105,7 @@ type odrTrie struct { trie *trie.Trie } -func (t *odrTrie) TryGetStorage(_ common.Address, key []byte) ([]byte, error) { +func (t *odrTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) { key = crypto.Keccak256(key) var res []byte err := t.do(key, func() (err error) { @@ -115,7 +115,7 @@ func (t *odrTrie) TryGetStorage(_ common.Address, key []byte) ([]byte, error) { return res, err } -func (t *odrTrie) TryGetAccount(address common.Address) (*types.StateAccount, error) { +func (t *odrTrie) GetAccount(address common.Address) (*types.StateAccount, error) { var res types.StateAccount key := crypto.Keccak256(address.Bytes()) err := t.do(key, func() (err error) { @@ -131,7 +131,7 @@ func (t *odrTrie) TryGetAccount(address common.Address) (*types.StateAccount, er return &res, err } -func (t *odrTrie) TryUpdateAccount(address common.Address, acc *types.StateAccount) error { +func (t *odrTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error { key := crypto.Keccak256(address.Bytes()) value, err := rlp.EncodeToBytes(acc) if err != nil { @@ -142,14 +142,14 @@ func (t *odrTrie) TryUpdateAccount(address common.Address, acc *types.StateAccou }) } -func (t *odrTrie) TryUpdateStorage(_ common.Address, key, value []byte) error { +func (t *odrTrie) UpdateStorage(_ common.Address, key, value []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { return t.trie.TryUpdate(key, value) }) } -func (t *odrTrie) TryDeleteStorage(_ common.Address, key []byte) error { +func (t *odrTrie) DeleteStorage(_ common.Address, key []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { return t.trie.TryDelete(key) @@ -157,7 +157,7 @@ func (t *odrTrie) TryDeleteStorage(_ common.Address, key []byte) error { } // TryDeleteAccount abstracts an account deletion from the trie. -func (t *odrTrie) TryDeleteAccount(address common.Address) error { +func (t *odrTrie) DeleteAccount(address common.Address) error { key := crypto.Keccak256(address.Bytes()) return t.do(key, func() error { return t.trie.TryDelete(key) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 01e004d02e..b25bf758c1 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -75,25 +75,25 @@ func NewStateTrie(id *ID, db *Database) (*StateTrie, error) { // Get returns the value for key stored in the trie. // The value bytes must not be modified by the caller. func (t *StateTrie) Get(key []byte) []byte { - res, err := t.TryGetStorage(common.Address{}, key) + res, err := t.GetStorage(common.Address{}, key) if err != nil { log.Error("Unhandled trie error in StateTrie.Get", "err", err) } return res } -// TryGet returns the value for key stored in the trie. -// The value bytes must not be modified by the caller. -// If the specified node is not in the trie, nil will be returned. +// GetStorage attempts to retrieve a storage slot with provided account address +// and slot key. The value bytes must not be modified by the caller. +// If the specified storage slot is not in the trie, nil will be returned. // If a trie node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryGetStorage(_ common.Address, key []byte) ([]byte, error) { +func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) { return t.trie.TryGet(t.hashKey(key)) } -// TryGetAccount attempts to retrieve an account with provided account address. +// GetAccount attempts to retrieve an account with provided account address. // If the specified account is not in the trie, nil will be returned. // If a trie node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryGetAccount(address common.Address) (*types.StateAccount, error) { +func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, error) { res, err := t.trie.TryGet(t.hashKey(address.Bytes())) if res == nil || err != nil { return nil, err @@ -103,10 +103,10 @@ func (t *StateTrie) TryGetAccount(address common.Address) (*types.StateAccount, return ret, err } -// TryGetAccountByHash does the same thing as TryGetAccount, however -// it expects an account hash that is the hash of address. This constitutes an -// abstraction leak, since the client code needs to know the key format. -func (t *StateTrie) TryGetAccountByHash(addrHash common.Hash) (*types.StateAccount, error) { +// GetAccountByHash does the same thing as GetAccount, however it expects an +// account hash that is the hash of address. This constitutes an abstraction +// leak, since the client code needs to know the key format. +func (t *StateTrie) GetAccountByHash(addrHash common.Hash) (*types.StateAccount, error) { res, err := t.trie.TryGet(addrHash.Bytes()) if res == nil || err != nil { return nil, err @@ -116,11 +116,11 @@ func (t *StateTrie) TryGetAccountByHash(addrHash common.Hash) (*types.StateAccou return ret, err } -// TryGetNode attempts to retrieve a trie node by compact-encoded path. It is not +// GetNode attempts to retrieve a trie node by compact-encoded path. It is not // possible to use keybyte-encoding as the path might contain odd nibbles. // If the specified trie node is not in the trie, nil will be returned. // If a trie node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryGetNode(path []byte) ([]byte, int, error) { +func (t *StateTrie) GetNode(path []byte) ([]byte, int, error) { return t.trie.TryGetNode(path) } @@ -131,12 +131,12 @@ func (t *StateTrie) TryGetNode(path []byte) ([]byte, int, error) { // The value bytes must not be modified by the caller while they are // stored in the trie. func (t *StateTrie) Update(key, value []byte) { - if err := t.TryUpdateStorage(common.Address{}, key, value); err != nil { + if err := t.UpdateStorage(common.Address{}, key, value); err != nil { log.Error("Unhandled trie error in StateTrie.Update", "err", err) } } -// TryUpdate associates key with value in the trie. Subsequent calls to +// UpdateStorage associates key with value in the trie. Subsequent calls to // Get will return value. If value has length zero, any existing value // is deleted from the trie and calls to Get will return nil. // @@ -144,7 +144,7 @@ func (t *StateTrie) Update(key, value []byte) { // stored in the trie. // // If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryUpdateStorage(_ common.Address, key, value []byte) error { +func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error { hk := t.hashKey(key) err := t.trie.TryUpdate(hk, value) if err != nil { @@ -154,9 +154,8 @@ func (t *StateTrie) TryUpdateStorage(_ common.Address, key, value []byte) error return nil } -// TryUpdateAccount account will abstract the write of an account to the -// secure trie. -func (t *StateTrie) TryUpdateAccount(address common.Address, acc *types.StateAccount) error { +// UpdateAccount will abstract the write of an account to the secure trie. +func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error { hk := t.hashKey(address.Bytes()) data, err := rlp.EncodeToBytes(acc) if err != nil { @@ -171,22 +170,22 @@ func (t *StateTrie) TryUpdateAccount(address common.Address, acc *types.StateAcc // Delete removes any existing value for key from the trie. func (t *StateTrie) Delete(key []byte) { - if err := t.TryDeleteStorage(common.Address{}, key); err != nil { + if err := t.DeleteStorage(common.Address{}, key); err != nil { log.Error("Unhandled trie error in StateTrie.Delete", "err", err) } } -// TryDelete removes any existing value for key from the trie. +// DeleteStorage removes any existing storage slot from the trie. // If the specified trie node is not in the trie, nothing will be changed. // If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryDeleteStorage(_ common.Address, key []byte) error { +func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error { hk := t.hashKey(key) delete(t.getSecKeyCache(), string(hk)) return t.trie.TryDelete(hk) } -// TryDeleteAccount abstracts an account deletion from the trie. -func (t *StateTrie) TryDeleteAccount(address common.Address) error { +// DeleteAccount abstracts an account deletion from the trie. +func (t *StateTrie) DeleteAccount(address common.Address) error { hk := t.hashKey(address.Bytes()) delete(t.getSecKeyCache(), string(hk)) return t.trie.TryDelete(hk) diff --git a/trie/sync_test.go b/trie/sync_test.go index 8fec378333..f404dc1cda 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -154,7 +154,7 @@ func testIterativeSync(t *testing.T, count int, bypath bool) { } } else { for i, element := range elements { - data, _, err := srcTrie.TryGetNode(element.syncPath[len(element.syncPath)-1]) + data, _, err := srcTrie.GetNode(element.syncPath[len(element.syncPath)-1]) if err != nil { t.Fatalf("failed to retrieve node data for path %x: %v", element.path, err) } From 117530b0e6784be38e5f874d7ed88971fa49db9b Mon Sep 17 00:00:00 2001 From: Delweng Date: Mon, 27 Mar 2023 19:44:41 +0800 Subject: [PATCH 017/988] metrics/librato: ensure resp.body closed (#26969) This change ensures that we call Close on a http response body, in various places in the source code (mostly tests) --- graphql/graphql_test.go | 3 +++ metrics/librato/client.go | 4 +++- node/node_test.go | 1 + node/rpcstack_test.go | 1 + p2p/simulations/adapters/exec.go | 4 +++- p2p/simulations/mocker_test.go | 5 ++++- rpc/http_test.go | 1 + 7 files changed, 16 insertions(+), 3 deletions(-) diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 46acd15293..30b4e7c354 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -156,6 +156,7 @@ func TestGraphQLBlockSerialization(t *testing.T) { t.Fatalf("could not post: %v", err) } bodyBytes, err := io.ReadAll(resp.Body) + resp.Body.Close() if err != nil { t.Fatalf("could not read from response body: %v", err) } @@ -239,6 +240,7 @@ func TestGraphQLBlockSerializationEIP2718(t *testing.T) { t.Fatalf("could not post: %v", err) } bodyBytes, err := io.ReadAll(resp.Body) + resp.Body.Close() if err != nil { t.Fatalf("could not read from response body: %v", err) } @@ -263,6 +265,7 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) { if err != nil { t.Fatalf("could not post: %v", err) } + resp.Body.Close() // make sure the request is not handled successfully assert.Equal(t, http.StatusNotFound, resp.StatusCode) } diff --git a/metrics/librato/client.go b/metrics/librato/client.go index 729c2da9a9..f1b9e1e916 100644 --- a/metrics/librato/client.go +++ b/metrics/librato/client.go @@ -87,9 +87,11 @@ func (c *LibratoClient) PostMetrics(batch Batch) (err error) { req.Header.Set("Content-Type", "application/json") req.SetBasicAuth(c.Email, c.Token) - if resp, err = http.DefaultClient.Do(req); err != nil { + resp, err = http.DefaultClient.Do(req) + if err != nil { return } + defer resp.Body.Close() if resp.StatusCode != http.StatusOK { var body []byte diff --git a/node/node_test.go b/node/node_test.go index 560d487fa8..04810a815b 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -615,6 +615,7 @@ func doHTTPRequest(t *testing.T, req *http.Request) *http.Response { if err != nil { t.Fatalf("could not issue a GET request to the given endpoint: %v", err) } + t.Cleanup(func() { resp.Body.Close() }) return resp } diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index 4d10e61e2d..0790dddec4 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -320,6 +320,7 @@ func baseRpcRequest(t *testing.T, url, bodyStr string, extraHeaders ...string) * if err != nil { t.Fatal(err) } + t.Cleanup(func() { resp.Body.Close() }) return resp } diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go index 7bfa8aab6d..1d812514de 100644 --- a/p2p/simulations/adapters/exec.go +++ b/p2p/simulations/adapters/exec.go @@ -428,9 +428,11 @@ func execP2PNode() { // Send status to the host. statusJSON, _ := json.Marshal(status) - if _, err := http.Post(statusURL, "application/json", bytes.NewReader(statusJSON)); err != nil { + resp, err := http.Post(statusURL, "application/json", bytes.NewReader(statusJSON)) + if err != nil { log.Crit("Can't post startup info", "url", statusURL, "err", err) } + resp.Body.Close() if stackErr != nil { os.Exit(1) } diff --git a/p2p/simulations/mocker_test.go b/p2p/simulations/mocker_test.go index 56d81942bb..0112ee5cfd 100644 --- a/p2p/simulations/mocker_test.go +++ b/p2p/simulations/mocker_test.go @@ -124,6 +124,7 @@ func TestMocker(t *testing.T) { if err != nil { t.Fatalf("Could not start mocker: %s", err) } + resp.Body.Close() if resp.StatusCode != 200 { t.Fatalf("Invalid Status Code received for starting mocker, expected 200, got %d", resp.StatusCode) } @@ -145,15 +146,17 @@ func TestMocker(t *testing.T) { if err != nil { t.Fatalf("Could not stop mocker: %s", err) } + resp.Body.Close() if resp.StatusCode != 200 { t.Fatalf("Invalid Status Code received for stopping mocker, expected 200, got %d", resp.StatusCode) } //reset the network - _, err = http.Post(s.URL+"/reset", "", nil) + resp, err = http.Post(s.URL+"/reset", "", nil) if err != nil { t.Fatalf("Could not reset network: %s", err) } + resp.Body.Close() //now the number of nodes in the network should be zero nodesInfo, err = client.GetNodes() diff --git a/rpc/http_test.go b/rpc/http_test.go index 528e1bcfc5..584842a9aa 100644 --- a/rpc/http_test.go +++ b/rpc/http_test.go @@ -94,6 +94,7 @@ func confirmHTTPRequestYieldsStatusCode(t *testing.T, method, contentType, body if err != nil { t.Fatalf("request failed: %v", err) } + resp.Body.Close() confirmStatusCode(t, resp.StatusCode, expectedStatusCode) } From 881fed032c7183b2abeb357cc4123a8375c0c9f5 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Mon, 27 Mar 2023 21:40:20 +0800 Subject: [PATCH 018/988] core/vm: use atomic.Bool (#26951) Make use of new atomic types --------- Co-authored-by: Felix Lange Co-authored-by: Martin Holst Swende --- core/vm/evm.go | 7 +++---- core/vm/instructions.go | 6 ++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index d78ea07926..0084e4ca51 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -114,8 +114,7 @@ type EVM struct { // used throughout the execution of the tx. interpreter *EVMInterpreter // abort is used to abort the EVM calling operations - // NOTE: must be set atomically - abort int32 + abort atomic.Bool // callGasTemp holds the gas available for the current call. This is needed because the // available gas is calculated in gasCall* according to the 63/64 rule and later // applied in opCall*. @@ -147,12 +146,12 @@ func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) { // Cancel cancels any running EVM operation. This may be called concurrently and // it's safe to be called multiple times. func (evm *EVM) Cancel() { - atomic.StoreInt32(&evm.abort, 1) + evm.abort.Store(true) } // Cancelled returns true if Cancel has been called func (evm *EVM) Cancelled() bool { - return atomic.LoadInt32(&evm.abort) == 1 + return evm.abort.Load() } // Interpreter returns the current interpreter diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 77b6e02bfc..21d8cc215a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -17,8 +17,6 @@ package vm import ( - "sync/atomic" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -531,7 +529,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b } func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if atomic.LoadInt32(&interpreter.evm.abort) != 0 { + if interpreter.evm.abort.Load() { return nil, errStopToken } pos := scope.Stack.pop() @@ -543,7 +541,7 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt } func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if atomic.LoadInt32(&interpreter.evm.abort) != 0 { + if interpreter.evm.abort.Load() { return nil, errStopToken } pos, cond := scope.Stack.pop(), scope.Stack.pop() From 79532a25b1ecf81b281f7a22b251abbd35c784c2 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 28 Mar 2023 15:05:29 +0800 Subject: [PATCH 019/988] core/bloombits: use atomic type (#26993) --- core/bloombits/matcher.go | 6 +++--- core/bloombits/matcher_test.go | 12 ++++++------ core/bloombits/scheduler_test.go | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/bloombits/matcher.go b/core/bloombits/matcher.go index 0d2f6f950d..d8f932041b 100644 --- a/core/bloombits/matcher.go +++ b/core/bloombits/matcher.go @@ -83,7 +83,7 @@ type Matcher struct { retrievals chan chan *Retrieval // Retriever processes waiting for task allocations deliveries chan *Retrieval // Retriever processes waiting for task response deliveries - running uint32 // Atomic flag whether a session is live or not + running atomic.Bool // Atomic flag whether a session is live or not } // NewMatcher creates a new pipeline for retrieving bloom bit streams and doing @@ -146,10 +146,10 @@ func (m *Matcher) addScheduler(idx uint) { // channel is closed. func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uint64) (*MatcherSession, error) { // Make sure we're not creating concurrent sessions - if atomic.SwapUint32(&m.running, 1) == 1 { + if m.running.Swap(true) { return nil, errors.New("matcher already running") } - defer atomic.StoreUint32(&m.running, 0) + defer m.running.Store(false) // Initiate a new matching round session := &MatcherSession{ diff --git a/core/bloombits/matcher_test.go b/core/bloombits/matcher_test.go index 93d4632b85..36764c3f17 100644 --- a/core/bloombits/matcher_test.go +++ b/core/bloombits/matcher_test.go @@ -160,7 +160,7 @@ func testMatcher(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, in } } // Track the number of retrieval requests made - var requested uint32 + var requested atomic.Uint32 // Start the matching session for the filter and the retriever goroutines quit := make(chan struct{}) @@ -208,15 +208,15 @@ func testMatcher(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, in session.Close() close(quit) - if retrievals != 0 && requested != retrievals { - t.Errorf("filter = %v blocks = %v intermittent = %v: request count mismatch, have #%v, want #%v", filter, blocks, intermittent, requested, retrievals) + if retrievals != 0 && requested.Load() != retrievals { + t.Errorf("filter = %v blocks = %v intermittent = %v: request count mismatch, have #%v, want #%v", filter, blocks, intermittent, requested.Load(), retrievals) } - return requested + return requested.Load() } // startRetrievers starts a batch of goroutines listening for section requests // and serving them. -func startRetrievers(session *MatcherSession, quit chan struct{}, retrievals *uint32, batch int) { +func startRetrievers(session *MatcherSession, quit chan struct{}, retrievals *atomic.Uint32, batch int) { requests := make(chan chan *Retrieval) for i := 0; i < 10; i++ { @@ -238,7 +238,7 @@ func startRetrievers(session *MatcherSession, quit chan struct{}, retrievals *ui for i, section := range task.Sections { if rand.Int()%4 != 0 { // Handle occasional missing deliveries task.Bitsets[i] = generateBitset(task.Bit, section) - atomic.AddUint32(retrievals, 1) + retrievals.Add(1) } } request <- task diff --git a/core/bloombits/scheduler_test.go b/core/bloombits/scheduler_test.go index 49e113c117..dcaaa91525 100644 --- a/core/bloombits/scheduler_test.go +++ b/core/bloombits/scheduler_test.go @@ -45,13 +45,13 @@ func testScheduler(t *testing.T, clients int, fetchers int, requests int) { fetch := make(chan *request, 16) defer close(fetch) - var delivered uint32 + var delivered atomic.Uint32 for i := 0; i < fetchers; i++ { go func() { defer fetchPend.Done() for req := range fetch { - atomic.AddUint32(&delivered, 1) + delivered.Add(1) f.deliver([]uint64{ req.section + uint64(requests), // Non-requested data (ensure it doesn't go out of bounds) @@ -97,7 +97,7 @@ func testScheduler(t *testing.T, clients int, fetchers int, requests int) { } pend.Wait() - if have := atomic.LoadUint32(&delivered); int(have) != requests { + if have := delivered.Load(); int(have) != requests { t.Errorf("request count mismatch: have %v, want %v", have, requests) } } From fb8a3aaf1e084f6190c72f039571f3c7da565b4a Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 28 Mar 2023 15:06:50 +0800 Subject: [PATCH 020/988] core/state: use atomic.Bool (#26992) --- core/state/snapshot/difflayer.go | 6 +++--- core/state/snapshot/snapshot.go | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index f916a020e7..4701acccd3 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -103,7 +103,7 @@ type diffLayer struct { memory uint64 // Approximate guess as to how much memory we use root common.Hash // Root hash to which this snapshot diff belongs to - stale uint32 // Signals that the layer became stale (state progressed) + stale atomic.Bool // Signals that the layer became stale (state progressed) // destructSet is a very special helper marker. If an account is marked as // deleted, then it's recorded in this set. However it's allowed that an account @@ -267,7 +267,7 @@ func (dl *diffLayer) Parent() snapshot { // Stale return whether this layer has become stale (was flattened across) or if // it's still live. func (dl *diffLayer) Stale() bool { - return atomic.LoadUint32(&dl.stale) != 0 + return dl.stale.Load() } // Account directly retrieves the account associated with a particular hash in @@ -449,7 +449,7 @@ func (dl *diffLayer) flatten() snapshot { // Before actually writing all our data to the parent, first ensure that the // parent hasn't been 'corrupted' by someone else already flattening into it - if atomic.SwapUint32(&parent.stale, 1) != 0 { + if parent.stale.Swap(true) { panic("parent diff layer is stale") // we've flattened into the same parent from two children, boo } // Overwrite all the updated accounts blindly, merge the sorted list diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 0f3fa2c7a4..2e57a059dd 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -22,7 +22,6 @@ import ( "errors" "fmt" "sync" - "sync/atomic" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" @@ -272,7 +271,7 @@ func (t *Tree) Disable() { case *diffLayer: // If the layer is a simple diff, simply mark as stale layer.lock.Lock() - atomic.StoreUint32(&layer.stale, 1) + layer.stale.Store(true) layer.lock.Unlock() default: @@ -726,7 +725,7 @@ func (t *Tree) Rebuild(root common.Hash) { case *diffLayer: // If the layer is a simple diff, simply mark as stale layer.lock.Lock() - atomic.StoreUint32(&layer.stale, 1) + layer.stale.Store(true) layer.lock.Unlock() default: From a236e03d0094fd2703cecfb235d91e1e36d0b276 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 28 Mar 2023 09:08:10 +0200 Subject: [PATCH 021/988] graphql: fix data races (#26965) Fixes multiple data races caused by the fact that resolving fields are done concurrently by the graphql library. It also enforces caching at the stateobject level for account fields. --- graphql/graphql.go | 306 ++++++++++++++++++++-------------------- graphql/graphql_test.go | 76 +++++++--- 2 files changed, 211 insertions(+), 171 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 0c13cc80f5..3c637d2d2c 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -24,6 +24,7 @@ import ( "math/big" "sort" "strconv" + "sync" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" @@ -80,12 +81,26 @@ type Account struct { r *Resolver address common.Address blockNrOrHash rpc.BlockNumberOrHash + state *state.StateDB + mu sync.Mutex } // getState fetches the StateDB object for an account. func (a *Account) getState(ctx context.Context) (*state.StateDB, error) { + a.mu.Lock() + defer a.mu.Unlock() + if a.state != nil { + return a.state, nil + } state, _, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash) - return state, err + if err != nil { + return nil, err + } + a.state = state + // Cache the state object. This is done so that concurrent resolvers + // don't have to fetch the object from DB individually. + a.state.GetOrNewStateObject(a.address) + return a.state, nil } func (a *Account) Address(ctx context.Context) (common.Address, error) { @@ -184,32 +199,39 @@ func (at *AccessTuple) StorageKeys(ctx context.Context) []common.Hash { // Transaction represents an Ethereum transaction. // backend and hash are mandatory; all others will be fetched when required. type Transaction struct { - r *Resolver - hash common.Hash + r *Resolver + hash common.Hash // Must be present after initialization + mu sync.Mutex + // mu protects following resources tx *types.Transaction block *Block index uint64 } // resolve returns the internal transaction object, fetching it if needed. -func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, error) { - if t.tx == nil { - // Try to return an already finalized transaction - tx, blockHash, _, index, err := t.r.backend.GetTransaction(ctx, t.hash) - if err == nil && tx != nil { - t.tx = tx - blockNrOrHash := rpc.BlockNumberOrHashWithHash(blockHash, false) - t.block = &Block{ - r: t.r, - numberOrHash: &blockNrOrHash, - } - t.index = index - return t.tx, nil +// It also returns the block the tx blongs to, unless it is a pending tx. +func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, *Block, error) { + t.mu.Lock() + defer t.mu.Unlock() + if t.tx != nil { + return t.tx, t.block, nil + } + // Try to return an already finalized transaction + tx, blockHash, _, index, err := t.r.backend.GetTransaction(ctx, t.hash) + if err == nil && tx != nil { + t.tx = tx + blockNrOrHash := rpc.BlockNumberOrHashWithHash(blockHash, false) + t.block = &Block{ + r: t.r, + numberOrHash: &blockNrOrHash, + hash: blockHash, } - // No finalized transaction, try to retrieve it from the pool - t.tx = t.r.backend.GetPoolTransaction(t.hash) + t.index = index + return t.tx, t.block, nil } - return t.tx, nil + // No finalized transaction, try to retrieve it from the pool + t.tx = t.r.backend.GetPoolTransaction(t.hash) + return t.tx, nil, nil } func (t *Transaction) Hash(ctx context.Context) common.Hash { @@ -217,7 +239,7 @@ func (t *Transaction) Hash(ctx context.Context) common.Hash { } func (t *Transaction) InputData(ctx context.Context) (hexutil.Bytes, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Bytes{}, err } @@ -225,7 +247,7 @@ func (t *Transaction) InputData(ctx context.Context) (hexutil.Bytes, error) { } func (t *Transaction) Gas(ctx context.Context) (hexutil.Uint64, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return 0, err } @@ -233,7 +255,7 @@ func (t *Transaction) Gas(ctx context.Context) (hexutil.Uint64, error) { } func (t *Transaction) GasPrice(ctx context.Context) (hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, block, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Big{}, err } @@ -241,8 +263,8 @@ func (t *Transaction) GasPrice(ctx context.Context) (hexutil.Big, error) { case types.AccessListTxType: return hexutil.Big(*tx.GasPrice()), nil case types.DynamicFeeTxType: - if t.block != nil { - if baseFee, _ := t.block.BaseFeePerGas(ctx); baseFee != nil { + if block != nil { + if baseFee, _ := block.BaseFeePerGas(ctx); baseFee != nil { // price = min(tip, gasFeeCap - baseFee) + baseFee return (hexutil.Big)(*math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee.ToInt()), tx.GasFeeCap())), nil } @@ -254,15 +276,15 @@ func (t *Transaction) GasPrice(ctx context.Context) (hexutil.Big, error) { } func (t *Transaction) EffectiveGasPrice(ctx context.Context) (*hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, block, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } // Pending tx - if t.block == nil { + if block == nil { return nil, nil } - header, err := t.block.resolveHeader(ctx) + header, err := block.resolveHeader(ctx) if err != nil || header == nil { return nil, err } @@ -273,7 +295,7 @@ func (t *Transaction) EffectiveGasPrice(ctx context.Context) (*hexutil.Big, erro } func (t *Transaction) MaxFeePerGas(ctx context.Context) (*hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } @@ -288,7 +310,7 @@ func (t *Transaction) MaxFeePerGas(ctx context.Context) (*hexutil.Big, error) { } func (t *Transaction) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } @@ -303,15 +325,15 @@ func (t *Transaction) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, e } func (t *Transaction) EffectiveTip(ctx context.Context) (*hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, block, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } // Pending tx - if t.block == nil { + if block == nil { return nil, nil } - header, err := t.block.resolveHeader(ctx) + header, err := block.resolveHeader(ctx) if err != nil || header == nil { return nil, err } @@ -327,7 +349,7 @@ func (t *Transaction) EffectiveTip(ctx context.Context) (*hexutil.Big, error) { } func (t *Transaction) Value(ctx context.Context) (hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Big{}, err } @@ -338,7 +360,7 @@ func (t *Transaction) Value(ctx context.Context) (hexutil.Big, error) { } func (t *Transaction) Nonce(ctx context.Context) (hexutil.Uint64, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return 0, err } @@ -346,7 +368,7 @@ func (t *Transaction) Nonce(ctx context.Context) (hexutil.Uint64, error) { } func (t *Transaction) To(ctx context.Context, args BlockNumberArgs) (*Account, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } @@ -362,7 +384,7 @@ func (t *Transaction) To(ctx context.Context, args BlockNumberArgs) (*Account, e } func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) (*Account, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } @@ -376,17 +398,20 @@ func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) (*Account, } func (t *Transaction) Block(ctx context.Context) (*Block, error) { - if _, err := t.resolve(ctx); err != nil { + _, block, err := t.resolve(ctx) + if err != nil { return nil, err } - return t.block, nil + return block, nil } func (t *Transaction) Index(ctx context.Context) (*int32, error) { - if _, err := t.resolve(ctx); err != nil { + _, block, err := t.resolve(ctx) + if err != nil { return nil, err } - if t.block == nil { + // Pending tx + if block == nil { return nil, nil } index := int32(t.index) @@ -395,13 +420,15 @@ func (t *Transaction) Index(ctx context.Context) (*int32, error) { // getReceipt returns the receipt associated with this transaction, if any. func (t *Transaction) getReceipt(ctx context.Context) (*types.Receipt, error) { - if _, err := t.resolve(ctx); err != nil { + _, block, err := t.resolve(ctx) + if err != nil { return nil, err } - if t.block == nil { + // Pending tx + if block == nil { return nil, nil } - receipts, err := t.block.resolveReceipts(ctx) + receipts, err := block.resolveReceipts(ctx) if err != nil { return nil, err } @@ -451,28 +478,25 @@ func (t *Transaction) CreatedContract(ctx context.Context, args BlockNumberArgs) } func (t *Transaction) Logs(ctx context.Context) (*[]*Log, error) { - if _, err := t.resolve(ctx); err != nil { + _, block, err := t.resolve(ctx) + if err != nil { return nil, err } - if t.block == nil { + // Pending tx + if block == nil { return nil, nil } - if _, ok := t.block.numberOrHash.Hash(); !ok { - header, err := t.r.backend.HeaderByNumberOrHash(ctx, *t.block.numberOrHash) - if err != nil { - return nil, err - } - hash := header.Hash() - t.block.numberOrHash.BlockHash = &hash + h, err := block.Hash(ctx) + if err != nil { + return nil, err } - return t.getLogs(ctx) + return t.getLogs(ctx, h) } // getLogs returns log objects for the given tx. // Assumes block hash is resolved. -func (t *Transaction) getLogs(ctx context.Context) (*[]*Log, error) { +func (t *Transaction) getLogs(ctx context.Context, hash common.Hash) (*[]*Log, error) { var ( - hash, _ = t.block.numberOrHash.Hash() filter = t.r.filterSystem.NewBlockFilter(hash, nil, nil) logs, err = filter.Logs(ctx) ) @@ -494,7 +518,7 @@ func (t *Transaction) getLogs(ctx context.Context) (*[]*Log, error) { } func (t *Transaction) Type(ctx context.Context) (*int32, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil { return nil, err } @@ -503,7 +527,7 @@ func (t *Transaction) Type(ctx context.Context) (*int32, error) { } func (t *Transaction) AccessList(ctx context.Context) (*[]*AccessTuple, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } @@ -519,7 +543,7 @@ func (t *Transaction) AccessList(ctx context.Context) (*[]*AccessTuple, error) { } func (t *Transaction) R(ctx context.Context) (hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Big{}, err } @@ -528,7 +552,7 @@ func (t *Transaction) R(ctx context.Context) (hexutil.Big, error) { } func (t *Transaction) S(ctx context.Context) (hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Big{}, err } @@ -537,7 +561,7 @@ func (t *Transaction) S(ctx context.Context) (hexutil.Big, error) { } func (t *Transaction) V(ctx context.Context) (hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Big{}, err } @@ -546,7 +570,7 @@ func (t *Transaction) V(ctx context.Context) (hexutil.Big, error) { } func (t *Transaction) Raw(ctx context.Context) (hexutil.Bytes, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Bytes{}, err } @@ -568,16 +592,20 @@ type BlockType int // when required. type Block struct { r *Resolver - numberOrHash *rpc.BlockNumberOrHash - hash common.Hash - header *types.Header - block *types.Block - receipts []*types.Receipt + numberOrHash *rpc.BlockNumberOrHash // Field resolvers assume numberOrHash is always present + mu sync.Mutex + // mu protects following resources + hash common.Hash // Must be resolved during initialization + header *types.Header + block *types.Block + receipts []*types.Receipt } // resolve returns the internal Block object representing this block, fetching // it if necessary. func (b *Block) resolve(ctx context.Context) (*types.Block, error) { + b.mu.Lock() + defer b.mu.Unlock() if b.block != nil { return b.block, nil } @@ -587,10 +615,10 @@ func (b *Block) resolve(ctx context.Context) (*types.Block, error) { } var err error b.block, err = b.r.backend.BlockByNumberOrHash(ctx, *b.numberOrHash) - if b.block != nil && b.header == nil { - b.header = b.block.Header() - if hash, ok := b.numberOrHash.Hash(); ok { - b.hash = hash + if b.block != nil { + b.hash = b.block.Hash() + if b.header == nil { + b.header = b.block.Header() } } return b.block, err @@ -600,39 +628,39 @@ func (b *Block) resolve(ctx context.Context) (*types.Block, error) { // if necessary. Call this function instead of `resolve` unless you need the // additional data (transactions and uncles). func (b *Block) resolveHeader(ctx context.Context) (*types.Header, error) { + b.mu.Lock() + defer b.mu.Unlock() + if b.header != nil { + return b.header, nil + } if b.numberOrHash == nil && b.hash == (common.Hash{}) { return nil, errBlockInvariant } var err error - if b.header == nil { - if b.hash != (common.Hash{}) { - b.header, err = b.r.backend.HeaderByHash(ctx, b.hash) - } else { - b.header, err = b.r.backend.HeaderByNumberOrHash(ctx, *b.numberOrHash) - } + b.header, err = b.r.backend.HeaderByNumberOrHash(ctx, *b.numberOrHash) + if err != nil { + return nil, err + } + if b.hash == (common.Hash{}) { + b.hash = b.header.Hash() } - return b.header, err + return b.header, nil } // resolveReceipts returns the list of receipts for this block, fetching them // if necessary. func (b *Block) resolveReceipts(ctx context.Context) ([]*types.Receipt, error) { - if b.receipts == nil { - hash := b.hash - if hash == (common.Hash{}) { - header, err := b.resolveHeader(ctx) - if err != nil { - return nil, err - } - hash = header.Hash() - } - receipts, err := b.r.backend.GetReceipts(ctx, hash) - if err != nil { - return nil, err - } - b.receipts = receipts + b.mu.Lock() + defer b.mu.Unlock() + if b.receipts != nil { + return b.receipts, nil } - return b.receipts, nil + receipts, err := b.r.backend.GetReceipts(ctx, b.hash) + if err != nil { + return nil, err + } + b.receipts = receipts + return receipts, nil } func (b *Block) Number(ctx context.Context) (Long, error) { @@ -645,13 +673,8 @@ func (b *Block) Number(ctx context.Context) (Long, error) { } func (b *Block) Hash(ctx context.Context) (common.Hash, error) { - if b.hash == (common.Hash{}) { - header, err := b.resolveHeader(ctx) - if err != nil { - return common.Hash{}, err - } - b.hash = header.Hash() - } + b.mu.Lock() + defer b.mu.Unlock() return b.hash, nil } @@ -705,11 +728,18 @@ func (b *Block) Parent(ctx context.Context) (*Block, error) { if b.header == nil || b.header.Number.Uint64() < 1 { return nil, nil } - num := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(b.header.Number.Uint64() - 1)) + var ( + num = rpc.BlockNumber(b.header.Number.Uint64() - 1) + hash = b.header.ParentHash + numOrHash = rpc.BlockNumberOrHash{ + BlockNumber: &num, + BlockHash: &hash, + } + ) return &Block{ r: b.r, - numberOrHash: &num, - hash: b.header.ParentHash, + numberOrHash: &numOrHash, + hash: hash, }, nil } @@ -798,6 +828,7 @@ func (b *Block) Ommers(ctx context.Context) (*[]*Block, error) { r: b.r, numberOrHash: &blockNumberOrHash, header: uncle, + hash: uncle.Hash(), }) } return &ret, nil @@ -820,17 +851,13 @@ func (b *Block) LogsBloom(ctx context.Context) (hexutil.Bytes, error) { } func (b *Block) TotalDifficulty(ctx context.Context) (hexutil.Big, error) { - h := b.hash - if h == (common.Hash{}) { - header, err := b.resolveHeader(ctx) - if err != nil { - return hexutil.Big{}, err - } - h = header.Hash() + hash, err := b.Hash(ctx) + if err != nil { + return hexutil.Big{}, err } - td := b.r.backend.GetTd(ctx, h) + td := b.r.backend.GetTd(ctx, hash) if td == nil { - return hexutil.Big{}, fmt.Errorf("total difficulty not found %x", b.hash) + return hexutil.Big{}, fmt.Errorf("total difficulty not found %x", hash) } return hexutil.Big(*td), nil } @@ -948,6 +975,7 @@ func (b *Block) OmmerAt(ctx context.Context, args struct{ Index int32 }) (*Block r: b.r, numberOrHash: &blockNumberOrHash, header: uncle, + hash: uncle.Hash(), }, nil } @@ -997,15 +1025,11 @@ func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteri if args.Filter.Topics != nil { topics = *args.Filter.Topics } - hash := b.hash - if hash == (common.Hash{}) { - header, err := b.resolveHeader(ctx) - if err != nil { - return nil, err - } - hash = header.Hash() - } // Construct the range filter + hash, err := b.Hash(ctx) + if err != nil { + return nil, err + } filter := b.r.filterSystem.NewBlockFilter(hash, addresses, topics) // Run the filter and return all the logs @@ -1015,12 +1039,6 @@ func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteri func (b *Block) Account(ctx context.Context, args struct { Address common.Address }) (*Account, error) { - if b.numberOrHash == nil { - _, err := b.resolveHeader(ctx) - if err != nil { - return nil, err - } - } return &Account{ r: b.r, address: args.Address, @@ -1063,12 +1081,6 @@ func (c *CallResult) Status() Long { func (b *Block) Call(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (*CallResult, error) { - if b.numberOrHash == nil { - _, err := b.resolve(ctx) - if err != nil { - return nil, err - } - } result, err := ethapi.DoCall(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCEVMTimeout(), b.r.backend.RPCGasCap()) if err != nil { return nil, err @@ -1088,12 +1100,6 @@ func (b *Block) Call(ctx context.Context, args struct { func (b *Block) EstimateGas(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (Long, error) { - if b.numberOrHash == nil { - _, err := b.resolveHeader(ctx) - if err != nil { - return 0, err - } - } gas, err := ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, b.r.backend.RPCGasCap()) return Long(gas), err } @@ -1173,29 +1179,21 @@ func (r *Resolver) Block(ctx context.Context, args struct { Number *Long Hash *common.Hash }) (*Block, error) { - var block *Block + var numberOrHash rpc.BlockNumberOrHash if args.Number != nil { if *args.Number < 0 { return nil, nil } number := rpc.BlockNumber(*args.Number) - numberOrHash := rpc.BlockNumberOrHashWithNumber(number) - block = &Block{ - r: r, - numberOrHash: &numberOrHash, - } + numberOrHash = rpc.BlockNumberOrHashWithNumber(number) } else if args.Hash != nil { - numberOrHash := rpc.BlockNumberOrHashWithHash(*args.Hash, false) - block = &Block{ - r: r, - numberOrHash: &numberOrHash, - } + numberOrHash = rpc.BlockNumberOrHashWithHash(*args.Hash, false) } else { - numberOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) - block = &Block{ - r: r, - numberOrHash: &numberOrHash, - } + numberOrHash = rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) + } + block := &Block{ + r: r, + numberOrHash: &numberOrHash, } // Resolve the header, return nil if it doesn't exist. // Note we don't resolve block directly here since it will require an @@ -1256,7 +1254,7 @@ func (r *Resolver) Transaction(ctx context.Context, args struct{ Hash common.Has hash: args.Hash, } // Resolve the transaction; if it doesn't exist, return nil. - t, err := tx.resolve(ctx) + t, _, err := tx.resolve(ctx) if err != nil { return nil, err } else if t == nil { diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 30b4e7c354..9354eac0f3 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -270,7 +270,7 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) { assert.Equal(t, http.StatusNotFound, resp.StatusCode) } -func TestGraphQLTransactionLogs(t *testing.T) { +func TestGraphQLConcurrentResolvers(t *testing.T) { var ( key, _ = crypto.GenerateKey() addr = crypto.PubkeyToAddress(key.PublicKey) @@ -295,8 +295,9 @@ func TestGraphQLTransactionLogs(t *testing.T) { ) defer stack.Close() - handler := newGQLService(t, stack, genesis, 1, func(i int, gen *core.BlockGen) { - tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) + var tx *types.Transaction + handler, chain := newGQLService(t, stack, genesis, 1, func(i int, gen *core.BlockGen) { + tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) gen.AddTx(tx) tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Nonce: 1, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) gen.AddTx(tx) @@ -307,18 +308,59 @@ func TestGraphQLTransactionLogs(t *testing.T) { if err := stack.Start(); err != nil { t.Fatalf("could not start node: %v", err) } - query := `{block { transactions { logs { account { address } } } } }` - res := handler.Schema.Exec(context.Background(), query, "", map[string]interface{}{}) - if res.Errors != nil { - t.Fatalf("graphql query failed: %v", res.Errors) - } - have, err := json.Marshal(res.Data) - if err != nil { - t.Fatalf("failed to encode graphql response: %s", err) - } - want := fmt.Sprintf(`{"block":{"transactions":[{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]},{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]},{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]}]}}`, dadStr, dadStr, dadStr, dadStr, dadStr, dadStr) - if string(have) != want { - t.Errorf("response unmatch. expected %s, got %s", want, have) + + for i, tt := range []struct { + body string + want string + }{ + // Multiple txes race to get/set the block hash. + { + body: "{block { transactions { logs { account { address } } } } }", + want: fmt.Sprintf(`{"block":{"transactions":[{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]},{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]},{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]}]}}`, dadStr, dadStr, dadStr, dadStr, dadStr, dadStr), + }, + // Multiple fields of a tx race to resolve it. Happens in this case + // because resolving the tx body belonging to a log is delayed. + { + body: `{block { logs(filter: {}) { transaction { nonce value gasPrice }}}}`, + want: `{"block":{"logs":[{"transaction":{"nonce":"0x0","value":"0x0","gasPrice":"0x3b9aca00"}},{"transaction":{"nonce":"0x0","value":"0x0","gasPrice":"0x3b9aca00"}},{"transaction":{"nonce":"0x1","value":"0x0","gasPrice":"0x3b9aca00"}},{"transaction":{"nonce":"0x1","value":"0x0","gasPrice":"0x3b9aca00"}},{"transaction":{"nonce":"0x2","value":"0x0","gasPrice":"0x3b9aca00"}},{"transaction":{"nonce":"0x2","value":"0x0","gasPrice":"0x3b9aca00"}}]}}`, + }, + // Multiple txes of a block race to set/retrieve receipts of a block. + { + body: "{block { transactions { status gasUsed } } }", + want: `{"block":{"transactions":[{"status":1,"gasUsed":21768},{"status":1,"gasUsed":21768},{"status":1,"gasUsed":21768}]}}`, + }, + // Multiple fields of block race to resolve header and body. + { + body: "{ block { number hash gasLimit ommerCount transactionCount totalDifficulty } }", + want: fmt.Sprintf(`{"block":{"number":1,"hash":"%s","gasLimit":11500000,"ommerCount":0,"transactionCount":3,"totalDifficulty":"0x200000"}}`, chain[len(chain)-1].Hash()), + }, + // Multiple fields of a block race to resolve the header and body. + { + body: fmt.Sprintf(`{ transaction(hash: "%s") { block { number hash gasLimit ommerCount transactionCount } } }`, tx.Hash()), + want: fmt.Sprintf(`{"transaction":{"block":{"number":1,"hash":"%s","gasLimit":11500000,"ommerCount":0,"transactionCount":3}}}`, chain[len(chain)-1].Hash()), + }, + // Account fields race the resolve the state object. + { + body: fmt.Sprintf(`{ block { account(address: "%s") { balance transactionCount code } } }`, dadStr), + want: `{"block":{"account":{"balance":"0x0","transactionCount":"0x0","code":"0x60006000a060006000a060006000f3"}}}`, + }, + // Test values for a non-existent account. + { + body: fmt.Sprintf(`{ block { account(address: "%s") { balance transactionCount code } } }`, "0x1111111111111111111111111111111111111111"), + want: `{"block":{"account":{"balance":"0x0","transactionCount":"0x0","code":"0x"}}}`, + }, + } { + res := handler.Schema.Exec(context.Background(), tt.body, "", map[string]interface{}{}) + if res.Errors != nil { + t.Fatalf("failed to execute query for testcase #%d: %v", i, res.Errors) + } + have, err := json.Marshal(res.Data) + if err != nil { + t.Fatalf("failed to encode graphql response for testcase #%d: %s", i, err) + } + if string(have) != tt.want { + t.Errorf("response unmatch for testcase #%d.\nExpected:\n%s\nGot:\n%s\n", i, tt.want, have) + } } } @@ -336,7 +378,7 @@ func createNode(t *testing.T) *node.Node { return stack } -func newGQLService(t *testing.T, stack *node.Node, gspec *core.Genesis, genBlocks int, genfunc func(i int, gen *core.BlockGen)) *handler { +func newGQLService(t *testing.T, stack *node.Node, gspec *core.Genesis, genBlocks int, genfunc func(i int, gen *core.BlockGen)) (*handler, []*types.Block) { ethConf := ðconfig.Config{ Genesis: gspec, Ethash: ethash.Config{ @@ -367,5 +409,5 @@ func newGQLService(t *testing.T, stack *node.Node, gspec *core.Genesis, genBlock if err != nil { t.Fatalf("could not create graphql service: %v", err) } - return handler + return handler, chain } From fd94b4fcfa244179c0500b70fb2944cb686b9ca4 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 28 Mar 2023 02:46:53 -0700 Subject: [PATCH 022/988] eth/tracers/native: prevent panic for LOG edge-cases (#26848) This PR fixes OOM panic in the callTracer as well as panicing on opcode validation errors (e.g. stack underflow) in callTracer and prestateTracer. Co-authored-by: Martin Holst Swende --- .../internal/tracetest/calltrace_test.go | 181 +++++++++++------- eth/tracers/js/goja.go | 21 +- eth/tracers/js/tracer_test.go | 4 +- eth/tracers/native/call.go | 11 +- eth/tracers/native/prestate.go | 3 + eth/tracers/tracers.go | 25 +++ eth/tracers/tracers_test.go | 38 ++++ 7 files changed, 194 insertions(+), 89 deletions(-) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 62182e3a82..c5405e2451 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" @@ -260,75 +259,121 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { } } -// TestZeroValueToNotExitCall tests the calltracer(s) on the following: -// Tx to A, A calls B with zero value. B does not already exist. -// Expected: that enter/exit is invoked and the inner call is shown in the result -func TestZeroValueToNotExitCall(t *testing.T) { - var to = common.HexToAddress("0x00000000000000000000000000000000deadbeef") - privkey, err := crypto.HexToECDSA("0000000000000000deadbeef00000000000000000000000000000000deadbeef") - if err != nil { - t.Fatalf("err %v", err) - } - signer := types.NewEIP155Signer(big.NewInt(1)) - tx, err := types.SignNewTx(privkey, signer, &types.LegacyTx{ - GasPrice: big.NewInt(0), - Gas: 50000, - To: &to, - }) - if err != nil { - t.Fatalf("err %v", err) - } - origin, _ := signer.Sender(tx) - txContext := vm.TxContext{ - Origin: origin, - GasPrice: big.NewInt(1), - } - context := vm.BlockContext{ - CanTransfer: core.CanTransfer, - Transfer: core.Transfer, - Coinbase: common.Address{}, - BlockNumber: new(big.Int).SetUint64(8000000), - Time: 5, - Difficulty: big.NewInt(0x30000), - GasLimit: uint64(6000000), - } - var code = []byte{ - byte(vm.PUSH1), 0x0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), // in and outs zero - byte(vm.DUP1), byte(vm.PUSH1), 0xff, byte(vm.GAS), // value=0,address=0xff, gas=GAS - byte(vm.CALL), +func TestInternals(t *testing.T) { + var ( + to = common.HexToAddress("0x00000000000000000000000000000000deadbeef") + origin = common.HexToAddress("0x00000000000000000000000000000000feed") + txContext = vm.TxContext{ + Origin: origin, + GasPrice: big.NewInt(1), + } + context = vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + Coinbase: common.Address{}, + BlockNumber: new(big.Int).SetUint64(8000000), + Time: 5, + Difficulty: big.NewInt(0x30000), + GasLimit: uint64(6000000), + } + ) + mkTracer := func(name string, cfg json.RawMessage) tracers.Tracer { + tr, err := tracers.DefaultDirectory.New(name, nil, cfg) + if err != nil { + t.Fatalf("failed to create call tracer: %v", err) + } + return tr } - var alloc = core.GenesisAlloc{ - to: core.GenesisAccount{ - Nonce: 1, - Code: code, + + for _, tc := range []struct { + name string + code []byte + tracer tracers.Tracer + want string + }{ + { + // TestZeroValueToNotExitCall tests the calltracer(s) on the following: + // Tx to A, A calls B with zero value. B does not already exist. + // Expected: that enter/exit is invoked and the inner call is shown in the result + name: "ZeroValueToNotExitCall", + code: []byte{ + byte(vm.PUSH1), 0x0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), // in and outs zero + byte(vm.DUP1), byte(vm.PUSH1), 0xff, byte(vm.GAS), // value=0,address=0xff, gas=GAS + byte(vm.CALL), + }, + tracer: mkTracer("callTracer", nil), + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x7148","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, }, - origin: core.GenesisAccount{ - Nonce: 0, - Balance: big.NewInt(500000000000000), + { + name: "Stack depletion in LOG0", + code: []byte{byte(vm.LOG3)}, + tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x7148","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, }, - } - _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false) - // Create the tracer, the EVM environment and run it - tracer, err := tracers.DefaultDirectory.New("callTracer", nil, nil) - if err != nil { - t.Fatalf("failed to create call tracer: %v", err) - } - evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) - msg, err := core.TransactionToMessage(tx, signer, nil) - if err != nil { - t.Fatalf("failed to prepare transaction for tracing: %v", err) - } - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) - if _, err = st.TransitionDb(); err != nil { - t.Fatalf("failed to execute transaction: %v", err) - } - // Retrieve the trace result and compare against the etalon - res, err := tracer.GetResult() - if err != nil { - t.Fatalf("failed to retrieve trace result: %v", err) - } - wantStr := `{"from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","gas":"0x7148","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}` - if string(res) != wantStr { - t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), wantStr) + { + name: "Mem expansion in LOG0", + code: []byte{ + byte(vm.PUSH1), 0x1, + byte(vm.PUSH1), 0x0, + byte(vm.MSTORE), + byte(vm.PUSH1), 0xff, + byte(vm.PUSH1), 0x0, + byte(vm.LOG0), + }, + tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x7148","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`, + }, + { + // Leads to OOM on the prestate tracer + name: "Prestate-tracer - mem expansion in CREATE2", + code: []byte{ + byte(vm.PUSH1), 0x1, + byte(vm.PUSH1), 0x0, + byte(vm.MSTORE), + byte(vm.PUSH1), 0x1, + byte(vm.PUSH5), 0xff, 0xff, 0xff, 0xff, 0xff, + byte(vm.PUSH1), 0x1, + byte(vm.PUSH1), 0x0, + byte(vm.CREATE2), + byte(vm.PUSH1), 0xff, + byte(vm.PUSH1), 0x0, + byte(vm.LOG0), + }, + tracer: mkTracer("prestateTracer", json.RawMessage(`{ "withLog": true }`)), + want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52640350"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"}}`, + }, + } { + _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), + core.GenesisAlloc{ + to: core.GenesisAccount{ + Code: tc.code, + }, + origin: core.GenesisAccount{ + Balance: big.NewInt(500000000000000), + }, + }, false) + evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tc.tracer}) + msg := &core.Message{ + To: &to, + From: origin, + Value: big.NewInt(0), + GasLimit: 50000, + GasPrice: big.NewInt(0), + GasFeeCap: big.NewInt(0), + GasTipCap: big.NewInt(0), + SkipAccountChecks: false, + } + st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) + if _, err := st.TransitionDb(); err != nil { + t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err) + } + // Retrieve the trace result and compare against the expected + res, err := tc.tracer.GetResult() + if err != nil { + t.Fatalf("test %v: failed to retrieve trace result: %v", tc.name, err) + } + if string(res) != tc.want { + t.Fatalf("test %v: trace mismatch\n have: %v\n want: %v\n", tc.name, string(res), tc.want) + } } } diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 8e52f5b210..33298f3097 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -32,10 +32,6 @@ import ( jsassets "github.com/ethereum/go-ethereum/eth/tracers/js/internal/tracers" ) -const ( - memoryPadLimit = 1024 * 1024 -) - var assetTracers = make(map[string]string) // init retrieves the JavaScript transaction tracers included in go-ethereum. @@ -571,14 +567,10 @@ func (mo *memoryObj) slice(begin, end int64) ([]byte, error) { if end < begin || begin < 0 { return nil, fmt.Errorf("tracer accessed out of bound memory: offset %d, end %d", begin, end) } - mlen := mo.memory.Len() - if end-int64(mlen) > memoryPadLimit { - return nil, fmt.Errorf("tracer reached limit for padding memory slice: end %d, memorySize %d", end, mlen) + slice, err := tracers.GetMemoryCopyPadded(mo.memory, begin, end-begin) + if err != nil { + return nil, err } - slice := make([]byte, end-begin) - end = min(end, int64(mo.memory.Len())) - ptr := mo.memory.GetPtr(begin, end-begin) - copy(slice[:], ptr[:]) return slice, nil } @@ -959,10 +951,3 @@ func (l *steplog) setupObject() *goja.Object { o.Set("contract", l.contract.setupObject()) return o } - -func min(a, b int64) int64 { - if a < b { - return a - } - return b -} diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 524d174749..1f37537211 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -150,12 +150,12 @@ func TestTracer(t *testing.T) { }, { code: "{res: [], step: function(log) { if (log.op.toString() === 'STOP') { this.res.push(log.memory.slice(5, 1025 * 1024)) } }, fault: function() {}, result: function() { return this.res }}", want: "", - fail: "tracer reached limit for padding memory slice: end 1049600, memorySize 32 at step (:1:83(20)) in server-side tracer function 'step'", + fail: "reached limit for padding memory slice: 1049568 at step (:1:83(20)) in server-side tracer function 'step'", contract: []byte{byte(vm.PUSH1), byte(0xff), byte(vm.PUSH1), byte(0x00), byte(vm.MSTORE8), byte(vm.STOP)}, }, } { if have, err := execTracer(tt.code, tt.contract); tt.want != string(have) || tt.fail != err { - t.Errorf("testcase %d: expected return value to be '%s' got '%s', error to be '%s' got '%s'\n\tcode: %v", i, tt.want, string(have), tt.fail, err, tt.code) + t.Errorf("testcase %d: expected return value to be \n'%s'\n\tgot\n'%s'\nerror to be\n'%s'\n\tgot\n'%s'\n\tcode: %v", i, tt.want, string(have), tt.fail, err, tt.code) } } } diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 02ee152a5a..88fc2be40c 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -148,6 +148,10 @@ func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { // CaptureState implements the EVMLogger interface to trace a single step of VM execution. func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { + // skip if the previous op caused an error + if err != nil { + return + } // Only logs need to be captured via opcode processing if !t.config.WithLog { return @@ -176,7 +180,12 @@ func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco topics[i] = common.Hash(topic.Bytes32()) } - data := scope.Memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64())) + data, err := tracers.GetMemoryCopyPadded(scope.Memory, int64(mStart.Uint64()), int64(mSize.Uint64())) + if err != nil { + // mSize was unrealistically large + return + } + log := callLog{Address: scope.Contract.Address(), Topics: topics, Data: hexutil.Bytes(data)} t.callstack[len(t.callstack)-1].Logs = append(t.callstack[len(t.callstack)-1].Logs, log) } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 948d09ef76..42ec4fe782 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -133,6 +133,9 @@ func (t *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { // CaptureState implements the EVMLogger interface to trace a single step of VM execution. func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { + if err != nil { + return + } stack := scope.Stack stackData := stack.Data() stackLen := len(stackData) diff --git a/eth/tracers/tracers.go b/eth/tracers/tracers.go index 856f52a10d..023f73ef37 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/tracers.go @@ -19,6 +19,7 @@ package tracers import ( "encoding/json" + "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -95,3 +96,27 @@ func (d *directory) IsJS(name string) bool { // JS eval will execute JS code return true } + +const ( + memoryPadLimit = 1024 * 1024 +) + +// GetMemoryCopyPadded returns offset + size as a new slice. +// It zero-pads the slice if it extends beyond memory bounds. +func GetMemoryCopyPadded(m *vm.Memory, offset, size int64) ([]byte, error) { + if offset < 0 || size < 0 { + return nil, fmt.Errorf("offset or size must not be negative") + } + if int(offset+size) < m.Len() { // slice fully inside memory + return m.GetCopy(offset, size), nil + } + paddingNeeded := int(offset+size) - m.Len() + if paddingNeeded > memoryPadLimit { + return nil, fmt.Errorf("reached limit for padding memory slice: %d", paddingNeeded) + } + cpy := make([]byte, size) + if overlap := int64(m.Len()) - offset; overlap > 0 { + copy(cpy, m.GetPtr(offset, overlap)) + } + return cpy, nil +} diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 7c5ec65650..46182db48b 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -109,3 +109,41 @@ func BenchmarkTransactionTrace(b *testing.B) { tracer.Reset() } } + +func TestMemCopying(t *testing.T) { + for i, tc := range []struct { + memsize int64 + offset int64 + size int64 + wantErr string + wantSize int + }{ + {0, 0, 100, "", 100}, // Should pad up to 100 + {0, 100, 0, "", 0}, // No need to pad (0 size) + {100, 50, 100, "", 100}, // Should pad 100-150 + {100, 50, 5, "", 5}, // Wanted range fully within memory + {100, -50, 0, "offset or size must not be negative", 0}, // Errror + {0, 1, 1024*1024 + 1, "reached limit for padding memory slice: 1048578", 0}, // Errror + {10, 0, 1024*1024 + 100, "reached limit for padding memory slice: 1048666", 0}, // Errror + + } { + mem := vm.NewMemory() + mem.Resize(uint64(tc.memsize)) + cpy, err := GetMemoryCopyPadded(mem, tc.offset, tc.size) + if want := tc.wantErr; want != "" { + if err == nil { + t.Fatalf("test %d: want '%v' have no error", i, want) + } + if have := err.Error(); want != have { + t.Fatalf("test %d: want '%v' have '%v'", i, want, have) + } + continue + } + if err != nil { + t.Fatalf("test %d: unexpected error: %v", i, err) + } + if want, have := tc.wantSize, len(cpy); have != want { + t.Fatalf("test %d: want %v have %v", i, want, have) + } + } +} From 56c1f98f8acfcc79e4348ba3aeecd3ea2e0c9a84 Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Tue, 28 Mar 2023 22:37:40 +1000 Subject: [PATCH 023/988] internal/debug: add log.logfmt flag to set logging to use logfmt (#26970) --- internal/debug/flags.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index e014a85d7f..0bae9883ec 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -54,6 +54,11 @@ var ( Usage: "Format logs with JSON", Category: flags.LoggingCategory, } + logfmtFlag = &cli.BoolFlag{ + Name: "log.logfmt", + Usage: "Format logs with logfmt", + Category: flags.LoggingCategory, + } logFileFlag = &cli.StringFlag{ Name: "log.file", Usage: "Write logs to a file", @@ -115,6 +120,7 @@ var Flags = []cli.Flag{ verbosityFlag, vmoduleFlag, logjsonFlag, + logfmtFlag, logFileFlag, backtraceAtFlag, debugFlag, @@ -147,6 +153,8 @@ func Setup(ctx *cli.Context) error { var logfmt log.Format if ctx.Bool(logjsonFlag.Name) { logfmt = log.JSONFormat() + } else if ctx.Bool(logfmtFlag.Name) { + logfmt = log.LogfmtFormat() } else { logfmt = log.TerminalFormat(useColor) } From 7ca4f60a1abd2a8c9df2ed9ae35a891b0ac9e464 Mon Sep 17 00:00:00 2001 From: David Murdoch <187813+davidmurdoch@users.noreply.github.com> Date: Tue, 28 Mar 2023 08:59:37 -0400 Subject: [PATCH 024/988] docs: update outdated DeriveSha docs comment (#26968) --- core/types/hashing.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/types/hashing.go b/core/types/hashing.go index 3df75432a4..71295c107c 100644 --- a/core/types/hashing.go +++ b/core/types/hashing.go @@ -83,7 +83,7 @@ func encodeForDerive(list DerivableList, i int, buf *bytes.Buffer) []byte { return common.CopyBytes(buf.Bytes()) } -// DeriveSha creates the tree hashes of transactions and receipts in a block header. +// DeriveSha creates the tree hashes of transactions, receipts, and withdrawals in a block header. func DeriveSha(list DerivableList, hasher TrieHasher) common.Hash { hasher.Reset() From a03490c6b2ff0e1d9a1274afdbe087a695d533eb Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 30 Mar 2023 10:58:23 +0200 Subject: [PATCH 025/988] remove @gballet as a GraphQL codeowner (#27012) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 780f2a800e..faf922df01 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -10,7 +10,7 @@ core/ @karalabe @holiman @rjl493456442 eth/ @karalabe @holiman @rjl493456442 eth/catalyst/ @gballet eth/tracers/ @s1na -graphql/ @gballet @s1na +graphql/ @s1na les/ @zsfelfoldi @rjl493456442 light/ @zsfelfoldi @rjl493456442 node/ @fjl From 949cee2fe343532a2fb9cd4a5edebfedae86a371 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Thu, 30 Mar 2023 18:53:32 +0800 Subject: [PATCH 026/988] core: use atomic type (#27011) --- core/blockchain.go | 28 ++++++++++++++-------------- core/chain_indexer.go | 6 +++--- core/state_prefetcher.go | 4 ++-- core/types.go | 4 +++- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 8fc520e776..d7094c516a 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -174,7 +174,7 @@ type BlockChain struct { triegc *prque.Prque[int64, common.Hash] // Priority queue mapping block numbers to tries to gc gcproc time.Duration // Accumulates canonical block processing for trie dumping lastWrite uint64 // Last block when the state was flushed - flushInterval int64 // Time interval (processing time) after which to flush a state + flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state triedb *trie.Database // The database handler for maintaining trie nodes. stateCache state.Database // State database to reuse between imports (contains state cache) @@ -215,8 +215,8 @@ type BlockChain struct { wg sync.WaitGroup // quit chan struct{} // shutdown signal, closed in Stop. - running int32 // 0 if chain is running, 1 when stopped - procInterrupt int32 // interrupt signaler for block processing + stopping atomic.Bool // false if chain is running, true when stopped + procInterrupt atomic.Bool // interrupt signaler for block processing engine consensus.Engine validator Validator // Block and state validator interface @@ -260,7 +260,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis cacheConfig: cacheConfig, db: db, triedb: triedb, - flushInterval: int64(cacheConfig.TrieTimeLimit), triegc: prque.New[int64, common.Hash](nil), quit: make(chan struct{}), chainmu: syncx.NewClosableMutex(), @@ -273,6 +272,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis engine: engine, vmConfig: vmConfig, } + bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) bc.forker = NewForkChoice(bc, shouldPreserve) bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) bc.validator = NewBlockValidator(chainConfig, bc, engine) @@ -916,7 +916,7 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) { // This method has been exposed to allow tests to stop the blockchain while simulating // a crash. func (bc *BlockChain) stopWithoutSaving() { - if !atomic.CompareAndSwapInt32(&bc.running, 0, 1) { + if !bc.stopping.CompareAndSwap(false, true) { return } @@ -998,12 +998,12 @@ func (bc *BlockChain) Stop() { // errInsertionInterrupted as soon as possible. Insertion is permanently disabled after // calling this method. func (bc *BlockChain) StopInsert() { - atomic.StoreInt32(&bc.procInterrupt, 1) + bc.procInterrupt.Store(true) } // insertStopped returns true after StopInsert has been called. func (bc *BlockChain) insertStopped() bool { - return atomic.LoadInt32(&bc.procInterrupt) == 1 + return bc.procInterrupt.Load() } func (bc *BlockChain) procFutureBlocks() { @@ -1382,7 +1382,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } // Find the next state trie we need to commit chosen := current - TriesInMemory - flushInterval := time.Duration(atomic.LoadInt64(&bc.flushInterval)) + flushInterval := time.Duration(bc.flushInterval.Load()) // If we exceeded time allowance, flush an entire trie to disk if bc.gcproc > flushInterval { // If the header is missing (canonical chain behind), we're reorging a low @@ -1735,7 +1735,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) // If we have a followup block, run that against the current state to pre-cache // transactions and probabilistically some of the account/storage trie nodes. - var followupInterrupt uint32 + var followupInterrupt atomic.Bool if !bc.cacheConfig.TrieCleanNoPrefetch { if followup, err := it.peek(); followup != nil && err == nil { throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps) @@ -1744,7 +1744,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt) blockPrefetchExecuteTimer.Update(time.Since(start)) - if atomic.LoadUint32(&followupInterrupt) == 1 { + if followupInterrupt.Load() { blockPrefetchInterruptMeter.Mark(1) } }(time.Now(), followup, throwaway) @@ -1756,7 +1756,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { bc.reportBlock(block, receipts, err) - atomic.StoreUint32(&followupInterrupt, 1) + followupInterrupt.Store(true) return it.index, err } ptime := time.Since(pstart) @@ -1764,7 +1764,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) vstart := time.Now() if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { bc.reportBlock(block, receipts, err) - atomic.StoreUint32(&followupInterrupt, 1) + followupInterrupt.Store(true) return it.index, err } vtime := time.Since(vstart) @@ -1797,7 +1797,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) } else { status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) } - atomic.StoreUint32(&followupInterrupt, 1) + followupInterrupt.Store(true) if err != nil { return it.index, err } @@ -2497,5 +2497,5 @@ func (bc *BlockChain) SetBlockValidatorAndProcessorForTesting(v Validator, p Pro // The interval is in terms of block processing time, not wall clock. // It is thread-safe and can be called repeatedly without side effects. func (bc *BlockChain) SetTrieFlushInterval(interval time.Duration) { - atomic.StoreInt64(&bc.flushInterval, int64(interval)) + bc.flushInterval.Store(int64(interval)) } diff --git a/core/chain_indexer.go b/core/chain_indexer.go index 95901a0eaa..23ab23ef0f 100644 --- a/core/chain_indexer.go +++ b/core/chain_indexer.go @@ -75,7 +75,7 @@ type ChainIndexer struct { backend ChainIndexerBackend // Background processor generating the index data content children []*ChainIndexer // Child indexers to cascade chain updates to - active uint32 // Flag whether the event loop was started + active atomic.Bool // Flag whether the event loop was started update chan struct{} // Notification channel that headers should be processed quit chan chan error // Quit channel to tear down running goroutines ctx context.Context @@ -166,7 +166,7 @@ func (c *ChainIndexer) Close() error { errs = append(errs, err) } // If needed, tear down the secondary event loop - if atomic.LoadUint32(&c.active) != 0 { + if c.active.Load() { c.quit <- errc if err := <-errc; err != nil { errs = append(errs, err) @@ -196,7 +196,7 @@ func (c *ChainIndexer) Close() error { // queue. func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainHeadEvent, sub event.Subscription) { // Mark the chain indexer as active, requiring an additional teardown - atomic.StoreUint32(&c.active, 1) + c.active.Store(true) defer sub.Unsubscribe() diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index c258eee4f4..721f4056b2 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -47,7 +47,7 @@ func newStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine conse // Prefetch processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb, but any changes are discarded. The // only goal is to pre-cache transaction signatures and state trie nodes. -func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *uint32) { +func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *atomic.Bool) { var ( header = block.Header() gaspool = new(GasPool).AddGas(block.GasLimit()) @@ -59,7 +59,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c byzantium := p.config.IsByzantium(block.Number()) for i, tx := range block.Transactions() { // If block precaching was interrupted, abort - if interrupt != nil && atomic.LoadUint32(interrupt) == 1 { + if interrupt != nil && interrupt.Load() { return } // Convert the transaction into an executable message and pre-cache its sender diff --git a/core/types.go b/core/types.go index 4c5b74a498..36eb0d1ded 100644 --- a/core/types.go +++ b/core/types.go @@ -17,6 +17,8 @@ package core import ( + "sync/atomic" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -39,7 +41,7 @@ type Prefetcher interface { // Prefetch processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb, but any changes are discarded. The // only goal is to pre-cache transaction signatures and state trie nodes. - Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *uint32) + Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *atomic.Bool) } // Processor is an interface for processing blocks using a given initial state. From 62fb7d3f851aa8dda0b5abc7d761dd2fc7c499c2 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Thu, 30 Mar 2023 12:57:49 +0200 Subject: [PATCH 027/988] graphql: revert storage access regression (#27007) --- graphql/graphql.go | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 3c637d2d2c..45a1f7a2aa 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -81,26 +81,12 @@ type Account struct { r *Resolver address common.Address blockNrOrHash rpc.BlockNumberOrHash - state *state.StateDB - mu sync.Mutex } // getState fetches the StateDB object for an account. func (a *Account) getState(ctx context.Context) (*state.StateDB, error) { - a.mu.Lock() - defer a.mu.Unlock() - if a.state != nil { - return a.state, nil - } state, _, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash) - if err != nil { - return nil, err - } - a.state = state - // Cache the state object. This is done so that concurrent resolvers - // don't have to fetch the object from DB individually. - a.state.GetOrNewStateObject(a.address) - return a.state, nil + return state, err } func (a *Account) Address(ctx context.Context) (common.Address, error) { From 2d1492821d058a3488b4da2c1f62906eaf6d7c95 Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Thu, 30 Mar 2023 23:24:48 +1000 Subject: [PATCH 028/988] cmd/geth: Add `--log.format` cli param (#27001) Removes the new --log.logfmt directive and hides --log.json, replacing both with log.format=(json|logfmt|terminal). The hidden log.json option is still respected if log.format is not specified for backwards compatibility. Co-authored-by: Martin Holst Swende --- internal/debug/flags.go | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 0bae9883ec..068817d532 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -52,11 +52,12 @@ var ( logjsonFlag = &cli.BoolFlag{ Name: "log.json", Usage: "Format logs with JSON", + Hidden: true, Category: flags.LoggingCategory, } - logfmtFlag = &cli.BoolFlag{ - Name: "log.logfmt", - Usage: "Format logs with logfmt", + logFormatFlag = &cli.StringFlag{ + Name: "log.format", + Usage: "Log format to use (json|logfmt|terminal)", Category: flags.LoggingCategory, } logFileFlag = &cli.StringFlag{ @@ -120,7 +121,7 @@ var Flags = []cli.Flag{ verbosityFlag, vmoduleFlag, logjsonFlag, - logfmtFlag, + logFormatFlag, logFileFlag, backtraceAtFlag, debugFlag, @@ -151,12 +152,24 @@ func Setup(ctx *cli.Context) error { useColor := logFile == "" && os.Getenv("TERM") != "dumb" && (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) var logfmt log.Format - if ctx.Bool(logjsonFlag.Name) { + switch ctx.String(logFormatFlag.Name) { + case "json": logfmt = log.JSONFormat() - } else if ctx.Bool(logfmtFlag.Name) { + case "logfmt": logfmt = log.LogfmtFormat() - } else { + case "terminal": logfmt = log.TerminalFormat(useColor) + case "": + // Retain backwards compatibility with `--log.json` flag if `--log.format` not set + if ctx.Bool(logjsonFlag.Name) { + defer log.Warn("The flag '--log.json' is deprecated, please use '--log.format=json' instead") + logfmt = log.JSONFormat() + } else { + logfmt = log.TerminalFormat(useColor) + } + default: + // Unknown log format specified + return fmt.Errorf("unknown log format: %v", ctx.String(logFormatFlag.Name)) } if logFile != "" { From 50317bdacec8fc61f434c5b07ac77afed95e0c4a Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Fri, 31 Mar 2023 03:02:14 +0800 Subject: [PATCH 029/988] ethdb/pebble: use atomic type (#27014) --- ethdb/pebble/pebble.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 4e374c9e28..7c01b879b8 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -75,14 +75,14 @@ type Database struct { log log.Logger // Contextual logger tracking the database path - activeComp int // Current number of active compactions - compStartTime time.Time // The start time of the earliest currently-active compaction - compTime int64 // Total time spent in compaction in ns - level0Comp uint32 // Total number of level-zero compactions - nonLevel0Comp uint32 // Total number of non level-zero compactions - writeDelayStartTime time.Time // The start time of the latest write stall - writeDelayCount int64 // Total number of write stall counts - writeDelayTime int64 // Total time spent in write stalls + activeComp int // Current number of active compactions + compStartTime time.Time // The start time of the earliest currently-active compaction + compTime atomic.Int64 // Total time spent in compaction in ns + level0Comp atomic.Uint32 // Total number of level-zero compactions + nonLevel0Comp atomic.Uint32 // Total number of non level-zero compactions + writeDelayStartTime time.Time // The start time of the latest write stall + writeDelayCount atomic.Int64 // Total number of write stall counts + writeDelayTime atomic.Int64 // Total time spent in write stalls } func (d *Database) onCompactionBegin(info pebble.CompactionInfo) { @@ -91,16 +91,16 @@ func (d *Database) onCompactionBegin(info pebble.CompactionInfo) { } l0 := info.Input[0] if l0.Level == 0 { - atomic.AddUint32(&d.level0Comp, 1) + d.level0Comp.Add(1) } else { - atomic.AddUint32(&d.nonLevel0Comp, 1) + d.nonLevel0Comp.Add(1) } d.activeComp++ } func (d *Database) onCompactionEnd(info pebble.CompactionInfo) { if d.activeComp == 1 { - atomic.AddInt64(&d.compTime, int64(time.Since(d.compStartTime))) + d.compTime.Add(int64(time.Since(d.compStartTime))) } else if d.activeComp == 0 { panic("should not happen") } @@ -112,7 +112,7 @@ func (d *Database) onWriteStallBegin(b pebble.WriteStallBeginInfo) { } func (d *Database) onWriteStallEnd() { - atomic.AddInt64(&d.writeDelayTime, int64(time.Since(d.writeDelayStartTime))) + d.writeDelayTime.Add(int64(time.Since(d.writeDelayStartTime))) } // New returns a wrapped pebble DB object. The namespace is the prefix that the @@ -407,11 +407,11 @@ func (d *Database) meter(refresh time.Duration) { nWrite int64 metrics = d.db.Metrics() - compTime = atomic.LoadInt64(&d.compTime) - writeDelayCount = atomic.LoadInt64(&d.writeDelayCount) - writeDelayTime = atomic.LoadInt64(&d.writeDelayTime) - nonLevel0CompCount = int64(atomic.LoadUint32(&d.nonLevel0Comp)) - level0CompCount = int64(atomic.LoadUint32(&d.level0Comp)) + compTime = d.compTime.Load() + writeDelayCount = d.writeDelayCount.Load() + writeDelayTime = d.writeDelayTime.Load() + nonLevel0CompCount = int64(d.nonLevel0Comp.Load()) + level0CompCount = int64(d.level0Comp.Load()) ) writeDelayTimes[i%2] = writeDelayTime writeDelayCounts[i%2] = writeDelayCount From 9ce047452e35919b0c78ad9fc140f2644aab8a48 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 31 Mar 2023 03:04:28 +0800 Subject: [PATCH 030/988] common: fix json marshaller MixedcaseAddress (#26998) Fix the json marshaller of MixedcaseAddress --- common/types.go | 2 +- common/types_test.go | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/common/types.go b/common/types.go index 218ca0be4c..0b68a19dd3 100644 --- a/common/types.go +++ b/common/types.go @@ -400,7 +400,7 @@ func (ma *MixedcaseAddress) UnmarshalJSON(input []byte) error { } // MarshalJSON marshals the original value -func (ma *MixedcaseAddress) MarshalJSON() ([]byte, error) { +func (ma MixedcaseAddress) MarshalJSON() ([]byte, error) { if strings.HasPrefix(ma.original, "0x") || strings.HasPrefix(ma.original, "0X") { return json.Marshal(fmt.Sprintf("0x%s", ma.original[2:])) } diff --git a/common/types_test.go b/common/types_test.go index 94492278d8..88c642522d 100644 --- a/common/types_test.go +++ b/common/types_test.go @@ -154,6 +154,31 @@ func BenchmarkAddressHex(b *testing.B) { } } +// Test checks if the customized json marshaller of MixedcaseAddress object +// is invoked correctly. In golang the struct pointer will inherit the +// non-pointer receiver methods, the reverse is not true. In the case of +// MixedcaseAddress, it must define the MarshalJSON method in the object +// but not the pointer level, so that this customized marshalled can be used +// for both MixedcaseAddress object and pointer. +func TestMixedcaseAddressMarshal(t *testing.T) { + var ( + output string + input = "0xae967917c465db8578ca9024c205720b1a3651A9" + ) + addr, err := NewMixedcaseAddressFromString(input) + if err != nil { + t.Fatal(err) + } + blob, err := json.Marshal(*addr) + if err != nil { + t.Fatal(err) + } + json.Unmarshal(blob, &output) + if output != input { + t.Fatal("Failed to marshal/unmarshal MixedcaseAddress object") + } +} + func TestMixedcaseAccount_Address(t *testing.T) { // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md // Note: 0X{checksum_addr} is not valid according to spec above @@ -177,7 +202,7 @@ func TestMixedcaseAccount_Address(t *testing.T) { } } - //These should throw exceptions: + // These should throw exceptions: var r2 []MixedcaseAddress for _, r := range []string{ `["0x11111111111111111111122222222222233333"]`, // Too short From d0fbb10658a85f0b2bd4466892747758bacddaf7 Mon Sep 17 00:00:00 2001 From: openex Date: Fri, 31 Mar 2023 03:09:35 +0800 Subject: [PATCH 031/988] eth/catalyst: improve consensus heartbeat (#26896) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit improve the heartbeat function that is no longer suitable in the current situation Co-authored-by: “openex27†<“openexkevin@gmail.comâ€> --- eth/catalyst/api.go | 85 +++++---------------------------------------- 1 file changed, 8 insertions(+), 77 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 9077f20bff..1fe9842472 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -20,7 +20,6 @@ package catalyst import ( "errors" "fmt" - "math/big" "sync" "time" @@ -64,11 +63,6 @@ const ( // attached before starting to issue warnings. beaconUpdateStartupTimeout = 30 * time.Second - // beaconUpdateExchangeTimeout is the max time allowed for a beacon client to - // do a transition config exchange before it's considered offline and the user - // is warned. - beaconUpdateExchangeTimeout = 2 * time.Minute - // beaconUpdateConsensusTimeout is the max time allowed for a beacon client // to send a consensus update before it's considered offline and the user is // warned. @@ -667,14 +661,13 @@ func (api *ConsensusAPI) heartbeat() { // attached, so no need to print scary warnings to the user. time.Sleep(beaconUpdateStartupTimeout) - var ( - offlineLogged time.Time - ttd = api.eth.BlockChain().Config().TerminalTotalDifficulty - ) // If the network is not yet merged/merging, don't bother continuing. - if ttd == nil { + if api.eth.BlockChain().Config().TerminalTotalDifficulty == nil { return } + + var offlineLogged time.Time + for { // Sleep a bit and retrieve the last known consensus updates time.Sleep(5 * time.Second) @@ -698,20 +691,14 @@ func (api *ConsensusAPI) heartbeat() { offlineLogged = time.Time{} continue } - if time.Since(lastTransitionUpdate) > beaconUpdateExchangeTimeout { - if time.Since(offlineLogged) > beaconUpdateWarnFrequency { + + if time.Since(offlineLogged) > beaconUpdateWarnFrequency { + if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() { if lastTransitionUpdate.IsZero() { log.Warn("Post-merge network, but no beacon client seen. Please launch one to follow the chain!") } else { - log.Warn("Previously seen beacon client is offline. Please ensure it is operational to follow the chain!") + log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!") } - offlineLogged = time.Now() - } - continue - } - if time.Since(offlineLogged) > beaconUpdateWarnFrequency { - if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() { - log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!") } else { log.Warn("Beacon client online, but no consensus updates received in a while. Please fix your beacon client to follow the chain!") } @@ -719,62 +706,6 @@ func (api *ConsensusAPI) heartbeat() { } continue } - if time.Since(lastTransitionUpdate) <= beaconUpdateExchangeTimeout { - offlineLogged = time.Time{} - continue - } - if time.Since(offlineLogged) > beaconUpdateWarnFrequency { - // Retrieve the last few blocks and make a rough estimate as - // to when the merge transition should happen - var ( - chain = api.eth.BlockChain() - head = chain.CurrentHeader() - htd = chain.GetTd(head.Hash(), head.Number.Uint64()) - ) - if htd.Cmp(ttd) >= 0 { - if lastTransitionUpdate.IsZero() { - log.Warn("Merge already reached, but no beacon client seen. Please launch one to follow the chain!") - } else { - log.Warn("Merge already reached, but previously seen beacon client is offline. Please ensure it is operational to follow the chain!") - } - offlineLogged = time.Now() - continue - } - var eta time.Duration - if head.Number.Uint64() > 0 { - // Accumulate the last 64 difficulties to estimate the growth - var ( - deltaDiff uint64 - deltaTime uint64 - current = head - ) - for i := 0; i < 64; i++ { - parent := chain.GetHeader(current.ParentHash, current.Number.Uint64()-1) - if parent == nil { - break - } - deltaDiff += current.Difficulty.Uint64() - deltaTime += current.Time - parent.Time - current = parent - } - // Estimate an ETA based on the block times and the difficulty growth - if deltaTime > 0 { - growth := deltaDiff / deltaTime - left := new(big.Int).Sub(ttd, htd) - eta = time.Duration(new(big.Int).Div(left, new(big.Int).SetUint64(growth+1)).Uint64()) * time.Second - } - } - message := "Merge is configured, but previously seen beacon client is offline. Please ensure it is operational before the transition arrives!" - if lastTransitionUpdate.IsZero() { - message = "Merge is configured, but no beacon client seen. Please ensure you have one available before the transition arrives!" - } - if eta < time.Second { - log.Warn(message) - } else { - log.Warn(message, "eta", common.PrettyAge(time.Now().Add(-eta))) // weird hack, but duration formatted doesn't handle days - } - offlineLogged = time.Now() - } } } From b92d0ea3bbb04cbe99b57dd0934ad4dfba932a16 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Fri, 31 Mar 2023 14:32:47 +0800 Subject: [PATCH 032/988] miner: use atomic type (#27013) Use the new typed atomics in the miner package --- miner/worker.go | 46 ++++++++++++++++++++++---------------------- miner/worker_test.go | 6 +++--- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 67a5842d23..9fbece8658 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -164,7 +164,7 @@ const ( // newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. type newWorkReq struct { - interrupt *int32 + interrupt *atomic.Int32 noempty bool timestamp int64 } @@ -239,15 +239,15 @@ type worker struct { snapshotState *state.StateDB // atomic status counters - running int32 // The indicator whether the consensus engine is running or not. - newTxs int32 // New arrival transaction count since last sealing work submitting. + running atomic.Bool // The indicator whether the consensus engine is running or not. + newTxs atomic.Int32 // New arrival transaction count since last sealing work submitting. // noempty is the flag used to control whether the feature of pre-seal empty // block is enabled. The default value is false(pre-seal is enabled by default). // But in some special scenario the consensus engine will seal blocks instantaneously, // in this case this feature will add all empty blocks into canonical chain // non-stop and no real transaction will be included. - noempty uint32 + noempty atomic.Bool // newpayloadTimeout is the maximum timeout allowance for creating payload. // The default value is 2 seconds but node operator can set it to arbitrary @@ -372,12 +372,12 @@ func (w *worker) setRecommitInterval(interval time.Duration) { // disablePreseal disables pre-sealing feature func (w *worker) disablePreseal() { - atomic.StoreUint32(&w.noempty, 1) + w.noempty.Store(true) } // enablePreseal enables pre-sealing feature func (w *worker) enablePreseal() { - atomic.StoreUint32(&w.noempty, 0) + w.noempty.Store(false) } // pending returns the pending state and corresponding block. @@ -409,24 +409,24 @@ func (w *worker) pendingBlockAndReceipts() (*types.Block, types.Receipts) { // start sets the running status as 1 and triggers new work submitting. func (w *worker) start() { - atomic.StoreInt32(&w.running, 1) + w.running.Store(true) w.startCh <- struct{}{} } // stop sets the running status as 0. func (w *worker) stop() { - atomic.StoreInt32(&w.running, 0) + w.running.Store(false) } // isRunning returns an indicator whether worker is running or not. func (w *worker) isRunning() bool { - return atomic.LoadInt32(&w.running) == 1 + return w.running.Load() } // close terminates all background threads maintained by the worker. // Note the worker does not support being closed multiple times. func (w *worker) close() { - atomic.StoreInt32(&w.running, 0) + w.running.Store(false) close(w.exitCh) w.wg.Wait() } @@ -457,7 +457,7 @@ func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) t func (w *worker) newWorkLoop(recommit time.Duration) { defer w.wg.Done() var ( - interrupt *int32 + interrupt *atomic.Int32 minRecommit = recommit // minimal resubmit interval specified by user. timestamp int64 // timestamp for each round of sealing. ) @@ -469,16 +469,16 @@ func (w *worker) newWorkLoop(recommit time.Duration) { // commit aborts in-flight transaction execution with given signal and resubmits a new one. commit := func(noempty bool, s int32) { if interrupt != nil { - atomic.StoreInt32(interrupt, s) + interrupt.Store(s) } - interrupt = new(int32) + interrupt = new(atomic.Int32) select { case w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp}: case <-w.exitCh: return } timer.Reset(recommit) - atomic.StoreInt32(&w.newTxs, 0) + w.newTxs.Store(0) } // clearPending cleans the stale pending tasks. clearPending := func(number uint64) { @@ -508,7 +508,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { // higher priced transactions. Disable this overhead for pending blocks. if w.isRunning() && (w.chainConfig.Clique == nil || w.chainConfig.Clique.Period > 0) { // Short circuit if no new transaction arrives. - if atomic.LoadInt32(&w.newTxs) == 0 { + if w.newTxs.Load() == 0 { timer.Reset(recommit) continue } @@ -650,7 +650,7 @@ func (w *worker) mainLoop() { w.commitWork(nil, true, time.Now().Unix()) } } - atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) + w.newTxs.Add(int32(len(ev.Txs))) // System stopped case <-w.exitCh: @@ -877,7 +877,7 @@ func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]* return receipt.Logs, nil } -func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByPriceAndNonce, interrupt *int32) error { +func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByPriceAndNonce, interrupt *atomic.Int32) error { gasLimit := env.header.GasLimit if env.gasPool == nil { env.gasPool = new(core.GasPool).AddGas(gasLimit) @@ -887,7 +887,7 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP for { // Check interruption signal and abort building if it's fired. if interrupt != nil { - if signal := atomic.LoadInt32(interrupt); signal != commitInterruptNone { + if signal := interrupt.Load(); signal != commitInterruptNone { return signalToErr(signal) } } @@ -1067,7 +1067,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { // fillTransactions retrieves the pending transactions from the txpool and fills them // into the given sealing block. The transaction selection and ordering strategy can // be customized with the plugin in the future. -func (w *worker) fillTransactions(interrupt *int32, env *environment) error { +func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) error { // Split the pending transactions into locals and remotes // Fill the block with all available pending transactions. pending := w.eth.TxPool().Pending(true) @@ -1102,9 +1102,9 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, *big.Int, e defer work.discard() if !params.noTxs { - interrupt := new(int32) + interrupt := new(atomic.Int32) timer := time.AfterFunc(w.newpayloadTimeout, func() { - atomic.StoreInt32(interrupt, commitInterruptTimeout) + interrupt.Store(commitInterruptTimeout) }) defer timer.Stop() @@ -1122,7 +1122,7 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, *big.Int, e // commitWork generates several new sealing tasks based on the parent block // and submit them to the sealer. -func (w *worker) commitWork(interrupt *int32, noempty bool, timestamp int64) { +func (w *worker) commitWork(interrupt *atomic.Int32, noempty bool, timestamp int64) { start := time.Now() // Set the coinbase if the worker is running or it's required @@ -1143,7 +1143,7 @@ func (w *worker) commitWork(interrupt *int32, noempty bool, timestamp int64) { } // Create an empty block based on temporary copied state for // sealing in advance without waiting block execution finished. - if !noempty && atomic.LoadUint32(&w.noempty) == 0 { + if !noempty && !w.noempty.Load() { w.commit(work.copy(), nil, false, start) } // Fill pending transactions from the txpool into the block. diff --git a/miner/worker_test.go b/miner/worker_test.go index e60de67932..9db64a240d 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -454,11 +454,11 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co progress = make(chan struct{}, 10) result = make([]float64, 0, 10) index = 0 - start uint32 + start atomic.Bool ) w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) { // Short circuit if interval checking hasn't started. - if atomic.LoadUint32(&start) == 0 { + if !start.Load() { return } var wantMinInterval, wantRecommitInterval time.Duration @@ -493,7 +493,7 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co w.start() time.Sleep(time.Second) // Ensure two tasks have been submitted due to start opt - atomic.StoreUint32(&start, 1) + start.Store(true) w.setRecommitInterval(3 * time.Second) select { From 00a73fbcce3250b87fc4160f3deddc44390848f4 Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Fri, 31 Mar 2023 02:35:29 -0400 Subject: [PATCH 033/988] accounts/abi/bind: handle UnpackLog with zero topics (#26920) Adds error handling for the case that UnpackLog or UnpackLogIntoMap is called with a log that has zero topics. --------- Co-authored-by: Sina Mahmoodi --- accounts/abi/bind/base.go | 17 +++++++++++++++-- accounts/abi/bind/base_test.go | 17 +++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index df3f52a403..b03f431f77 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -34,6 +34,11 @@ import ( const basefeeWiggleMultiplier = 2 +var ( + errNoEventSignature = errors.New("no event signature") + errEventSignatureMismatch = errors.New("event signature mismatch") +) + // SignerFn is a signer function callback when a contract requires a method to // sign the transaction before submission. type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error) @@ -488,8 +493,12 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter // UnpackLog unpacks a retrieved log into the provided output structure. func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { + // Anonymous events are not supported. + if len(log.Topics) == 0 { + return errNoEventSignature + } if log.Topics[0] != c.abi.Events[event].ID { - return fmt.Errorf("event signature mismatch") + return errEventSignatureMismatch } if len(log.Data) > 0 { if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil { @@ -507,8 +516,12 @@ func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) // UnpackLogIntoMap unpacks a retrieved log into the provided map. func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error { + // Anonymous events are not supported. + if len(log.Topics) == 0 { + return errNoEventSignature + } if log.Topics[0] != c.abi.Events[event].ID { - return fmt.Errorf("event signature mismatch") + return errEventSignatureMismatch } if len(log.Data) > 0 { if err := c.abi.UnpackIntoMap(out, event, log.Data); err != nil { diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go index 2307b9874b..ca0128148f 100644 --- a/accounts/abi/bind/base_test.go +++ b/accounts/abi/bind/base_test.go @@ -186,6 +186,23 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } +func TestUnpackAnonymousLogIntoMap(t *testing.T) { + mockLog := newMockLog(nil, common.HexToHash("0x0")) + + abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` + parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + + var received map[string]interface{} + err := bc.UnpackLogIntoMap(received, "received", mockLog) + if err == nil { + t.Error("unpacking anonymous event is not supported") + } + if err.Error() != "no event signature" { + t.Errorf("expected error 'no event signature', got '%s'", err) + } +} + func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"}) if err != nil { From bed07cd5906e6c26168512f0bf3047e1a948c0e1 Mon Sep 17 00:00:00 2001 From: Guruprasad Kamath <48196632+gurukamath@users.noreply.github.com> Date: Mon, 3 Apr 2023 09:33:17 +0200 Subject: [PATCH 034/988] cmd/evm: use correct parent number for t8n base fee calculation (#27032) Currently the t8n tool uses the same block number for the current block and its parent while calculating the base fee. This causes incorrect base fee calculation for the london fork block. This commit sets the parent block number to be one less than the current block number --- cmd/evm/internal/t8ntool/transition.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index cb7466d86c..f63635687b 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -250,9 +250,9 @@ func Transition(ctx *cli.Context) error { if chainConfig.IsLondon(big.NewInt(int64(prestate.Env.Number))) { if prestate.Env.BaseFee != nil { // Already set, base fee has precedent over parent base fee. - } else if prestate.Env.ParentBaseFee != nil { + } else if prestate.Env.ParentBaseFee != nil && prestate.Env.Number != 0 { parent := &types.Header{ - Number: new(big.Int).SetUint64(prestate.Env.Number), + Number: new(big.Int).SetUint64(prestate.Env.Number - 1), BaseFee: prestate.Env.ParentBaseFee, GasUsed: prestate.Env.ParentGasUsed, GasLimit: prestate.Env.ParentGasLimit, From dc2f4b9304517fd17321c26c47fb5e9ef1ca544b Mon Sep 17 00:00:00 2001 From: ucwong Date: Mon, 3 Apr 2023 01:35:13 -0600 Subject: [PATCH 035/988] go.mod : update snappy (#27027) --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 95c80c6fd8..efde64a5fb 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/gofrs/flock v0.8.1 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/golang/protobuf v1.5.2 - github.com/golang/snappy v0.0.4 + github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa github.com/google/uuid v1.3.0 github.com/gorilla/websocket v1.4.2 diff --git a/go.sum b/go.sum index 4c134a2772..67baa0b2ac 100644 --- a/go.sum +++ b/go.sum @@ -190,8 +190,9 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= From 2c5798464eea24fb78089e51c09e5e1f98f9fd8a Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 3 Apr 2023 01:51:31 -0600 Subject: [PATCH 036/988] common: delete MakeName (#27023) common,p2p: remove unused function MakeName --- common/path.go | 9 --------- p2p/server.go | 1 - 2 files changed, 10 deletions(-) diff --git a/common/path.go b/common/path.go index 69820cfe5d..c1e382fd29 100644 --- a/common/path.go +++ b/common/path.go @@ -17,19 +17,10 @@ package common import ( - "fmt" "os" "path/filepath" - "runtime" ) -// MakeName creates a node name that follows the ethereum convention -// for such names. It adds the operation system name and Go runtime version -// the name. -func MakeName(name, version string) string { - return fmt.Sprintf("%s/v%s/%s/%s", name, version, runtime.GOOS, runtime.Version()) -} - // FileExist checks if a file exists at filePath. func FileExist(filePath string) bool { _, err := os.Stat(filePath) diff --git a/p2p/server.go b/p2p/server.go index 610b82d784..b8a2f8fd21 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -94,7 +94,6 @@ type Config struct { DiscoveryV5 bool `toml:",omitempty"` // Name sets the node name of this server. - // Use common.MakeName to create a name that follows existing conventions. Name string `toml:"-"` // BootstrapNodes are used to establish connectivity From 7076ae00aa36ae250608455de928557ce4e5549f Mon Sep 17 00:00:00 2001 From: sudeep Date: Mon, 3 Apr 2023 14:35:36 +0530 Subject: [PATCH 037/988] cmd/geth: enable log rotation (#26843) This change enables log rotation, which can be activated using the flag --log.rotate. Additional parameters that can be given are: - log.maxsize to set maximum size before files are rotated, - log.maxbackups to set how many files are retailed, - log.maxage to configure max age of rotated files, - log.compress whether to compress rotated files The way to configure location of the logfile(s) is left unchanged, via the `log.logfile` parameter. --------- Co-authored-by: Martin Holst Swende --- .gitignore | 1 + go.mod | 1 + go.sum | 3 + internal/debug/flags.go | 139 +++++++++++++++++++++++++++++++--------- 4 files changed, 114 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index 1ee8b83022..e24e1d1677 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ profile.cov /dashboard/assets/package-lock.json **/yarn-error.log +logs/ \ No newline at end of file diff --git a/go.mod b/go.mod index efde64a5fb..c3e4ee0b49 100644 --- a/go.mod +++ b/go.mod @@ -65,6 +65,7 @@ require ( golang.org/x/text v0.8.0 golang.org/x/time v0.0.0-20220922220347-f3bd1da661af golang.org/x/tools v0.7.0 + gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce ) diff --git a/go.sum b/go.sum index 67baa0b2ac..1022db1e43 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,7 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= @@ -617,6 +618,8 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8 gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 068817d532..3c8b569b4f 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -20,8 +20,9 @@ import ( "fmt" "io" "net/http" - _ "net/http/pprof" // nolint: gosec + _ "net/http/pprof" "os" + "path/filepath" "runtime" "github.com/ethereum/go-ethereum/internal/flags" @@ -32,6 +33,7 @@ import ( "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" "github.com/urfave/cli/v2" + "gopkg.in/natefinch/lumberjack.v2" ) var Memsize memsizeui.Handler @@ -76,6 +78,34 @@ var ( Usage: "Prepends log messages with call-site location (file and line number)", Category: flags.LoggingCategory, } + logRotateFlag = &cli.BoolFlag{ + Name: "log.rotate", + Usage: "Enables log file rotation", + } + logMaxSizeMBsFlag = &cli.IntFlag{ + Name: "log.maxsize", + Usage: "Maximum size in MBs of a single log file", + Value: 100, + Category: flags.LoggingCategory, + } + logMaxBackupsFlag = &cli.IntFlag{ + Name: "log.maxbackups", + Usage: "Maximum number of log files to retain", + Value: 10, + Category: flags.LoggingCategory, + } + logMaxAgeFlag = &cli.IntFlag{ + Name: "log.maxage", + Usage: "Maximum number of days to retain a log file", + Value: 30, + Category: flags.LoggingCategory, + } + logCompressFlag = &cli.BoolFlag{ + Name: "log.compress", + Usage: "Compress the log files", + Value: false, + Category: flags.LoggingCategory, + } pprofFlag = &cli.BoolFlag{ Name: "pprof", Usage: "Enable the pprof HTTP server", @@ -120,11 +150,16 @@ var ( var Flags = []cli.Flag{ verbosityFlag, vmoduleFlag, + backtraceAtFlag, + debugFlag, logjsonFlag, logFormatFlag, logFileFlag, - backtraceAtFlag, - debugFlag, + logRotateFlag, + logMaxSizeMBsFlag, + logMaxBackupsFlag, + logMaxAgeFlag, + logCompressFlag, pprofFlag, pprofAddrFlag, pprofPortFlag, @@ -148,44 +183,71 @@ func init() { // Setup initializes profiling and logging based on the CLI flags. // It should be called as early as possible in the program. func Setup(ctx *cli.Context) error { - logFile := ctx.String(logFileFlag.Name) - useColor := logFile == "" && os.Getenv("TERM") != "dumb" && (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) - - var logfmt log.Format - switch ctx.String(logFormatFlag.Name) { - case "json": + var ( + logfmt log.Format + output = io.Writer(os.Stderr) + logFmtFlag = ctx.String(logFormatFlag.Name) + ) + switch { + case ctx.Bool(logjsonFlag.Name): + // Retain backwards compatibility with `--log.json` flag if `--log.format` not set + defer log.Warn("The flag '--log.json' is deprecated, please use '--log.format=json' instead") logfmt = log.JSONFormat() - case "logfmt": + case logFmtFlag == "json": + logfmt = log.JSONFormat() + case logFmtFlag == "logfmt": logfmt = log.LogfmtFormat() - case "terminal": - logfmt = log.TerminalFormat(useColor) - case "": - // Retain backwards compatibility with `--log.json` flag if `--log.format` not set - if ctx.Bool(logjsonFlag.Name) { - defer log.Warn("The flag '--log.json' is deprecated, please use '--log.format=json' instead") - logfmt = log.JSONFormat() - } else { - logfmt = log.TerminalFormat(useColor) + case logFmtFlag == "", logFmtFlag == "terminal": + useColor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" + if useColor { + output = colorable.NewColorableStderr() } + logfmt = log.TerminalFormat(useColor) default: // Unknown log format specified return fmt.Errorf("unknown log format: %v", ctx.String(logFormatFlag.Name)) } - - if logFile != "" { - var err error - logOutputStream, err = log.FileHandler(logFile, logfmt) - if err != nil { - return err + var ( + stdHandler = log.StreamHandler(output, logfmt) + ostream = stdHandler + logFile = ctx.String(logFileFlag.Name) + rotation = ctx.Bool(logRotateFlag.Name) + ) + if len(logFile) > 0 { + if err := validateLogLocation(filepath.Dir(logFile)); err != nil { + return fmt.Errorf("failed to initiatilize file logger: %v", err) } + } + context := []interface{}{"rotate", rotation} + if len(logFmtFlag) > 0 { + context = append(context, "format", logFmtFlag) } else { - output := io.Writer(os.Stderr) - if useColor { - output = colorable.NewColorableStderr() + context = append(context, "format", "terminal") + } + if rotation { + // Lumberjack uses -lumberjack.log in is.TempDir() if empty. + // so typically /tmp/geth-lumberjack.log on linux + if len(logFile) > 0 { + context = append(context, "location", logFile) + } else { + context = append(context, "location", filepath.Join(os.TempDir(), "geth-lumberjack.log")) + } + ostream = log.MultiHandler(log.StreamHandler(&lumberjack.Logger{ + Filename: logFile, + MaxSize: ctx.Int(logMaxSizeMBsFlag.Name), + MaxBackups: ctx.Int(logMaxBackupsFlag.Name), + MaxAge: ctx.Int(logMaxAgeFlag.Name), + Compress: ctx.Bool(logCompressFlag.Name), + }, logfmt), stdHandler) + } else if logFile != "" { + if logOutputStream, err := log.FileHandler(logFile, logfmt); err != nil { + return err + } else { + ostream = log.MultiHandler(logOutputStream, stdHandler) + context = append(context, "location", logFile) } - logOutputStream = log.StreamHandler(output, logfmt) } - glogger.SetHandler(logOutputStream) + glogger.SetHandler(ostream) // logging verbosity := ctx.Int(verbosityFlag.Name) @@ -236,6 +298,9 @@ func Setup(ctx *cli.Context) error { // It cannot be imported because it will cause a cyclical dependency. StartPProf(address, !ctx.IsSet("metrics.addr")) } + if len(logFile) > 0 || rotation { + log.Info("Logging configured", context...) + } return nil } @@ -263,3 +328,17 @@ func Exit() { closer.Close() } } + +func validateLogLocation(path string) error { + if err := os.MkdirAll(path, os.ModePerm); err != nil { + return fmt.Errorf("error creating the directory: %w", err) + } + // Check if the path is writable by trying to create a temporary file + tmp := filepath.Join(path, "tmp") + if f, err := os.Create(tmp); err != nil { + return err + } else { + f.Close() + } + return os.Remove(tmp) +} From 94457cce072d1e45f47d13dce290e0473615ec5d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 3 Apr 2023 17:08:06 +0800 Subject: [PATCH 038/988] cmd, miner, signer: avoid panic if keystore is not available (#27039) * cmd, miner, singer: avoid panic if keystore is not available * cmd/geth: print warning instead of panic --- cmd/geth/accountcmd.go | 18 +++++++++++++++--- cmd/geth/main.go | 7 ++++++- miner/stress/beacon/main.go | 6 +++++- signer/core/uiapi.go | 6 +++++- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go index 5158b7606c..a36da7d55f 100644 --- a/cmd/geth/accountcmd.go +++ b/cmd/geth/accountcmd.go @@ -301,7 +301,11 @@ func accountUpdate(ctx *cli.Context) error { utils.Fatalf("No accounts specified to update") } stack, _ := makeConfigNode(ctx) - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + backends := stack.AccountManager().Backends(keystore.KeyStoreType) + if len(backends) == 0 { + utils.Fatalf("Keystore is not available") + } + ks := backends[0].(*keystore.KeyStore) for _, addr := range ctx.Args().Slice() { account, oldPassword := unlockAccount(ks, addr, 0, nil) @@ -326,7 +330,11 @@ func importWallet(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) passphrase := utils.GetPassPhraseWithList("", false, 0, utils.MakePasswordList(ctx)) - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + backends := stack.AccountManager().Backends(keystore.KeyStoreType) + if len(backends) == 0 { + utils.Fatalf("Keystore is not available") + } + ks := backends[0].(*keystore.KeyStore) acct, err := ks.ImportPreSaleKey(keyJSON, passphrase) if err != nil { utils.Fatalf("%v", err) @@ -347,7 +355,11 @@ func accountImport(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) passphrase := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + backends := stack.AccountManager().Backends(keystore.KeyStoreType) + if len(backends) == 0 { + utils.Fatalf("Keystore is not available") + } + ks := backends[0].(*keystore.KeyStore) acct, err := ks.ImportECDSA(key, passphrase) if err != nil { utils.Fatalf("Could not create the account: %v", err) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index a970e76523..f55adb1449 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -464,7 +464,12 @@ func unlockAccounts(ctx *cli.Context, stack *node.Node) { if !stack.Config().InsecureUnlockAllowed && stack.Config().ExtRPCEnabled() { utils.Fatalf("Account unlock with HTTP access is forbidden!") } - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + backends := stack.AccountManager().Backends(keystore.KeyStoreType) + if len(backends) == 0 { + log.Warn("Failed to unlock accounts, keystore is not available") + return + } + ks := backends[0].(*keystore.KeyStore) passwords := utils.MakePasswordList(ctx) for i, account := range unlocks { unlockAccount(ks, account, i, passwords) diff --git a/miner/stress/beacon/main.go b/miner/stress/beacon/main.go index 516862c9cb..65318f1a0e 100644 --- a/miner/stress/beacon/main.go +++ b/miner/stress/beacon/main.go @@ -127,7 +127,11 @@ func newNode(typ nodetype, genesis *core.Genesis, enodes []*enode.Node) *ethNode // Inject the signer key and start sealing with it stack.AccountManager().AddBackend(keystore.NewPlaintextKeyStore("beacon-stress")) - store := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + ks := stack.AccountManager().Backends(keystore.KeyStoreType) + if len(ks) == 0 { + panic("Keystore is not available") + } + store := ks[0].(*keystore.KeyStore) if _, err := store.NewAccount(""); err != nil { panic(err) } diff --git a/signer/core/uiapi.go b/signer/core/uiapi.go index 59466d8fa0..924203a139 100644 --- a/signer/core/uiapi.go +++ b/signer/core/uiapi.go @@ -111,7 +111,11 @@ func (s *UIServerAPI) DeriveAccount(url string, path string, pin *bool) (account // fetchKeystore retrieves the encrypted keystore from the account manager. func fetchKeystore(am *accounts.Manager) *keystore.KeyStore { - return am.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + ks := am.Backends(keystore.KeyStoreType) + if len(ks) == 0 { + return nil + } + return ks[0].(*keystore.KeyStore) } // ImportRawKey stores the given hex encoded ECDSA key into the key directory, From a25dd8064ed7329dd5924bce18b2a04d0b2843e8 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 3 Apr 2023 05:42:34 -0400 Subject: [PATCH 039/988] test/fuzzers: fuzz rlp handling of big.Int and uint256.Int (#26917) test/fuzzers: fuzz rlp handling of big.Lnt and uint256.Int --- tests/fuzzers/rlp/rlp_fuzzer.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/fuzzers/rlp/rlp_fuzzer.go b/tests/fuzzers/rlp/rlp_fuzzer.go index ac02e1651d..9fcdb57769 100644 --- a/tests/fuzzers/rlp/rlp_fuzzer.go +++ b/tests/fuzzers/rlp/rlp_fuzzer.go @@ -19,9 +19,11 @@ package rlp import ( "bytes" "fmt" + "math/big" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" + "github.com/holiman/uint256" ) func decodeEncode(input []byte, val interface{}, i int) { @@ -126,5 +128,16 @@ func Fuzz(input []byte) int { var rs types.Receipts decodeEncode(input, &rs, i) } + { + i++ + var v struct { + AnIntPtr *big.Int + AnInt big.Int + AnU256Ptr *uint256.Int + AnU256 uint256.Int + NotAnU256 [4]uint64 + } + decodeEncode(input, &v, i) + } return 1 } From beda6c41adbc72d1e39215359cdfd75ae0d2f053 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 3 Apr 2023 07:16:57 -0400 Subject: [PATCH 040/988] core/txpool: move some validation to outside of mutex (#27006) Currently, most of transaction validation while holding the txpool mutex: one exception being an early-on signature check. This PR changes that, so that we do all non-stateful checks before we entering the mutex area. This means they can be performed in parallel, and to enable that, certain fields have been made atomic bools and uint64. --- core/txpool/txpool.go | 81 +++++++++++++++++++++----------------- core/txpool/txpool_test.go | 31 ++++++++------- 2 files changed, 61 insertions(+), 51 deletions(-) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index ac4486c6cb..3a5ed69568 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -23,6 +23,7 @@ import ( "math/big" "sort" "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -250,14 +251,14 @@ type TxPool struct { signer types.Signer mu sync.RWMutex - istanbul bool // Fork indicator whether we are in the istanbul stage. - eip2718 bool // Fork indicator whether we are using EIP-2718 type transactions. - eip1559 bool // Fork indicator whether we are using EIP-1559 type transactions. - shanghai bool // Fork indicator whether we are in the Shanghai stage. + istanbul atomic.Bool // Fork indicator whether we are in the istanbul stage. + eip2718 atomic.Bool // Fork indicator whether we are using EIP-2718 type transactions. + eip1559 atomic.Bool // Fork indicator whether we are using EIP-1559 type transactions. + shanghai atomic.Bool // Fork indicator whether we are in the Shanghai stage. currentState *state.StateDB // Current state in the blockchain head pendingNonces *noncer // Pending state tracking virtual nonces - currentMaxGas uint64 // Current gas limit for transaction caps + currentMaxGas atomic.Uint64 // Current gas limit for transaction caps locals *accountSet // Set of local transaction to exempt from eviction rules journal *journal // Journal of local transaction to back up to disk @@ -592,15 +593,17 @@ func (pool *TxPool) local() map[common.Address]types.Transactions { return txs } -// validateTx checks whether a transaction is valid according to the consensus -// rules and adheres to some heuristic limits of the local node (price and size). -func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { +// validateTxBasics checks whether a transaction is valid according to the consensus +// rules, but does not check state-dependent validation such as sufficient balance. +// This check is meant as an early check which only needs to be performed once, +// and does not require the pool mutex to be held. +func (pool *TxPool) validateTxBasics(tx *types.Transaction, local bool) error { // Accept only legacy transactions until EIP-2718/2930 activates. - if !pool.eip2718 && tx.Type() != types.LegacyTxType { + if !pool.eip2718.Load() && tx.Type() != types.LegacyTxType { return core.ErrTxTypeNotSupported } // Reject dynamic fee transactions until EIP-1559 activates. - if !pool.eip1559 && tx.Type() == types.DynamicFeeTxType { + if !pool.eip1559.Load() && tx.Type() == types.DynamicFeeTxType { return core.ErrTxTypeNotSupported } // Reject transactions over defined size to prevent DOS attacks @@ -608,7 +611,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrOversizedData } // Check whether the init code size has been exceeded. - if pool.shanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { + if pool.shanghai.Load() && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { return fmt.Errorf("%w: code size %v limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize) } // Transactions can't be negative. This may never happen using RLP decoded @@ -617,7 +620,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrNegativeValue } // Ensure the transaction doesn't exceed the current block limit gas. - if pool.currentMaxGas < tx.Gas() { + if pool.currentMaxGas.Load() < tx.Gas() { return ErrGasLimit } // Sanity check for extremely large numbers @@ -632,14 +635,29 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return core.ErrTipAboveFeeCap } // Make sure the transaction is signed properly. - from, err := types.Sender(pool.signer, tx) - if err != nil { + if _, err := types.Sender(pool.signer, tx); err != nil { return ErrInvalidSender } // Drop non-local transactions under our own minimal accepted gas price or tip if !local && tx.GasTipCapIntCmp(pool.gasPrice) < 0 { return ErrUnderpriced } + // Ensure the transaction has more gas than the basic tx fee. + intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul.Load(), pool.shanghai.Load()) + if err != nil { + return err + } + if tx.Gas() < intrGas { + return core.ErrIntrinsicGas + } + return nil +} + +// validateTx checks whether a transaction is valid according to the consensus +// rules and adheres to some heuristic limits of the local node (price and size). +func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { + // Signature has been checked already, this cannot error. + from, _ := types.Sender(pool.signer, tx) // Ensure the transaction adheres to nonce ordering if pool.currentState.GetNonce(from) > tx.Nonce() { return core.ErrNonceTooLow @@ -664,15 +682,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrOverdraft } } - - // Ensure the transaction has more gas than the basic tx fee. - intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai) - if err != nil { - return err - } - if tx.Gas() < intrGas { - return core.ErrIntrinsicGas - } return nil } @@ -969,12 +978,12 @@ func (pool *TxPool) addTxs(txs []*types.Transaction, local, sync bool) []error { knownTxMeter.Mark(1) continue } - // Exclude transactions with invalid signatures as soon as - // possible and cache senders in transactions before - // obtaining lock - _, err := types.Sender(pool.signer, tx) - if err != nil { - errs[i] = ErrInvalidSender + // Exclude transactions with basic errors, e.g invalid signatures and + // insufficient intrinsic gas as soon as possible and cache senders + // in transactions before obtaining lock + + if err := pool.validateTxBasics(tx, local); err != nil { + errs[i] = err invalidTxMeter.Mark(1) continue } @@ -1364,7 +1373,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { } pool.currentState = statedb pool.pendingNonces = newNoncer(statedb) - pool.currentMaxGas = newHead.GasLimit + pool.currentMaxGas.Store(newHead.GasLimit) // Inject any transactions discarded due to reorgs log.Debug("Reinjecting stale transactions", "count", len(reinject)) @@ -1373,10 +1382,10 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { // Update all fork indicator by next pending block number. next := new(big.Int).Add(newHead.Number, big.NewInt(1)) - pool.istanbul = pool.chainconfig.IsIstanbul(next) - pool.eip2718 = pool.chainconfig.IsBerlin(next) - pool.eip1559 = pool.chainconfig.IsLondon(next) - pool.shanghai = pool.chainconfig.IsShanghai(uint64(time.Now().Unix())) + pool.istanbul.Store(pool.chainconfig.IsIstanbul(next)) + pool.eip2718.Store(pool.chainconfig.IsBerlin(next)) + pool.eip1559.Store(pool.chainconfig.IsLondon(next)) + pool.shanghai.Store(pool.chainconfig.IsShanghai(uint64(time.Now().Unix()))) } // promoteExecutables moves transactions that have become processable from the @@ -1400,7 +1409,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans } log.Trace("Removed old queued transactions", "count", len(forwards)) // Drop all transactions that are too costly (low balance or out of gas) - drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) + drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas.Load()) for _, tx := range drops { hash := tx.Hash() pool.all.Remove(hash) @@ -1597,7 +1606,7 @@ func (pool *TxPool) demoteUnexecutables() { log.Trace("Removed old pending transaction", "hash", hash) } // Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later - drops, invalids := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) + drops, invalids := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas.Load()) for _, tx := range drops { hash := tx.Hash() log.Trace("Removed unpayable pending transaction", "hash", hash) diff --git a/core/txpool/txpool_test.go b/core/txpool/txpool_test.go index 7771c5f7cd..a4889fa62f 100644 --- a/core/txpool/txpool_test.go +++ b/core/txpool/txpool_test.go @@ -293,28 +293,29 @@ func TestInvalidTransactions(t *testing.T) { tx := transaction(0, 100, key) from, _ := deriveSender(tx) + // Intrinsic gas too low testAddBalance(pool, from, big.NewInt(1)) - if err := pool.AddRemote(tx); !errors.Is(err, core.ErrInsufficientFunds) { - t.Error("expected", core.ErrInsufficientFunds) + if err, want := pool.AddRemote(tx), core.ErrIntrinsicGas; !errors.Is(err, want) { + t.Errorf("want %v have %v", want, err) } - balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice())) - testAddBalance(pool, from, balance) - if err := pool.AddRemote(tx); !errors.Is(err, core.ErrIntrinsicGas) { - t.Error("expected", core.ErrIntrinsicGas, "got", err) + // Insufficient funds + tx = transaction(0, 100000, key) + if err, want := pool.AddRemote(tx), core.ErrInsufficientFunds; !errors.Is(err, want) { + t.Errorf("want %v have %v", want, err) } testSetNonce(pool, from, 1) testAddBalance(pool, from, big.NewInt(0xffffffffffffff)) tx = transaction(0, 100000, key) - if err := pool.AddRemote(tx); !errors.Is(err, core.ErrNonceTooLow) { - t.Error("expected", core.ErrNonceTooLow) + if err, want := pool.AddRemote(tx), core.ErrNonceTooLow; !errors.Is(err, want) { + t.Errorf("want %v have %v", want, err) } tx = transaction(1, 100000, key) pool.gasPrice = big.NewInt(1000) - if err := pool.AddRemote(tx); err != ErrUnderpriced { - t.Error("expected", ErrUnderpriced, "got", err) + if err, want := pool.AddRemote(tx), ErrUnderpriced; !errors.Is(err, want) { + t.Errorf("want %v have %v", want, err) } if err := pool.AddLocal(tx); err != nil { t.Error("expected", nil, "got", err) @@ -1217,22 +1218,22 @@ func TestAllowedTxSize(t *testing.T) { // All those fields are summed up to at most 213 bytes. baseSize := uint64(213) dataSize := txMaxSize - baseSize - + maxGas := pool.currentMaxGas.Load() // Try adding a transaction with maximal allowed size - tx := pricedDataTransaction(0, pool.currentMaxGas, big.NewInt(1), key, dataSize) + tx := pricedDataTransaction(0, maxGas, big.NewInt(1), key, dataSize) if err := pool.addRemoteSync(tx); err != nil { t.Fatalf("failed to add transaction of size %d, close to maximal: %v", int(tx.Size()), err) } // Try adding a transaction with random allowed size - if err := pool.addRemoteSync(pricedDataTransaction(1, pool.currentMaxGas, big.NewInt(1), key, uint64(rand.Intn(int(dataSize))))); err != nil { + if err := pool.addRemoteSync(pricedDataTransaction(1, maxGas, big.NewInt(1), key, uint64(rand.Intn(int(dataSize))))); err != nil { t.Fatalf("failed to add transaction of random allowed size: %v", err) } // Try adding a transaction of minimal not allowed size - if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentMaxGas, big.NewInt(1), key, txMaxSize)); err == nil { + if err := pool.addRemoteSync(pricedDataTransaction(2, maxGas, big.NewInt(1), key, txMaxSize)); err == nil { t.Fatalf("expected rejection on slightly oversize transaction") } // Try adding a transaction of random not allowed size - if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentMaxGas, big.NewInt(1), key, dataSize+1+uint64(rand.Intn(10*txMaxSize)))); err == nil { + if err := pool.addRemoteSync(pricedDataTransaction(2, maxGas, big.NewInt(1), key, dataSize+1+uint64(rand.Intn(10*txMaxSize)))); err == nil { t.Fatalf("expected rejection on oversize transaction") } // Run some sanity checks on the pool internals From db18293c32f6dc5d6886e5e68ab8bfd12e33cad6 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 4 Apr 2023 03:48:10 +0800 Subject: [PATCH 041/988] eth/downloader: use atomic types (#27030) * eth/downloader: use atomic type * Update eth/downloader/downloader_test.go Co-authored-by: Martin Holst Swende * Update eth/downloader/downloader_test.go Co-authored-by: Martin Holst Swende --------- Co-authored-by: Martin Holst Swende --- eth/downloader/beaconsync.go | 3 +-- eth/downloader/downloader.go | 30 +++++++++++++++--------------- eth/downloader/downloader_test.go | 25 +++++++++++++------------ eth/downloader/queue.go | 18 +++++++++--------- eth/downloader/resultstore.go | 8 ++++---- eth/downloader/skeleton_test.go | 24 ++++++++++++------------ 6 files changed, 54 insertions(+), 54 deletions(-) diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index ff985e6b03..df8af68bc7 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -19,7 +19,6 @@ package downloader import ( "fmt" "sync" - "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -371,7 +370,7 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error { continue } // If the pivot block is committed, signal header sync termination - if atomic.LoadInt32(&d.committed) == 1 { + if d.committed.Load() { select { case d.headerProcCh <- nil: return nil diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index fb9de79912..a3d8a21060 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -98,7 +98,7 @@ type headerTask struct { } type Downloader struct { - mode uint32 // Synchronisation mode defining the strategy used (per sync cycle), use d.getMode() to get the SyncMode + mode atomic.Uint32 // Synchronisation mode defining the strategy used (per sync cycle), use d.getMode() to get the SyncMode mux *event.TypeMux // Event multiplexer to announce sync operation events checkpoint uint64 // Checkpoint block number to enforce head against (e.g. snap sync) @@ -122,9 +122,9 @@ type Downloader struct { // Status synchroniseMock func(id string, hash common.Hash) error // Replacement for synchronise during testing - synchronising int32 - notified int32 - committed int32 + synchronising atomic.Bool + notified atomic.Bool + committed atomic.Bool ancientLimit uint64 // The maximum block number which can be regarded as ancient data. // Channels @@ -292,7 +292,7 @@ func (d *Downloader) Progress() ethereum.SyncProgress { // Synchronising returns whether the downloader is currently retrieving blocks. func (d *Downloader) Synchronising() bool { - return atomic.LoadInt32(&d.synchronising) > 0 + return d.synchronising.Load() } // RegisterPeer injects a new download peer into the set of block source to be @@ -392,13 +392,13 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, return d.synchroniseMock(id, hash) } // Make sure only one goroutine is ever allowed past this point at once - if !atomic.CompareAndSwapInt32(&d.synchronising, 0, 1) { + if !d.synchronising.CompareAndSwap(false, true) { return errBusy } - defer atomic.StoreInt32(&d.synchronising, 0) + defer d.synchronising.Store(false) // Post a user notification of the sync (only once per session) - if atomic.CompareAndSwapInt32(&d.notified, 0, 1) { + if d.notified.CompareAndSwap(false, true) { log.Info("Block synchronisation started") } if mode == SnapSync { @@ -435,7 +435,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, defer d.Cancel() // No matter what, we can't leave the cancel channel open // Atomically set the requested sync mode - atomic.StoreUint32(&d.mode, uint32(mode)) + d.mode.Store(uint32(mode)) // Retrieve the origin peer and initiate the downloading process var p *peerConnection @@ -452,7 +452,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, } func (d *Downloader) getMode() SyncMode { - return SyncMode(atomic.LoadUint32(&d.mode)) + return SyncMode(d.mode.Load()) } // syncWithPeer starts a block synchronization based on the hash chain from the @@ -562,9 +562,9 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * rawdb.WriteLastPivotNumber(d.stateDB, pivotNumber) } } - d.committed = 1 + d.committed.Store(true) if mode == SnapSync && pivot.Number.Uint64() != 0 { - d.committed = 0 + d.committed.Store(false) } if mode == SnapSync { // Set the ancient data limitation. If we are running snap sync, all block @@ -1128,7 +1128,7 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, head uint64) e // If no more headers are inbound, notify the content fetchers and return if len(headers) == 0 { // Don't abort header fetches while the pivot is downloading - if atomic.LoadInt32(&d.committed) == 0 && pivot <= from { + if !d.committed.Load() && pivot <= from { p.log.Debug("No headers, waiting for pivot commit") select { case <-time.After(fsHeaderContCheck): @@ -1669,7 +1669,7 @@ func (d *Downloader) processSnapSyncContent() error { results = append(append([]*fetchResult{oldPivot}, oldTail...), results...) } // Split around the pivot block and process the two sides via snap/full sync - if atomic.LoadInt32(&d.committed) == 0 { + if !d.committed.Load() { latest := results[len(results)-1].Header // If the height is above the pivot block by 2 sets, it means the pivot // become stale in the network and it was garbage collected, move to a @@ -1794,7 +1794,7 @@ func (d *Downloader) commitPivotBlock(result *fetchResult) error { if err := d.blockchain.SnapSyncCommitHead(block.Hash()); err != nil { return err } - atomic.StoreInt32(&d.committed, 1) + d.committed.Store(true) return nil } diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index a884c1e950..37f7a76704 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -476,9 +476,10 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { tester.newPeer("peer", protocol, testChainBase.blocks[1:]) // Wrap the importer to allow stepping - blocked, proceed := uint32(0), make(chan struct{}) + var blocked atomic.Uint32 + proceed := make(chan struct{}) tester.downloader.chainInsertHook = func(results []*fetchResult) { - atomic.StoreUint32(&blocked, uint32(len(results))) + blocked.Store(uint32(len(results))) <-proceed } // Start a synchronisation concurrently @@ -505,7 +506,7 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { tester.downloader.queue.resultCache.lock.Lock() { cached = tester.downloader.queue.resultCache.countCompleted() - frozen = int(atomic.LoadUint32(&blocked)) + frozen = int(blocked.Load()) retrieved = int(tester.chain.CurrentSnapBlock().Number.Uint64()) + 1 } tester.downloader.queue.resultCache.lock.Unlock() @@ -528,8 +529,8 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { t.Fatalf("block count mismatch: have %v, want %v (owned %v, blocked %v, target %v)", cached, blockCacheMaxItems, retrieved, frozen, targetBlocks+1) } // Permit the blocked blocks to import - if atomic.LoadUint32(&blocked) > 0 { - atomic.StoreUint32(&blocked, uint32(0)) + if blocked.Load() > 0 { + blocked.Store(uint32(0)) proceed <- struct{}{} } } @@ -786,12 +787,12 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { tester.newPeer("peer", protocol, chain.blocks[1:]) // Instrument the downloader to signal body requests - bodiesHave, receiptsHave := int32(0), int32(0) + var bodiesHave, receiptsHave atomic.Int32 tester.downloader.bodyFetchHook = func(headers []*types.Header) { - atomic.AddInt32(&bodiesHave, int32(len(headers))) + bodiesHave.Add(int32(len(headers))) } tester.downloader.receiptFetchHook = func(headers []*types.Header) { - atomic.AddInt32(&receiptsHave, int32(len(headers))) + receiptsHave.Add(int32(len(headers))) } // Synchronise with the peer and make sure all blocks were retrieved if err := tester.sync("peer", nil, mode); err != nil { @@ -811,11 +812,11 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { receiptsNeeded++ } } - if int(bodiesHave) != bodiesNeeded { - t.Errorf("body retrieval count mismatch: have %v, want %v", bodiesHave, bodiesNeeded) + if int(bodiesHave.Load()) != bodiesNeeded { + t.Errorf("body retrieval count mismatch: have %v, want %v", bodiesHave.Load(), bodiesNeeded) } - if int(receiptsHave) != receiptsNeeded { - t.Errorf("receipt retrieval count mismatch: have %v, want %v", receiptsHave, receiptsNeeded) + if int(receiptsHave.Load()) != receiptsNeeded { + t.Errorf("receipt retrieval count mismatch: have %v, want %v", receiptsHave.Load(), receiptsNeeded) } } diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 5af5068c98..e9907297a0 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -61,7 +61,7 @@ type fetchRequest struct { // fetchResult is a struct collecting partial results from data fetchers until // all outstanding pieces complete and the result as a whole can be processed. type fetchResult struct { - pending int32 // Flag telling what deliveries are outstanding + pending atomic.Int32 // Flag telling what deliveries are outstanding Header *types.Header Uncles []*types.Header @@ -75,38 +75,38 @@ func newFetchResult(header *types.Header, fastSync bool) *fetchResult { Header: header, } if !header.EmptyBody() { - item.pending |= (1 << bodyType) + item.pending.Store(item.pending.Load() | (1 << bodyType)) } else if header.WithdrawalsHash != nil { item.Withdrawals = make(types.Withdrawals, 0) } if fastSync && !header.EmptyReceipts() { - item.pending |= (1 << receiptType) + item.pending.Store(item.pending.Load() | (1 << receiptType)) } return item } // SetBodyDone flags the body as finished. func (f *fetchResult) SetBodyDone() { - if v := atomic.LoadInt32(&f.pending); (v & (1 << bodyType)) != 0 { - atomic.AddInt32(&f.pending, -1) + if v := f.pending.Load(); (v & (1 << bodyType)) != 0 { + f.pending.Add(-1) } } // AllDone checks if item is done. func (f *fetchResult) AllDone() bool { - return atomic.LoadInt32(&f.pending) == 0 + return f.pending.Load() == 0 } // SetReceiptsDone flags the receipts as finished. func (f *fetchResult) SetReceiptsDone() { - if v := atomic.LoadInt32(&f.pending); (v & (1 << receiptType)) != 0 { - atomic.AddInt32(&f.pending, -2) + if v := f.pending.Load(); (v & (1 << receiptType)) != 0 { + f.pending.Add(-2) } } // Done checks if the given type is done already func (f *fetchResult) Done(kind uint) bool { - v := atomic.LoadInt32(&f.pending) + v := f.pending.Load() return v&(1<= int32(len(r.items)) { break @@ -156,7 +156,7 @@ func (r *resultStore) countCompleted() int { break } } - atomic.StoreInt32(&r.indexIncomplete, index) + r.indexIncomplete.Store(index) return int(index) } @@ -179,7 +179,7 @@ func (r *resultStore) GetCompleted(limit int) []*fetchResult { } // Advance the expected block number of the first cache entry r.resultOffset += uint64(limit) - atomic.AddInt32(&r.indexIncomplete, int32(-limit)) + r.indexIncomplete.Add(int32(-limit)) return results } diff --git a/eth/downloader/skeleton_test.go b/eth/downloader/skeleton_test.go index b19494a7b0..6a76d78ac8 100644 --- a/eth/downloader/skeleton_test.go +++ b/eth/downloader/skeleton_test.go @@ -82,8 +82,8 @@ type skeletonTestPeer struct { serve func(origin uint64) []*types.Header // Hook to allow custom responses - served uint64 // Number of headers served by this peer - dropped uint64 // Flag whether the peer was dropped (stop responding) + served atomic.Uint64 // Number of headers served by this peer + dropped atomic.Uint64 // Flag whether the peer was dropped (stop responding) } // newSkeletonTestPeer creates a new mock peer to test the skeleton sync with. @@ -113,7 +113,7 @@ func (p *skeletonTestPeer) RequestHeadersByNumber(origin uint64, amount int, ski // Since skeleton test peer are in-memory mocks, dropping the does not make // them inaccessible. As such, check a local `dropped` field to see if the // peer has been dropped and should not respond any more. - if atomic.LoadUint64(&p.dropped) != 0 { + if p.dropped.Load() != 0 { return nil, errors.New("peer already dropped") } // Skeleton sync retrieves batches of headers going backward without gaps. @@ -161,7 +161,7 @@ func (p *skeletonTestPeer) RequestHeadersByNumber(origin uint64, amount int, ski } } } - atomic.AddUint64(&p.served, uint64(len(headers))) + p.served.Add(uint64(len(headers))) hashes := make([]common.Hash, len(headers)) for i, header := range headers { @@ -182,7 +182,7 @@ func (p *skeletonTestPeer) RequestHeadersByNumber(origin uint64, amount int, ski sink <- res if err := <-res.Done; err != nil { log.Warn("Skeleton test peer response rejected", "err", err) - atomic.AddUint64(&p.dropped, 1) + p.dropped.Add(1) } }() return req, nil @@ -817,7 +817,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) { dropped := make(map[string]int) drop := func(peer string) { if p := peerset.Peer(peer); p != nil { - atomic.AddUint64(&p.peer.(*skeletonTestPeer).dropped, 1) + p.peer.(*skeletonTestPeer).dropped.Add(1) } peerset.Unregister(peer) dropped[peer]++ @@ -895,14 +895,14 @@ func TestSkeletonSyncRetrievals(t *testing.T) { if !tt.unpredictable { var served uint64 for _, peer := range tt.peers { - served += atomic.LoadUint64(&peer.served) + served += peer.served.Load() } if served != tt.midserve { t.Errorf("test %d, mid state: served headers mismatch: have %d, want %d", i, served, tt.midserve) } var drops uint64 for _, peer := range tt.peers { - drops += atomic.LoadUint64(&peer.dropped) + drops += peer.dropped.Load() } if drops != tt.middrop { t.Errorf("test %d, mid state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) @@ -950,20 +950,20 @@ func TestSkeletonSyncRetrievals(t *testing.T) { if !tt.unpredictable { served := uint64(0) for _, peer := range tt.peers { - served += atomic.LoadUint64(&peer.served) + served += peer.served.Load() } if tt.newPeer != nil { - served += atomic.LoadUint64(&tt.newPeer.served) + served += tt.newPeer.served.Load() } if served != tt.endserve { t.Errorf("test %d, end state: served headers mismatch: have %d, want %d", i, served, tt.endserve) } drops := uint64(0) for _, peer := range tt.peers { - drops += atomic.LoadUint64(&peer.dropped) + drops += peer.dropped.Load() } if tt.newPeer != nil { - drops += atomic.LoadUint64(&tt.newPeer.dropped) + drops += tt.newPeer.dropped.Load() } if drops != tt.enddrop { t.Errorf("test %d, end state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) From 9b1a82c6009385be860608fbc573d5842c8c187f Mon Sep 17 00:00:00 2001 From: joohhnnn <68833933+joohhnnn@users.noreply.github.com> Date: Tue, 4 Apr 2023 14:59:40 +0800 Subject: [PATCH 042/988] core/vm: clarify comment (#27045) --- core/vm/analysis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 4aa8cfe70f..38af9084ac 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -63,7 +63,7 @@ func (bits *bitvec) codeSegment(pos uint64) bool { // codeBitmap collects data locations in code. func codeBitmap(code []byte) bitvec { // The bitmap is 4 bytes longer than necessary, in case the code - // ends with a PUSH32, the algorithm will push zeroes onto the + // ends with a PUSH32, the algorithm will set bits on the // bitvector outside the bounds of the actual code. bits := make(bitvec, len(code)/8+1+4) return codeBitmapInternal(code, bits) From 91faf2c55958d182677f15dc30c0ad9847342395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 4 Apr 2023 10:02:50 +0300 Subject: [PATCH 043/988] consensus, core/typer: add 4844 excessDataGas to header, tie it to Cancun (#27046) --- consensus/beacon/consensus.go | 10 +++++++++- consensus/clique/clique.go | 3 +++ consensus/ethash/consensus.go | 3 +++ core/types/block.go | 3 +++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index b4da9b553a..1129ac06c8 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -263,11 +263,19 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa // Verify existence / non-existence of withdrawalsHash. shanghai := chain.Config().IsShanghai(header.Time) if shanghai && header.WithdrawalsHash == nil { - return fmt.Errorf("missing withdrawalsHash") + return errors.New("missing withdrawalsHash") } if !shanghai && header.WithdrawalsHash != nil { return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash) } + // Verify the existence / non-existence of excessDataGas + cancun := chain.Config().IsCancun(header.Time) + if cancun && header.ExcessDataGas == nil { + return errors.New("missing excessDataGas") + } + if !cancun && header.ExcessDataGas != nil { + return fmt.Errorf("invalid excessDataGas: have %d, expected nil", header.ExcessDataGas) + } return nil } diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 6c20803b2a..1b9a1d9236 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -301,6 +301,9 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H if chain.Config().IsShanghai(header.Time) { return fmt.Errorf("clique does not support shanghai fork") } + if chain.Config().IsCancun(header.Time) { + return fmt.Errorf("clique does not support cancun fork") + } // If all checks passed, validate any special fields for hard forks if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil { return err diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index c3c06c541c..8f1b497cbd 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -313,6 +313,9 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa if chain.Config().IsShanghai(header.Time) { return fmt.Errorf("ethash does not support shanghai fork") } + if chain.Config().IsCancun(header.Time) { + return fmt.Errorf("ethash does not support cancun fork") + } // Verify the engine specific seal securing the block if seal { if err := ethash.verifySeal(chain, header, false); err != nil { diff --git a/core/types/block.go b/core/types/block.go index e2c71abebd..a1a14f5b16 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -85,6 +85,9 @@ type Header struct { // WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers. WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` + // ExcessDataGas was added by EIP-4844 and is ignored in legacy headers. + ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"` + /* TODO (MariusVanDerWijden) Add this field once needed // Random was added during the merge and contains the BeaconState randomness From d2cf49327f3d083e6e4eec0c747a8683f7c7b97f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 4 Apr 2023 11:25:28 +0300 Subject: [PATCH 044/988] consensus/misc, params: add EIP-4844 blobfee conversions (#27041) * consensus/misc, params: add EIP-4844 blobfee conversions * consensus/misc: pull in fakeExponential test cases * consensus/misc: reuse bigints * consensus/misc: nit renames, additional larger testcase --------- Co-authored-by: Roberto Bayardo Co-authored-by: Martin Holst Swende --- consensus/misc/eip4844.go | 54 +++++++++++++++++++++ consensus/misc/eip4844_test.go | 85 ++++++++++++++++++++++++++++++++++ params/protocol_params.go | 3 ++ 3 files changed, 142 insertions(+) create mode 100644 consensus/misc/eip4844.go create mode 100644 consensus/misc/eip4844_test.go diff --git a/consensus/misc/eip4844.go b/consensus/misc/eip4844.go new file mode 100644 index 0000000000..66ca9bd26d --- /dev/null +++ b/consensus/misc/eip4844.go @@ -0,0 +1,54 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package misc + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/params" +) + +var ( + minDataGasPrice = big.NewInt(params.BlobTxMinDataGasprice) + dataGaspriceUpdateFraction = big.NewInt(params.BlobTxDataGaspriceUpdateFraction) +) + +// CalcBlobFee calculates the blobfee from the header's excess data gas field. +func CalcBlobFee(excessDataGas *big.Int) *big.Int { + // If this block does not yet have EIP-4844 enabled, return the starting fee + if excessDataGas == nil { + return big.NewInt(params.BlobTxMinDataGasprice) + } + return fakeExponential(minDataGasPrice, excessDataGas, dataGaspriceUpdateFraction) +} + +// fakeExponential approximates factor * e ** (numerator / denominator) using +// Taylor expansion. +func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { + var ( + output = new(big.Int) + accum = new(big.Int).Mul(factor, denominator) + ) + for i := 1; accum.Sign() > 0; i++ { + output.Add(output, accum) + + accum.Mul(accum, numerator) + accum.Div(accum, denominator) + accum.Div(accum, big.NewInt(int64(i))) + } + return output.Div(output, denominator) +} diff --git a/consensus/misc/eip4844_test.go b/consensus/misc/eip4844_test.go new file mode 100644 index 0000000000..5838cab8e6 --- /dev/null +++ b/consensus/misc/eip4844_test.go @@ -0,0 +1,85 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package misc + +import ( + "fmt" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/params" +) + +func TestCalcBlobFee(t *testing.T) { + tests := []struct { + excessDataGas int64 + blobfee int64 + }{ + {0, 1}, + {1542706, 1}, + {1542707, 2}, + {10 * 1024 * 1024, 111}, + } + have := CalcBlobFee(nil) + if have.Int64() != params.BlobTxMinDataGasprice { + t.Errorf("nil test: blobfee mismatch: have %v, want %v", have, params.BlobTxMinDataGasprice) + } + for i, tt := range tests { + have := CalcBlobFee(big.NewInt(tt.excessDataGas)) + if have.Int64() != tt.blobfee { + t.Errorf("test %d: blobfee mismatch: have %v want %v", i, have, tt.blobfee) + } + } +} + +func TestFakeExponential(t *testing.T) { + tests := []struct { + factor int64 + numerator int64 + denominator int64 + want int64 + }{ + // When numerator == 0 the return value should always equal the value of factor + {1, 0, 1, 1}, + {38493, 0, 1000, 38493}, + {0, 1234, 2345, 0}, // should be 0 + {1, 2, 1, 6}, // approximate 7.389 + {1, 4, 2, 6}, + {1, 3, 1, 16}, // approximate 20.09 + {1, 6, 2, 18}, + {1, 4, 1, 49}, // approximate 54.60 + {1, 8, 2, 50}, + {10, 8, 2, 542}, // approximate 540.598 + {11, 8, 2, 596}, // approximate 600.58 + {1, 5, 1, 136}, // approximate 148.4 + {1, 5, 2, 11}, // approximate 12.18 + {2, 5, 2, 23}, // approximate 24.36 + {1, 50000000, 2225652, 5709098764}, + } + for i, tt := range tests { + f, n, d := big.NewInt(tt.factor), big.NewInt(tt.numerator), big.NewInt(tt.denominator) + original := fmt.Sprintf("%d %d %d", f, n, d) + have := fakeExponential(f, n, d) + if have.Int64() != tt.want { + t.Errorf("test %d: fake exponential mismatch: have %v want %v", i, have, tt.want) + } + later := fmt.Sprintf("%d %d %d", f, n, d) + if original != later { + t.Errorf("test %d: fake exponential modified arguments: have\n%v\nwant\n%v", i, later, original) + } + } +} diff --git a/params/protocol_params.go b/params/protocol_params.go index bb703d0b74..ab5ed13c06 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -159,6 +159,9 @@ const ( // up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529 RefundQuotient uint64 = 2 RefundQuotientEIP3529 uint64 = 5 + + BlobTxMinDataGasprice = 1 // Minimum gas price for data blobs + BlobTxDataGaspriceUpdateFraction = 2225652 // Controls the maximum rate of change for data gas price ) // Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations From 0b76eb3708626fbd2eb9c1b58d7b4eac6a5eec15 Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 4 Apr 2023 18:34:23 +0800 Subject: [PATCH 045/988] eth/tracers: report correct gasLimit in call tracers (#27029) This includes a semantic change to the `callTracer` as well as `flatCallTracer`. The value of field `gas` in the **first** call frame will change as follows: - It previously contained gas available after initial deductions (i.e. tx costs) - It will now contain the full tx gasLimit value Signed-off-by: jsvisa --- eth/tracers/internal/tracetest/calltrace_test.go | 6 +++--- eth/tracers/internal/tracetest/flat_calltrace_test.go | 4 ++-- .../internal/tracetest/testdata/call_tracer/create.json | 2 +- .../internal/tracetest/testdata/call_tracer/deep_calls.json | 2 +- .../tracetest/testdata/call_tracer/delegatecall.json | 2 +- .../testdata/call_tracer/inner_create_oog_outer_throw.json | 2 +- .../tracetest/testdata/call_tracer/inner_instafail.json | 2 +- .../tracetest/testdata/call_tracer/inner_revert_reason.json | 2 +- .../testdata/call_tracer/inner_throw_outer_revert.json | 2 +- .../internal/tracetest/testdata/call_tracer/oog.json | 2 +- .../internal/tracetest/testdata/call_tracer/revert.json | 2 +- .../tracetest/testdata/call_tracer/revert_reason.json | 4 ++-- .../tracetest/testdata/call_tracer/selfdestruct.json | 2 +- .../internal/tracetest/testdata/call_tracer/simple.json | 2 +- .../tracetest/testdata/call_tracer/simple_onlytop.json | 2 +- .../internal/tracetest/testdata/call_tracer/throw.json | 2 +- .../tracetest/testdata/call_tracer_flat/big_slow.json | 2 +- .../call_tracer_flat/callcode_precompiled_fail_hide.json | 2 +- .../testdata/call_tracer_flat/callcode_precompiled_oog.json | 2 +- .../call_tracer_flat/callcode_precompiled_throw.json | 2 +- .../tracetest/testdata/call_tracer_flat/create.json | 2 +- .../tracetest/testdata/call_tracer_flat/deep_calls.json | 2 +- .../tracetest/testdata/call_tracer_flat/delegatecall.json | 2 +- .../call_tracer_flat/delegatecall_parent_value.json | 2 +- .../internal/tracetest/testdata/call_tracer_flat/gas.json | 2 +- .../testdata/call_tracer_flat/include_precompiled.json | 2 +- .../call_tracer_flat/inner_create_oog_outer_throw.json | 2 +- .../testdata/call_tracer_flat/inner_instafail.json | 2 +- .../call_tracer_flat/inner_precompiled_wrong_gas.json | 2 +- .../testdata/call_tracer_flat/inner_throw_outer_revert.json | 2 +- .../tracetest/testdata/call_tracer_flat/nested_create.json | 2 +- .../call_tracer_flat/nested_create2_action_gas.json | 2 +- .../testdata/call_tracer_flat/nested_create_action_gas.json | 2 +- .../testdata/call_tracer_flat/nested_create_inerror.json | 2 +- .../testdata/call_tracer_flat/nested_pointer_issue.json | 2 +- .../internal/tracetest/testdata/call_tracer_flat/oog.json | 2 +- .../call_tracer_flat/option_convert_parity_errors.json | 2 +- .../tracetest/testdata/call_tracer_flat/result_output.json | 2 +- .../tracetest/testdata/call_tracer_flat/revert.json | 2 +- .../tracetest/testdata/call_tracer_flat/revert_reason.json | 2 +- .../tracetest/testdata/call_tracer_flat/selfdestruct.json | 2 +- .../tracetest/testdata/call_tracer_flat/simple.json | 2 +- .../testdata/call_tracer_flat/skip_no_balance_error.json | 2 +- .../testdata/call_tracer_flat/staticcall_precompiled.json | 2 +- .../tracetest/testdata/call_tracer_flat/suicide.json | 2 +- .../internal/tracetest/testdata/call_tracer_flat/throw.json | 2 +- .../tracetest/testdata/call_tracer_legacy/create.json | 2 +- .../tracetest/testdata/call_tracer_legacy/deep_calls.json | 2 +- .../tracetest/testdata/call_tracer_legacy/delegatecall.json | 2 +- .../call_tracer_legacy/inner_create_oog_outer_throw.json | 2 +- .../testdata/call_tracer_legacy/inner_instafail.json | 4 ++-- .../call_tracer_legacy/inner_throw_outer_revert.json | 2 +- .../internal/tracetest/testdata/call_tracer_legacy/oog.json | 2 +- .../tracetest/testdata/call_tracer_legacy/revert.json | 2 +- .../testdata/call_tracer_legacy/revert_reason.json | 2 +- .../tracetest/testdata/call_tracer_legacy/selfdestruct.json | 2 +- .../tracetest/testdata/call_tracer_legacy/simple.json | 2 +- .../tracetest/testdata/call_tracer_legacy/throw.json | 2 +- .../tracetest/testdata/call_tracer_withLog/calldata.json | 2 +- .../testdata/call_tracer_withLog/delegatecall.json | 2 +- .../testdata/call_tracer_withLog/multi_contracts.json | 2 +- .../tracetest/testdata/call_tracer_withLog/multilogs.json | 2 +- .../tracetest/testdata/call_tracer_withLog/notopic.json | 2 +- .../tracetest/testdata/call_tracer_withLog/simple.json | 2 +- .../tracetest/testdata/call_tracer_withLog/tx_failed.json | 2 +- .../testdata/call_tracer_withLog/tx_partial_failed.json | 2 +- .../testdata/call_tracer_withLog/with_onlyTopCall.json | 2 +- eth/tracers/js/goja.go | 2 +- eth/tracers/native/call.go | 2 +- 69 files changed, 74 insertions(+), 74 deletions(-) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index c5405e2451..a70842d40c 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -302,13 +302,13 @@ func TestInternals(t *testing.T) { byte(vm.CALL), }, tracer: mkTracer("callTracer", nil), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x7148","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, }, { name: "Stack depletion in LOG0", code: []byte{byte(vm.LOG3)}, tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x7148","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, }, { name: "Mem expansion in LOG0", @@ -321,7 +321,7 @@ func TestInternals(t *testing.T) { byte(vm.LOG0), }, tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x7148","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`, + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`, }, { // Leads to OOM on the prestate tracer diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 8cd5a42bc0..9b51ba80ff 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -124,8 +124,8 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err != nil { return fmt.Errorf("failed to retrieve trace result: %v", err) } - ret := new([]flatCallTrace) - if err := json.Unmarshal(res, ret); err != nil { + ret := make([]flatCallTrace, 0) + if err := json.Unmarshal(res, &ret); err != nil { return fmt.Errorf("failed to unmarshal trace result: %v", err) } if !jsonEqualFlat(ret, test.Result) { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer/create.json index 8557f8efd6..df0b2872b4 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/create.json @@ -47,7 +47,7 @@ "input": "0xf907ef098504e3b29200830897be8080b9079c606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a1129a01060f46676a5dff6f407f0f51eb6f37f5c8c54e238c70221e18e65fc29d3ea65a0557b01c50ff4ffaac8ed6e5d31237a4ecbac843ab1bfe8bb0165a0060df7c54f", "result": { "from": "0x13e4acefe6a6700604929946e70e6443e4e73447", - "gas": "0x5e106", + "gas": "0x897be", "gasUsed": "0x897be", "input": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11", "output": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json index 174f23fc45..975616064a 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json @@ -399,7 +399,7 @@ } ], "from": "0x70c9217d814985faef62b124420f8dfbddd96433", - "gas": "0x37b38", + "gas": "0x3d090", "gasUsed": "0x1810b", "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json index 5fd946f734..6a2cda7dc9 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json @@ -87,7 +87,7 @@ } ], "from": "0xa529806c67cc6486d4d62024471772f47f6fd672", - "gas": "0x2d6e28", + "gas": "0x2dc6c0", "gasUsed": "0xbd55", "input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e", "to": "0x269296dddce321a6bcbaa2f0181127593d732cba", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json index 95c5889269..bb16a4a430 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json @@ -67,7 +67,7 @@ ], "error": "invalid jump destination", "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", - "gas": "0x435c8", + "gas": "0x493e0", "gasUsed": "0x493e0", "input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8", "to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json index 4d7305a154..9b45b52fe9 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json @@ -54,7 +54,7 @@ "from": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", "to": "0x6c06b16512b332e6cd8293a2974872674716ce18", "value": "0x0", - "gas": "0x1a466", + "gas": "0x1f97e", "gasUsed": "0x72de", "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000" } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json index b5355f65fe..ad0627ccd6 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json @@ -50,7 +50,7 @@ "input": "0x02f9029d82053980849502f90085010c388d00832dc6c08080b90241608060405234801561001057600080fd5b50600060405161001f906100a2565b604051809103906000f08015801561003b573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b815260040160006040518083038186803b15801561008457600080fd5b505afa158015610098573d6000803e3d6000fd5b50505050506100af565b610145806100fc83390190565b603f806100bd6000396000f3fe6080604052600080fdfea264697066735822122077f7dbd3450d6e817079cf3fe27107de5768bb3163a402b94e2206b468eb025664736f6c63430008070033608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033c001a07566181071cabaf58b70fc41557eb813bfc7a24f5c58554e7fed0bf7c031f169a0420af50b5fe791a4d839e181a676db5250b415dfb35cb85d544db7a1475ae2cc", "result": { "from": "0x3623191d4ccfbbdf09e8ebf6382a1f8257417bc1", - "gas": "0x2cd774", + "gas": "0x2dc6c0", "gasUsed": "0x25590", "input": "0x608060405234801561001057600080fd5b50600060405161001f906100a2565b604051809103906000f08015801561003b573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b815260040160006040518083038186803b15801561008457600080fd5b505afa158015610098573d6000803e3d6000fd5b50505050506100af565b610145806100fc83390190565b603f806100bd6000396000f3fe6080604052600080fdfea264697066735822122077f7dbd3450d6e817079cf3fe27107de5768bb3163a402b94e2206b468eb025664736f6c63430008070033608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033", "output": "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012546869732063616c6c6564206661696c65640000000000000000000000000000", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json index 2be2dee23f..a023ed6d9b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json @@ -71,7 +71,7 @@ ], "error": "execution reverted", "from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826", - "gas": "0x78d9e", + "gas": "0x7dfa6", "gasUsed": "0x7c1c8", "input": "0x", "to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json index 8022f53a99..333bdd038c 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json @@ -50,7 +50,7 @@ "result": { "error": "out of gas", "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", - "gas": "0x7045", + "gas": "0xca1d", "gasUsed": "0xca1d", "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json index aee894d11f..3207a298a9 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json @@ -48,7 +48,7 @@ "result": { "error": "execution reverted", "from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9", - "gas": "0x2d55e8", + "gas": "0x2dc6c0", "gasUsed": "0x719b", "input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000", "to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json index 8c8abd4d6d..f02e5c6863 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json @@ -27,7 +27,7 @@ "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, - "IstanbulBlock":1561651, + "IstanbulBlock": 1561651, "chainId": 5, "daoForkSupport": true, "eip150Block": 0, @@ -53,7 +53,7 @@ "result": { "error": "execution reverted", "from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", - "gas": "0x2d7308", + "gas": "0x2dc6c0", "gasUsed": "0x5940", "input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", "to": "0xf58833cf0c791881b494eb79d461e08a1f043f52", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json index a89d4dc745..620df1d614 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json @@ -64,7 +64,7 @@ } ], "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", - "gas": "0x10738", + "gas": "0x15f90", "gasUsed": "0x6fcb", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json index 0a6d66a5c4..6c7d01de1f 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json @@ -69,7 +69,7 @@ } ], "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", - "gas": "0x10738", + "gas": "0x15f90", "gasUsed": "0x9751", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x0000000000000000000000000000000000000000000000000000000000000001", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json b/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json index 5e25a01cef..affb4ab033 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json @@ -61,7 +61,7 @@ }, "result": { "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", - "gas": "0x10738", + "gas": "0x15f90", "gasUsed": "0x9751", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x0000000000000000000000000000000000000000000000000000000000000001", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json index 76fae3c392..499b449a6e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json @@ -52,7 +52,7 @@ "result": { "error": "invalid jump destination", "from": "0x70c9217d814985faef62b124420f8dfbddd96433", - "gas": "0x37b38", + "gas": "0x3d090", "gasUsed": "0x3d090", "input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json index e54ede92b0..617f52a14e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json @@ -46,7 +46,7 @@ { "action": { "from": "0xf8bda96b67036ee48107f2a0695ea673479dda56", - "gas": "0x22410c", + "gas": "0x231860", "init": "0x5b620186a05a131560135760016020526000565b600080601f600039601f565b6000f3", "value": "0x0" }, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json index be198885cb..c796804a4b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf08", + "gas": "0x19f78", "init": "0x60206000600060006013600462030d40f260025560005160005500" }, "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json index 94b864ff49..fb29e49660 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf08", + "gas": "0x1a758", "init": "0x7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb7f260025560a060020a60805106600055600054321460015500" }, "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json index 506dc5ff68..3c1e370f91 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf08", + "gas": "0x1a034", "init": "0x36600060003760406103e8366000600060095af26001556103e8516002556104085160035500" }, "error": "out of gas", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json index b83236690c..11bc4eae02 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json @@ -49,7 +49,7 @@ { "action": { "from": "0x13e4acefe6a6700604929946e70e6443e4e73447", - "gas": "0x5e106", + "gas": "0x897be", "init": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11", "value": "0x0" }, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json index 5931b40809..375a163614 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json @@ -113,7 +113,7 @@ "action": { "callType": "call", "from": "0x70c9217d814985faef62b124420f8dfbddd96433", - "gas": "0x37b38", + "gas": "0x3d090", "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json index 3a03ffc0fa..e5a37cbfdd 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json @@ -66,7 +66,7 @@ "action": { "callType": "call", "from": "0xa529806c67cc6486d4d62024471772f47f6fd672", - "gas": "0x2d6e28", + "gas": "0x2dc6c0", "input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e", "to": "0x269296dddce321a6bcbaa2f0181127593d732cba", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json index 800a6a4288..177912420a 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json @@ -59,7 +59,7 @@ "action": { "callType": "call", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "gas": "0x10b68", + "gas": "0x15f90", "input": "0x4e45375a47413941", "to": "0x91765918420bcb5ad22ee0997abed04056705798", "value": "0x8ac7230489e80000" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json index 3b44a5e2cd..d977dbe30d 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf08", + "gas": "0x1a9c8", "init": "0x601b565b6000555b005b630badf00d6003565b63c001f00d6003565b7319e7e376e7c213b7e7e7e46cc70a5dd086daff2a7f22ae6da6b482f9b1b19b0b897c3fd43884180a1c5ee361e1107a1bc635649dda600052601b603f537f16433dce375ce6dc8151d3f0a22728bc4a1d9fd6ed39dfd18b4609331937367f6040527f306964c0cf5d74f04129fdc60b54d35b596dde1bf89ad92cb4123318f4c0e40060605260206080607f60006000600161fffff21560075760805114601257600956" }, "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json index d33375bfd2..0f28c07a9b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json @@ -83,7 +83,7 @@ "balance": "0x0", "callType": "call", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "gas": "0x119d28", + "gas": "0x124f80", "input": "0x13f955e100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000019004000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a67040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae704000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc30304000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de04000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e000000000000000000000000000000000", "refundAddress": "0x0000000000000000000000000000000000000000", "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json index 170948e156..6c4ce18063 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json @@ -58,7 +58,7 @@ "action": { "callType": "call", "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", - "gas": "0x435c8", + "gas": "0x493e0", "input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8", "to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json index 328b743270..4de08f2cca 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json @@ -54,7 +54,7 @@ "action": { "callType": "call", "from": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", - "gas": "0x1a466", + "gas": "0x1f97e", "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000", "to": "0x6c06b16512b332e6cd8293a2974872674716ce18", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json index 6b5738101c..70442fdb9a 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json @@ -80,7 +80,7 @@ "balance": "0x0", "callType": "call", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "gas": "0x119d28", + "gas": "0x124f80", "input": "0x13f955e100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000019004000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a67040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae704000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc30304000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de04000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e000000000000000000000000000000000", "refundAddress": "0x0000000000000000000000000000000000000000", "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json index b11b8e040d..bc94708718 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json @@ -61,7 +61,7 @@ "action": { "callType": "call", "from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826", - "gas": "0x78d9e", + "gas": "0x7dfa6", "input": "0x", "to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76", "value": "0xe92596fd6290000" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json index 64425dbadd..3fcc61fc80 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0x3951c", + "gas": "0x53e90", "init": "0x60606040525b60405161015b806102a0833901809050604051809103906000f0600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b610247806100596000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900480632ef9db1314610044578063e37678761461007157610042565b005b61005b6004803590602001803590602001506100ad565b6040518082815260200191505060405180910390f35b61008860048035906020018035906020015061008a565b005b8060006000506000848152602001908152602001600020600050819055505b5050565b6000600060008484604051808381526020018281526020019250505060405180910390209150610120600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff167f6164640000000000000000000000000000000000000000000000000000000000846101e3565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681868660405180807f616464000000000000000000000000000000000000000000000000000000000081526020015060200184815260200183815260200182815260200193505050506000604051808303816000866161da5a03f191505050600060005060008281526020019081526020016000206000505492506101db565b505092915050565b60004340848484604051808581526020018473ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140183815260200182815260200194505050505060405180910390209050610240565b9392505050566060604052610148806100136000396000f30060606040526000357c010000000000000000000000000000000000000000000000000000000090048063471407e614610044578063e37678761461007757610042565b005b6100616004803590602001803590602001803590602001506100b3565b6040518082815260200191505060405180910390f35b61008e600480359060200180359060200150610090565b005b8060006000506000848152602001908152602001600020600050819055505b5050565b6000818301905080506100c684826100d5565b8090506100ce565b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff16828260405180807f7265676973746572496e74000000000000000000000000000000000000000000815260200150602001838152602001828152602001925050506000604051808303816000866161da5a03f1915050505b505056" }, "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json index bbd9904d9c..0eaa3f867a 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf6c", + "gas": "0x19ed8", "init": "0x6000600060006000f500" }, "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json index 19ae5fc5d3..132b84df36 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf08", + "gas": "0x19ee4", "init": "0x5a600055600060006000f0505a60015500" }, "error": "out of gas", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json index a62d4bb645..28e96684b2 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json @@ -61,7 +61,7 @@ "from": "0xa3b31cbd5168d3c99756660d4b7625d679e12573", "to": "0x76554b33410b6d90b7dc889bfed0451ad195f27e", "value": "0x0", - "gas": "0x2e138", + "gas": "0x33450", "input": "0x391521f4", "callType": "call" }, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json index 792845538f..c3191d61bc 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json @@ -99,7 +99,7 @@ { "action": { "from": "0x5409ed021d9299bf6814279a6a1411a7e866a631", - "gas": "0x215c47", + "gas": "0x2c8c7f", "init": "0x60806040523480156200001157600080fd5b5060405162002d2c38038062002d2c83398101806040526200003791908101906200051d565b6000805433600160a060020a031991821617825560018054909116600160a060020a0386161790558251849084908490849081906200007e906004906020870190620003d0565b50825162000094906005906020860190620003d0565b50620000b0836010640100000000620019476200036f82021704565b9150620000cd846010640100000000620019476200036f82021704565b60028054600160a060020a03948516600160a060020a031991821617909155600380549285169290911691909117905550600154604080517f4552433230546f6b656e28616464726573732900000000000000000000000000815290519081900360130181207f6070410800000000000000000000000000000000000000000000000000000000825291909216945063607041089350620001739250906004016200068e565b602060405180830381600087803b1580156200018e57600080fd5b505af1158015620001a3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620001c99190810190620004f4565b9050600160a060020a038116151562000219576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200021090620006b0565b60405180910390fd5b6002546040517f095ea7b3000000000000000000000000000000000000000000000000000000008152600160a060020a039091169063095ea7b39062000268908490600019906004016200066f565b602060405180830381600087803b1580156200028357600080fd5b505af115801562000298573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002be9190810190620005a1565b506003546040517f095ea7b3000000000000000000000000000000000000000000000000000000008152600160a060020a039091169063095ea7b3906200030e908490600019906004016200066f565b602060405180830381600087803b1580156200032957600080fd5b505af11580156200033e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620003649190810190620005a1565b50505050506200077a565b600081601401835110151515620003b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000210906200069e565b506014818301810151910190600160a060020a03165b92915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200041357805160ff191683800117855562000443565b8280016001018555821562000443579182015b828111156200044357825182559160200191906001019062000426565b506200045192915062000455565b5090565b6200047291905b808211156200045157600081556001016200045c565b90565b600062000483825162000711565b9392505050565b600062000483825162000742565b6000601f82018313620004aa57600080fd5b8151620004c1620004bb82620006e9565b620006c2565b91508082526020830160208301858383011115620004de57600080fd5b620004eb83828462000747565b50505092915050565b6000602082840312156200050757600080fd5b600062000515848462000475565b949350505050565b6000806000606084860312156200053357600080fd5b600062000541868662000475565b93505060208401516001604060020a038111156200055e57600080fd5b6200056c8682870162000498565b92505060408401516001604060020a038111156200058957600080fd5b620005978682870162000498565b9150509250925092565b600060208284031215620005b457600080fd5b60006200051584846200048a565b620005cd8162000711565b82525050565b620005cd816200071d565b602681527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601881527f554e524547495354455245445f41535345545f50524f58590000000000000000602082015260400190565b620005cd8162000472565b604081016200067f8285620005c2565b62000483602083018462000664565b60208101620003ca8284620005d3565b60208082528101620003ca81620005de565b60208082528101620003ca8162000634565b6040518181016001604060020a0381118282101715620006e157600080fd5b604052919050565b60006001604060020a038211156200070057600080fd5b506020601f91909101601f19160190565b600160a060020a031690565b7fffffffff000000000000000000000000000000000000000000000000000000001690565b151590565b60005b83811015620007645781810151838201526020016200074a565b8381111562000774576000848401525b50505050565b6125a2806200078a6000396000f30060806040526004361061006c5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166318978e8281146100c8578063630f1e6c146100f25780638da5cb5b146101125780639395525c14610134578063f2fde38b14610147575b60025473ffffffffffffffffffffffffffffffffffffffff1633146100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612388565b60405180910390fd5b005b6100db6100d6366004611df1565b610167565b6040516100e9929190612488565b60405180910390f35b3480156100fe57600080fd5b506100c661010d366004611eec565b6102f7565b34801561011e57600080fd5b50610127610388565b6040516100e99190612337565b6100db610142366004611d0b565b6103a4565b34801561015357600080fd5b506100c6610162366004611ce5565b61050a565b61016f6119fa565b6101776119fa565b6000806101826105bb565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100600188161502019095169490940493840181900481028201810190925282815261025c939092909183018282801561022d5780601f106102025761010080835404028352916020019161022d565b820191906000526020600020905b81548152906001019060200180831161021057829003601f168201915b50505050508c600081518110151561024157fe5b6020908102909101015161014001519063ffffffff61069616565b156102875761026c8b8b8b6107c3565b935061028084600001518560600151610ac1565b90506102ae565b6102928b8b8b610b03565b9350836060015191506102a68883896107c3565b845190935090505b6102c2846020015184602001518888610d15565b6102e98b60008151811015156102d457fe5b90602001906020020151610140015182610f29565b505097509795505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610348576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612438565b61038383838080601f01602080910402602001604051908101604052809392919081815260200183838082843750879450610f299350505050565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b6103ac6119fa565b6103b46119fa565b60008060006103c16105bb565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152610441939092909183018282801561022d5780601f106102025761010080835404028352916020019161022d565b156104925761046a670de0b6b3a7640000610464670de0b6b3a76400008a611045565b3461108f565b92506104778b848c6110e7565b945061048b85600001518660600151610ac1565b90506104d6565b6104ad670d2f13f7789f0000670de0b6b3a76400003461108f565b92506104ba8b848c6110e7565b9450846060015191506104ce89838a6107c3565b855190945090505b6104ea856020015185602001518989610d15565b6104fc8b60008151811015156102d457fe5b505050965096945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461055b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612438565b73ffffffffffffffffffffffffffffffffffffffff8116156105b857600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b50565b600034116105f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612398565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004016000604051808303818588803b15801561067b57600080fd5b505af115801561068f573d6000803e3d6000fd5b5050505050565b6000815183511480156107ba5750816040518082805190602001908083835b602083106106f257805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016106b5565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0180199092169116179052604051919093018190038120885190955088945090928392508401908083835b6020831061078757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161074a565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916145b90505b92915050565b6107cb6119fa565b60608060008060008060006107de6119fa565b8a15156107ea57610ab2565b6004805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561088e5780601f106108635761010080835404028352916020019161088e565b820191906000526020600020905b81548152906001019060200180831161087157829003601f168201915b505060058054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152969e509194509250840190508282801561093d5780601f106109125761010080835404028352916020019161093d565b820191906000526020600020905b81548152906001019060200180831161092057829003601f168201915b50505050509650600095508b519450600093505b838514610a7857878c8581518110151561096757fe5b6020908102909101015161014001528b5187908d908690811061098657fe5b60209081029091010151610160015261099f8b87610ac1565b9250610a068c858151811015156109b257fe5b9060200190602002015160a00151610a008e878151811015156109d157fe5b90602001906020020151608001518f888151811015156109ed57fe5b9060200190602002015160e00151610ac1565b8561128b565b9150610a418c85815181101515610a1957fe5b90602001906020020151838c87815181101515610a3257fe5b906020019060200201516112e6565b9050610a4d898261135e565b610a5f89600001518a60600151610ac1565b95508a8610610a6d57610a78565b600190930192610951565b8a861015610ab2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612418565b50505050505050509392505050565b600082821115610afd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123b8565b50900390565b610b0b6119fa565b606080600080600080610b1c6119fa565b60008b6000815181101515610b2d57fe5b6020908102919091018101516101400151600580546040805160026001841615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190931692909204601f8101869004860283018601909152808252929b5092909190830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505096508b519550600094505b848614610cdb57878c86815181101515610c0b57fe5b6020908102909101015161014001528b5187908d9087908110610c2a57fe5b6020908102909101015161016001528851610c46908c90610ac1565b9350610c898c86815181101515610c5957fe5b9060200190602002015160a001518d87815181101515610c7557fe5b90602001906020020151608001518661128b565b9250610cb58c86815181101515610c9c57fe5b90602001906020020151848c88815181101515610a3257fe5b9150610cc1898361135e565b5087518a8110610cd057610cdb565b600190940193610bf5565b8a811015610ab2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612418565b600080808066b1a2bc2ec50000861115610d5b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612448565b610d658888611045565b935034841115610da1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123a8565b610dab3485610ac1565b9250610dc086670de0b6b3a76400008a61108f565b915082821115610dfc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612428565b6000831115610f1f576002546040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d90610e5b9086906004016124a4565b600060405180830381600087803b158015610e7557600080fd5b505af1158015610e89573d6000803e3d6000fd5b505050506000821115610edb5760405173ffffffffffffffffffffffffffffffffffffffff86169083156108fc029084906000818181858888f19350505050158015610ed9573d6000803e3d6000fd5b505b610ee58383610ac1565b90506000811115610f1f57604051339082156108fc029083906000818181858888f19350505050158015610f1d573d6000803e3d6000fd5b505b5050505050505050565b6000610f3b838263ffffffff6113c016565b604080517f4552433230546f6b656e28616464726573732900000000000000000000000000815290519081900360130190209091507fffffffff0000000000000000000000000000000000000000000000000000000080831691161415610fab57610fa6838361142d565b610383565b604080517f455243373231546f6b656e28616464726573732c75696e7432353629000000008152905190819003601c0190207fffffffff000000000000000000000000000000000000000000000000000000008281169116141561101357610fa6838361161b565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123f8565b600082820183811015611084576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123e8565b8091505b5092915050565b60008083116110ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123d8565b6110dd6110d78584611703565b8461175e565b90505b9392505050565b6110ef6119fa565b60608060008060006110ff6119fa565b89600081518110151561110e57fe5b6020908102919091018101516101400151600580546040805160026001841615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190931692909204601f8101869004860283018601909152808252929950929091908301828280156111c65780601f1061119b576101008083540402835291602001916111c6565b820191906000526020600020905b8154815290600101906020018083116111a957829003601f168201915b5050505050945089519350600092505b82841461127e57858a848151811015156111ec57fe5b602090810290910101516101400152895185908b908590811061120b57fe5b90602001906020020151610160018190525061122b898860200151610ac1565b91506112578a8481518110151561123e57fe5b90602001906020020151838a86815181101515610a3257fe5b9050611263878261135e565b602087015189116112735761127e565b6001909201916111d6565b5050505050509392505050565b60008083116112c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123d8565b6110dd6110d76112d68685611703565b6112e1866001610ac1565b611045565b6112ee6119fa565b606060006112fd868686611775565b600154815191935073ffffffffffffffffffffffffffffffffffffffff1691506080908390602082016000855af1801561135457825184526020830151602085015260408301516040850152606083015160608501525b5050509392505050565b8151815161136c9190611045565b8252602080830151908201516113829190611045565b60208301526040808301519082015161139b9190611045565b6040830152606080830151908201516113b49190611045565b60609092019190915250565b600081600401835110151515611402576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612468565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b60008061144184601063ffffffff61194716565b604080517f7472616e7366657228616464726573732c75696e7432353629000000000000008152905190819003601901812091935073ffffffffffffffffffffffffffffffffffffffff8416919061149f903390879060240161236d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931783525181519192909182919080838360005b8381101561154357818101518382015260200161152b565b50505050905090810190601f1680156115705780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af1925050508015156115bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612408565b3d156115dc575060003d602014156115dc5760206000803e506000515b801515611615576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612408565b50505050565b60008060018314611658576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612478565b61166984601063ffffffff61194716565b915061167c84602463ffffffff6119a816565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8316906323b872dd906116d590309033908690600401612345565b600060405180830381600087803b1580156116ef57600080fd5b505af1158015610f1f573d6000803e3d6000fd5b6000808315156117165760009150611088565b5082820282848281151561172657fe5b0414611084576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123e8565b600080828481151561176c57fe5b04949350505050565b604080517fb4be83d5000000000000000000000000000000000000000000000000000000006020808301919091526060602483018181528751608485019081528884015160a48601529488015160c48501529087015160e4840152608087015161010484015260a087015161012484015260c087015161014484015260e08701516101648401526101008701516101848401526101208701516101a4840152610140870180516101c485019081526101608901516101e4860152610180905251805161020485018190529394919384936044870192849261022489019291820191601f82010460005b8181101561187c57835185526020948501949093019260010161185e565b50505050818103610160808401919091528a0151805180835260209283019291820191601f82010460005b818110156118c55783518552602094850194909301926001016118a7565b50505089845250848103602093840190815288518083529093918201918981019190601f82010460005b8181101561190d5783518552602094850194909301926001016118ef565b5050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08883030188525060405250505050509392505050565b600081601401835110151515611989576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612458565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b60006107ba83836000816020018351101515156119f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123c8565b50016020015190565b608060405190810160405280600081526020016000815260200160008152602001600081525090565b60006107ba8235612540565b6000601f82018313611a4057600080fd5b8135611a53611a4e826124d9565b6124b2565b81815260209384019390925082018360005b83811015611a915781358601611a7b8882611b41565b8452506020928301929190910190600101611a65565b5050505092915050565b6000601f82018313611aac57600080fd5b8135611aba611a4e826124d9565b81815260209384019390925082018360005b83811015611a915781358601611ae28882611b90565b8452506020928301929190910190600101611acc565b600080601f83018413611b0a57600080fd5b50813567ffffffffffffffff811115611b2257600080fd5b602083019150836001820283011115611b3a57600080fd5b9250929050565b6000601f82018313611b5257600080fd5b8135611b60611a4e826124fa565b91508082526020830160208301858383011115611b7c57600080fd5b611b8783828461255c565b50505092915050565b60006101808284031215611ba357600080fd5b611bae6101806124b2565b90506000611bbc8484611a23565b8252506020611bcd84848301611a23565b6020830152506040611be184828501611a23565b6040830152506060611bf584828501611a23565b6060830152506080611c0984828501611cd9565b60808301525060a0611c1d84828501611cd9565b60a08301525060c0611c3184828501611cd9565b60c08301525060e0611c4584828501611cd9565b60e083015250610100611c5a84828501611cd9565b61010083015250610120611c7084828501611cd9565b6101208301525061014082013567ffffffffffffffff811115611c9257600080fd5b611c9e84828501611b41565b6101408301525061016082013567ffffffffffffffff811115611cc057600080fd5b611ccc84828501611b41565b6101608301525092915050565b60006107ba8235612559565b600060208284031215611cf757600080fd5b6000611d038484611a23565b949350505050565b60008060008060008060c08789031215611d2457600080fd5b863567ffffffffffffffff811115611d3b57600080fd5b611d4789828a01611a9b565b965050602087013567ffffffffffffffff811115611d6457600080fd5b611d7089828a01611a2f565b955050604087013567ffffffffffffffff811115611d8d57600080fd5b611d9989828a01611a9b565b945050606087013567ffffffffffffffff811115611db657600080fd5b611dc289828a01611a2f565b9350506080611dd389828a01611cd9565b92505060a0611de489828a01611a23565b9150509295509295509295565b600080600080600080600060e0888a031215611e0c57600080fd5b873567ffffffffffffffff811115611e2357600080fd5b611e2f8a828b01611a9b565b9750506020611e408a828b01611cd9565b965050604088013567ffffffffffffffff811115611e5d57600080fd5b611e698a828b01611a2f565b955050606088013567ffffffffffffffff811115611e8657600080fd5b611e928a828b01611a9b565b945050608088013567ffffffffffffffff811115611eaf57600080fd5b611ebb8a828b01611a2f565b93505060a0611ecc8a828b01611cd9565b92505060c0611edd8a828b01611a23565b91505092959891949750929550565b600080600060408486031215611f0157600080fd5b833567ffffffffffffffff811115611f1857600080fd5b611f2486828701611af8565b93509350506020611f3786828701611cd9565b9150509250925092565b611f4a81612540565b82525050565b602381527f44454641554c545f46554e4354494f4e5f574554485f434f4e54524143545f4f60208201527f4e4c590000000000000000000000000000000000000000000000000000000000604082015260600190565b601181527f494e56414c49445f4d53475f56414c5545000000000000000000000000000000602082015260400190565b600d81527f4f564552534f4c445f5745544800000000000000000000000000000000000000602082015260400190565b601181527f55494e543235365f554e444552464c4f57000000000000000000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601081527f4449564953494f4e5f42595f5a45524f00000000000000000000000000000000602082015260400190565b601081527f55494e543235365f4f564552464c4f5700000000000000000000000000000000602082015260400190565b601781527f554e535550504f525445445f41535345545f50524f5859000000000000000000602082015260400190565b600f81527f5452414e534645525f4641494c45440000000000000000000000000000000000602082015260400190565b601481527f434f4d504c4554455f46494c4c5f4641494c4544000000000000000000000000602082015260400190565b601a81527f494e53554646494349454e545f4554485f52454d41494e494e47000000000000602082015260400190565b601381527f4f4e4c595f434f4e54524143545f4f574e455200000000000000000000000000602082015260400190565b601881527f4645455f50455243454e544147455f544f4f5f4c415247450000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b602581527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160208201527f5549524544000000000000000000000000000000000000000000000000000000604082015260600190565b600e81527f494e56414c49445f414d4f554e54000000000000000000000000000000000000602082015260400190565b805160808301906122f9848261232e565b50602082015161230c602085018261232e565b50604082015161231f604085018261232e565b50606082015161161560608501825b611f4a81612559565b602081016107bd8284611f41565b606081016123538286611f41565b6123606020830185611f41565b611d03604083018461232e565b6040810161237b8285611f41565b6110e0602083018461232e565b602080825281016107bd81611f50565b602080825281016107bd81611fa6565b602080825281016107bd81611fd6565b602080825281016107bd81612006565b602080825281016107bd81612036565b602080825281016107bd8161208c565b602080825281016107bd816120bc565b602080825281016107bd816120ec565b602080825281016107bd8161211c565b602080825281016107bd8161214c565b602080825281016107bd8161217c565b602080825281016107bd816121ac565b602080825281016107bd816121dc565b602080825281016107bd8161220c565b602080825281016107bd81612262565b602080825281016107bd816122b8565b610100810161249782856122e8565b6110e060808301846122e8565b602081016107bd828461232e565b60405181810167ffffffffffffffff811182821017156124d157600080fd5b604052919050565b600067ffffffffffffffff8211156124f057600080fd5b5060209081020190565b600067ffffffffffffffff82111561251157600080fd5b506020601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b73ffffffffffffffffffffffffffffffffffffffff1690565b90565b828183375060009101525600a265627a7a72305820d9f418f11e0f91f06f6f9d22924be0add925495eeb76a6388b5417adb505eeb36c6578706572696d656e74616cf5003700000000000000000000000048bacb9266a570d521063ef5dd96e61686dbe788000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e808200000000000000000000000000000000000000000000000000000000", "value": "0x0" }, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json index 26ae2f0604..bd6059faef 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json @@ -52,7 +52,7 @@ "action": { "callType": "call", "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", - "gas": "0x7045", + "gas": "0xca1d", "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json index 0216c318b5..8888d3e68a 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json @@ -55,7 +55,7 @@ "action": { "callType": "call", "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", - "gas": "0x7045", + "gas": "0xca1d", "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json index f58d20cd2b..62baf333b6 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json @@ -68,7 +68,7 @@ "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "to": "0x531f76bad925f6a925474996c7d738c1008045f6", "value": "0xde0b6b3a7640000", - "gas": "0x3b920", + "gas": "0x40b28", "input": "0x", "callType": "call" }, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json index 897aebb0e0..b0346d8603 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json @@ -50,7 +50,7 @@ "action": { "callType": "call", "from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9", - "gas": "0x2d55e8", + "gas": "0x2dc6c0", "input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000", "to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json index 62dbaf20dc..6759b05e52 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json @@ -55,7 +55,7 @@ "action": { "callType": "call", "from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", - "gas": "0x2d7308", + "gas": "0x2dc6c0", "input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", "to": "0xf58833cf0c791881b494eb79d461e08a1f043f52", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json index cd34d0b6d0..74fd87cc6c 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf08", + "gas": "0x19ecc", "init": "0x605a600053600160006001f0ff00" }, "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json index 6d084410a3..a7244e9747 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json @@ -61,7 +61,7 @@ "action": { "callType": "call", "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", - "gas": "0x10738", + "gas": "0x15f90", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json index d530fe908b..96060d5545 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xd550", + "gas": "0x1aab0", "init": "0x7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b5547f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000000000000000000000000000000000000000c3507f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000037f055" }, "error": "out of gas", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json index 9291149bdb..45ffbe2db9 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json @@ -65,7 +65,7 @@ "balance": "0x0", "callType": "call", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "gas": "0x4053e", + "gas": "0x48196", "input": "0x200b1e64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001b9af799918107e9a339eba0584b8b60b35aae6f087c74f6bfc00c9301849b204d094ed65e09c76c2597f5516f9440aad2921e50dde096e7caaa65a536d4d9265e00000000000000000000000000000000000000000000000000000000000000504269747669657720697320616e20616d617a696e6720776562736974652e20596f752073686f756c6420646566696e6974656c792061646420796f75722070726f6475637420746f2069742e20e282bf00000000000000000000000000000000", "refundAddress": "0x0000000000000000000000000000000000000000", "to": "0x8521f13dd5e4bc3dab3cf0f01a195a5af899e851", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json index bd9e057c02..16d43767d5 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json @@ -55,7 +55,7 @@ "action": { "callType": "call", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "gas": "0x445708", + "gas": "0x44aa20", "input": "0x41c0e1b5", "to": "0x8ee79c5b3f6e1d214d2c4fcf7ea4092a32e26e91", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json index b119bed528..a001178a42 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json @@ -54,7 +54,7 @@ "action": { "callType": "call", "from": "0x70c9217d814985faef62b124420f8dfbddd96433", - "gas": "0x37b38", + "gas": "0x3d090", "input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json index 8557f8efd6..df0b2872b4 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json @@ -47,7 +47,7 @@ "input": "0xf907ef098504e3b29200830897be8080b9079c606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a1129a01060f46676a5dff6f407f0f51eb6f37f5c8c54e238c70221e18e65fc29d3ea65a0557b01c50ff4ffaac8ed6e5d31237a4ecbac843ab1bfe8bb0165a0060df7c54f", "result": { "from": "0x13e4acefe6a6700604929946e70e6443e4e73447", - "gas": "0x5e106", + "gas": "0x897be", "gasUsed": "0x897be", "input": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11", "output": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json index ef28a930b3..80fc0b0ada 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json @@ -404,7 +404,7 @@ } ], "from": "0x70c9217d814985faef62b124420f8dfbddd96433", - "gas": "0x37b38", + "gas": "0x3d090", "gasUsed": "0x1810b", "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", "output": "0x", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json index c4c1390fa2..2cd28bacc4 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json @@ -86,7 +86,7 @@ } ], "from": "0xa529806c67cc6486d4d62024471772f47f6fd672", - "gas": "0x2d6e28", + "gas": "0x2dc6c0", "gasUsed": "0xbd55", "input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e", "output": "0x", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json index 0b60e34d0e..07fda21d4b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json @@ -67,7 +67,7 @@ ], "error": "invalid jump destination", "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", - "gas": "0x435c8", + "gas": "0x493e0", "gasUsed": "0x493e0", "input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8", "to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json index c1ed766ef9..16e4136230 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json @@ -54,7 +54,7 @@ "from": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", "to": "0x6c06b16512b332e6cd8293a2974872674716ce18", "value": "0x0", - "gas": "0x1a466", + "gas": "0x1f97e", "gasUsed": "0x72de", "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000", "output": "0x", @@ -64,7 +64,7 @@ "from": "0x6c06b16512b332e6cd8293a2974872674716ce18", "to": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", "value": "0x14d1120d7b160000", - "error":"internal failure", + "error": "internal failure", "input": "0x" } ] diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json index 2be2dee23f..a023ed6d9b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json @@ -71,7 +71,7 @@ ], "error": "execution reverted", "from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826", - "gas": "0x78d9e", + "gas": "0x7dfa6", "gasUsed": "0x7c1c8", "input": "0x", "to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json index 8022f53a99..333bdd038c 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json @@ -50,7 +50,7 @@ "result": { "error": "out of gas", "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", - "gas": "0x7045", + "gas": "0xca1d", "gasUsed": "0xca1d", "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json index aee894d11f..3207a298a9 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json @@ -48,7 +48,7 @@ "result": { "error": "execution reverted", "from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9", - "gas": "0x2d55e8", + "gas": "0x2dc6c0", "gasUsed": "0x719b", "input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000", "to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json index 4f7fee97d9..5c7e5629e9 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json @@ -53,7 +53,7 @@ "result": { "error": "execution reverted", "from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", - "gas": "0x2d7308", + "gas": "0x2dc6c0", "gasUsed": "0x5940", "input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", "to": "0xf58833cf0c791881b494eb79d461e08a1f043f52", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json index 55b63dbdb6..11b23a990e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json @@ -62,7 +62,7 @@ } ], "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", - "gas": "0x10738", + "gas": "0x15f90", "gasUsed": "0x6fcb", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json index c9192a19f9..37723f17dd 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json @@ -67,7 +67,7 @@ } ], "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", - "gas": "0x10738", + "gas": "0x15f90", "gasUsed": "0x9751", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x0000000000000000000000000000000000000000000000000000000000000001", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json index 76fae3c392..499b449a6e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json @@ -52,7 +52,7 @@ "result": { "error": "invalid jump destination", "from": "0x70c9217d814985faef62b124420f8dfbddd96433", - "gas": "0x37b38", + "gas": "0x3d090", "gasUsed": "0x3d090", "input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json index b18c80e58e..9264f1e2fd 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json @@ -77,7 +77,7 @@ }, "result": { "from": "0x4f5777744b500616697cb655dcb02ee6cd51deb5", - "gas": "0x2dced", + "gas": "0x33085", "gasUsed": "0x1a9e5", "to": "0x200edd17f30485a8735878661960cd7a9a95733f", "input": "0xba51a6df0000000000000000000000000000000000000000000000000000000000000000", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json index 2c82138022..f63dbd47dc 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json @@ -134,7 +134,7 @@ }, "result": { "from": "0x3de712784baf97260455ae25fb74f574ec9c1add", - "gas": "0x7e2c0", + "gas": "0x84398", "gasUsed": "0x27ec3", "to": "0x6ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", "input": "0xbbd4f854e9efd3ab89acad6a3edf9828c3b00ed1c4a74e974d05d32d3b2fb15aa16fc3770000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000080d29fa5cccfadac", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json index 649a5b1b56..5e5d953867 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json @@ -299,7 +299,7 @@ }, "result": { "from": "0xbe3ae5cb97c253dda67181c6e34e43f5c275e08b", - "gas": "0x3514c8", + "gas": "0x3567e0", "gasUsed": "0x26e1ef", "to": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", "input": "0xbe9a6555", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json index 858931558a..1ffffd240e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json @@ -167,7 +167,7 @@ }, "result": { "from": "0x3fcb0342353c541e210013aaddc2e740b9a33d08", - "gas": "0x2b0868", + "gas": "0x2dc6c0", "gasUsed": "0x2570bf", "to": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", "input": "0xe021fadb000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000006e00000000000000000000000000000000000000000000000000000000000000d4000000000000000000000000000000000000000000000000000000000000013a00000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fd000000000000000000000000000000000000000000000000000000000000034300000000000000000000000000000000000000000000000000000000000002fd0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003900000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003900000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000032fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebebebffffffffffffffffffffffffffffffffffffffffffffffffffffffffff888888ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb3b3b3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3e3e3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3e3e3effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbdbdbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f4f4fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0b0b0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0a0a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b5b5bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa9a9a9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb9b9b9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababaffffffffffffffffffffffffffffffffffffffffffffffffffffffffff636363fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9c9cfffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4d4e53ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f494b00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e08000", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json index 09aa7af461..116606b3c7 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json @@ -102,7 +102,7 @@ }, "result": { "from": "0x6412becf35cc7e2a9e7e47966e443f295e1e4f4a", - "gas": "0x2bb38", + "gas": "0x30d40", "gasUsed": "0x249eb", "to": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", "input": "0x", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json index 1a03f0e7fb..30f1777067 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json @@ -63,7 +63,7 @@ }, "result": { "from": "0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb", - "gas": "0x1f36d", + "gas": "0x24d45", "gasUsed": "0xc6a5", "to": "0xf4eced2f682ce333f96f2d8966c613ded8fc95dd", "input": "0xa9059cbb000000000000000000000000dbf03b407c01e7cd3cbea99509d93f8dddc8c6fb0000000000000000000000000000000000000000000000000000000000989680", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json index 4e0aec529f..30346d07f1 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json @@ -137,7 +137,7 @@ }, "result": { "from": "0xe6002189a74b43e6868b20c1311bc108e38aac57", - "gas": "0xa59c8", + "gas": "0xaae60", "gasUsed": "0xaae60", "to": "0x630a0cd35d5bd57e61410fda76fea850225cda18", "input": "0xe1fa763800000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000000", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json index 8df52db23c..eb2514427c 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json @@ -75,7 +75,7 @@ }, "result": { "from": "0x01115b41bd2731353dd3e6abf44818fdc035aaf1", - "gas": "0x28e28", + "gas": "0x30d40", "gasUsed": "0x288c9", "to": "0xcf1476387d780169410d4e936d75a206fda2a68c", "input": "0xb61d27f6000000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c18941300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008861393035396362623030303030303030303030303030303030303030303030303930643363313831326465323636396266383037626437373538636562316533343937616337653430303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303031633662663532363334303030000000000000000000000000000000000000000000000000", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json index c805296adb..e73081107f 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json @@ -78,7 +78,7 @@ }, "result": { "from": "0x4f5777744b500616697cb655dcb02ee6cd51deb5", - "gas": "0x2dced", + "gas": "0x33085", "gasUsed": "0x1a9e5", "to": "0x200edd17f30485a8735878661960cd7a9a95733f", "input": "0xba51a6df0000000000000000000000000000000000000000000000000000000000000000", diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 33298f3097..2a2789e93d 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -235,7 +235,7 @@ func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr t.ctx["from"] = t.vm.ToValue(from.Bytes()) t.ctx["to"] = t.vm.ToValue(to.Bytes()) t.ctx["input"] = t.vm.ToValue(input) - t.ctx["gas"] = t.vm.ToValue(gas) + t.ctx["gas"] = t.vm.ToValue(t.gasLimit) t.ctx["gasPrice"] = t.vm.ToValue(env.TxContext.GasPrice) valueBig, err := t.toBig(t.vm, value.String()) if err != nil { diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 88fc2be40c..c3db1ad034 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -133,7 +133,7 @@ func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad From: from, To: &toCopy, Input: common.CopyBytes(input), - Gas: gas, + Gas: t.gasLimit, Value: value, } if create { From ab1a404b0133252dca1a1d4daec2548292b295ff Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 4 Apr 2023 09:50:13 -0400 Subject: [PATCH 046/988] all: remove debug-field from vm config (#27048) This PR removes the Debug field from vmconfig, making it so that if a tracer is set, debug=true is implied. --------- Co-authored-by: 0xTylerHolmes Co-authored-by: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> --- cmd/evm/internal/t8ntool/execution.go | 1 - cmd/evm/internal/t8ntool/transition.go | 1 - cmd/evm/runner.go | 1 - cmd/evm/staterunner.go | 1 - core/blockchain.go | 1 - core/blockchain_test.go | 2 -- core/state_transition.go | 6 +++--- core/vm/evm.go | 15 ++++++++------- core/vm/instructions.go | 6 +++--- core/vm/interpreter.go | 10 +++++----- core/vm/runtime/runtime_test.go | 5 ----- eth/tracers/api.go | 3 +-- eth/tracers/internal/tracetest/calltrace_test.go | 6 +++--- .../internal/tracetest/flat_calltrace_test.go | 2 +- eth/tracers/internal/tracetest/prestate_test.go | 2 +- eth/tracers/js/tracer_test.go | 6 +++--- eth/tracers/logger/logger_test.go | 2 +- eth/tracers/tracers_test.go | 2 +- internal/ethapi/api.go | 2 +- tests/state_test.go | 3 +-- 20 files changed, 32 insertions(+), 45 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 5f796c1d66..156bce7edb 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -174,7 +174,6 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, return nil, nil, err } vmConfig.Tracer = tracer - vmConfig.Debug = (tracer != nil) statedb.SetTxContext(tx.Hash(), txIndex) var ( diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index f63635687b..0b87edd11c 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -180,7 +180,6 @@ func Transition(ctx *cli.Context) error { vmConfig := vm.Config{ Tracer: tracer, - Debug: (tracer != nil), } // Construct the chainconfig var chainConfig *params.ChainConfig diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index d6ec8ae752..18ec3330c4 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -218,7 +218,6 @@ func runCmd(ctx *cli.Context) error { BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), EVMConfig: vm.Config{ Tracer: tracer, - Debug: ctx.Bool(DebugFlag.Name) || ctx.Bool(MachineFlag.Name), }, } diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 5eba25c725..e9229eaeca 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -92,7 +92,6 @@ func stateTestCmd(ctx *cli.Context) error { // Iterate over all the tests, run them and aggregate the results cfg := vm.Config{ Tracer: tracer, - Debug: ctx.Bool(DebugFlag.Name) || ctx.Bool(MachineFlag.Name), } results := make([]StatetestResult, 0, len(tests)) for key, test := range tests { diff --git a/core/blockchain.go b/core/blockchain.go index d7094c516a..804375bf16 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -233,7 +233,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis if cacheConfig == nil { cacheConfig = defaultCacheConfig } - // Open trie database with provided config triedb := trie.NewDatabaseWithConfig(db, &trie.Config{ Cache: cacheConfig.TrieCleanLimit, diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 0f9ef6a192..01ad157cc2 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -3024,7 +3024,6 @@ func TestDeleteRecreateSlots(t *testing.T) { }) // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ - Debug: true, Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) if err != nil { @@ -3102,7 +3101,6 @@ func TestDeleteRecreateAccount(t *testing.T) { }) // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ - Debug: true, Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) if err != nil { diff --git a/core/state_transition.go b/core/state_transition.go index 1802f1daf7..fedccf1a71 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -324,10 +324,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, err } - if st.evm.Config.Debug { - st.evm.Config.Tracer.CaptureTxStart(st.initialGas) + if tracer := st.evm.Config.Tracer; tracer != nil { + tracer.CaptureTxStart(st.initialGas) defer func() { - st.evm.Config.Tracer.CaptureTxEnd(st.gasRemaining) + tracer.CaptureTxEnd(st.gasRemaining) }() } diff --git a/core/vm/evm.go b/core/vm/evm.go index 0084e4ca51..01017572d1 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -182,11 +182,12 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } snapshot := evm.StateDB.Snapshot() p, isPrecompile := evm.precompile(addr) + debug := evm.Config.Tracer != nil if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { // Calling a non existing account, don't do anything, but ping the tracer - if evm.Config.Debug { + if debug { if evm.depth == 0 { evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) evm.Config.Tracer.CaptureEnd(ret, 0, nil) @@ -202,7 +203,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value) // Capture the tracer start/end events in debug mode - if evm.Config.Debug { + if debug { if evm.depth == 0 { evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) defer func(startGas uint64) { // Lazy evaluation of the parameters @@ -272,7 +273,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, var snapshot = evm.StateDB.Snapshot() // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Debug { + if evm.Config.Tracer != nil { evm.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value) defer func(startGas uint64) { evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) @@ -313,7 +314,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by var snapshot = evm.StateDB.Snapshot() // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Debug { + if evm.Config.Tracer != nil { // NOTE: caller must, at all times be a contract. It should never happen // that caller is something other than a Contract. parent := caller.(*Contract) @@ -367,7 +368,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte evm.StateDB.AddBalance(addr, big0) // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Debug { + if evm.Config.Tracer != nil { evm.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil) defer func(startGas uint64) { evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) @@ -450,7 +451,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, contract := NewContract(caller, AccountRef(address), value, gas) contract.SetCodeOptionalHash(&address, codeAndHash) - if evm.Config.Debug { + if evm.Config.Tracer != nil { if evm.depth == 0 { evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value) } else { @@ -493,7 +494,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } } - if evm.Config.Debug { + if evm.Config.Tracer != nil { if evm.depth == 0 { evm.Config.Tracer.CaptureEnd(ret, gas-contract.Gas, err) } else { diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 21d8cc215a..505aef4127 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -822,9 +822,9 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance) interpreter.evm.StateDB.Suicide(scope.Contract.Address()) - if interpreter.evm.Config.Debug { - interpreter.evm.Config.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) - interpreter.evm.Config.Tracer.CaptureExit([]byte{}, 0, nil) + if tracer := interpreter.evm.Config.Tracer; tracer != nil { + tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + tracer.CaptureExit([]byte{}, 0, nil) } return nil, errStopToken } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 0ab520b90f..5b2082bc9e 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -25,7 +25,6 @@ import ( // Config are the configuration options for the Interpreter type Config struct { - Debug bool // Enables debugging Tracer EVMLogger // Opcode logger NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages @@ -143,6 +142,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( gasCopy uint64 // for EVMLogger to log gas remaining before execution logged bool // deferred EVMLogger should ignore already logged steps res []byte // result of the opcode execution function + debug = in.evm.Config.Tracer != nil ) // Don't move this deferred function, it's placed before the capturestate-deferred method, // so that it get's executed _after_: the capturestate needs the stacks before @@ -152,7 +152,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( }() contract.Input = input - if in.evm.Config.Debug { + if debug { defer func() { if err != nil { if !logged { @@ -168,7 +168,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // the execution of one of the operations or until the done flag is set by the // parent context. for { - if in.evm.Config.Debug { + if debug { // Capture pre-execution values for tracing. logged, pcCopy, gasCopy = false, pc, contract.Gas } @@ -213,14 +213,14 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( return nil, ErrOutOfGas } // Do tracing before memory expansion - if in.evm.Config.Debug { + if debug { in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) logged = true } if memorySize > 0 { mem.Resize(memorySize) } - } else if in.evm.Config.Debug { + } else if debug { in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) logged = true } diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 6072591065..62953a4365 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -335,7 +335,6 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode b.Fatal(err) } cfg.EVMConfig = vm.Config{ - Debug: true, Tracer: tracer, } } @@ -511,7 +510,6 @@ func TestEip2929Cases(t *testing.T) { code, ops) Execute(code, nil, &Config{ EVMConfig: vm.Config{ - Debug: true, Tracer: logger.NewMarkdownLogger(nil, os.Stdout), ExtraEips: []int{2929}, }, @@ -665,7 +663,6 @@ func TestColdAccountAccessCost(t *testing.T) { tracer := logger.NewStructLogger(nil) Execute(tc.code, nil, &Config{ EVMConfig: vm.Config{ - Debug: true, Tracer: tracer, }, }) @@ -837,7 +834,6 @@ func TestRuntimeJSTracer(t *testing.T) { GasLimit: 1000000, State: statedb, EVMConfig: vm.Config{ - Debug: true, Tracer: tracer, }}) if err != nil { @@ -872,7 +868,6 @@ func TestJSTracerCreateTx(t *testing.T) { _, _, _, err = Create(code, &Config{ State: statedb, EVMConfig: vm.Config{ - Debug: true, Tracer: tracer, }}) if err != nil { diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 58ad0c3c9a..9eef8c2e06 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -805,7 +805,6 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Swap out the noop logger to the standard tracer writer = bufio.NewWriter(dump) vmConf = vm.Config{ - Debug: true, Tracer: logger.NewJSONLogger(&logConfig, writer), EnablePreimageRecording: true, } @@ -965,7 +964,7 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Conte return nil, err } } - vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true}) + vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true}) // Define a meaningful timeout of a single transaction trace if config.Timeout != nil { diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index a70842d40c..e517d436af 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -143,7 +143,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) + evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) @@ -246,7 +246,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { if err != nil { b.Fatalf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) + evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) snap := statedb.Snapshot() st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if _, err = st.TransitionDb(); err != nil { @@ -352,7 +352,7 @@ func TestInternals(t *testing.T) { Balance: big.NewInt(500000000000000), }, }, false) - evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tc.tracer}) + evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer}) msg := &core.Message{ To: &to, From: origin, diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 9b51ba80ff..16c01de25c 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -107,7 +107,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err != nil { return fmt.Errorf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) + evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index f578e2f0f5..5fc99dd124 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -114,7 +114,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) + evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 1f37537211..a61754352a 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -62,7 +62,7 @@ func testCtx() *vmContext { func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { var ( - env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Debug: true, Tracer: tracer}) + env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer}) gasLimit uint64 = 31000 startGas uint64 = 10000 value = big.NewInt(0) @@ -180,7 +180,7 @@ func TestHaltBetweenSteps(t *testing.T) { if err != nil { t.Fatal(err) } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) + env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer}) scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0), } @@ -204,7 +204,7 @@ func TestNoStepExec(t *testing.T) { if err != nil { t.Fatal(err) } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) + env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer}) tracer.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) tracer.CaptureEnd(nil, 0, nil) ret, err := tracer.GetResult() diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index 1bc7456d31..bde43e5ff7 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -55,7 +55,7 @@ func (*dummyStatedb) SetState(_ common.Address, _ common.Hash, _ common.Hash) {} func TestStoreCapture(t *testing.T) { var ( logger = NewStructLogger(nil) - env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: logger}) + env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger}) contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 100000) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 46182db48b..759e3a4dd3 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -87,7 +87,7 @@ func BenchmarkTransactionTrace(b *testing.B) { //EnableMemory: false, //EnableReturnData: false, }) - evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer}) + evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer}) msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 4e39855309..b7ad30a6ea 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1473,7 +1473,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) - config := vm.Config{Tracer: tracer, Debug: true, NoBaseFee: true} + config := vm.Config{Tracer: tracer, NoBaseFee: true} vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config) if err != nil { return nil, 0, nil, err diff --git a/tests/state_test.go b/tests/state_test.go index 787427f01e..9d3862e1dc 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -115,8 +115,7 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) { } buf := new(bytes.Buffer) w := bufio.NewWriter(buf) - tracer := logger.NewJSONLogger(&logger.Config{}, w) - config.Debug, config.Tracer = true, tracer + config.Tracer = logger.NewJSONLogger(&logger.Config{}, w) err2 := test(config) if !reflect.DeepEqual(err, err2) { t.Errorf("different error for second run: %v", err2) From b4dcd1a391f98a92d619966d0606a6b58a019851 Mon Sep 17 00:00:00 2001 From: Exca-DK <85954505+Exca-DK@users.noreply.github.com> Date: Tue, 4 Apr 2023 15:53:44 +0200 Subject: [PATCH 047/988] metrics: make gauge_float64 and counter_float64 lock free (#27025) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes the float-gauges lock-free name old time/op new time/op delta CounterFloat64Parallel-8 1.45µs ±10% 0.85µs ± 6% -41.65% (p=0.008 n=5+5) --------- Co-authored-by: Exca-DK Co-authored-by: Martin Holst Swende --- metrics/counter_float64.go | 38 +++++++++++++++++--------------- metrics/counter_float_64_test.go | 24 +++++++++++++++++++- metrics/gauge_float64.go | 22 ++++++++---------- metrics/gauge_float64_test.go | 23 ++++++++++++++++++- 4 files changed, 74 insertions(+), 33 deletions(-) diff --git a/metrics/counter_float64.go b/metrics/counter_float64.go index f05f62fed6..d1197bb8e0 100644 --- a/metrics/counter_float64.go +++ b/metrics/counter_float64.go @@ -1,7 +1,8 @@ package metrics import ( - "sync" + "math" + "sync/atomic" ) // CounterFloat64 holds a float64 value that can be incremented and decremented. @@ -38,13 +39,13 @@ func NewCounterFloat64() CounterFloat64 { if !Enabled { return NilCounterFloat64{} } - return &StandardCounterFloat64{count: 0.0} + return &StandardCounterFloat64{} } // NewCounterFloat64Forced constructs a new StandardCounterFloat64 and returns it no matter if // the global switch is enabled or not. func NewCounterFloat64Forced() CounterFloat64 { - return &StandardCounterFloat64{count: 0.0} + return &StandardCounterFloat64{} } // NewRegisteredCounterFloat64 constructs and registers a new StandardCounterFloat64. @@ -113,41 +114,42 @@ func (NilCounterFloat64) Inc(i float64) {} func (NilCounterFloat64) Snapshot() CounterFloat64 { return NilCounterFloat64{} } // StandardCounterFloat64 is the standard implementation of a CounterFloat64 and uses the -// sync.Mutex package to manage a single float64 value. +// atomic to manage a single float64 value. type StandardCounterFloat64 struct { - mutex sync.Mutex - count float64 + floatBits atomic.Uint64 } // Clear sets the counter to zero. func (c *StandardCounterFloat64) Clear() { - c.mutex.Lock() - defer c.mutex.Unlock() - c.count = 0.0 + c.floatBits.Store(0) } // Count returns the current value. func (c *StandardCounterFloat64) Count() float64 { - c.mutex.Lock() - defer c.mutex.Unlock() - return c.count + return math.Float64frombits(c.floatBits.Load()) } // Dec decrements the counter by the given amount. func (c *StandardCounterFloat64) Dec(v float64) { - c.mutex.Lock() - defer c.mutex.Unlock() - c.count -= v + atomicAddFloat(&c.floatBits, -v) } // Inc increments the counter by the given amount. func (c *StandardCounterFloat64) Inc(v float64) { - c.mutex.Lock() - defer c.mutex.Unlock() - c.count += v + atomicAddFloat(&c.floatBits, v) } // Snapshot returns a read-only copy of the counter. func (c *StandardCounterFloat64) Snapshot() CounterFloat64 { return CounterFloat64Snapshot(c.Count()) } + +func atomicAddFloat(fbits *atomic.Uint64, v float64) { + for { + loadedBits := fbits.Load() + newBits := math.Float64bits(math.Float64frombits(loadedBits) + v) + if fbits.CompareAndSwap(loadedBits, newBits) { + break + } + } +} diff --git a/metrics/counter_float_64_test.go b/metrics/counter_float_64_test.go index 44d9b4c20c..f17aca330c 100644 --- a/metrics/counter_float_64_test.go +++ b/metrics/counter_float_64_test.go @@ -1,6 +1,9 @@ package metrics -import "testing" +import ( + "sync" + "testing" +) func BenchmarkCounterFloat64(b *testing.B) { c := NewCounterFloat64() @@ -10,6 +13,25 @@ func BenchmarkCounterFloat64(b *testing.B) { } } +func BenchmarkCounterFloat64Parallel(b *testing.B) { + c := NewCounterFloat64() + b.ResetTimer() + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + for i := 0; i < b.N; i++ { + c.Inc(1.0) + } + wg.Done() + }() + } + wg.Wait() + if have, want := c.Count(), 10.0*float64(b.N); have != want { + b.Fatalf("have %f want %f", have, want) + } +} + func TestCounterFloat64Clear(t *testing.T) { c := NewCounterFloat64() c.Inc(1.0) diff --git a/metrics/gauge_float64.go b/metrics/gauge_float64.go index 66819c9577..237ff8036e 100644 --- a/metrics/gauge_float64.go +++ b/metrics/gauge_float64.go @@ -1,6 +1,9 @@ package metrics -import "sync" +import ( + "math" + "sync/atomic" +) // GaugeFloat64s hold a float64 value that can be set arbitrarily. type GaugeFloat64 interface { @@ -23,9 +26,7 @@ func NewGaugeFloat64() GaugeFloat64 { if !Enabled { return NilGaugeFloat64{} } - return &StandardGaugeFloat64{ - value: 0.0, - } + return &StandardGaugeFloat64{} } // NewRegisteredGaugeFloat64 constructs and registers a new StandardGaugeFloat64. @@ -83,10 +84,9 @@ func (NilGaugeFloat64) Update(v float64) {} func (NilGaugeFloat64) Value() float64 { return 0.0 } // StandardGaugeFloat64 is the standard implementation of a GaugeFloat64 and uses -// sync.Mutex to manage a single float64 value. +// atomic to manage a single float64 value. type StandardGaugeFloat64 struct { - mutex sync.Mutex - value float64 + floatBits atomic.Uint64 } // Snapshot returns a read-only copy of the gauge. @@ -96,16 +96,12 @@ func (g *StandardGaugeFloat64) Snapshot() GaugeFloat64 { // Update updates the gauge's value. func (g *StandardGaugeFloat64) Update(v float64) { - g.mutex.Lock() - defer g.mutex.Unlock() - g.value = v + g.floatBits.Store(math.Float64bits(v)) } // Value returns the gauge's current value. func (g *StandardGaugeFloat64) Value() float64 { - g.mutex.Lock() - defer g.mutex.Unlock() - return g.value + return math.Float64frombits(g.floatBits.Load()) } // FunctionalGaugeFloat64 returns value from given function diff --git a/metrics/gauge_float64_test.go b/metrics/gauge_float64_test.go index 7b854d232b..647d090009 100644 --- a/metrics/gauge_float64_test.go +++ b/metrics/gauge_float64_test.go @@ -1,6 +1,9 @@ package metrics -import "testing" +import ( + "sync" + "testing" +) func BenchmarkGaugeFloat64(b *testing.B) { g := NewGaugeFloat64() @@ -10,6 +13,24 @@ func BenchmarkGaugeFloat64(b *testing.B) { } } +func BenchmarkGaugeFloat64Parallel(b *testing.B) { + c := NewGaugeFloat64() + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + for i := 0; i < b.N; i++ { + c.Update(float64(i)) + } + wg.Done() + }() + } + wg.Wait() + if have, want := c.Value(), float64(b.N-1); have != want { + b.Fatalf("have %f want %f", have, want) + } +} + func TestGaugeFloat64(t *testing.T) { g := NewGaugeFloat64() g.Update(47.0) From 2adce0b06640aa665706d014a92cd06f0720dcab Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Wed, 5 Apr 2023 00:34:52 +0800 Subject: [PATCH 048/988] eth/tracers: use atomic type (#27031) Use the new atomic types in package eth/tracers --------- Co-authored-by: Martin Holst Swende Co-authored-by: Sina Mahmoodi --- eth/tracers/api_test.go | 16 +++++++++------- eth/tracers/logger/logger.go | 8 ++++---- eth/tracers/native/4byte.go | 6 +++--- eth/tracers/native/call.go | 10 +++++----- eth/tracers/native/prestate.go | 10 +++++++--- 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index b1eaf60b16..6343021038 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -835,8 +835,8 @@ func TestTraceChain(t *testing.T) { signer := types.HomesteadSigner{} var ( - ref uint32 // total refs has made - rel uint32 // total rels has made + ref atomic.Uint32 // total refs has made + rel atomic.Uint32 // total rels has made nonce uint64 ) backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { @@ -849,8 +849,8 @@ func TestTraceChain(t *testing.T) { nonce += 1 } }) - backend.refHook = func() { atomic.AddUint32(&ref, 1) } - backend.relHook = func() { atomic.AddUint32(&rel, 1) } + backend.refHook = func() { ref.Add(1) } + backend.relHook = func() { rel.Add(1) } api := NewAPI(backend) single := `{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}` @@ -863,7 +863,8 @@ func TestTraceChain(t *testing.T) { {10, 20, nil}, // the middle chain range, blocks [11, 20] } for _, c := range cases { - ref, rel = 0, 0 // clean up the counters + ref.Store(0) + rel.Store(0) from, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.start)) to, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.end)) @@ -888,8 +889,9 @@ func TestTraceChain(t *testing.T) { if next != c.end+1 { t.Error("Missing tracing block") } - if ref != rel { - t.Errorf("Ref and deref actions are not equal, ref %d rel %d", ref, rel) + + if nref, nrel := ref.Load(), rel.Load(); nref != nrel { + t.Errorf("Ref and deref actions are not equal, ref %d rel %d", nref, nrel) } } } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 5e75318b9a..c7f171c5bd 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -116,8 +116,8 @@ type StructLogger struct { gasLimit uint64 usedGas uint64 - interrupt uint32 // Atomic flag to signal execution interruption - reason error // Textual reason for the interruption + interrupt atomic.Bool // Atomic flag to signal execution interruption + reason error // Textual reason for the interruption } // NewStructLogger returns a new logger @@ -149,7 +149,7 @@ func (l *StructLogger) CaptureStart(env *vm.EVM, from common.Address, to common. // CaptureState also tracks SLOAD/SSTORE ops to track storage change. func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { // If tracing was interrupted, set the error and stop - if atomic.LoadUint32(&l.interrupt) > 0 { + if l.interrupt.Load() { return } // check if already accumulated the specified number of logs @@ -258,7 +258,7 @@ func (l *StructLogger) GetResult() (json.RawMessage, error) { // Stop terminates execution of the tracer at the first opportune moment. func (l *StructLogger) Stop(err error) { l.reason = err - atomic.StoreUint32(&l.interrupt, 1) + l.interrupt.Store(true) } func (l *StructLogger) CaptureTxStart(gasLimit uint64) { diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 1b4649baa3..5a2c4f9111 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -48,7 +48,7 @@ func init() { type fourByteTracer struct { noopTracer ids map[string]int // ids aggregates the 4byte ids found - interrupt uint32 // Atomic flag to signal execution interruption + interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption activePrecompiles []common.Address // Updated on CaptureStart based on given rules } @@ -93,7 +93,7 @@ func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to commo // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { // Skip if tracing was interrupted - if atomic.LoadUint32(&t.interrupt) > 0 { + if t.interrupt.Load() { return } if len(input) < 4 { @@ -124,7 +124,7 @@ func (t *fourByteTracer) GetResult() (json.RawMessage, error) { // Stop terminates execution of the tracer at the first opportune moment. func (t *fourByteTracer) Stop(err error) { t.reason = err - atomic.StoreUint32(&t.interrupt, 1) + t.interrupt.Store(true) } func bytesToHex(s []byte) string { diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index c3db1ad034..4ac03e512f 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -102,8 +102,8 @@ type callTracer struct { callstack []callFrame config callTracerConfig gasLimit uint64 - interrupt uint32 // Atomic flag to signal execution interruption - reason error // Textual reason for the interruption + interrupt atomic.Bool // Atomic flag to signal execution interruption + reason error // Textual reason for the interruption } type callTracerConfig struct { @@ -161,7 +161,7 @@ func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco return } // Skip if tracing was interrupted - if atomic.LoadUint32(&t.interrupt) > 0 { + if t.interrupt.Load() { return } switch op { @@ -197,7 +197,7 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. return } // Skip if tracing was interrupted - if atomic.LoadUint32(&t.interrupt) > 0 { + if t.interrupt.Load() { return } @@ -262,7 +262,7 @@ func (t *callTracer) GetResult() (json.RawMessage, error) { // Stop terminates execution of the tracer at the first opportune moment. func (t *callTracer) Stop(err error) { t.reason = err - atomic.StoreUint32(&t.interrupt, 1) + t.interrupt.Store(true) } // clearFailedLogs clears the logs of a callframe and all its children diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 42ec4fe782..b71d5d6215 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -62,8 +62,8 @@ type prestateTracer struct { to common.Address gasLimit uint64 // Amount of gas bought for the whole tx config prestateTracerConfig - interrupt uint32 // Atomic flag to signal execution interruption - reason error // Textual reason for the interruption + interrupt atomic.Bool // Atomic flag to signal execution interruption + reason error // Textual reason for the interruption created map[common.Address]bool deleted map[common.Address]bool } @@ -136,6 +136,10 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, if err != nil { return } + // Skip if tracing was interrupted + if t.interrupt.Load() { + return + } stack := scope.Stack stackData := stack.Data() stackLen := len(stackData) @@ -259,7 +263,7 @@ func (t *prestateTracer) GetResult() (json.RawMessage, error) { // Stop terminates execution of the tracer at the first opportune moment. func (t *prestateTracer) Stop(err error) { t.reason = err - atomic.StoreUint32(&t.interrupt, 1) + t.interrupt.Store(true) } // lookupAccount fetches details of an account and adds it to the prestate From 9d37102134b27f8584441c488c026ae5a3081a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Tue, 4 Apr 2023 22:24:30 +0200 Subject: [PATCH 049/988] build: upgrade -dlgo version to Go 1.20.3 --- build/checksums.txt | 28 ++++++++++++++-------------- build/ci.go | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index e349d3eba0..9b038582a8 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,19 +1,19 @@ # This file contains sha256 checksums of optional build dependencies. -4d0e2850d197b4ddad3bdb0196300179d095bb3aefd4dfbc3b36702c3728f8ab go1.20.2.src.tar.gz -c93b8ced9517d07e1cd4c362c6e2d5242cb139e29b417a328fbf19aded08764c go1.20.2.darwin-amd64.tar.gz -7343c87f19e79c0063532e82e1c4d6f42175a32d99f7a4d15e658e88bf97f885 go1.20.2.darwin-arm64.tar.gz -14f9be2004e042b3a64d0facb0c020756a9084a5c7333e33b0752b393b6016ea go1.20.2.freebsd-386.tar.gz -b41b67b4f1b56797a7cecf6ee7f47fcf4f93960b2788a3683c07dd009d30b2a4 go1.20.2.freebsd-amd64.tar.gz -ee240ed33ae57504c41f04c12236aeaa17fbeb6ea9fcd096cd9dc7a89d10d4db go1.20.2.linux-386.tar.gz -4eaea32f59cde4dc635fbc42161031d13e1c780b87097f4b4234cfce671f1768 go1.20.2.linux-amd64.tar.gz -78d632915bb75e9a6356a47a42625fd1a785c83a64a643fedd8f61e31b1b3bef go1.20.2.linux-arm64.tar.gz -d79d56bafd6b52b8d8cbe3f8e967caaac5383a23d7a4fa9ac0e89778cd16a076 go1.20.2.linux-armv6l.tar.gz -850564ddb760cb703db63bf20182dc4407abd2ff090a95fa66d6634d172fd095 go1.20.2.linux-ppc64le.tar.gz -8da24c5c4205fe8115f594237e5db7bcb1d23df67bc1fa9a999954b1976896e8 go1.20.2.linux-s390x.tar.gz -31838b291117495bbb93683603e98d5118bfabd2eb318b4d07540bfd524bab86 go1.20.2.windows-386.zip -fe439f0e438f7555a7f5f7194ddb6f4a07b0de1fa414385d19f2aeb26d9f43db go1.20.2.windows-amd64.zip -ac5010c8b8b22849228a8dea698d58b9c7be2195d30c6d778cce0f709858fa64 go1.20.2.windows-arm64.zip +e447b498cde50215c4f7619e5124b0fc4e25fb5d16ea47271c47f278e7aa763a go1.20.3.src.tar.gz +c1e1161d6d859deb576e6cfabeb40e3d042ceb1c6f444f617c3c9d76269c3565 go1.20.3.darwin-amd64.tar.gz +86b0ed0f2b2df50fa8036eea875d1cf2d76cefdacf247c44639a1464b7e36b95 go1.20.3.darwin-arm64.tar.gz +340e80abd047c597fdc0f50a6cc59617f06c297d62f7fc77f4a0164e2da6f7aa go1.20.3.freebsd-386.tar.gz +2169fcd8b6c94c5fbe07c0b470ccfb6001d343f6548ad49f3d9ab78e3b5753c7 go1.20.3.freebsd-amd64.tar.gz +e12384311403f1389d14cc1c1295bfb4e0dd5ab919403b80da429f671a223507 go1.20.3.linux-386.tar.gz +979694c2c25c735755bf26f4f45e19e64e4811d661dd07b8c010f7a8e18adfca go1.20.3.linux-amd64.tar.gz +eb186529f13f901e7a2c4438a05c2cd90d74706aaa0a888469b2a4a617b6ee54 go1.20.3.linux-arm64.tar.gz +b421e90469a83671641f81b6e20df6500f033e9523e89cbe7b7223704dd1035c go1.20.3.linux-armv6l.tar.gz +943c89aa1624ea544a022b31e3d6e16a037200e436370bdd5fd67f3fa60be282 go1.20.3.linux-ppc64le.tar.gz +126cf823a5634ef2544b866db107b9d351d3ea70d9e240b0bdcfb46f4dcae54b go1.20.3.linux-s390x.tar.gz +37e9146e1f9d681cfcaa6fee6c7b890c44c64bc50228c9588f3c4231346d33bd go1.20.3.windows-386.zip +143a2837821c7dbacf7744cbb1a8421c1f48307c6fdfaeffc5f8c2f69e1b7932 go1.20.3.windows-amd64.zip +158cb159e00bc979f473e0f5b5a561613129c5e51067967b72b8e072e5a4db81 go1.20.3.windows-arm64.zip fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz 75b8f0ff3a4e68147156be4161a49d4576f1be37a0b506473f8c482140c1e7f2 golangci-lint-1.51.1-darwin-arm64.tar.gz diff --git a/build/ci.go b/build/ci.go index 3e145b20b0..eab011752d 100644 --- a/build/ci.go +++ b/build/ci.go @@ -139,7 +139,7 @@ var ( // This is the version of Go that will be downloaded by // // go run ci.go install -dlgo - dlgoVersion = "1.20.2" + dlgoVersion = "1.20.3" // This is the version of Go that will be used to bootstrap the PPA builder. // From 230df98e4d8b6af92281db6d0e51a55ff950e656 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 5 Apr 2023 10:59:32 +0200 Subject: [PATCH 050/988] core/txpool: disallow future churn by remote txs (#26907) Prior to this change, it was possible that transactions are erroneously deemed as 'future' although they are in fact 'pending', causing them to be dropped due to 'future' not being allowed to replace 'pending'. This change fixes that, by doing a more in-depth inspection of the queue. --- core/txpool/list.go | 8 ++++---- core/txpool/txpool.go | 34 +++++++++++++++++++++------------- core/txpool/txpool2_test.go | 28 ++++++++++++++++++++++++++-- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/core/txpool/list.go b/core/txpool/list.go index 639d69bcbe..fae7c2fcac 100644 --- a/core/txpool/list.go +++ b/core/txpool/list.go @@ -270,10 +270,10 @@ func newList(strict bool) *list { } } -// Overlaps returns whether the transaction specified has the same nonce as one -// already contained within the list. -func (l *list) Overlaps(tx *types.Transaction) bool { - return l.txs.Get(tx.Nonce()) != nil +// Contains returns whether the list contains a transaction +// with the provided nonce. +func (l *list) Contains(nonce uint64) bool { + return l.txs.Get(nonce) != nil } // Add tries to insert a new transaction into the list, returning whether the diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 3a5ed69568..9eb19b0094 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -745,11 +745,11 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e } // If the new transaction is a future transaction it should never churn pending transactions - if !isLocal && pool.isFuture(from, tx) { + if !isLocal && pool.isGapped(from, tx) { var replacesPending bool for _, dropTx := range drop { dropSender, _ := types.Sender(pool.signer, dropTx) - if list := pool.pending[dropSender]; list != nil && list.Overlaps(dropTx) { + if list := pool.pending[dropSender]; list != nil && list.Contains(dropTx.Nonce()) { replacesPending = true break } @@ -774,7 +774,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e } // Try to replace an existing transaction in the pending pool - if list := pool.pending[from]; list != nil && list.Overlaps(tx) { + if list := pool.pending[from]; list != nil && list.Contains(tx.Nonce()) { // Nonce already pending, check if required price bump is met inserted, old := list.Add(tx, pool.config.PriceBump) if !inserted { @@ -817,18 +817,26 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e return replaced, nil } -// isFuture reports whether the given transaction is immediately executable. -func (pool *TxPool) isFuture(from common.Address, tx *types.Transaction) bool { - list := pool.pending[from] - if list == nil { - return pool.pendingNonces.get(from) != tx.Nonce() +// isGapped reports whether the given transaction is immediately executable. +func (pool *TxPool) isGapped(from common.Address, tx *types.Transaction) bool { + // Short circuit if transaction matches pending nonce and can be promoted + // to pending list as an executable transaction. + next := pool.pendingNonces.get(from) + if tx.Nonce() == next { + return false } - // Sender has pending transactions. - if old := list.txs.Get(tx.Nonce()); old != nil { - return false // It replaces a pending transaction. + // The transaction has a nonce gap with pending list, it's only considered + // as executable if transactions in queue can fill up the nonce gap. + queue, ok := pool.queue[from] + if !ok { + return true } - // Not replacing, check if parent nonce exists in pending. - return list.txs.Get(tx.Nonce()-1) == nil + for nonce := next; nonce < tx.Nonce(); nonce++ { + if !queue.Contains(nonce) { + return true // txs in queue can't fill up the nonce gap + } + } + return false } // enqueueTx inserts a new transaction into the non-executable transaction queue. diff --git a/core/txpool/txpool2_test.go b/core/txpool/txpool2_test.go index 6d84975d83..7e2a9eb908 100644 --- a/core/txpool/txpool2_test.go +++ b/core/txpool/txpool2_test.go @@ -42,7 +42,7 @@ func count(t *testing.T, pool *TxPool) (pending int, queued int) { return pending, queued } -func fillPool(t *testing.T, pool *TxPool) { +func fillPool(t testing.TB, pool *TxPool) { t.Helper() // Create a number of test accounts, fund them and make transactions executableTxs := types.Transactions{} @@ -189,7 +189,7 @@ func TestTransactionZAttack(t *testing.T) { key, _ := crypto.GenerateKey() pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) for j := 0; j < int(pool.config.GlobalSlots); j++ { - overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 60000000000, 21000, big.NewInt(500), key)) + overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key)) } } pool.AddRemotesSync(overDraftTxs) @@ -210,3 +210,27 @@ func TestTransactionZAttack(t *testing.T) { newIvPending, ivPending, pool.config.GlobalSlots, newQueued) } } + +func BenchmarkFutureAttack(b *testing.B) { + // Create the pool to test the limit enforcement with + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + config := testTxPoolConfig + config.GlobalQueue = 100 + config.GlobalSlots = 100 + pool := NewTxPool(config, eip1559Config, blockchain) + defer pool.Stop() + fillPool(b, pool) + + key, _ := crypto.GenerateKey() + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) + futureTxs := types.Transactions{} + + for n := 0; n < b.N; n++ { + futureTxs = append(futureTxs, pricedTransaction(1000+uint64(n), 100000, big.NewInt(500), key)) + } + b.ResetTimer() + for i := 0; i < 5; i++ { + pool.AddRemotesSync(futureTxs) + } +} From b946b7a13b749c99979e312c83dce34cac8dd7b1 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 5 Apr 2023 19:09:25 +0800 Subject: [PATCH 051/988] core, miner: drop transactions from the same sender when error occurs (#27038) This PR unifies the error handling in miner. Whenever an error occur while applying a transaction, the transaction should be regarded as invalid and all following transactions from the same sender not executable because of the nonce restriction. The only exception is the `nonceTooLow` error which is handled separately. --- core/state_transition.go | 2 +- miner/worker.go | 21 +++------------------ 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index fedccf1a71..72f975775c 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -136,7 +136,7 @@ type Message struct { Data []byte AccessList types.AccessList - // When SkipAccountCheckss is true, the message nonce is not checked against the + // When SkipAccountChecks is true, the message nonce is not checked against the // account nonce in state. It also disables checking that the sender is an EOA. // This field will be set to true for operations like RPC eth_call. SkipAccountChecks bool diff --git a/miner/worker.go b/miner/worker.go index 9fbece8658..c481239d40 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -918,37 +918,22 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP logs, err := w.commitTransaction(env, tx) switch { - case errors.Is(err, core.ErrGasLimitReached): - // Pop the current out-of-gas transaction without shifting in the next from the account - log.Trace("Gas limit exceeded for current block", "sender", from) - txs.Pop() - case errors.Is(err, core.ErrNonceTooLow): // New head notification data race between the transaction pool and miner, shift log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce()) txs.Shift() - case errors.Is(err, core.ErrNonceTooHigh): - // Reorg notification data race between the transaction pool and miner, skip account = - log.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce()) - txs.Pop() - case errors.Is(err, nil): // Everything ok, collect the logs and shift in the next transaction from the same account coalescedLogs = append(coalescedLogs, logs...) env.tcount++ txs.Shift() - case errors.Is(err, types.ErrTxTypeNotSupported): - // Pop the unsupported transaction without shifting in the next from the account - log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type()) - txs.Pop() - default: - // Strange error, discard the transaction and get the next in line (note, the - // nonce-too-high clause will prevent us from executing in vain). + // Transaction is regarded as invalid, drop all consecutive transactions from + // the same sender because of `nonce-too-high` clause. log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err) - txs.Shift() + txs.Pop() } } if !w.isRunning() && len(coalescedLogs) > 0 { From 5aa5295cf940a36516a474ca9be9ffad4a7bdb60 Mon Sep 17 00:00:00 2001 From: Parithosh Jayanthi Date: Mon, 17 Apr 2023 10:15:25 +0200 Subject: [PATCH 052/988] params: new sepolia bootnodes (#27099) New sepolia bootnodes managed by EF devops --- params/bootnodes.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/params/bootnodes.go b/params/bootnodes.go index 45e27c441a..4ae94cfbd3 100644 --- a/params/bootnodes.go +++ b/params/bootnodes.go @@ -31,10 +31,12 @@ var MainnetBootnodes = []string{ // SepoliaBootnodes are the enode URLs of the P2P bootstrap nodes running on the // Sepolia test network. var SepoliaBootnodes = []string{ - // geth - "enode://9246d00bc8fd1742e5ad2428b80fc4dc45d786283e05ef6edbd9002cbc335d40998444732fbe921cb88e1d2c73d1b1de53bae6a2237996e9bfe14f871baf7066@18.168.182.86:30303", - // besu - "enode://ec66ddcf1a974950bd4c782789a7e04f8aa7110a72569b6e65fcd51e937e74eed303b1ea734e4d19cfaec9fbff9b6ee65bf31dcb50ba79acce9dd63a6aca61c7@52.14.151.177:30303", + // EF DevOps + "enode://4e5e92199ee224a01932a377160aa432f31d0b351f84ab413a8e0a42f4f36476f8fb1cbe914af0d9aef0d51665c214cf653c651c4bbd9d5550a934f241f1682b@138.197.51.181:30303", // sepolia-bootnode-1-nyc3 + "enode://143e11fb766781d22d92a2e33f8f104cddae4411a122295ed1fdb6638de96a6ce65f5b7c964ba3763bba27961738fef7d3ecc739268f3e5e771fb4c87b6234ba@146.190.1.103:30303", // sepolia-bootnode-1-sfo3 + "enode://8b61dc2d06c3f96fddcbebb0efb29d60d3598650275dc469c22229d3e5620369b0d3dedafd929835fe7f489618f19f456fe7c0df572bf2d914a9f4e006f783a9@170.64.250.88:30303", // sepolia-bootnode-1-syd1 + "enode://10d62eff032205fcef19497f35ca8477bea0eadfff6d769a147e895d8b2b8f8ae6341630c645c30f5df6e67547c03494ced3d9c5764e8622a26587b083b028e8@139.59.49.206:30303", // sepolia-bootnode-1-blr1 + "enode://9e9492e2e8836114cc75f5b929784f4f46c324ad01daf87d956f98b3b6c5fcba95524d6e5cf9861dc96a2c8a171ea7105bb554a197455058de185fa870970c7c@138.68.123.152:30303", // sepolia-bootnode-1-ams3 } // RinkebyBootnodes are the enode URLs of the P2P bootstrap nodes running on the From 8fe807c8f27e33bbfd77e4670818522821aec979 Mon Sep 17 00:00:00 2001 From: noel <72006780+0x00Duke@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:29:27 +0200 Subject: [PATCH 053/988] cmd/devp2p: fix erroneous log output in crawler (#27089) cmd/devp2p: fix log of ignored recent nodes counter --- cmd/devp2p/crawl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/devp2p/crawl.go b/cmd/devp2p/crawl.go index 8c9755ac1c..1b964164d8 100644 --- a/cmd/devp2p/crawl.go +++ b/cmd/devp2p/crawl.go @@ -141,7 +141,7 @@ loop: "added", atomic.LoadUint64(&added), "updated", atomic.LoadUint64(&updated), "removed", atomic.LoadUint64(&removed), - "ignored(recent)", atomic.LoadUint64(&removed), + "ignored(recent)", atomic.LoadUint64(&recent), "ignored(incompatible)", atomic.LoadUint64(&skipped)) } } From bedf2856d1ed21b7c3eb6a67fd73495f7a1b6ecb Mon Sep 17 00:00:00 2001 From: Taeguk Kwon Date: Mon, 17 Apr 2023 23:36:47 +0900 Subject: [PATCH 054/988] signer/core: rename testdata files (#27063) Sets a meaningful name on test-files --- .../testdata/{expfail_extradata-2.json => expfail_extradata.json} | 0 .../{expfail_extradata-1.json => expfail_nonexistant_type2.json} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename signer/core/testdata/{expfail_extradata-2.json => expfail_extradata.json} (100%) rename signer/core/testdata/{expfail_extradata-1.json => expfail_nonexistant_type2.json} (100%) diff --git a/signer/core/testdata/expfail_extradata-2.json b/signer/core/testdata/expfail_extradata.json similarity index 100% rename from signer/core/testdata/expfail_extradata-2.json rename to signer/core/testdata/expfail_extradata.json diff --git a/signer/core/testdata/expfail_extradata-1.json b/signer/core/testdata/expfail_nonexistant_type2.json similarity index 100% rename from signer/core/testdata/expfail_extradata-1.json rename to signer/core/testdata/expfail_nonexistant_type2.json From cb66eba85ad9d64ffd33326f5ac6650a72d4588e Mon Sep 17 00:00:00 2001 From: Anusha <63559942+anusha-ctrl@users.noreply.github.com> Date: Mon, 17 Apr 2023 08:02:31 -0700 Subject: [PATCH 055/988] core: fix comment to reflect function name (#27070) --- core/blockchain.go | 2 +- core/state/snapshot/snapshot_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 804375bf16..80fefac9b0 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -908,7 +908,7 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) { headBlockGauge.Update(int64(block.NumberU64())) } -// stop stops the blockchain service. If any imports are currently in progress +// stopWithoutSaving stops the blockchain service. If any imports are currently in progress // it will abort them using the procInterrupt. This method stops all running // goroutines, but does not do all the post-stop work of persisting data. // OBS! It is generally recommended to use the Stop method! diff --git a/core/state/snapshot/snapshot_test.go b/core/state/snapshot/snapshot_test.go index 6893f6001e..249da10aa6 100644 --- a/core/state/snapshot/snapshot_test.go +++ b/core/state/snapshot/snapshot_test.go @@ -118,7 +118,7 @@ func TestDiskLayerExternalInvalidationFullFlatten(t *testing.T) { if err := snaps.Cap(common.HexToHash("0x02"), 0); err != nil { t.Fatalf("failed to merge diff layer onto disk: %v", err) } - // Since the base layer was modified, ensure that data retrieval on the external reference fail + // Since the base layer was modified, ensure that data retrievals on the external reference fail if acc, err := ref.Account(common.HexToHash("0x01")); err != ErrSnapshotStale { t.Errorf("stale reference returned account: %#x (err: %v)", acc, err) } From 5e4d726e2a05aee80a75e5f99fd699f220dd503e Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 18 Apr 2023 15:49:09 +0800 Subject: [PATCH 056/988] params: remove `EIP150Hash` from chainconfig (#27087) The EIP150Hash was an idea where, after the fork, we hardcoded the forked hash as an extra defensive mechanism. It wasn't really used, since forks weren't contentious and for all the various testnets and private networks it's been a hassle to have around. This change removes that config field. --------- Signed-off-by: jsvisa --- consensus/clique/clique.go | 4 ---- consensus/ethash/consensus.go | 3 --- consensus/misc/eip1559_test.go | 1 - consensus/misc/forks.go | 43 ---------------------------------- core/vm/runtime/runtime.go | 1 - eth/tracers/js/tracer_test.go | 2 +- miner/stress/1559/main.go | 1 - miner/stress/clique/main.go | 1 - miner/stress/ethash/main.go | 1 - params/config.go | 10 +------- tests/difficulty_test.go | 3 --- 11 files changed, 2 insertions(+), 68 deletions(-) delete mode 100644 consensus/misc/forks.go diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 1b9a1d9236..2345a5ca03 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -304,10 +304,6 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H if chain.Config().IsCancun(header.Time) { return fmt.Errorf("clique does not support cancun fork") } - // If all checks passed, validate any special fields for hard forks - if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil { - return err - } // All basic checks passed, verify cascading fields return c.verifyCascadingFields(chain, header, parents) } diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 8f1b497cbd..e3e0f28b3e 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -326,9 +326,6 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa if err := misc.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil { return err } - if err := misc.VerifyForkHashes(chain.Config(), header, uncle); err != nil { - return err - } return nil } diff --git a/consensus/misc/eip1559_test.go b/consensus/misc/eip1559_test.go index 23cd9023de..1a9f96bc43 100644 --- a/consensus/misc/eip1559_test.go +++ b/consensus/misc/eip1559_test.go @@ -34,7 +34,6 @@ func copyConfig(original *params.ChainConfig) *params.ChainConfig { DAOForkBlock: original.DAOForkBlock, DAOForkSupport: original.DAOForkSupport, EIP150Block: original.EIP150Block, - EIP150Hash: original.EIP150Hash, EIP155Block: original.EIP155Block, EIP158Block: original.EIP158Block, ByzantiumBlock: original.ByzantiumBlock, diff --git a/consensus/misc/forks.go b/consensus/misc/forks.go deleted file mode 100644 index a6f3303ea6..0000000000 --- a/consensus/misc/forks.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package misc - -import ( - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" -) - -// VerifyForkHashes verifies that blocks conforming to network hard-forks do have -// the correct hashes, to avoid clients going off on different chains. This is an -// optional feature. -func VerifyForkHashes(config *params.ChainConfig, header *types.Header, uncle bool) error { - // We don't care about uncles - if uncle { - return nil - } - // If the homestead reprice hash is set, validate it - if config.EIP150Block != nil && config.EIP150Block.Cmp(header.Number) == 0 { - if config.EIP150Hash != (common.Hash{}) && config.EIP150Hash != header.Hash() { - return fmt.Errorf("homestead gas reprice fork: have %#x, want %#x", header.Hash(), config.EIP150Hash) - } - } - // All ok, return - return nil -} diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 56ff5eeabe..005ef0c754 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -57,7 +57,6 @@ func setDefaults(cfg *Config) { DAOForkBlock: new(big.Int), DAOForkSupport: false, EIP150Block: new(big.Int), - EIP150Hash: common.Hash{}, EIP155Block: new(big.Int), EIP158Block: new(big.Int), ByzantiumBlock: new(big.Int), diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index a61754352a..bf6427faf6 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -229,7 +229,7 @@ func TestNoStepExec(t *testing.T) { } func TestIsPrecompile(t *testing.T) { - chaincfg := ¶ms.ChainConfig{ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(100), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(200), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(300), LondonBlock: big.NewInt(0), TerminalTotalDifficulty: nil, Ethash: new(params.EthashConfig), Clique: nil} + chaincfg := ¶ms.ChainConfig{ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(100), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(200), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(300), LondonBlock: big.NewInt(0), TerminalTotalDifficulty: nil, Ethash: new(params.EthashConfig), Clique: nil} chaincfg.ByzantiumBlock = big.NewInt(100) chaincfg.IstanbulBlock = big.NewInt(200) chaincfg.BerlinBlock = big.NewInt(300) diff --git a/miner/stress/1559/main.go b/miner/stress/1559/main.go index c27875000d..2e8b78d85e 100644 --- a/miner/stress/1559/main.go +++ b/miner/stress/1559/main.go @@ -205,7 +205,6 @@ func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { genesis.GasLimit = 8_000_000 genesis.Config.ChainID = big.NewInt(18) - genesis.Config.EIP150Hash = common.Hash{} genesis.Alloc = core.GenesisAlloc{} for _, faucet := range faucets { diff --git a/miner/stress/clique/main.go b/miner/stress/clique/main.go index 688c2b6984..74962c6d51 100644 --- a/miner/stress/clique/main.go +++ b/miner/stress/clique/main.go @@ -153,7 +153,6 @@ func makeGenesis(faucets []*ecdsa.PrivateKey, sealers []*ecdsa.PrivateKey) *core genesis.Config.ChainID = big.NewInt(18) genesis.Config.Clique.Period = 1 - genesis.Config.EIP150Hash = common.Hash{} genesis.Alloc = core.GenesisAlloc{} for _, faucet := range faucets { diff --git a/miner/stress/ethash/main.go b/miner/stress/ethash/main.go index 6b6e7059d3..6905bf01f1 100644 --- a/miner/stress/ethash/main.go +++ b/miner/stress/ethash/main.go @@ -139,7 +139,6 @@ func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { genesis.GasLimit = 25000000 genesis.Config.ChainID = big.NewInt(18) - genesis.Config.EIP150Hash = common.Hash{} genesis.Alloc = core.GenesisAlloc{} for _, faucet := range faucets { diff --git a/params/config.go b/params/config.go index 190eb737c4..82d00bc8f5 100644 --- a/params/config.go +++ b/params/config.go @@ -62,7 +62,6 @@ var ( DAOForkBlock: big.NewInt(1_920_000), DAOForkSupport: true, EIP150Block: big.NewInt(2_463_000), - EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), EIP155Block: big.NewInt(2_675_000), EIP158Block: big.NewInt(2_675_000), ByzantiumBlock: big.NewInt(4_370_000), @@ -139,7 +138,6 @@ var ( DAOForkBlock: nil, DAOForkSupport: true, EIP150Block: big.NewInt(2), - EIP150Hash: common.HexToHash("0x9b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9"), EIP155Block: big.NewInt(3), EIP158Block: big.NewInt(3), ByzantiumBlock: big.NewInt(1_035_301), @@ -231,7 +229,6 @@ var ( DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), - EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), @@ -261,7 +258,6 @@ var ( DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), - EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), @@ -291,7 +287,6 @@ var ( DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), - EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), @@ -321,7 +316,6 @@ var ( DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: nil, - EIP150Hash: common.Hash{}, EIP155Block: nil, EIP158Block: nil, ByzantiumBlock: nil, @@ -415,9 +409,7 @@ type ChainConfig struct { DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) - EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork) - EIP150Hash common.Hash `json:"eip150Hash,omitempty"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) - + EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork) EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block diff --git a/tests/difficulty_test.go b/tests/difficulty_test.go index a8273303e3..03e14df7c4 100644 --- a/tests/difficulty_test.go +++ b/tests/difficulty_test.go @@ -20,7 +20,6 @@ import ( "math/big" "testing" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" ) @@ -31,7 +30,6 @@ var ( DAOForkBlock: big.NewInt(1920000), DAOForkSupport: true, EIP150Block: big.NewInt(2463000), - EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), EIP155Block: big.NewInt(2675000), EIP158Block: big.NewInt(2675000), ByzantiumBlock: big.NewInt(4370000), @@ -43,7 +41,6 @@ var ( DAOForkBlock: nil, DAOForkSupport: true, EIP150Block: big.NewInt(0), - EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), EIP155Block: big.NewInt(10), EIP158Block: big.NewInt(10), ByzantiumBlock: big.NewInt(1_700_000), From b1972627d9cf6b38f8f41a2093eb8b333ba0b16f Mon Sep 17 00:00:00 2001 From: joohhnnn <68833933+joohhnnn@users.noreply.github.com> Date: Tue, 18 Apr 2023 17:57:08 +0800 Subject: [PATCH 057/988] p2p: access embedded fields of Server directly (#27078) --- p2p/server.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/server.go b/p2p/server.go index b8a2f8fd21..f7bf948b69 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -443,7 +443,7 @@ func (srv *Server) Start() (err error) { return errors.New("server already running") } srv.running = true - srv.log = srv.Config.Logger + srv.log = srv.Logger if srv.log == nil { srv.log = log.Root() } @@ -501,7 +501,7 @@ func (srv *Server) setupLocalNode() error { sort.Sort(capsByNameAndVersion(srv.ourHandshake.Caps)) // Create the local node. - db, err := enode.OpenDB(srv.Config.NodeDatabase) + db, err := enode.OpenDB(srv.NodeDatabase) if err != nil { return err } From 3768b0074791169441ca5eb3a7c73c7b9e74c24a Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 18 Apr 2023 20:54:06 +0800 Subject: [PATCH 058/988] consensus/ethash: use atomic type (#27068) --- consensus/ethash/algorithm.go | 12 ++++++------ consensus/ethash/ethash.go | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/consensus/ethash/algorithm.go b/consensus/ethash/algorithm.go index d539183822..a2a6081f55 100644 --- a/consensus/ethash/algorithm.go +++ b/consensus/ethash/algorithm.go @@ -163,7 +163,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) { rows := int(size) / hashBytes // Start a monitoring goroutine to report progress on low end devices - var progress uint32 + var progress atomic.Uint32 done := make(chan struct{}) defer close(done) @@ -174,7 +174,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) { case <-done: return case <-time.After(3 * time.Second): - logger.Info("Generating ethash verification cache", "percentage", atomic.LoadUint32(&progress)*100/uint32(rows)/(cacheRounds+1), "elapsed", common.PrettyDuration(time.Since(start))) + logger.Info("Generating ethash verification cache", "percentage", progress.Load()*100/uint32(rows)/(cacheRounds+1), "elapsed", common.PrettyDuration(time.Since(start))) } } }() @@ -185,7 +185,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) { keccak512(cache, seed) for offset := uint64(hashBytes); offset < size; offset += hashBytes { keccak512(cache[offset:], cache[offset-hashBytes:offset]) - atomic.AddUint32(&progress, 1) + progress.Add(1) } // Use a low-round version of randmemohash temp := make([]byte, hashBytes) @@ -200,7 +200,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) { bitutil.XORBytes(temp, cache[srcOff:srcOff+hashBytes], cache[xorOff:xorOff+hashBytes]) keccak512(cache[dstOff:], temp) - atomic.AddUint32(&progress, 1) + progress.Add(1) } } // Swap the byte order on big endian systems and return @@ -299,7 +299,7 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) { var pend sync.WaitGroup pend.Add(threads) - var progress uint64 + var progress atomic.Uint64 for i := 0; i < threads; i++ { go func(id int) { defer pend.Done() @@ -323,7 +323,7 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) { } copy(dataset[index*hashBytes:], item) - if status := atomic.AddUint64(&progress, 1); status%percent == 0 { + if status := progress.Add(1); status%percent == 0 { logger.Info("Generating DAG in progress", "percentage", (status*100)/(size/hashBytes), "elapsed", common.PrettyDuration(time.Since(start))) } } diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index 6cb3124827..462f109564 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -308,12 +308,12 @@ func (c *cache) finalizer() { // dataset wraps an ethash dataset with some metadata to allow easier concurrent use. type dataset struct { - epoch uint64 // Epoch for which this cache is relevant - dump *os.File // File descriptor of the memory mapped cache - mmap mmap.MMap // Memory map itself to unmap before releasing - dataset []uint32 // The actual cache data content - once sync.Once // Ensures the cache is generated only once - done uint32 // Atomic flag to determine generation status + epoch uint64 // Epoch for which this cache is relevant + dump *os.File // File descriptor of the memory mapped cache + mmap mmap.MMap // Memory map itself to unmap before releasing + dataset []uint32 // The actual cache data content + once sync.Once // Ensures the cache is generated only once + done atomic.Bool // Atomic flag to determine generation status } // newDataset creates a new ethash mining dataset and returns it as a plain Go @@ -326,7 +326,7 @@ func newDataset(epoch uint64) *dataset { func (d *dataset) generate(dir string, limit int, lock bool, test bool) { d.once.Do(func() { // Mark the dataset generated after we're done. This is needed for remote - defer atomic.StoreUint32(&d.done, 1) + defer d.done.Store(true) csize := cacheSize(d.epoch*epochLength + 1) dsize := datasetSize(d.epoch*epochLength + 1) @@ -390,7 +390,7 @@ func (d *dataset) generate(dir string, limit int, lock bool, test bool) { // or not (it may not have been started at all). This is useful for remote miners // to default to verification caches instead of blocking on DAG generations. func (d *dataset) generated() bool { - return atomic.LoadUint32(&d.done) == 1 + return d.done.Load() } // finalizer closes any file handlers and memory maps open. From 2b0a34bea6a61efe17b8cb860362547ba235e84b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 19 Apr 2023 06:46:56 -0400 Subject: [PATCH 059/988] cmd/devp2p: make crawler-route53-updater less verbose (#27116) Follow-up to #26697, makes the crawler less verbose on route53-based scenarios. It also changes the loglevel from debug to info on Updates, which are typically the root, and can be interesting to see. --- cmd/devp2p/dns_cloudflare.go | 2 +- cmd/devp2p/dns_route53.go | 26 +++++++++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/cmd/devp2p/dns_cloudflare.go b/cmd/devp2p/dns_cloudflare.go index bfe92257ee..798fdc7332 100644 --- a/cmd/devp2p/dns_cloudflare.go +++ b/cmd/devp2p/dns_cloudflare.go @@ -144,7 +144,7 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string) _, err = c.CreateDNSRecord(context.Background(), c.zoneID, record) } else if old.Content != val { // Entry already exists, only change its content. - log.Debug(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val)) + log.Info(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val)) updated++ old.Content = val err = c.UpdateDNSRecord(context.Background(), c.zoneID, old.ID, old) diff --git a/cmd/devp2p/dns_route53.go b/cmd/devp2p/dns_route53.go index 81734eb2ad..400ab1b1cf 100644 --- a/cmd/devp2p/dns_route53.go +++ b/cmd/devp2p/dns_route53.go @@ -221,7 +221,13 @@ func (c *route53Client) computeChanges(name string, records map[string]string, e } records = lrecords - var changes []types.Change + var ( + changes []types.Change + inserts int + upserts int + skips int + ) + for path, newValue := range records { prevRecords, exists := existing[path] prevValue := strings.Join(prevRecords.values, "") @@ -237,20 +243,30 @@ func (c *route53Client) computeChanges(name string, records map[string]string, e if !exists { // Entry is unknown, push a new one - log.Info(fmt.Sprintf("Creating %s = %s", path, newValue)) + log.Debug(fmt.Sprintf("Creating %s = %s", path, newValue)) changes = append(changes, newTXTChange("CREATE", path, ttl, newValue)) + inserts++ } else if prevValue != newValue || prevRecords.ttl != ttl { // Entry already exists, only change its content. log.Info(fmt.Sprintf("Updating %s from %s to %s", path, prevValue, newValue)) changes = append(changes, newTXTChange("UPSERT", path, ttl, newValue)) + upserts++ } else { log.Debug(fmt.Sprintf("Skipping %s = %s", path, newValue)) + skips++ } } // Iterate over the old records and delete anything stale. - changes = append(changes, makeDeletionChanges(existing, records)...) - + deletions := makeDeletionChanges(existing, records) + changes = append(changes, deletions...) + + log.Info("Computed DNS changes", + "changes", len(changes), + "inserts", inserts, + "skips", skips, + "deleted", len(deletions), + "upserts", upserts) // Ensure changes are in the correct order. sortChanges(changes) return changes @@ -263,7 +279,7 @@ func makeDeletionChanges(records map[string]recordSet, keep map[string]string) [ if _, ok := keep[path]; ok { continue } - log.Info(fmt.Sprintf("Deleting %s = %s", path, strings.Join(set.values, ""))) + log.Debug(fmt.Sprintf("Deleting %s = %s", path, strings.Join(set.values, ""))) changes = append(changes, newTXTChange("DELETE", path, set.ttl, set.values...)) } return changes From f2df2b1981fa1e014e4cb34cf9a8dd7b8519e0ac Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Wed, 19 Apr 2023 21:18:02 +1000 Subject: [PATCH 060/988] cmd/geth: rename --vmodule to --log.vmodule (#27071) renames `--vmodule` to `--log.vmodule`, and prints a warning if the old form is used. --- internal/debug/flags.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 3c8b569b4f..d425a17db4 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -45,10 +45,17 @@ var ( Value: 3, Category: flags.LoggingCategory, } + logVmoduleFlag = &cli.StringFlag{ + Name: "log.vmodule", + Usage: "Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4)", + Value: "", + Category: flags.LoggingCategory, + } vmoduleFlag = &cli.StringFlag{ Name: "vmodule", Usage: "Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4)", Value: "", + Hidden: true, Category: flags.LoggingCategory, } logjsonFlag = &cli.BoolFlag{ @@ -149,6 +156,7 @@ var ( // Flags holds all command-line flags required for debugging. var Flags = []cli.Flag{ verbosityFlag, + logVmoduleFlag, vmoduleFlag, backtraceAtFlag, debugFlag, @@ -252,7 +260,14 @@ func Setup(ctx *cli.Context) error { // logging verbosity := ctx.Int(verbosityFlag.Name) glogger.Verbosity(log.Lvl(verbosity)) - vmodule := ctx.String(vmoduleFlag.Name) + vmodule := ctx.String(logVmoduleFlag.Name) + if vmodule == "" { + // Retain backwards compatibility with `--vmodule` flag if `--log.vmodule` not set + vmodule = ctx.String(vmoduleFlag.Name) + if vmodule != "" { + defer log.Warn("The flag '--vmodule' is deprecated, please use '--log.vmodule' instead") + } + } glogger.Vmodule(vmodule) debug := ctx.Bool(debugFlag.Name) From 3f7afc3f573abdb1469d7afcbf9028cfe328d66d Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 20 Apr 2023 08:52:00 +0200 Subject: [PATCH 061/988] core/vm: order opcodes properly (#27113) --- core/vm/opcodes.go | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 9f199eb8f6..910491c600 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -204,6 +204,12 @@ const ( LOG4 ) +// 0xb0 range. +const ( + TLOAD OpCode = 0xb3 + TSTORE OpCode = 0xb4 +) + // 0xf0 range - closures. const ( CREATE OpCode = 0xf0 @@ -219,12 +225,6 @@ const ( SELFDESTRUCT OpCode = 0xff ) -// 0xb0 range. -const ( - TLOAD OpCode = 0xb3 - TSTORE OpCode = 0xb4 -) - // Since the opcodes aren't all in order we can't use a regular slice. var opCodeToString = map[OpCode]string{ // 0x0 range - arithmetic ops. @@ -290,9 +290,7 @@ var opCodeToString = map[OpCode]string{ BASEFEE: "BASEFEE", // 0x50 range - 'storage' and execution. - POP: "POP", - //DUP: "DUP", - //SWAP: "SWAP", + POP: "POP", MLOAD: "MLOAD", MSTORE: "MSTORE", MSTORE8: "MSTORE8", @@ -306,7 +304,7 @@ var opCodeToString = map[OpCode]string{ JUMPDEST: "JUMPDEST", PUSH0: "PUSH0", - // 0x60 range - push. + // 0x60 range - pushes. PUSH1: "PUSH1", PUSH2: "PUSH2", PUSH3: "PUSH3", @@ -340,6 +338,7 @@ var opCodeToString = map[OpCode]string{ PUSH31: "PUSH31", PUSH32: "PUSH32", + // 0x80 - dups. DUP1: "DUP1", DUP2: "DUP2", DUP3: "DUP3", @@ -357,6 +356,7 @@ var opCodeToString = map[OpCode]string{ DUP15: "DUP15", DUP16: "DUP16", + // 0x90 - swaps. SWAP1: "SWAP1", SWAP2: "SWAP2", SWAP3: "SWAP3", @@ -373,17 +373,19 @@ var opCodeToString = map[OpCode]string{ SWAP14: "SWAP14", SWAP15: "SWAP15", SWAP16: "SWAP16", - LOG0: "LOG0", - LOG1: "LOG1", - LOG2: "LOG2", - LOG3: "LOG3", - LOG4: "LOG4", + + // 0xa0 range - logging ops. + LOG0: "LOG0", + LOG1: "LOG1", + LOG2: "LOG2", + LOG3: "LOG3", + LOG4: "LOG4", // 0xb0 range. TLOAD: "TLOAD", TSTORE: "TSTORE", - // 0xf0 range. + // 0xf0 range - closures. CREATE: "CREATE", CALL: "CALL", RETURN: "RETURN", @@ -473,8 +475,6 @@ var stringToOp = map[string]OpCode{ "GAS": GAS, "JUMPDEST": JUMPDEST, "PUSH0": PUSH0, - "TLOAD": TLOAD, - "TSTORE": TSTORE, "PUSH1": PUSH1, "PUSH2": PUSH2, "PUSH3": PUSH3, @@ -544,6 +544,8 @@ var stringToOp = map[string]OpCode{ "LOG2": LOG2, "LOG3": LOG3, "LOG4": LOG4, + "TLOAD": TLOAD, + "TSTORE": TSTORE, "CREATE": CREATE, "CREATE2": CREATE2, "CALL": CALL, From ae93e0b484fa9345a3a9eb2a5f1ced9d450d2b52 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Thu, 20 Apr 2023 15:36:54 +0800 Subject: [PATCH 062/988] metrics: use atomic type (#27121) --- metrics/counter.go | 14 +++++++------- metrics/ewma.go | 8 ++++---- metrics/gauge.go | 12 ++++++------ metrics/meter.go | 25 ++++++++++++++----------- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/metrics/counter.go b/metrics/counter.go index 2f78c90d5c..55e1c59540 100644 --- a/metrics/counter.go +++ b/metrics/counter.go @@ -38,13 +38,13 @@ func NewCounter() Counter { if !Enabled { return NilCounter{} } - return &StandardCounter{0} + return &StandardCounter{} } // NewCounterForced constructs a new StandardCounter and returns it no matter if // the global switch is enabled or not. func NewCounterForced() Counter { - return &StandardCounter{0} + return &StandardCounter{} } // NewRegisteredCounter constructs and registers a new StandardCounter. @@ -115,27 +115,27 @@ func (NilCounter) Snapshot() Counter { return NilCounter{} } // StandardCounter is the standard implementation of a Counter and uses the // sync/atomic package to manage a single int64 value. type StandardCounter struct { - count int64 + count atomic.Int64 } // Clear sets the counter to zero. func (c *StandardCounter) Clear() { - atomic.StoreInt64(&c.count, 0) + c.count.Store(0) } // Count returns the current count. func (c *StandardCounter) Count() int64 { - return atomic.LoadInt64(&c.count) + return c.count.Load() } // Dec decrements the counter by the given amount. func (c *StandardCounter) Dec(i int64) { - atomic.AddInt64(&c.count, -i) + c.count.Add(-i) } // Inc increments the counter by the given amount. func (c *StandardCounter) Inc(i int64) { - atomic.AddInt64(&c.count, i) + c.count.Add(i) } // Snapshot returns a read-only copy of the counter. diff --git a/metrics/ewma.go b/metrics/ewma.go index 039286493e..ed95cba19b 100644 --- a/metrics/ewma.go +++ b/metrics/ewma.go @@ -75,7 +75,7 @@ func (NilEWMA) Update(n int64) {} // of uncounted events and processes them on each tick. It uses the // sync/atomic package to manage uncounted events. type StandardEWMA struct { - uncounted int64 // /!\ this should be the first member to ensure 64-bit alignment + uncounted atomic.Int64 alpha float64 rate float64 init bool @@ -97,8 +97,8 @@ func (a *StandardEWMA) Snapshot() EWMA { // Tick ticks the clock to update the moving average. It assumes it is called // every five seconds. func (a *StandardEWMA) Tick() { - count := atomic.LoadInt64(&a.uncounted) - atomic.AddInt64(&a.uncounted, -count) + count := a.uncounted.Load() + a.uncounted.Add(-count) instantRate := float64(count) / float64(5*time.Second) a.mutex.Lock() defer a.mutex.Unlock() @@ -112,5 +112,5 @@ func (a *StandardEWMA) Tick() { // Update adds n uncounted events. func (a *StandardEWMA) Update(n int64) { - atomic.AddInt64(&a.uncounted, n) + a.uncounted.Add(n) } diff --git a/metrics/gauge.go b/metrics/gauge.go index b6b2758b0d..81137d7f7c 100644 --- a/metrics/gauge.go +++ b/metrics/gauge.go @@ -25,7 +25,7 @@ func NewGauge() Gauge { if !Enabled { return NilGauge{} } - return &StandardGauge{0} + return &StandardGauge{} } // NewRegisteredGauge constructs and registers a new StandardGauge. @@ -101,7 +101,7 @@ func (NilGauge) Value() int64 { return 0 } // StandardGauge is the standard implementation of a Gauge and uses the // sync/atomic package to manage a single int64 value. type StandardGauge struct { - value int64 + value atomic.Int64 } // Snapshot returns a read-only copy of the gauge. @@ -111,22 +111,22 @@ func (g *StandardGauge) Snapshot() Gauge { // Update updates the gauge's value. func (g *StandardGauge) Update(v int64) { - atomic.StoreInt64(&g.value, v) + g.value.Store(v) } // Value returns the gauge's current value. func (g *StandardGauge) Value() int64 { - return atomic.LoadInt64(&g.value) + return g.value.Load() } // Dec decrements the gauge's current value by the given amount. func (g *StandardGauge) Dec(i int64) { - atomic.AddInt64(&g.value, -i) + g.value.Add(-i) } // Inc increments the gauge's current value by the given amount. func (g *StandardGauge) Inc(i int64) { - atomic.AddInt64(&g.value, i) + g.value.Add(i) } // FunctionalGauge returns value from given function diff --git a/metrics/meter.go b/metrics/meter.go index 60ae919d04..e8564d6a5e 100644 --- a/metrics/meter.go +++ b/metrics/meter.go @@ -101,11 +101,7 @@ func NewRegisteredMeterForced(name string, r Registry) Meter { // MeterSnapshot is a read-only copy of another Meter. type MeterSnapshot struct { - // WARNING: The `temp` field is accessed atomically. - // On 32 bit platforms, only 64-bit aligned fields can be atomic. The struct is - // guaranteed to be so aligned, so take advantage of that. For more information, - // see https://golang.org/pkg/sync/atomic/#pkg-note-BUG. - temp int64 + temp atomic.Int64 count int64 rate1, rate5, rate15, rateMean float64 } @@ -173,7 +169,7 @@ type StandardMeter struct { snapshot *MeterSnapshot a1, a5, a15 EWMA startTime time.Time - stopped uint32 + stopped atomic.Bool } func newStandardMeter() *StandardMeter { @@ -188,8 +184,8 @@ func newStandardMeter() *StandardMeter { // Stop stops the meter, Mark() will be a no-op if you use it after being stopped. func (m *StandardMeter) Stop() { - stopped := atomic.SwapUint32(&m.stopped, 1) - if stopped != 1 { + stopped := m.stopped.Swap(true) + if !stopped { arbiter.Lock() delete(arbiter.meters, m) arbiter.Unlock() @@ -207,7 +203,7 @@ func (m *StandardMeter) Count() int64 { // Mark records the occurrence of n events. func (m *StandardMeter) Mark(n int64) { - atomic.AddInt64(&m.snapshot.temp, n) + m.snapshot.temp.Add(n) } // Rate1 returns the one-minute moving average rate of events per second. @@ -241,7 +237,14 @@ func (m *StandardMeter) RateMean() float64 { // Snapshot returns a read-only copy of the meter. func (m *StandardMeter) Snapshot() Meter { m.lock.RLock() - snapshot := *m.snapshot + snapshot := MeterSnapshot{ + count: m.snapshot.count, + rate1: m.snapshot.rate1, + rate5: m.snapshot.rate5, + rate15: m.snapshot.rate15, + rateMean: m.snapshot.rateMean, + } + snapshot.temp.Store(m.snapshot.temp.Load()) m.lock.RUnlock() return &snapshot } @@ -257,7 +260,7 @@ func (m *StandardMeter) updateSnapshot() { func (m *StandardMeter) updateMeter() { // should only run with write lock held on m.lock - n := atomic.SwapInt64(&m.snapshot.temp, 0) + n := m.snapshot.temp.Swap(0) m.snapshot.count += n m.a1.Update(n) m.a5.Update(n) From 99f81d27248f13a8e43731a0a1294044ced5d675 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 20 Apr 2023 18:57:24 +0800 Subject: [PATCH 063/988] all: refactor trie API (#26995) In this PR, all TryXXX(e.g. TryGet) APIs of trie are renamed to XXX(e.g. Get) with an error returned. The original XXX(e.g. Get) APIs are renamed to MustXXX(e.g. MustGet) and does not return any error -- they print a log output. A future PR will change the behaviour to panic on errorrs. --- core/rawdb/accessors_indexes_test.go | 3 +- core/state/snapshot/conversion.go | 2 +- core/state/snapshot/generate.go | 2 +- core/state/snapshot/generate_test.go | 14 +-- core/state/sync_test.go | 6 +- core/types/block_test.go | 3 +- core/types/hashing.go | 5 +- core/types/hashing_test.go | 3 +- eth/protocols/snap/sync_test.go | 20 ++-- les/server_handler.go | 2 +- light/postprocess.go | 12 ++- light/trie.go | 12 +-- tests/fuzzers/les/les-fuzzer.go | 4 +- tests/fuzzers/rangeproof/rangeproof-fuzzer.go | 6 +- tests/fuzzers/stacktrie/trie_fuzzer.go | 6 +- tests/fuzzers/trie/trie-fuzzer.go | 8 +- trie/errors.go | 2 +- trie/iterator_test.go | 26 ++--- trie/proof.go | 4 +- trie/proof_test.go | 20 ++-- trie/secure_trie.go | 54 ++++++----- trie/secure_trie_test.go | 20 ++-- trie/stacktrie.go | 10 +- trie/stacktrie_test.go | 30 +++--- trie/sync_test.go | 8 +- trie/tracer_test.go | 24 ++--- trie/trie.go | 97 +++++++++++-------- trie/trie_test.go | 82 ++++++++-------- 28 files changed, 256 insertions(+), 229 deletions(-) diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go index 4734e986e2..c5447b16d2 100644 --- a/core/rawdb/accessors_indexes_test.go +++ b/core/rawdb/accessors_indexes_test.go @@ -45,9 +45,10 @@ func (h *testHasher) Reset() { h.hasher.Reset() } -func (h *testHasher) Update(key, val []byte) { +func (h *testHasher) Update(key, val []byte) error { h.hasher.Write(key) h.hasher.Write(val) + return nil } func (h *testHasher) Hash() common.Hash { diff --git a/core/state/snapshot/conversion.go b/core/state/snapshot/conversion.go index ed7cb963ad..0e583e6269 100644 --- a/core/state/snapshot/conversion.go +++ b/core/state/snapshot/conversion.go @@ -371,7 +371,7 @@ func stackTrieGenerate(db ethdb.KeyValueWriter, scheme string, owner common.Hash } t := trie.NewStackTrieWithOwner(nodeWriter, owner) for leaf := range in { - t.TryUpdate(leaf.key[:], leaf.value) + t.Update(leaf.key[:], leaf.value) } var root common.Hash if db == nil { diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index d46705d31e..68c2f574b8 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -230,7 +230,7 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, trieId *trie.ID, prefix [ if origin == nil && !diskMore { stackTr := trie.NewStackTrie(nil) for i, key := range keys { - stackTr.TryUpdate(key, vals[i]) + stackTr.Update(key, vals[i]) } if gotRoot := stackTr.Hash(); gotRoot != root { return &proofResult{ diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 1bac4fd560..546132e7dd 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -161,7 +161,7 @@ func newHelper() *testHelper { func (t *testHelper) addTrieAccount(acckey string, acc *Account) { val, _ := rlp.EncodeToBytes(acc) - t.accTrie.Update([]byte(acckey), val) + t.accTrie.MustUpdate([]byte(acckey), val) } func (t *testHelper) addSnapAccount(acckey string, acc *Account) { @@ -186,7 +186,7 @@ func (t *testHelper) makeStorageTrie(stateRoot, owner common.Hash, keys []string id := trie.StorageTrieID(stateRoot, owner, common.Hash{}) stTrie, _ := trie.NewStateTrie(id, t.triedb) for i, k := range keys { - stTrie.Update([]byte(k), []byte(vals[i])) + stTrie.MustUpdate([]byte(k), []byte(vals[i])) } if !commit { return stTrie.Hash().Bytes() @@ -491,7 +491,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) { ) acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) - helper.accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e // Identical in the snap key := hashData([]byte("acc-1")) @@ -562,7 +562,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) { ) acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) - helper.accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e // Identical in the snap key := hashData([]byte("acc-1")) @@ -613,8 +613,8 @@ func TestGenerateWithExtraBeforeAndAfter(t *testing.T) { { acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) - helper.accTrie.Update(common.HexToHash("0x03").Bytes(), val) - helper.accTrie.Update(common.HexToHash("0x07").Bytes(), val) + helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val) + helper.accTrie.MustUpdate(common.HexToHash("0x07").Bytes(), val) rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x01"), val) rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x02"), val) @@ -650,7 +650,7 @@ func TestGenerateWithMalformedSnapdata(t *testing.T) { { acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) - helper.accTrie.Update(common.HexToHash("0x03").Bytes(), val) + helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val) junk := make([]byte, 100) copy(junk, []byte{0xde, 0xad}) diff --git a/core/state/sync_test.go b/core/state/sync_test.go index aff91268aa..090d55e473 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -213,14 +213,14 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { for i, node := range nodeElements { if bypath { if len(node.syncPath) == 1 { - data, _, err := srcTrie.TryGetNode(node.syncPath[0]) + data, _, err := srcTrie.GetNode(node.syncPath[0]) if err != nil { t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[0], err) } nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} } else { var acc types.StateAccount - if err := rlp.DecodeBytes(srcTrie.Get(node.syncPath[0]), &acc); err != nil { + if err := rlp.DecodeBytes(srcTrie.MustGet(node.syncPath[0]), &acc); err != nil { t.Fatalf("failed to decode account on path %x: %v", node.syncPath[0], err) } id := trie.StorageTrieID(srcRoot, common.BytesToHash(node.syncPath[0]), acc.Root) @@ -228,7 +228,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { if err != nil { t.Fatalf("failed to retriev storage trie for path %x: %v", node.syncPath[1], err) } - data, _, err := stTrie.TryGetNode(node.syncPath[1]) + data, _, err := stTrie.GetNode(node.syncPath[1]) if err != nil { t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[1], err) } diff --git a/core/types/block_test.go b/core/types/block_test.go index 49197c9237..966015eb01 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -232,9 +232,10 @@ func (h *testHasher) Reset() { h.hasher.Reset() } -func (h *testHasher) Update(key, val []byte) { +func (h *testHasher) Update(key, val []byte) error { h.hasher.Write(key) h.hasher.Write(val) + return nil } func (h *testHasher) Hash() common.Hash { diff --git a/core/types/hashing.go b/core/types/hashing.go index 71295c107c..fbdeaf0d07 100644 --- a/core/types/hashing.go +++ b/core/types/hashing.go @@ -62,7 +62,7 @@ func prefixedRlpHash(prefix byte, x interface{}) (h common.Hash) { // This is internal, do not use. type TrieHasher interface { Reset() - Update([]byte, []byte) + Update([]byte, []byte) error Hash() common.Hash } @@ -93,6 +93,9 @@ func DeriveSha(list DerivableList, hasher TrieHasher) common.Hash { // StackTrie requires values to be inserted in increasing hash order, which is not the // order that `list` provides hashes in. This insertion sequence ensures that the // order is correct. + // + // The error returned by hasher is omitted because hasher will produce an incorrect + // hash in case any error occurs. var indexBuf []byte for i := 1; i < list.Len() && i <= 0x7f; i++ { indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i)) diff --git a/core/types/hashing_test.go b/core/types/hashing_test.go index 294a3977d0..c5b9f690d8 100644 --- a/core/types/hashing_test.go +++ b/core/types/hashing_test.go @@ -219,9 +219,10 @@ func (d *hashToHumanReadable) Reset() { d.data = make([]byte, 0) } -func (d *hashToHumanReadable) Update(i []byte, i2 []byte) { +func (d *hashToHumanReadable) Update(i []byte, i2 []byte) error { l := fmt.Sprintf("%x %x\n", i, i2) d.data = append(d.data, []byte(l)...) + return nil } func (d *hashToHumanReadable) Hash() common.Hash { diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 0a61179729..6a3b482d5d 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -216,7 +216,7 @@ func defaultTrieRequestHandler(t *testPeer, requestId uint64, root common.Hash, for _, pathset := range paths { switch len(pathset) { case 1: - blob, _, err := t.accountTrie.TryGetNode(pathset[0]) + blob, _, err := t.accountTrie.GetNode(pathset[0]) if err != nil { t.logger.Info("Error handling req", "error", err) break @@ -225,7 +225,7 @@ func defaultTrieRequestHandler(t *testPeer, requestId uint64, root common.Hash, default: account := t.storageTries[(common.BytesToHash(pathset[0]))] for _, path := range pathset[1:] { - blob, _, err := account.TryGetNode(path) + blob, _, err := account.GetNode(path) if err != nil { t.logger.Info("Error handling req", "error", err) break @@ -1381,7 +1381,7 @@ func makeAccountTrieNoStorage(n int) (string, *trie.Trie, entrySlice) { }) key := key32(i) elem := &kv{key, value} - accTrie.Update(elem.k, elem.v) + accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } sort.Sort(entries) @@ -1431,7 +1431,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { CodeHash: getCodeHash(uint64(i)), }) elem := &kv{boundaries[i].Bytes(), value} - accTrie.Update(elem.k, elem.v) + accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } // Fill other accounts if required @@ -1443,7 +1443,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { CodeHash: getCodeHash(i), }) elem := &kv{key32(i), value} - accTrie.Update(elem.k, elem.v) + accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } sort.Sort(entries) @@ -1487,7 +1487,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) CodeHash: codehash, }) elem := &kv{key, value} - accTrie.Update(elem.k, elem.v) + accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) storageRoots[common.BytesToHash(key)] = stRoot @@ -1551,7 +1551,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin CodeHash: codehash, }) elem := &kv{key, value} - accTrie.Update(elem.k, elem.v) + accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) // we reuse the same one for all accounts @@ -1599,7 +1599,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas key := crypto.Keccak256Hash(slotKey[:]) elem := &kv{key[:], rlpSlotValue} - trie.Update(elem.k, elem.v) + trie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } sort.Sort(entries) @@ -1638,7 +1638,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo val := []byte{0xde, 0xad, 0xbe, 0xef} elem := &kv{key[:], val} - trie.Update(elem.k, elem.v) + trie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } // Fill other slots if required @@ -1650,7 +1650,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo rlpSlotValue, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(slotValue[:])) elem := &kv{key[:], rlpSlotValue} - trie.Update(elem.k, elem.v) + trie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } sort.Sort(entries) diff --git a/les/server_handler.go b/les/server_handler.go index 2ea496ac2c..39c7ace1c9 100644 --- a/les/server_handler.go +++ b/les/server_handler.go @@ -364,7 +364,7 @@ func getAccount(triedb *trie.Database, root, hash common.Hash) (types.StateAccou if err != nil { return types.StateAccount{}, err } - blob, err := trie.TryGet(hash[:]) + blob, err := trie.Get(hash[:]) if err != nil { return types.StateAccount{}, err } diff --git a/light/postprocess.go b/light/postprocess.go index e800a1f0f7..763ba27529 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -206,8 +206,7 @@ func (c *ChtIndexerBackend) Process(ctx context.Context, header *types.Header) e var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], num) data, _ := rlp.EncodeToBytes(ChtNode{hash, td}) - c.trie.Update(encNumber[:], data) - return nil + return c.trie.Update(encNumber[:], data) } // Commit implements core.ChainIndexerBackend @@ -450,10 +449,15 @@ func (b *BloomTrieIndexerBackend) Commit() error { decompSize += uint64(len(decomp)) compSize += uint64(len(comp)) + + var terr error if len(comp) > 0 { - b.trie.Update(encKey[:], comp) + terr = b.trie.Update(encKey[:], comp) } else { - b.trie.Delete(encKey[:]) + terr = b.trie.Delete(encKey[:]) + } + if terr != nil { + return terr } } root, nodes := b.trie.Commit(false) diff --git a/light/trie.go b/light/trie.go index 2f8f71c61e..38dd6b5c27 100644 --- a/light/trie.go +++ b/light/trie.go @@ -109,7 +109,7 @@ func (t *odrTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) { key = crypto.Keccak256(key) var res []byte err := t.do(key, func() (err error) { - res, err = t.trie.TryGet(key) + res, err = t.trie.Get(key) return err }) return res, err @@ -119,7 +119,7 @@ func (t *odrTrie) GetAccount(address common.Address) (*types.StateAccount, error var res types.StateAccount key := crypto.Keccak256(address.Bytes()) err := t.do(key, func() (err error) { - value, err := t.trie.TryGet(key) + value, err := t.trie.Get(key) if err != nil { return err } @@ -138,21 +138,21 @@ func (t *odrTrie) UpdateAccount(address common.Address, acc *types.StateAccount) return fmt.Errorf("decoding error in account update: %w", err) } return t.do(key, func() error { - return t.trie.TryUpdate(key, value) + return t.trie.Update(key, value) }) } func (t *odrTrie) UpdateStorage(_ common.Address, key, value []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { - return t.trie.TryUpdate(key, value) + return t.trie.Update(key, value) }) } func (t *odrTrie) DeleteStorage(_ common.Address, key []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { - return t.trie.TryDelete(key) + return t.trie.Delete(key) }) } @@ -160,7 +160,7 @@ func (t *odrTrie) DeleteStorage(_ common.Address, key []byte) error { func (t *odrTrie) DeleteAccount(address common.Address) error { key := crypto.Keccak256(address.Bytes()) return t.do(key, func() error { - return t.trie.TryDelete(key) + return t.trie.Delete(key) }) } diff --git a/tests/fuzzers/les/les-fuzzer.go b/tests/fuzzers/les/les-fuzzer.go index 924a749e58..926de04585 100644 --- a/tests/fuzzers/les/les-fuzzer.go +++ b/tests/fuzzers/les/les-fuzzer.go @@ -93,13 +93,13 @@ func makeTries() (chtTrie *trie.Trie, bloomTrie *trie.Trie, chtKeys, bloomKeys [ // The element in CHT is -> key := make([]byte, 8) binary.BigEndian.PutUint64(key, uint64(i+1)) - chtTrie.Update(key, []byte{0x1, 0xf}) + chtTrie.MustUpdate(key, []byte{0x1, 0xf}) chtKeys = append(chtKeys, key) // The element in Bloom trie is <2 byte bit index> + -> bloom key2 := make([]byte, 10) binary.BigEndian.PutUint64(key2[2:], uint64(i+1)) - bloomTrie.Update(key2, []byte{0x2, 0xe}) + bloomTrie.MustUpdate(key2, []byte{0x2, 0xe}) bloomKeys = append(bloomKeys, key2) } return diff --git a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go index bca93bbe19..2881c7a7c2 100644 --- a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go +++ b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go @@ -69,8 +69,8 @@ func (f *fuzzer) randomTrie(n int) (*trie.Trie, map[string]*kv) { for i := byte(0); i < byte(size); i++ { value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), []byte{i}, false} - trie.Update(value.k, value.v) - trie.Update(value2.k, value2.v) + trie.MustUpdate(value.k, value.v) + trie.MustUpdate(value2.k, value2.v) vals[string(value.k)] = value vals[string(value2.k)] = value2 } @@ -82,7 +82,7 @@ func (f *fuzzer) randomTrie(n int) (*trie.Trie, map[string]*kv) { k := f.randBytes(32) v := f.randBytes(20) value := &kv{k, v, false} - trie.Update(k, v) + trie.MustUpdate(k, v) vals[string(k)] = value if f.exhausted { return nil, nil diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index 435aa3a47c..809dba8ce5 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -175,7 +175,7 @@ func (f *fuzzer) fuzz() int { } keys[string(k)] = struct{}{} vals = append(vals, kv{k: k, v: v}) - trieA.Update(k, v) + trieA.MustUpdate(k, v) useful = true } if !useful { @@ -195,7 +195,7 @@ func (f *fuzzer) fuzz() int { if f.debugging { fmt.Printf("{\"%#x\" , \"%#x\"} // stacktrie.Update\n", kv.k, kv.v) } - trieB.Update(kv.k, kv.v) + trieB.MustUpdate(kv.k, kv.v) } rootB := trieB.Hash() trieB.Commit() @@ -223,7 +223,7 @@ func (f *fuzzer) fuzz() int { checked int ) for _, kv := range vals { - trieC.Update(kv.k, kv.v) + trieC.MustUpdate(kv.k, kv.v) } rootC, _ := trieC.Commit() if rootA != rootC { diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index 40dec76b8f..c0cbceff31 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -147,13 +147,13 @@ func runRandTest(rt randTest) error { for i, step := range rt { switch step.op { case opUpdate: - tr.Update(step.key, step.value) + tr.MustUpdate(step.key, step.value) values[string(step.key)] = string(step.value) case opDelete: - tr.Delete(step.key) + tr.MustDelete(step.key) delete(values, string(step.key)) case opGet: - v := tr.Get(step.key) + v := tr.MustGet(step.key) want := values[string(step.key)] if string(v) != want { rt[i].err = fmt.Errorf("mismatch for key %#x, got %#x want %#x", step.key, v, want) @@ -176,7 +176,7 @@ func runRandTest(rt randTest) error { checktr := trie.NewEmpty(triedb) it := trie.NewIterator(tr.NodeIterator(nil)) for it.Next() { - checktr.Update(it.Key, it.Value) + checktr.MustUpdate(it.Key, it.Value) } if tr.Hash() != checktr.Hash() { return fmt.Errorf("hash mismatch in opItercheckhash") diff --git a/trie/errors.go b/trie/errors.go index afe344bed2..bd82b950aa 100644 --- a/trie/errors.go +++ b/trie/errors.go @@ -22,7 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// MissingNodeError is returned by the trie functions (TryGet, TryUpdate, TryDelete) +// MissingNodeError is returned by the trie functions (Get, Update, Delete) // in the case where a trie node is not present in the local database. It contains // information necessary for retrieving the missing node. type MissingNodeError struct { diff --git a/trie/iterator_test.go b/trie/iterator_test.go index ac2a3d2a4c..6dc38db6f1 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -58,7 +58,7 @@ func TestIterator(t *testing.T) { all := make(map[string]string) for _, val := range vals { all[val.k] = val.v - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } root, nodes := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -89,8 +89,8 @@ func TestIteratorLargeData(t *testing.T) { for i := byte(0); i < 255; i++ { value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false} - trie.Update(value.k, value.v) - trie.Update(value2.k, value2.v) + trie.MustUpdate(value.k, value.v) + trie.MustUpdate(value2.k, value2.v) vals[string(value.k)] = value vals[string(value2.k)] = value2 } @@ -178,7 +178,7 @@ var testdata2 = []kvs{ func TestIteratorSeek(t *testing.T) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for _, val := range testdata1 { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } // Seek to the middle. @@ -220,7 +220,7 @@ func TestDifferenceIterator(t *testing.T) { dba := NewDatabase(rawdb.NewMemoryDatabase()) triea := NewEmpty(dba) for _, val := range testdata1 { - triea.Update([]byte(val.k), []byte(val.v)) + triea.MustUpdate([]byte(val.k), []byte(val.v)) } rootA, nodesA := triea.Commit(false) dba.Update(NewWithNodeSet(nodesA)) @@ -229,7 +229,7 @@ func TestDifferenceIterator(t *testing.T) { dbb := NewDatabase(rawdb.NewMemoryDatabase()) trieb := NewEmpty(dbb) for _, val := range testdata2 { - trieb.Update([]byte(val.k), []byte(val.v)) + trieb.MustUpdate([]byte(val.k), []byte(val.v)) } rootB, nodesB := trieb.Commit(false) dbb.Update(NewWithNodeSet(nodesB)) @@ -262,7 +262,7 @@ func TestUnionIterator(t *testing.T) { dba := NewDatabase(rawdb.NewMemoryDatabase()) triea := NewEmpty(dba) for _, val := range testdata1 { - triea.Update([]byte(val.k), []byte(val.v)) + triea.MustUpdate([]byte(val.k), []byte(val.v)) } rootA, nodesA := triea.Commit(false) dba.Update(NewWithNodeSet(nodesA)) @@ -271,7 +271,7 @@ func TestUnionIterator(t *testing.T) { dbb := NewDatabase(rawdb.NewMemoryDatabase()) trieb := NewEmpty(dbb) for _, val := range testdata2 { - trieb.Update([]byte(val.k), []byte(val.v)) + trieb.MustUpdate([]byte(val.k), []byte(val.v)) } rootB, nodesB := trieb.Commit(false) dbb.Update(NewWithNodeSet(nodesB)) @@ -314,7 +314,7 @@ func TestUnionIterator(t *testing.T) { func TestIteratorNoDups(t *testing.T) { tr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for _, val := range testdata1 { - tr.Update([]byte(val.k), []byte(val.v)) + tr.MustUpdate([]byte(val.k), []byte(val.v)) } checkIteratorNoDups(t, tr.NodeIterator(nil), nil) } @@ -329,7 +329,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) { tr := NewEmpty(triedb) for _, val := range testdata1 { - tr.Update([]byte(val.k), []byte(val.v)) + tr.MustUpdate([]byte(val.k), []byte(val.v)) } _, nodes := tr.Commit(false) triedb.Update(NewWithNodeSet(nodes)) @@ -421,7 +421,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { ctr := NewEmpty(triedb) for _, val := range testdata1 { - ctr.Update([]byte(val.k), []byte(val.v)) + ctr.MustUpdate([]byte(val.k), []byte(val.v)) } root, nodes := ctr.Commit(false) triedb.Update(NewWithNodeSet(nodes)) @@ -540,7 +540,7 @@ func makeLargeTestTrie() (*Database, *StateTrie, *loggingDb) { binary.BigEndian.PutUint64(val, uint64(i)) key = crypto.Keccak256(key) val = crypto.Keccak256(val) - trie.Update(key, val) + trie.MustUpdate(key, val) } _, nodes := trie.Commit(false) triedb.Update(NewWithNodeSet(nodes)) @@ -580,7 +580,7 @@ func TestIteratorNodeBlob(t *testing.T) { all := make(map[string]string) for _, val := range vals { all[val.k] = val.v - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } _, nodes := trie.Commit(false) triedb.Update(NewWithNodeSet(nodes)) diff --git a/trie/proof.go b/trie/proof.go index f11dfc47af..65df7577b9 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -498,7 +498,7 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key if proof == nil { tr := NewStackTrie(nil) for index, key := range keys { - tr.TryUpdate(key, values[index]) + tr.Update(key, values[index]) } if have, want := tr.Hash(), rootHash; have != want { return false, fmt.Errorf("invalid proof, want hash %x, got %x", want, have) @@ -568,7 +568,7 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key tr.root = nil } for index, key := range keys { - tr.TryUpdate(key, values[index]) + tr.Update(key, values[index]) } if tr.Hash() != rootHash { return false, fmt.Errorf("invalid proof, want hash %x, got %x", rootHash, tr.Hash()) diff --git a/trie/proof_test.go b/trie/proof_test.go index 6b23bcdb27..69e3f8e9ce 100644 --- a/trie/proof_test.go +++ b/trie/proof_test.go @@ -403,7 +403,7 @@ func TestOneElementRangeProof(t *testing.T) { // Test the mini trie with only a single element. tinyTrie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) entry := &kv{randBytes(32), randBytes(20), false} - tinyTrie.Update(entry.k, entry.v) + tinyTrie.MustUpdate(entry.k, entry.v) first = common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000").Bytes() last = entry.k @@ -477,7 +477,7 @@ func TestSingleSideRangeProof(t *testing.T) { var entries entrySlice for i := 0; i < 4096; i++ { value := &kv{randBytes(32), randBytes(20), false} - trie.Update(value.k, value.v) + trie.MustUpdate(value.k, value.v) entries = append(entries, value) } sort.Sort(entries) @@ -512,7 +512,7 @@ func TestReverseSingleSideRangeProof(t *testing.T) { var entries entrySlice for i := 0; i < 4096; i++ { value := &kv{randBytes(32), randBytes(20), false} - trie.Update(value.k, value.v) + trie.MustUpdate(value.k, value.v) entries = append(entries, value) } sort.Sort(entries) @@ -619,7 +619,7 @@ func TestGappedRangeProof(t *testing.T) { var entries []*kv // Sorted entries for i := byte(0); i < 10; i++ { value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} - trie.Update(value.k, value.v) + trie.MustUpdate(value.k, value.v) entries = append(entries, value) } first, last := 2, 8 @@ -693,7 +693,7 @@ func TestHasRightElement(t *testing.T) { var entries entrySlice for i := 0; i < 4096; i++ { value := &kv{randBytes(32), randBytes(20), false} - trie.Update(value.k, value.v) + trie.MustUpdate(value.k, value.v) entries = append(entries, value) } sort.Sort(entries) @@ -1047,14 +1047,14 @@ func randomTrie(n int) (*Trie, map[string]*kv) { for i := byte(0); i < 100; i++ { value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), []byte{i}, false} - trie.Update(value.k, value.v) - trie.Update(value2.k, value2.v) + trie.MustUpdate(value.k, value.v) + trie.MustUpdate(value2.k, value2.v) vals[string(value.k)] = value vals[string(value2.k)] = value2 } for i := 0; i < n; i++ { value := &kv{randBytes(32), randBytes(20), false} - trie.Update(value.k, value.v) + trie.MustUpdate(value.k, value.v) vals[string(value.k)] = value } return trie, vals @@ -1071,7 +1071,7 @@ func nonRandomTrie(n int) (*Trie, map[string]*kv) { binary.LittleEndian.PutUint64(value, i-max) //value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} elem := &kv{key, value, false} - trie.Update(elem.k, elem.v) + trie.MustUpdate(elem.k, elem.v) vals[string(elem.k)] = elem } return trie, vals @@ -1088,7 +1088,7 @@ func TestRangeProofKeysWithSharedPrefix(t *testing.T) { } trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i, key := range keys { - trie.Update(key, vals[i]) + trie.MustUpdate(key, vals[i]) } root := trie.Hash() proof := memorydb.New() diff --git a/trie/secure_trie.go b/trie/secure_trie.go index b25bf758c1..5bfd246501 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -19,7 +19,6 @@ package trie import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" ) @@ -72,14 +71,13 @@ func NewStateTrie(id *ID, db *Database) (*StateTrie, error) { return &StateTrie{trie: *trie, preimages: db.preimages}, nil } -// Get returns the value for key stored in the trie. +// MustGet returns the value for key stored in the trie. // The value bytes must not be modified by the caller. -func (t *StateTrie) Get(key []byte) []byte { - res, err := t.GetStorage(common.Address{}, key) - if err != nil { - log.Error("Unhandled trie error in StateTrie.Get", "err", err) - } - return res +// +// This function will omit any encountered error but just +// print out an error message. +func (t *StateTrie) MustGet(key []byte) []byte { + return t.trie.MustGet(t.hashKey(key)) } // GetStorage attempts to retrieve a storage slot with provided account address @@ -87,14 +85,14 @@ func (t *StateTrie) Get(key []byte) []byte { // If the specified storage slot is not in the trie, nil will be returned. // If a trie node is not found in the database, a MissingNodeError is returned. func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) { - return t.trie.TryGet(t.hashKey(key)) + return t.trie.Get(t.hashKey(key)) } // GetAccount attempts to retrieve an account with provided account address. // If the specified account is not in the trie, nil will be returned. // If a trie node is not found in the database, a MissingNodeError is returned. func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, error) { - res, err := t.trie.TryGet(t.hashKey(address.Bytes())) + res, err := t.trie.Get(t.hashKey(address.Bytes())) if res == nil || err != nil { return nil, err } @@ -107,7 +105,7 @@ func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, err // account hash that is the hash of address. This constitutes an abstraction // leak, since the client code needs to know the key format. func (t *StateTrie) GetAccountByHash(addrHash common.Hash) (*types.StateAccount, error) { - res, err := t.trie.TryGet(addrHash.Bytes()) + res, err := t.trie.Get(addrHash.Bytes()) if res == nil || err != nil { return nil, err } @@ -121,19 +119,22 @@ func (t *StateTrie) GetAccountByHash(addrHash common.Hash) (*types.StateAccount, // If the specified trie node is not in the trie, nil will be returned. // If a trie node is not found in the database, a MissingNodeError is returned. func (t *StateTrie) GetNode(path []byte) ([]byte, int, error) { - return t.trie.TryGetNode(path) + return t.trie.GetNode(path) } -// Update associates key with value in the trie. Subsequent calls to +// MustUpdate associates key with value in the trie. Subsequent calls to // Get will return value. If value has length zero, any existing value // is deleted from the trie and calls to Get will return nil. // // The value bytes must not be modified by the caller while they are // stored in the trie. -func (t *StateTrie) Update(key, value []byte) { - if err := t.UpdateStorage(common.Address{}, key, value); err != nil { - log.Error("Unhandled trie error in StateTrie.Update", "err", err) - } +// +// This function will omit any encountered error but just print out an +// error message. +func (t *StateTrie) MustUpdate(key, value []byte) { + hk := t.hashKey(key) + t.trie.MustUpdate(hk, value) + t.getSecKeyCache()[string(hk)] = common.CopyBytes(key) } // UpdateStorage associates key with value in the trie. Subsequent calls to @@ -146,7 +147,7 @@ func (t *StateTrie) Update(key, value []byte) { // If a node is not found in the database, a MissingNodeError is returned. func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error { hk := t.hashKey(key) - err := t.trie.TryUpdate(hk, value) + err := t.trie.Update(hk, value) if err != nil { return err } @@ -161,18 +162,19 @@ func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccoun if err != nil { return err } - if err := t.trie.TryUpdate(hk, data); err != nil { + if err := t.trie.Update(hk, data); err != nil { return err } t.getSecKeyCache()[string(hk)] = address.Bytes() return nil } -// Delete removes any existing value for key from the trie. -func (t *StateTrie) Delete(key []byte) { - if err := t.DeleteStorage(common.Address{}, key); err != nil { - log.Error("Unhandled trie error in StateTrie.Delete", "err", err) - } +// MustDelete removes any existing value for key from the trie. This function +// will omit any encountered error but just print out an error message. +func (t *StateTrie) MustDelete(key []byte) { + hk := t.hashKey(key) + delete(t.getSecKeyCache(), string(hk)) + t.trie.MustDelete(hk) } // DeleteStorage removes any existing storage slot from the trie. @@ -181,14 +183,14 @@ func (t *StateTrie) Delete(key []byte) { func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error { hk := t.hashKey(key) delete(t.getSecKeyCache(), string(hk)) - return t.trie.TryDelete(hk) + return t.trie.Delete(hk) } // DeleteAccount abstracts an account deletion from the trie. func (t *StateTrie) DeleteAccount(address common.Address) error { hk := t.hashKey(address.Bytes()) delete(t.getSecKeyCache(), string(hk)) - return t.trie.TryDelete(hk) + return t.trie.Delete(hk) } // GetKey returns the sha3 preimage of a hashed key that was diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index d3e6c67069..a55c10a60b 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -45,17 +45,17 @@ func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) { // Map the same data under multiple keys key, val := common.LeftPadBytes([]byte{1, i}, 32), []byte{i} content[string(key)] = val - trie.Update(key, val) + trie.MustUpdate(key, val) key, val = common.LeftPadBytes([]byte{2, i}, 32), []byte{i} content[string(key)] = val - trie.Update(key, val) + trie.MustUpdate(key, val) // Add some other data to inflate the trie for j := byte(3); j < 13; j++ { key, val = common.LeftPadBytes([]byte{j, i}, 32), []byte{j, i} content[string(key)] = val - trie.Update(key, val) + trie.MustUpdate(key, val) } } root, nodes := trie.Commit(false) @@ -81,9 +81,9 @@ func TestSecureDelete(t *testing.T) { } for _, val := range vals { if val.v != "" { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } else { - trie.Delete([]byte(val.k)) + trie.MustDelete([]byte(val.k)) } } hash := trie.Hash() @@ -95,13 +95,13 @@ func TestSecureDelete(t *testing.T) { func TestSecureGetKey(t *testing.T) { trie := newEmptySecure() - trie.Update([]byte("foo"), []byte("bar")) + trie.MustUpdate([]byte("foo"), []byte("bar")) key := []byte("foo") value := []byte("bar") seckey := crypto.Keccak256(key) - if !bytes.Equal(trie.Get(key), value) { + if !bytes.Equal(trie.MustGet(key), value) { t.Errorf("Get did not return bar") } if k := trie.GetKey(seckey); !bytes.Equal(k, key) { @@ -128,15 +128,15 @@ func TestStateTrieConcurrency(t *testing.T) { for j := byte(0); j < 255; j++ { // Map the same data under multiple keys key, val := common.LeftPadBytes([]byte{byte(index), 1, j}, 32), []byte{j} - tries[index].Update(key, val) + tries[index].MustUpdate(key, val) key, val = common.LeftPadBytes([]byte{byte(index), 2, j}, 32), []byte{j} - tries[index].Update(key, val) + tries[index].MustUpdate(key, val) // Add some other data to inflate the trie for k := byte(3); k < 13; k++ { key, val = common.LeftPadBytes([]byte{byte(index), k, j}, 32), []byte{k, j} - tries[index].Update(key, val) + tries[index].MustUpdate(key, val) } } tries[index].Commit(false) diff --git a/trie/stacktrie.go b/trie/stacktrie.go index 83034e29a5..030d2a596c 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -202,8 +202,8 @@ const ( hashedNode ) -// TryUpdate inserts a (key, value) pair into the stack trie -func (st *StackTrie) TryUpdate(key, value []byte) error { +// Update inserts a (key, value) pair into the stack trie. +func (st *StackTrie) Update(key, value []byte) error { k := keybytesToHex(key) if len(value) == 0 { panic("deletion not supported") @@ -212,8 +212,10 @@ func (st *StackTrie) TryUpdate(key, value []byte) error { return nil } -func (st *StackTrie) Update(key, value []byte) { - if err := st.TryUpdate(key, value); err != nil { +// MustUpdate is a wrapper of Update and will omit any encountered error but +// just print out an error message. +func (st *StackTrie) MustUpdate(key, value []byte) { + if err := st.Update(key, value); err != nil { log.Error("Unhandled trie error in StackTrie.Update", "err", err) } } diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go index 3e6cc8cd57..ea3eef7882 100644 --- a/trie/stacktrie_test.go +++ b/trie/stacktrie_test.go @@ -174,7 +174,7 @@ func TestStackTrieInsertAndHash(t *testing.T) { st.Reset() for j := 0; j < l; j++ { kv := &test[j] - if err := st.TryUpdate(common.FromHex(kv.K), []byte(kv.V)); err != nil { + if err := st.Update(common.FromHex(kv.K), []byte(kv.V)); err != nil { t.Fatal(err) } } @@ -193,8 +193,8 @@ func TestSizeBug(t *testing.T) { leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") - nt.TryUpdate(leaf, value) - st.TryUpdate(leaf, value) + nt.Update(leaf, value) + st.Update(leaf, value) if nt.Hash() != st.Hash() { t.Fatalf("error %x != %x", st.Hash(), nt.Hash()) @@ -218,8 +218,8 @@ func TestEmptyBug(t *testing.T) { } for _, kv := range kvs { - nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) - st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) + nt.Update(common.FromHex(kv.K), common.FromHex(kv.V)) + st.Update(common.FromHex(kv.K), common.FromHex(kv.V)) } if nt.Hash() != st.Hash() { @@ -241,8 +241,8 @@ func TestValLength56(t *testing.T) { } for _, kv := range kvs { - nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) - st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) + nt.Update(common.FromHex(kv.K), common.FromHex(kv.V)) + st.Update(common.FromHex(kv.K), common.FromHex(kv.V)) } if nt.Hash() != st.Hash() { @@ -263,8 +263,8 @@ func TestUpdateSmallNodes(t *testing.T) { {"65", "3000"}, // stacktrie.Update } for _, kv := range kvs { - nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) - st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) + nt.Update(common.FromHex(kv.K), common.FromHex(kv.V)) + st.Update(common.FromHex(kv.K), common.FromHex(kv.V)) } if nt.Hash() != st.Hash() { t.Fatalf("error %x != %x", st.Hash(), nt.Hash()) @@ -291,8 +291,8 @@ func TestUpdateVariableKeys(t *testing.T) { {"0x3330353463653239356131303167617430", "313131"}, } for _, kv := range kvs { - nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) - st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) + nt.Update(common.FromHex(kv.K), common.FromHex(kv.V)) + st.Update(common.FromHex(kv.K), common.FromHex(kv.V)) } if nt.Hash() != st.Hash() { t.Fatalf("error %x != %x", st.Hash(), nt.Hash()) @@ -309,7 +309,7 @@ func TestStacktrieNotModifyValues(t *testing.T) { value := make([]byte, 1, 100) value[0] = 0x2 want := common.CopyBytes(value) - st.TryUpdate([]byte{0x01}, value) + st.Update([]byte{0x01}, value) st.Hash() if have := value; !bytes.Equal(have, want) { t.Fatalf("tiny trie: have %#x want %#x", have, want) @@ -330,7 +330,7 @@ func TestStacktrieNotModifyValues(t *testing.T) { for i := 0; i < 1000; i++ { key := common.BigToHash(keyB) value := getValue(i) - st.TryUpdate(key.Bytes(), value) + st.Update(key.Bytes(), value) vals = append(vals, value) keyB = keyB.Add(keyB, keyDelta) keyDelta.Add(keyDelta, common.Big1) @@ -371,7 +371,7 @@ func TestStacktrieSerialization(t *testing.T) { keyDelta.Add(keyDelta, common.Big1) } for i, k := range keys { - nt.TryUpdate(k, common.CopyBytes(vals[i])) + nt.Update(k, common.CopyBytes(vals[i])) } for i, k := range keys { @@ -384,7 +384,7 @@ func TestStacktrieSerialization(t *testing.T) { t.Fatal(err) } st = newSt - st.TryUpdate(k, common.CopyBytes(vals[i])) + st.Update(k, common.CopyBytes(vals[i])) } if have, want := st.Hash(), nt.Hash(); have != want { t.Fatalf("have %#x want %#x", have, want) diff --git a/trie/sync_test.go b/trie/sync_test.go index f404dc1cda..70898604f8 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -40,17 +40,17 @@ func makeTestTrie() (*Database, *StateTrie, map[string][]byte) { // Map the same data under multiple keys key, val := common.LeftPadBytes([]byte{1, i}, 32), []byte{i} content[string(key)] = val - trie.Update(key, val) + trie.MustUpdate(key, val) key, val = common.LeftPadBytes([]byte{2, i}, 32), []byte{i} content[string(key)] = val - trie.Update(key, val) + trie.MustUpdate(key, val) // Add some other data to inflate the trie for j := byte(3); j < 13; j++ { key, val = common.LeftPadBytes([]byte{j, i}, 32), []byte{j, i} content[string(key)] = val - trie.Update(key, val) + trie.MustUpdate(key, val) } } root, nodes := trie.Commit(false) @@ -74,7 +74,7 @@ func checkTrieContents(t *testing.T, db *Database, root []byte, content map[stri t.Fatalf("inconsistent trie at %x: %v", root, err) } for key, val := range content { - if have := trie.Get([]byte(key)); !bytes.Equal(have, val) { + if have := trie.MustGet([]byte(key)); !bytes.Equal(have, val) { t.Errorf("entry %x: content mismatch: have %x, want %x", key, have, val) } } diff --git a/trie/tracer_test.go b/trie/tracer_test.go index 5e627c89c9..1b9f441084 100644 --- a/trie/tracer_test.go +++ b/trie/tracer_test.go @@ -64,7 +64,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { // Determine all new nodes are tracked for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } insertSet := copySet(trie.tracer.inserts) // copy before commit deleteSet := copySet(trie.tracer.deletes) // copy before commit @@ -82,7 +82,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { // Determine all deletions are tracked trie, _ = New(TrieID(root), db) for _, val := range vals { - trie.Delete([]byte(val.k)) + trie.MustDelete([]byte(val.k)) } insertSet, deleteSet = copySet(trie.tracer.inserts), copySet(trie.tracer.deletes) if !compareSet(insertSet, nil) { @@ -104,10 +104,10 @@ func TestTrieTracerNoop(t *testing.T) { func testTrieTracerNoop(t *testing.T, vals []struct{ k, v string }) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } for _, val := range vals { - trie.Delete([]byte(val.k)) + trie.MustDelete([]byte(val.k)) } if len(trie.tracer.inserts) != 0 { t.Fatal("Unexpected insertion set") @@ -132,7 +132,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { ) // Create trie from scratch for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } root, nodes := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -146,7 +146,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { trie, _ = New(TrieID(root), db) orig = trie.Copy() for _, val := range vals { - trie.Update([]byte(val.k), randBytes(32)) + trie.MustUpdate([]byte(val.k), randBytes(32)) } root, nodes = trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -163,7 +163,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { for i := 0; i < 30; i++ { key := randBytes(32) keys = append(keys, string(key)) - trie.Update(key, randBytes(32)) + trie.MustUpdate(key, randBytes(32)) } root, nodes = trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -177,7 +177,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { trie, _ = New(TrieID(root), db) orig = trie.Copy() for _, key := range keys { - trie.Update([]byte(key), nil) + trie.MustUpdate([]byte(key), nil) } root, nodes = trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -191,7 +191,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { trie, _ = New(TrieID(root), db) orig = trie.Copy() for _, val := range vals { - trie.Update([]byte(val.k), nil) + trie.MustUpdate([]byte(val.k), nil) } root, nodes = trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -210,7 +210,7 @@ func TestAccessListLeak(t *testing.T) { ) // Create trie from scratch for _, val := range standard { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } root, nodes := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -260,7 +260,7 @@ func TestTinyTree(t *testing.T) { trie = NewEmpty(db) ) for _, val := range tiny { - trie.Update([]byte(val.k), randBytes(32)) + trie.MustUpdate([]byte(val.k), randBytes(32)) } root, set := trie.Commit(false) db.Update(NewWithNodeSet(set)) @@ -268,7 +268,7 @@ func TestTinyTree(t *testing.T) { trie, _ = New(TrieID(root), db) orig := trie.Copy() for _, val := range tiny { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } root, set = trie.Commit(false) db.Update(NewWithNodeSet(set)) diff --git a/trie/trie.go b/trie/trie.go index 17bacba00f..4b6f6a55bb 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -105,28 +105,30 @@ func (t *Trie) NodeIterator(start []byte) NodeIterator { return newNodeIterator(t, start) } -// Get returns the value for key stored in the trie. -// The value bytes must not be modified by the caller. -func (t *Trie) Get(key []byte) []byte { - res, err := t.TryGet(key) +// MustGet is a wrapper of Get and will omit any encountered error but just +// print out an error message. +func (t *Trie) MustGet(key []byte) []byte { + res, err := t.Get(key) if err != nil { log.Error("Unhandled trie error in Trie.Get", "err", err) } return res } -// TryGet returns the value for key stored in the trie. +// Get returns the value for key stored in the trie. // The value bytes must not be modified by the caller. -// If a node was not found in the database, a MissingNodeError is returned. -func (t *Trie) TryGet(key []byte) ([]byte, error) { - value, newroot, didResolve, err := t.tryGet(t.root, keybytesToHex(key), 0) +// +// If the requested node is not present in trie, no error will be returned. +// If the trie is corrupted, a MissingNodeError is returned. +func (t *Trie) Get(key []byte) ([]byte, error) { + value, newroot, didResolve, err := t.get(t.root, keybytesToHex(key), 0) if err == nil && didResolve { t.root = newroot } return value, err } -func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode node, didResolve bool, err error) { +func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode node, didResolve bool, err error) { switch n := (origNode).(type) { case nil: return nil, nil, false, nil @@ -137,14 +139,14 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode // key not found in trie return nil, n, false, nil } - value, newnode, didResolve, err = t.tryGet(n.Val, key, pos+len(n.Key)) + value, newnode, didResolve, err = t.get(n.Val, key, pos+len(n.Key)) if err == nil && didResolve { n = n.copy() n.Val = newnode } return value, n, didResolve, err case *fullNode: - value, newnode, didResolve, err = t.tryGet(n.Children[key[pos]], key, pos+1) + value, newnode, didResolve, err = t.get(n.Children[key[pos]], key, pos+1) if err == nil && didResolve { n = n.copy() n.Children[key[pos]] = newnode @@ -155,17 +157,30 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode if err != nil { return nil, n, true, err } - value, newnode, _, err := t.tryGet(child, key, pos) + value, newnode, _, err := t.get(child, key, pos) return value, newnode, true, err default: panic(fmt.Sprintf("%T: invalid node: %v", origNode, origNode)) } } -// TryGetNode attempts to retrieve a trie node by compact-encoded path. It is not -// possible to use keybyte-encoding as the path might contain odd nibbles. -func (t *Trie) TryGetNode(path []byte) ([]byte, int, error) { - item, newroot, resolved, err := t.tryGetNode(t.root, compactToHex(path), 0) +// MustGetNode is a wrapper of GetNode and will omit any encountered error but +// just print out an error message. +func (t *Trie) MustGetNode(path []byte) ([]byte, int) { + item, resolved, err := t.GetNode(path) + if err != nil { + log.Error("Unhandled trie error in Trie.GetNode", "err", err) + } + return item, resolved +} + +// GetNode retrieves a trie node by compact-encoded path. It is not possible +// to use keybyte-encoding as the path might contain odd nibbles. +// +// If the requested node is not present in trie, no error will be returned. +// If the trie is corrupted, a MissingNodeError is returned. +func (t *Trie) GetNode(path []byte) ([]byte, int, error) { + item, newroot, resolved, err := t.getNode(t.root, compactToHex(path), 0) if err != nil { return nil, resolved, err } @@ -175,10 +190,10 @@ func (t *Trie) TryGetNode(path []byte) ([]byte, int, error) { if item == nil { return nil, resolved, nil } - return item, resolved, err + return item, resolved, nil } -func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, newnode node, resolved int, err error) { +func (t *Trie) getNode(origNode node, path []byte, pos int) (item []byte, newnode node, resolved int, err error) { // If non-existent path requested, abort if origNode == nil { return nil, nil, 0, nil @@ -211,7 +226,7 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new // Path branches off from short node return nil, n, 0, nil } - item, newnode, resolved, err = t.tryGetNode(n.Val, path, pos+len(n.Key)) + item, newnode, resolved, err = t.getNode(n.Val, path, pos+len(n.Key)) if err == nil && resolved > 0 { n = n.copy() n.Val = newnode @@ -219,7 +234,7 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new return item, n, resolved, err case *fullNode: - item, newnode, resolved, err = t.tryGetNode(n.Children[path[pos]], path, pos+1) + item, newnode, resolved, err = t.getNode(n.Children[path[pos]], path, pos+1) if err == nil && resolved > 0 { n = n.copy() n.Children[path[pos]] = newnode @@ -231,7 +246,7 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new if err != nil { return nil, n, 1, err } - item, newnode, resolved, err := t.tryGetNode(child, path, pos) + item, newnode, resolved, err := t.getNode(child, path, pos) return item, newnode, resolved + 1, err default: @@ -239,33 +254,28 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new } } -// Update associates key with value in the trie. Subsequent calls to -// Get will return value. If value has length zero, any existing value -// is deleted from the trie and calls to Get will return nil. -// -// The value bytes must not be modified by the caller while they are -// stored in the trie. -func (t *Trie) Update(key, value []byte) { - if err := t.TryUpdate(key, value); err != nil { +// MustUpdate is a wrapper of Update and will omit any encountered error but +// just print out an error message. +func (t *Trie) MustUpdate(key, value []byte) { + if err := t.Update(key, value); err != nil { log.Error("Unhandled trie error in Trie.Update", "err", err) } } -// TryUpdate associates key with value in the trie. Subsequent calls to +// Update associates key with value in the trie. Subsequent calls to // Get will return value. If value has length zero, any existing value // is deleted from the trie and calls to Get will return nil. // // The value bytes must not be modified by the caller while they are // stored in the trie. // -// If a node was not found in the database, a MissingNodeError is returned. -func (t *Trie) TryUpdate(key, value []byte) error { - return t.tryUpdate(key, value) +// If the requested node is not present in trie, no error will be returned. +// If the trie is corrupted, a MissingNodeError is returned. +func (t *Trie) Update(key, value []byte) error { + return t.update(key, value) } -// tryUpdate expects an RLP-encoded value and performs the core function -// for TryUpdate and TryUpdateAccount. -func (t *Trie) tryUpdate(key, value []byte) error { +func (t *Trie) update(key, value []byte) error { t.unhashed++ k := keybytesToHex(key) if len(value) != 0 { @@ -363,16 +373,19 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error } } -// Delete removes any existing value for key from the trie. -func (t *Trie) Delete(key []byte) { - if err := t.TryDelete(key); err != nil { +// MustDelete is a wrapper of Delete and will omit any encountered error but +// just print out an error message. +func (t *Trie) MustDelete(key []byte) { + if err := t.Delete(key); err != nil { log.Error("Unhandled trie error in Trie.Delete", "err", err) } } -// TryDelete removes any existing value for key from the trie. -// If a node was not found in the database, a MissingNodeError is returned. -func (t *Trie) TryDelete(key []byte) error { +// Delete removes any existing value for key from the trie. +// +// If the requested node is not present in trie, no error will be returned. +// If the trie is corrupted, a MissingNodeError is returned. +func (t *Trie) Delete(key []byte) error { t.unhashed++ k := keybytesToHex(key) _, n, err := t.delete(t.root, nil, k) diff --git a/trie/trie_test.go b/trie/trie_test.go index 089bb44a97..82ead8b441 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -56,8 +56,8 @@ func TestNull(t *testing.T) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) key := make([]byte, 32) value := []byte("test") - trie.Update(key, value) - if !bytes.Equal(trie.Get(key), value) { + trie.MustUpdate(key, value) + if !bytes.Equal(trie.MustGet(key), value) { t.Fatal("wrong value") } } @@ -90,27 +90,27 @@ func testMissingNode(t *testing.T, memonly bool) { } trie, _ = New(TrieID(root), triedb) - _, err := trie.TryGet([]byte("120000")) + _, err := trie.Get([]byte("120000")) if err != nil { t.Errorf("Unexpected error: %v", err) } trie, _ = New(TrieID(root), triedb) - _, err = trie.TryGet([]byte("120099")) + _, err = trie.Get([]byte("120099")) if err != nil { t.Errorf("Unexpected error: %v", err) } trie, _ = New(TrieID(root), triedb) - _, err = trie.TryGet([]byte("123456")) + _, err = trie.Get([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } trie, _ = New(TrieID(root), triedb) - err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) + err = trie.Update([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) if err != nil { t.Errorf("Unexpected error: %v", err) } trie, _ = New(TrieID(root), triedb) - err = trie.TryDelete([]byte("123456")) + err = trie.Delete([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -123,27 +123,27 @@ func testMissingNode(t *testing.T, memonly bool) { } trie, _ = New(TrieID(root), triedb) - _, err = trie.TryGet([]byte("120000")) + _, err = trie.Get([]byte("120000")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } trie, _ = New(TrieID(root), triedb) - _, err = trie.TryGet([]byte("120099")) + _, err = trie.Get([]byte("120099")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } trie, _ = New(TrieID(root), triedb) - _, err = trie.TryGet([]byte("123456")) + _, err = trie.Get([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } trie, _ = New(TrieID(root), triedb) - err = trie.TryUpdate([]byte("120099"), []byte("zxcv")) + err = trie.Update([]byte("120099"), []byte("zxcv")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } trie, _ = New(TrieID(root), triedb) - err = trie.TryDelete([]byte("123456")) + err = trie.Delete([]byte("123456")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } @@ -311,8 +311,8 @@ func TestReplication(t *testing.T) { func TestLargeValue(t *testing.T) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) - trie.Update([]byte("key1"), []byte{99, 99, 99, 99}) - trie.Update([]byte("key2"), bytes.Repeat([]byte{1}, 32)) + trie.MustUpdate([]byte("key1"), []byte{99, 99, 99, 99}) + trie.MustUpdate([]byte("key2"), bytes.Repeat([]byte{1}, 32)) trie.Hash() } @@ -460,13 +460,13 @@ func runRandTest(rt randTest) bool { switch step.op { case opUpdate: - tr.Update(step.key, step.value) + tr.MustUpdate(step.key, step.value) values[string(step.key)] = string(step.value) case opDelete: - tr.Delete(step.key) + tr.MustDelete(step.key) delete(values, string(step.key)) case opGet: - v := tr.Get(step.key) + v := tr.MustGet(step.key) want := values[string(step.key)] if string(v) != want { rt[i].err = fmt.Errorf("mismatch for key %#x, got %#x want %#x", step.key, v, want) @@ -509,7 +509,7 @@ func runRandTest(rt randTest) bool { checktr := NewEmpty(triedb) it := NewIterator(tr.NodeIterator(nil)) for it.Next() { - checktr.Update(it.Key, it.Value) + checktr.MustUpdate(it.Key, it.Value) } if tr.Hash() != checktr.Hash() { rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") @@ -595,13 +595,13 @@ func benchGet(b *testing.B) { k := make([]byte, 32) for i := 0; i < benchElemCount; i++ { binary.LittleEndian.PutUint64(k, uint64(i)) - trie.Update(k, k) + trie.MustUpdate(k, k) } binary.LittleEndian.PutUint64(k, benchElemCount/2) b.ResetTimer() for i := 0; i < b.N; i++ { - trie.Get(k) + trie.MustGet(k) } b.StopTimer() } @@ -612,7 +612,7 @@ func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { b.ReportAllocs() for i := 0; i < b.N; i++ { e.PutUint64(k, uint64(i)) - trie.Update(k, k) + trie.MustUpdate(k, k) } return trie } @@ -640,11 +640,11 @@ func BenchmarkHash(b *testing.B) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) i := 0 for ; i < len(addresses)/2; i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } trie.Hash() for ; i < len(addresses); i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } b.ResetTimer() b.ReportAllocs() @@ -670,7 +670,7 @@ func benchmarkCommitAfterHash(b *testing.B, collectLeaf bool) { addresses, accounts := makeAccounts(b.N) trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Insert the accounts into the trie and hash it trie.Hash() @@ -683,22 +683,22 @@ func TestTinyTrie(t *testing.T) { // Create a realistic account trie to hash _, accounts := makeAccounts(5) trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) - trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001337"), accounts[3]) + trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001337"), accounts[3]) if exp, root := common.HexToHash("8c6a85a4d9fda98feff88450299e574e5378e32391f75a055d470ac0653f1005"), trie.Hash(); exp != root { t.Errorf("1: got %x, exp %x", root, exp) } - trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001338"), accounts[4]) + trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001338"), accounts[4]) if exp, root := common.HexToHash("ec63b967e98a5720e7f720482151963982890d82c9093c0d486b7eb8883a66b1"), trie.Hash(); exp != root { t.Errorf("2: got %x, exp %x", root, exp) } - trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001339"), accounts[4]) + trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001339"), accounts[4]) if exp, root := common.HexToHash("0608c1d1dc3905fa22204c7a0e43644831c3b6d3def0f274be623a948197e64a"), trie.Hash(); exp != root { t.Errorf("3: got %x, exp %x", root, exp) } checktr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) it := NewIterator(trie.NodeIterator(nil)) for it.Next() { - checktr.Update(it.Key, it.Value) + checktr.MustUpdate(it.Key, it.Value) } if troot, itroot := trie.Hash(), checktr.Hash(); troot != itroot { t.Fatalf("hash mismatch in opItercheckhash, trie: %x, check: %x", troot, itroot) @@ -710,7 +710,7 @@ func TestCommitAfterHash(t *testing.T) { addresses, accounts := makeAccounts(1000) trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Insert the accounts into the trie and hash it trie.Hash() @@ -820,7 +820,7 @@ func TestCommitSequence(t *testing.T) { trie := NewEmpty(db) // Fill the trie with elements for i := 0; i < tc.count; i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Flush trie -> database root, nodes := trie.Commit(false) @@ -861,7 +861,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { } prng.Read(key) prng.Read(val) - trie.Update(key, val) + trie.MustUpdate(key, val) } // Flush trie -> database root, nodes := trie.Commit(false) @@ -899,8 +899,8 @@ func TestCommitSequenceStackTrie(t *testing.T) { val = make([]byte, 1+prng.Intn(1024)) } prng.Read(val) - trie.TryUpdate(key, val) - stTrie.TryUpdate(key, val) + trie.Update(key, val) + stTrie.Update(key, val) } // Flush trie -> database root, nodes := trie.Commit(false) @@ -948,8 +948,8 @@ func TestCommitSequenceSmallRoot(t *testing.T) { // Add a single small-element to the trie(s) key := make([]byte, 5) key[0] = 1 - trie.TryUpdate(key, []byte{0x1}) - stTrie.TryUpdate(key, []byte{0x1}) + trie.Update(key, []byte{0x1}) + stTrie.Update(key, []byte{0x1}) // Flush trie -> database root, nodes := trie.Commit(false) // Flush memdb -> disk (sponge) @@ -1017,7 +1017,7 @@ func benchmarkHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byt b.ReportAllocs() trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Insert the accounts into the trie and hash it b.StartTimer() @@ -1068,7 +1068,7 @@ func benchmarkCommitAfterHashFixedSize(b *testing.B, addresses [][20]byte, accou b.ReportAllocs() trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Insert the accounts into the trie and hash it trie.Hash() @@ -1121,7 +1121,7 @@ func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts [] triedb := NewDatabase(rawdb.NewMemoryDatabase()) trie := NewEmpty(triedb) for i := 0; i < len(addresses); i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } h := trie.Hash() _, nodes := trie.Commit(false) @@ -1132,15 +1132,15 @@ func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts [] } func getString(trie *Trie, k string) []byte { - return trie.Get([]byte(k)) + return trie.MustGet([]byte(k)) } func updateString(trie *Trie, k, v string) { - trie.Update([]byte(k), []byte(v)) + trie.MustUpdate([]byte(k), []byte(v)) } func deleteString(trie *Trie, k string) { - trie.Delete([]byte(k)) + trie.MustDelete([]byte(k)) } func TestDecodeNode(t *testing.T) { From ea9e62ca3db5c33aa7438ebf39c189afd53c6bf8 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 20 Apr 2023 20:14:51 +0200 Subject: [PATCH 064/988] params: go-ethereum v1.11.6 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 7df3a82b3d..7348093042 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 6 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 6 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 4ab4e4f3aaa00a8f1c62899f17f582e046bfa6a1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 20 Apr 2023 20:16:04 +0200 Subject: [PATCH 065/988] params: begin v1.11.7 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 7348093042..baa886eaa9 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 6 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 7 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From bbc565ab051772b7bb1f5f10110f148a6e171dec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 21 Apr 2023 12:52:02 +0300 Subject: [PATCH 066/988] core/types, params: add blob transaction type, RLP encoded for now (#27049) * core/types, params: add blob transaction type, RLP encoded for now * all: integrate Cancun (and timestamp based forks) into MakeSigner * core/types: fix 2 back-and-forth type refactors * core: fix review comment * core/types: swap blob tx type id to 0x03 --- accounts/abi/bind/backends/simulated.go | 8 +- cmd/evm/internal/t8ntool/execution.go | 2 +- cmd/evm/internal/t8ntool/transaction.go | 2 +- cmd/evm/internal/t8ntool/transition.go | 2 +- core/bench_test.go | 6 +- core/blockchain.go | 4 +- core/blockchain_reader.go | 6 +- core/blockchain_test.go | 8 +- core/rawdb/accessors_chain.go | 4 +- core/rawdb/accessors_chain_test.go | 10 +- core/rawdb/accessors_indexes.go | 6 +- core/state_prefetcher.go | 2 +- core/state_processor.go | 11 +- core/txpool/txpool.go | 4 + core/types/receipt.go | 4 +- core/types/receipt_test.go | 55 +++++++- core/types/transaction.go | 44 +++++- core/types/transaction_signing.go | 78 ++++++++++- core/types/tx_access_list.go | 25 ++-- core/types/tx_blob.go | 132 ++++++++++++++++++ core/types/tx_dynamic_fee.go | 26 ++-- core/types/tx_legacy.go | 27 ++-- eth/downloader/queue_test.go | 2 +- eth/downloader/testchain_test.go | 2 +- eth/fetcher/block_fetcher_test.go | 2 +- eth/filters/filter_system_test.go | 4 +- eth/gasprice/gasprice.go | 8 +- eth/state_accessor.go | 2 +- eth/tracers/api.go | 10 +- eth/tracers/api_test.go | 2 +- .../internal/tracetest/calltrace_test.go | 4 +- .../internal/tracetest/flat_calltrace_test.go | 2 +- .../internal/tracetest/prestate_test.go | 2 +- internal/ethapi/api.go | 29 ++-- internal/ethapi/api_test.go | 2 +- les/downloader/queue_test.go | 2 +- les/downloader/testchain_test.go | 2 +- les/fetcher/block_fetcher_test.go | 2 +- les/handler_test.go | 2 +- les/odr_test.go | 4 +- les/state_accessor.go | 2 +- light/odr_test.go | 7 +- light/odr_util.go | 2 +- miner/worker.go | 2 +- params/protocol_params.go | 1 + 45 files changed, 448 insertions(+), 115 deletions(-) create mode 100644 core/types/tx_blob.go diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 3d5259b894..0af520b5d9 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -684,7 +684,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa return fmt.Errorf("could not fetch parent") } // Check transaction validity - signer := types.MakeSigner(b.blockchain.Config(), block.Number()) + signer := types.MakeSigner(b.blockchain.Config(), block.Number(), block.Time()) sender, err := types.Sender(signer, tx) if err != nil { return fmt.Errorf("invalid transaction: %v", err) @@ -884,7 +884,11 @@ func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (typ if number == nil { return nil, nil } - return rawdb.ReadReceipts(fb.db, hash, *number, fb.bc.Config()), nil + header := rawdb.ReadHeader(fb.db, hash, *number) + if header == nil { + return nil, nil + } + return rawdb.ReadReceipts(fb.db, hash, *number, header.Time, fb.bc.Config()), nil } func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 156bce7edb..5295f3203c 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -125,7 +125,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } var ( statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre) - signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number)) + signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) gaspool = new(core.GasPool) blockHash = common.Hash{0x13, 0x37} rejectedTxs []*rejectedTx diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 21279e8f0a..b1f65815b7 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -112,7 +112,7 @@ func Transaction(ctx *cli.Context) error { return NewError(ErrorIO, errors.New("only rlp supported")) } } - signer := types.MakeSigner(chainConfig, new(big.Int)) + signer := types.MakeSigner(chainConfig, new(big.Int), 0) // We now have the transactions in 'body', which is supposed to be an // rlp list of transactions it, err := rlp.NewListIterator([]byte(body)) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 0b87edd11c..a5d061292f 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -240,7 +240,7 @@ func Transition(ctx *cli.Context) error { } } // We may have to sign the transactions. - signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number))) + signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number)), prestate.Env.Timestamp) if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil { return NewError(ErrorJson, fmt.Errorf("failed signing transactions: %v", err)) diff --git a/core/bench_test.go b/core/bench_test.go index 494998437c..55fa980a85 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -84,7 +84,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { toaddr := common.Address{} data := make([]byte, nbytes) gas, _ := IntrinsicGas(data, nil, false, false, false, false) - signer := types.MakeSigner(gen.config, big.NewInt(int64(i))) + signer := types.MakeSigner(gen.config, big.NewInt(int64(i)), gen.header.Time) gasPrice := big.NewInt(0) if gen.header.BaseFee != nil { gasPrice = gen.header.BaseFee @@ -128,7 +128,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) { if gen.header.BaseFee != nil { gasPrice = gen.header.BaseFee } - signer := types.MakeSigner(gen.config, big.NewInt(int64(i))) + signer := types.MakeSigner(gen.config, big.NewInt(int64(i)), gen.header.Time) for { gas -= params.TxGas if gas < params.TxGas { @@ -317,7 +317,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { if full { hash := header.Hash() rawdb.ReadBody(db, hash, n) - rawdb.ReadReceipts(db, hash, n, chain.Config()) + rawdb.ReadReceipts(db, hash, n, header.Time, chain.Config()) } } chain.Stop() diff --git a/core/blockchain.go b/core/blockchain.go index 80fefac9b0..2e3a45b905 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1540,7 +1540,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) } // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) - SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain) + SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain) var ( stats = insertStats{startTime: mclock.Now()} @@ -2049,7 +2049,7 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error) // the processing of a block. These logs are later announced as deleted or reborn. func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log { receipts := rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64()) - receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.BaseFee(), b.Transactions()) + receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.Time(), b.BaseFee(), b.Transactions()) var logs []*types.Log for _, receipt := range receipts { diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 21a9c6676b..a04323255c 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -217,7 +217,11 @@ func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts { if number == nil { return nil } - receipts := rawdb.ReadReceipts(bc.db, hash, *number, bc.chainConfig) + header := bc.GetHeader(hash, *number) + if header == nil { + return nil + } + receipts := rawdb.ReadReceipts(bc.db, hash, *number, header.Time, bc.chainConfig) if receipts == nil { return nil } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 01ad157cc2..77c3b00c1b 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -809,7 +809,7 @@ func TestFastVsFullChains(t *testing.T) { // Iterate over all chain data components, and cross reference for i := 0; i < len(blocks); i++ { - num, hash := blocks[i].NumberU64(), blocks[i].Hash() + num, hash, time := blocks[i].NumberU64(), blocks[i].Hash(), blocks[i].Time() if ftd, atd := fast.GetTd(hash, num), archive.GetTd(hash, num); ftd.Cmp(atd) != 0 { t.Errorf("block #%d [%x]: td mismatch: fastdb %v, archivedb %v", num, hash, ftd, atd) @@ -832,9 +832,9 @@ func TestFastVsFullChains(t *testing.T) { } // Check receipts. - freceipts := rawdb.ReadReceipts(fastDb, hash, num, fast.Config()) - anreceipts := rawdb.ReadReceipts(ancientDb, hash, num, fast.Config()) - areceipts := rawdb.ReadReceipts(archiveDb, hash, num, fast.Config()) + freceipts := rawdb.ReadReceipts(fastDb, hash, num, time, fast.Config()) + anreceipts := rawdb.ReadReceipts(ancientDb, hash, num, time, fast.Config()) + areceipts := rawdb.ReadReceipts(archiveDb, hash, num, time, fast.Config()) if types.DeriveSha(freceipts, trie.NewStackTrie(nil)) != types.DeriveSha(areceipts, trie.NewStackTrie(nil)) { t.Errorf("block #%d [%x]: receipts mismatch: fastdb %v, ancientdb %v, archivedb %v", num, hash, freceipts, anreceipts, areceipts) } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 3d0f36ba76..b479655b0b 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -625,7 +625,7 @@ func ReadRawReceipts(db ethdb.Reader, hash common.Hash, number uint64) types.Rec // The current implementation populates these metadata fields by reading the receipts' // corresponding block body, so if the block body is not found it will return nil even // if the receipt itself is stored. -func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, config *params.ChainConfig) types.Receipts { +func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, time uint64, config *params.ChainConfig) types.Receipts { // We're deriving many fields from the block body, retrieve beside the receipt receipts := ReadRawReceipts(db, hash, number) if receipts == nil { @@ -643,7 +643,7 @@ func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, config *para } else { baseFee = header.BaseFee } - if err := receipts.DeriveFields(config, hash, number, baseFee, body.Transactions); err != nil { + if err := receipts.DeriveFields(config, hash, number, time, baseFee, body.Transactions); err != nil { log.Error("Failed to derive block receipts fields", "hash", hash, "number", number, "err", err) return nil } diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 84eae1d90d..32e38a81ce 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -379,7 +379,7 @@ func TestBlockReceiptStorage(t *testing.T) { // Check that no receipt entries are in a pristine database hash := common.BytesToHash([]byte{0x03, 0x14}) - if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { + if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 { t.Fatalf("non existent receipts returned: %v", rs) } // Insert the body that corresponds to the receipts @@ -387,7 +387,7 @@ func TestBlockReceiptStorage(t *testing.T) { // Insert the receipt slice into the database and check presence WriteReceipts(db, hash, 0, receipts) - if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) == 0 { + if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) == 0 { t.Fatalf("no receipts returned") } else { if err := checkReceiptsRLP(rs, receipts); err != nil { @@ -396,7 +396,7 @@ func TestBlockReceiptStorage(t *testing.T) { } // Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed) DeleteBody(db, hash, 0) - if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); rs != nil { + if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); rs != nil { t.Fatalf("receipts returned when body was deleted: %v", rs) } // Ensure that receipts without metadata can be returned without the block body too @@ -407,7 +407,7 @@ func TestBlockReceiptStorage(t *testing.T) { WriteBody(db, hash, 0, body) DeleteReceipts(db, hash, 0) - if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { + if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 { t.Fatalf("deleted receipts returned: %v", rs) } } @@ -727,7 +727,7 @@ func TestReadLogs(t *testing.T) { hash := common.BytesToHash([]byte{0x03, 0x14}) // Check that no receipt entries are in a pristine database - if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { + if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 { t.Fatalf("non existent receipts returned: %v", rs) } // Insert the body that corresponds to the receipts diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index 25a44354bf..4f2ef0a880 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -130,8 +130,12 @@ func ReadReceipt(db ethdb.Reader, hash common.Hash, config *params.ChainConfig) if blockHash == (common.Hash{}) { return nil, common.Hash{}, 0, 0 } + blockHeader := ReadHeader(db, blockHash, *blockNumber) + if blockHeader == nil { + return nil, common.Hash{}, 0, 0 + } // Read all the receipts from the block and return the one with the matching hash - receipts := ReadReceipts(db, blockHash, *blockNumber, config) + receipts := ReadReceipts(db, blockHash, *blockNumber, blockHeader.Time, config) for receiptIndex, receipt := range receipts { if receipt.TxHash == hash { return receipt, blockHash, *blockNumber, uint64(receiptIndex) diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 721f4056b2..ff867309de 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -53,7 +53,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c gaspool = new(GasPool).AddGas(block.GasLimit()) blockContext = NewEVMBlockContext(header, p.bc, nil) evm = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) - signer = types.MakeSigner(p.config, header.Number) + signer = types.MakeSigner(p.config, header.Number, header.Time) ) // Iterate over and process the individual transactions byzantium := p.config.IsByzantium(block.Number()) diff --git a/core/state_processor.go b/core/state_processor.go index 2fa9c41bcc..25266f13b4 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -70,11 +70,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } - blockContext := NewEVMBlockContext(header, p.bc, nil) - vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) + var ( + context = NewEVMBlockContext(header, p.bc, nil) + vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) + signer = types.MakeSigner(p.config, header.Number, header.Time) + ) // Iterate over and process the individual transactions for i, tx := range block.Transactions() { - msg, err := TransactionToMessage(tx, types.MakeSigner(p.config, header.Number), header.BaseFee) + msg, err := TransactionToMessage(tx, signer, header.BaseFee) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -147,7 +150,7 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { - msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number), header.BaseFee) + msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number, header.Time), header.BaseFee) if err != nil { return nil, err } diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 9eb19b0094..4928b5afc6 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -606,6 +606,10 @@ func (pool *TxPool) validateTxBasics(tx *types.Transaction, local bool) error { if !pool.eip1559.Load() && tx.Type() == types.DynamicFeeTxType { return core.ErrTxTypeNotSupported } + // Reject blob transactions forever, those will have their own pool. + if tx.Type() == types.BlobTxType { + return core.ErrTxTypeNotSupported + } // Reject transactions over defined size to prevent DOS attacks if tx.Size() > txMaxSize { return ErrOversizedData diff --git a/core/types/receipt.go b/core/types/receipt.go index 61b3b35178..6300886c05 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -313,8 +313,8 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) { // DeriveFields fills the receipts with their computed fields based on consensus // data and contextual infos like containing block and transactions. -func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, baseFee *big.Int, txs []*Transaction) error { - signer := MakeSigner(config, new(big.Int).SetUint64(number)) +func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, time uint64, baseFee *big.Int, txs []*Transaction) error { + signer := MakeSigner(config, new(big.Int).SetUint64(number), time) logIndex := uint(0) if len(txs) != len(rs) { diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index 376177f976..00031ad563 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "github.com/holiman/uint256" "github.com/kylelemons/godebug/diff" ) @@ -99,6 +100,8 @@ func TestDeriveFields(t *testing.T) { to3 := common.HexToAddress("0x3") to4 := common.HexToAddress("0x4") to5 := common.HexToAddress("0x5") + to6 := common.HexToAddress("0x6") + to7 := common.HexToAddress("0x7") txs := Transactions{ NewTx(&LegacyTx{ Nonce: 1, @@ -127,19 +130,39 @@ func TestDeriveFields(t *testing.T) { Value: big.NewInt(4), Gas: 4, GasTipCap: big.NewInt(44), - GasFeeCap: big.NewInt(1045), + GasFeeCap: big.NewInt(1044), }), NewTx(&DynamicFeeTx{ To: &to5, Nonce: 5, Value: big.NewInt(5), Gas: 5, - GasTipCap: big.NewInt(56), + GasTipCap: big.NewInt(55), GasFeeCap: big.NewInt(1055), }), + // EIP-4844 transactions. + NewTx(&BlobTx{ + To: &to6, + Nonce: 6, + Value: uint256.NewInt(6), + Gas: 6, + GasTipCap: uint256.NewInt(66), + GasFeeCap: uint256.NewInt(1066), + BlobFeeCap: uint256.NewInt(100066), + }), + NewTx(&BlobTx{ + To: &to7, + Nonce: 7, + Value: uint256.NewInt(7), + Gas: 7, + GasTipCap: uint256.NewInt(77), + GasFeeCap: uint256.NewInt(1077), + BlobFeeCap: uint256.NewInt(100077), + }), } blockNumber := big.NewInt(1) + blockTime := uint64(2) blockHash := common.BytesToHash([]byte{0x03, 0x14}) // Create the corresponding receipts @@ -246,12 +269,38 @@ func TestDeriveFields(t *testing.T) { BlockNumber: blockNumber, TransactionIndex: 4, }, + &Receipt{ + Type: BlobTxType, + PostState: common.Hash{6}.Bytes(), + CumulativeGasUsed: 21, + Logs: []*Log{}, + // derived fields: + TxHash: txs[5].Hash(), + GasUsed: 6, + EffectiveGasPrice: big.NewInt(1066), + BlockHash: blockHash, + BlockNumber: blockNumber, + TransactionIndex: 5, + }, + &Receipt{ + Type: BlobTxType, + PostState: common.Hash{7}.Bytes(), + CumulativeGasUsed: 28, + Logs: []*Log{}, + // derived fields: + TxHash: txs[6].Hash(), + GasUsed: 7, + EffectiveGasPrice: big.NewInt(1077), + BlockHash: blockHash, + BlockNumber: blockNumber, + TransactionIndex: 6, + }, } // Re-derive receipts. basefee := big.NewInt(1000) derivedReceipts := clearComputedFieldsOnReceipts(receipts) - err := Receipts(derivedReceipts).DeriveFields(params.TestChainConfig, blockHash, blockNumber.Uint64(), basefee, txs) + err := Receipts(derivedReceipts).DeriveFields(params.TestChainConfig, blockHash, blockNumber.Uint64(), blockTime, basefee, txs) if err != nil { t.Fatalf("DeriveFields(...) = %v, want ", err) } diff --git a/core/types/transaction.go b/core/types/transaction.go index 89192f049b..f0b674f344 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -42,9 +42,10 @@ var ( // Transaction types. const ( - LegacyTxType = iota - AccessListTxType - DynamicFeeTxType + LegacyTxType = 0x00 + AccessListTxType = 0x01 + DynamicFeeTxType = 0x02 + BlobTxType = 0x03 ) // Transaction is an Ethereum transaction. @@ -82,6 +83,9 @@ type TxData interface { value() *big.Int nonce() uint64 to() *common.Address + blobGas() uint64 + blobGasFeeCap() *big.Int + blobHashes() []common.Hash rawSignatureValues() (v, r, s *big.Int) setSignatureValues(chainID, v, r, s *big.Int) @@ -192,6 +196,10 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { var inner DynamicFeeTx err := rlp.DecodeBytes(b[1:], &inner) return &inner, err + case BlobTxType: + var inner BlobTx + err := rlp.DecodeBytes(b[1:], &inner) // TODO(karalabe): This needs to be ssz + return &inner, err default: return nil, ErrTxTypeNotSupported } @@ -281,6 +289,15 @@ func (tx *Transaction) GasTipCap() *big.Int { return new(big.Int).Set(tx.inner.g // GasFeeCap returns the fee cap per gas of the transaction. func (tx *Transaction) GasFeeCap() *big.Int { return new(big.Int).Set(tx.inner.gasFeeCap()) } +// BlobGas returns the data gas limit of the transaction for blob transactions, 0 otherwise. +func (tx *Transaction) BlobGas() uint64 { return tx.inner.blobGas() } + +// BlobGasFeeCap returns the data gas fee cap per data gas of the transaction for blob transactions, nil otherwise. +func (tx *Transaction) BlobGasFeeCap() *big.Int { return tx.inner.blobGasFeeCap() } + +// BlobHashes returns the hases of the blob commitments for blob transactions, nil otherwise. +func (tx *Transaction) BlobHashes() []common.Hash { return tx.inner.blobHashes() } + // Value returns the ether amount of the transaction. func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) } @@ -293,9 +310,12 @@ func (tx *Transaction) To() *common.Address { return copyAddressPtr(tx.inner.to()) } -// Cost returns gas * gasPrice + value. +// Cost returns (gas * gasPrice) + (blobGas * blobGasPrice) + value. func (tx *Transaction) Cost() *big.Int { total := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas())) + if tx.Type() == BlobTxType { + total.Add(total, new(big.Int).Mul(tx.BlobGasFeeCap(), new(big.Int).SetUint64(tx.BlobGas()))) + } total.Add(total, tx.Value()) return total } @@ -364,6 +384,16 @@ func (tx *Transaction) EffectiveGasTipIntCmp(other *big.Int, baseFee *big.Int) i return tx.EffectiveGasTipValue(baseFee).Cmp(other) } +// BlobGasFeeCapCmp compares the blob fee cap of two transactions. +func (tx *Transaction) BlobGasFeeCapCmp(other *Transaction) int { + return tx.inner.blobGasFeeCap().Cmp(other.inner.blobGasFeeCap()) +} + +// BlobGasFeeCapIntCmp compares the blob fee cap of the transaction against the given blob fee cap. +func (tx *Transaction) BlobGasFeeCapIntCmp(other *big.Int) int { + return tx.inner.blobGasFeeCap().Cmp(other) +} + // Hash returns the transaction hash. func (tx *Transaction) Hash() common.Hash { if hash := tx.hash.Load(); hash != nil { @@ -387,7 +417,11 @@ func (tx *Transaction) Size() uint64 { return size.(uint64) } c := writeCounter(0) - rlp.Encode(&c, &tx.inner) + if tx.Type() == BlobTxType { + rlp.Encode(&c, &tx.inner) // TODO(karalabe): Replace with SSZ encoding + } else { + rlp.Encode(&c, &tx.inner) + } size := uint64(c) if tx.Type() != LegacyTxType { diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 87f0390a6f..d7c162898c 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -37,9 +37,11 @@ type sigCache struct { } // MakeSigner returns a Signer based on the given chain config and block number. -func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { +func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) Signer { var signer Signer switch { + case config.IsCancun(blockTime): + signer = NewCancunSigner(config.ChainID) case config.IsLondon(blockNumber): signer = NewLondonSigner(config.ChainID) case config.IsBerlin(blockNumber): @@ -63,6 +65,9 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { // have the current block number available, use MakeSigner instead. func LatestSigner(config *params.ChainConfig) Signer { if config.ChainID != nil { + if config.CancunTime != nil { + return NewCancunSigner(config.ChainID) + } if config.LondonBlock != nil { return NewLondonSigner(config.ChainID) } @@ -87,7 +92,7 @@ func LatestSignerForChainID(chainID *big.Int) Signer { if chainID == nil { return HomesteadSigner{} } - return NewLondonSigner(chainID) + return NewCancunSigner(chainID) } // SignTx signs the transaction using the given signer and private key. @@ -170,6 +175,75 @@ type Signer interface { Equal(Signer) bool } +type cancunSigner struct{ londonSigner } + +// NewCancunSigner returns a signer that accepts +// - EIP-4844 blob transactions +// - EIP-1559 dynamic fee transactions +// - EIP-2930 access list transactions, +// - EIP-155 replay protected transactions, and +// - legacy Homestead transactions. +func NewCancunSigner(chainId *big.Int) Signer { + return cancunSigner{londonSigner{eip2930Signer{NewEIP155Signer(chainId)}}} +} + +func (s cancunSigner) Sender(tx *Transaction) (common.Address, error) { + if tx.Type() != BlobTxType { + return s.londonSigner.Sender(tx) + } + V, R, S := tx.RawSignatureValues() + // Blob txs are defined to use 0 and 1 as their recovery + // id, add 27 to become equivalent to unprotected Homestead signatures. + V = new(big.Int).Add(V, big.NewInt(27)) + if tx.ChainId().Cmp(s.chainId) != 0 { + return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId) + } + return recoverPlain(s.Hash(tx), R, S, V, true) +} + +func (s cancunSigner) Equal(s2 Signer) bool { + x, ok := s2.(cancunSigner) + return ok && x.chainId.Cmp(s.chainId) == 0 +} + +func (s cancunSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) { + txdata, ok := tx.inner.(*BlobTx) + if !ok { + return s.londonSigner.SignatureValues(tx, sig) + } + // Check that chain ID of tx matches the signer. We also accept ID zero here, + // because it indicates that the chain ID was not specified in the tx. + if txdata.ChainID.Sign() != 0 && txdata.ChainID.ToBig().Cmp(s.chainId) != 0 { + return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) + } + R, S, _ = decodeSignature(sig) + V = big.NewInt(int64(sig[64])) + return R, S, V, nil +} + +// Hash returns the hash to be signed by the sender. +// It does not uniquely identify the transaction. +func (s cancunSigner) Hash(tx *Transaction) common.Hash { + if tx.Type() != BlobTxType { + return s.londonSigner.Hash(tx) + } + return prefixedRlpHash( + tx.Type(), + []interface{}{ + s.chainId, + tx.Nonce(), + tx.GasTipCap(), + tx.GasFeeCap(), + tx.Gas(), + tx.To(), + tx.Value(), + tx.Data(), + tx.AccessList(), + tx.BlobGasFeeCap(), + tx.BlobHashes(), + }) +} + type londonSigner struct{ eip2930Signer } // NewLondonSigner returns a signer that accepts diff --git a/core/types/tx_access_list.go b/core/types/tx_access_list.go index 692bba4ff2..825942a41d 100644 --- a/core/types/tx_access_list.go +++ b/core/types/tx_access_list.go @@ -94,17 +94,20 @@ func (tx *AccessListTx) copy() TxData { } // accessors for innerTx. -func (tx *AccessListTx) txType() byte { return AccessListTxType } -func (tx *AccessListTx) chainID() *big.Int { return tx.ChainID } -func (tx *AccessListTx) accessList() AccessList { return tx.AccessList } -func (tx *AccessListTx) data() []byte { return tx.Data } -func (tx *AccessListTx) gas() uint64 { return tx.Gas } -func (tx *AccessListTx) gasPrice() *big.Int { return tx.GasPrice } -func (tx *AccessListTx) gasTipCap() *big.Int { return tx.GasPrice } -func (tx *AccessListTx) gasFeeCap() *big.Int { return tx.GasPrice } -func (tx *AccessListTx) value() *big.Int { return tx.Value } -func (tx *AccessListTx) nonce() uint64 { return tx.Nonce } -func (tx *AccessListTx) to() *common.Address { return tx.To } +func (tx *AccessListTx) txType() byte { return AccessListTxType } +func (tx *AccessListTx) chainID() *big.Int { return tx.ChainID } +func (tx *AccessListTx) accessList() AccessList { return tx.AccessList } +func (tx *AccessListTx) data() []byte { return tx.Data } +func (tx *AccessListTx) gas() uint64 { return tx.Gas } +func (tx *AccessListTx) gasPrice() *big.Int { return tx.GasPrice } +func (tx *AccessListTx) gasTipCap() *big.Int { return tx.GasPrice } +func (tx *AccessListTx) gasFeeCap() *big.Int { return tx.GasPrice } +func (tx *AccessListTx) value() *big.Int { return tx.Value } +func (tx *AccessListTx) nonce() uint64 { return tx.Nonce } +func (tx *AccessListTx) to() *common.Address { return tx.To } +func (tx *AccessListTx) blobGas() uint64 { return 0 } +func (tx *AccessListTx) blobGasFeeCap() *big.Int { return nil } +func (tx *AccessListTx) blobHashes() []common.Hash { return nil } func (tx *AccessListTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { return dst.Set(tx.GasPrice) diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go new file mode 100644 index 0000000000..1f64a9871b --- /dev/null +++ b/core/types/tx_blob.go @@ -0,0 +1,132 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package types + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" +) + +// BlobTx represents an EIP-4844 transaction. +type BlobTx struct { + ChainID *uint256.Int + Nonce uint64 + GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas + GasFeeCap *uint256.Int // a.k.a. maxFeePerGas + Gas uint64 + To *common.Address // `rlp:"nil"` // nil means contract creation + Value *uint256.Int + Data []byte + AccessList AccessList + BlobFeeCap *uint256.Int // a.k.a. maxFeePerDataGas + BlobHashes []common.Hash + + // Signature values + V *uint256.Int `json:"v" gencodec:"required"` + R *uint256.Int `json:"r" gencodec:"required"` + S *uint256.Int `json:"s" gencodec:"required"` +} + +// copy creates a deep copy of the transaction data and initializes all fields. +func (tx *BlobTx) copy() TxData { + cpy := &BlobTx{ + Nonce: tx.Nonce, + To: copyAddressPtr(tx.To), + Data: common.CopyBytes(tx.Data), + Gas: tx.Gas, + // These are copied below. + AccessList: make(AccessList, len(tx.AccessList)), + BlobHashes: make([]common.Hash, len(tx.BlobHashes)), + Value: new(uint256.Int), + ChainID: new(uint256.Int), + GasTipCap: new(uint256.Int), + GasFeeCap: new(uint256.Int), + BlobFeeCap: new(uint256.Int), + V: new(uint256.Int), + R: new(uint256.Int), + S: new(uint256.Int), + } + copy(cpy.AccessList, tx.AccessList) + copy(cpy.BlobHashes, tx.BlobHashes) + + if tx.Value != nil { + cpy.Value.Set(tx.Value) + } + if tx.ChainID != nil { + cpy.ChainID.Set(tx.ChainID) + } + if tx.GasTipCap != nil { + cpy.GasTipCap.Set(tx.GasTipCap) + } + if tx.GasFeeCap != nil { + cpy.GasFeeCap.Set(tx.GasFeeCap) + } + if tx.BlobFeeCap != nil { + cpy.BlobFeeCap.Set(tx.BlobFeeCap) + } + if tx.V != nil { + cpy.V.Set(tx.V) + } + if tx.R != nil { + cpy.R.Set(tx.R) + } + if tx.S != nil { + cpy.S.Set(tx.S) + } + return cpy +} + +// accessors for innerTx. +func (tx *BlobTx) txType() byte { return BlobTxType } +func (tx *BlobTx) chainID() *big.Int { return tx.ChainID.ToBig() } +func (tx *BlobTx) accessList() AccessList { return tx.AccessList } +func (tx *BlobTx) data() []byte { return tx.Data } +func (tx *BlobTx) gas() uint64 { return tx.Gas } +func (tx *BlobTx) gasFeeCap() *big.Int { return tx.GasFeeCap.ToBig() } +func (tx *BlobTx) gasTipCap() *big.Int { return tx.GasTipCap.ToBig() } +func (tx *BlobTx) gasPrice() *big.Int { return tx.GasFeeCap.ToBig() } +func (tx *BlobTx) value() *big.Int { return tx.Value.ToBig() } +func (tx *BlobTx) nonce() uint64 { return tx.Nonce } +func (tx *BlobTx) to() *common.Address { return tx.To } +func (tx *BlobTx) blobGas() uint64 { return params.BlobTxDataGasPerBlob * uint64(len(tx.BlobHashes)) } +func (tx *BlobTx) blobGasFeeCap() *big.Int { return tx.BlobFeeCap.ToBig() } +func (tx *BlobTx) blobHashes() []common.Hash { return tx.BlobHashes } + +func (tx *BlobTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { + if baseFee == nil { + return dst.Set(tx.GasFeeCap.ToBig()) + } + tip := dst.Sub(tx.GasFeeCap.ToBig(), baseFee) + if tip.Cmp(tx.GasTipCap.ToBig()) > 0 { + tip.Set(tx.GasTipCap.ToBig()) + } + return tip.Add(tip, baseFee) +} + +func (tx *BlobTx) rawSignatureValues() (v, r, s *big.Int) { + return tx.V.ToBig(), tx.R.ToBig(), tx.S.ToBig() +} + +func (tx *BlobTx) setSignatureValues(chainID, v, r, s *big.Int) { + tx.ChainID.SetFromBig(chainID) + tx.V.SetFromBig(v) + tx.R.SetFromBig(r) + tx.S.SetFromBig(s) +} diff --git a/core/types/tx_dynamic_fee.go b/core/types/tx_dynamic_fee.go index 5708106658..47b870abbf 100644 --- a/core/types/tx_dynamic_fee.go +++ b/core/types/tx_dynamic_fee.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" ) +// DynamicFeeTx represents an EIP-1559 transaction. type DynamicFeeTx struct { ChainID *big.Int Nonce uint64 @@ -82,17 +83,20 @@ func (tx *DynamicFeeTx) copy() TxData { } // accessors for innerTx. -func (tx *DynamicFeeTx) txType() byte { return DynamicFeeTxType } -func (tx *DynamicFeeTx) chainID() *big.Int { return tx.ChainID } -func (tx *DynamicFeeTx) accessList() AccessList { return tx.AccessList } -func (tx *DynamicFeeTx) data() []byte { return tx.Data } -func (tx *DynamicFeeTx) gas() uint64 { return tx.Gas } -func (tx *DynamicFeeTx) gasFeeCap() *big.Int { return tx.GasFeeCap } -func (tx *DynamicFeeTx) gasTipCap() *big.Int { return tx.GasTipCap } -func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.GasFeeCap } -func (tx *DynamicFeeTx) value() *big.Int { return tx.Value } -func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce } -func (tx *DynamicFeeTx) to() *common.Address { return tx.To } +func (tx *DynamicFeeTx) txType() byte { return DynamicFeeTxType } +func (tx *DynamicFeeTx) chainID() *big.Int { return tx.ChainID } +func (tx *DynamicFeeTx) accessList() AccessList { return tx.AccessList } +func (tx *DynamicFeeTx) data() []byte { return tx.Data } +func (tx *DynamicFeeTx) gas() uint64 { return tx.Gas } +func (tx *DynamicFeeTx) gasFeeCap() *big.Int { return tx.GasFeeCap } +func (tx *DynamicFeeTx) gasTipCap() *big.Int { return tx.GasTipCap } +func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.GasFeeCap } +func (tx *DynamicFeeTx) value() *big.Int { return tx.Value } +func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce } +func (tx *DynamicFeeTx) to() *common.Address { return tx.To } +func (tx *DynamicFeeTx) blobGas() uint64 { return 0 } +func (tx *DynamicFeeTx) blobGasFeeCap() *big.Int { return nil } +func (tx *DynamicFeeTx) blobHashes() []common.Hash { return nil } func (tx *DynamicFeeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { if baseFee == nil { diff --git a/core/types/tx_legacy.go b/core/types/tx_legacy.go index 988de7db09..902e70cf94 100644 --- a/core/types/tx_legacy.go +++ b/core/types/tx_legacy.go @@ -22,7 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// LegacyTx is the transaction data of regular Ethereum transactions. +// LegacyTx is the transaction data of the original Ethereum transactions. type LegacyTx struct { Nonce uint64 // nonce of sender account GasPrice *big.Int // wei per gas @@ -91,17 +91,20 @@ func (tx *LegacyTx) copy() TxData { } // accessors for innerTx. -func (tx *LegacyTx) txType() byte { return LegacyTxType } -func (tx *LegacyTx) chainID() *big.Int { return deriveChainId(tx.V) } -func (tx *LegacyTx) accessList() AccessList { return nil } -func (tx *LegacyTx) data() []byte { return tx.Data } -func (tx *LegacyTx) gas() uint64 { return tx.Gas } -func (tx *LegacyTx) gasPrice() *big.Int { return tx.GasPrice } -func (tx *LegacyTx) gasTipCap() *big.Int { return tx.GasPrice } -func (tx *LegacyTx) gasFeeCap() *big.Int { return tx.GasPrice } -func (tx *LegacyTx) value() *big.Int { return tx.Value } -func (tx *LegacyTx) nonce() uint64 { return tx.Nonce } -func (tx *LegacyTx) to() *common.Address { return tx.To } +func (tx *LegacyTx) txType() byte { return LegacyTxType } +func (tx *LegacyTx) chainID() *big.Int { return deriveChainId(tx.V) } +func (tx *LegacyTx) accessList() AccessList { return nil } +func (tx *LegacyTx) data() []byte { return tx.Data } +func (tx *LegacyTx) gas() uint64 { return tx.Gas } +func (tx *LegacyTx) gasPrice() *big.Int { return tx.GasPrice } +func (tx *LegacyTx) gasTipCap() *big.Int { return tx.GasPrice } +func (tx *LegacyTx) gasFeeCap() *big.Int { return tx.GasPrice } +func (tx *LegacyTx) value() *big.Int { return tx.Value } +func (tx *LegacyTx) nonce() uint64 { return tx.Nonce } +func (tx *LegacyTx) to() *common.Address { return tx.To } +func (tx *LegacyTx) blobGas() uint64 { return 0 } +func (tx *LegacyTx) blobGasFeeCap() *big.Int { return nil } +func (tx *LegacyTx) blobHashes() []common.Hash { return nil } func (tx *LegacyTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { return dst.Set(tx.GasPrice) diff --git a/eth/downloader/queue_test.go b/eth/downloader/queue_test.go index 6babf94408..a8b1b45e00 100644 --- a/eth/downloader/queue_test.go +++ b/eth/downloader/queue_test.go @@ -42,7 +42,7 @@ func makeChain(n int, seed byte, parent *types.Block, empty bool) ([]*types.Bloc block.SetCoinbase(common.Address{seed}) // Add one tx to every secondblock if !empty && i%2 == 0 { - signer := types.MakeSigner(params.TestChainConfig, block.Number()) + signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp()) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) if err != nil { panic(err) diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index 01f81a7b1c..d791723b05 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -168,7 +168,7 @@ func (tc *testChain) generate(n int, seed byte, parent *types.Block, heavy bool) } // Include transactions to the miner to make blocks more interesting. if parent == tc.blocks[0] && i%22 == 0 { - signer := types.MakeSigner(params.TestChainConfig, block.Number()) + signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp()) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) if err != nil { panic(err) diff --git a/eth/fetcher/block_fetcher_test.go b/eth/fetcher/block_fetcher_test.go index 9e5693c02e..0553add4f1 100644 --- a/eth/fetcher/block_fetcher_test.go +++ b/eth/fetcher/block_fetcher_test.go @@ -58,7 +58,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common // If the block number is multiple of 3, send a bonus transaction to the miner if parent == genesis && i%3 == 0 { - signer := types.MakeSigner(params.TestChainConfig, block.Number()) + signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp()) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) if err != nil { panic(err) diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index b70b0158ad..ae0c83eb29 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -111,7 +111,9 @@ func (b *testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc. func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil { - return rawdb.ReadReceipts(b.db, hash, *number, params.TestChainConfig), nil + if header := rawdb.ReadHeader(b.db, hash, *number); header != nil { + return rawdb.ReadReceipts(b.db, hash, *number, header.Time, params.TestChainConfig), nil + } } return nil, nil } diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index 8e98a3409b..7475cef381 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -176,7 +176,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) { results []*big.Int ) for sent < oracle.checkBlocks && number > 0 { - go oracle.getBlockValues(ctx, types.MakeSigner(oracle.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, oracle.ignorePrice, result, quit) + go oracle.getBlockValues(ctx, number, sampleNumber, oracle.ignorePrice, result, quit) sent++ exp++ number-- @@ -199,7 +199,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) { // meaningful returned, try to query more blocks. But the maximum // is 2*checkBlocks. if len(res.values) == 1 && len(results)+1+exp < oracle.checkBlocks*2 && number > 0 { - go oracle.getBlockValues(ctx, types.MakeSigner(oracle.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, oracle.ignorePrice, result, quit) + go oracle.getBlockValues(ctx, number, sampleNumber, oracle.ignorePrice, result, quit) sent++ exp++ number-- @@ -255,7 +255,7 @@ func (s *txSorter) Less(i, j int) bool { // and sends it to the result channel. If the block is empty or all transactions // are sent by the miner itself(it doesn't make any sense to include this kind of // transaction prices for sampling), nil gasprice is returned. -func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, blockNum uint64, limit int, ignoreUnder *big.Int, result chan results, quit chan struct{}) { +func (oracle *Oracle) getBlockValues(ctx context.Context, blockNum uint64, limit int, ignoreUnder *big.Int, result chan results, quit chan struct{}) { block, err := oracle.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum)) if block == nil { select { @@ -264,6 +264,8 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, b } return } + signer := types.MakeSigner(oracle.backend.ChainConfig(), block.Number(), block.Time()) + // Sort the transaction by effective tip in ascending sort. txs := make([]*types.Transaction, len(block.Transactions())) copy(txs, block.Transactions()) diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 59b4714255..1b0ab0c545 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -209,7 +209,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, return nil, vm.BlockContext{}, statedb, release, nil } // Recompute transactions up to the target index. - signer := types.MakeSigner(eth.blockchain.Config(), block.Number()) + signer := types.MakeSigner(eth.blockchain.Config(), block.Number(), block.Time()) for idx, tx := range block.Transactions() { // Assemble the transaction call message and return if the requested offset msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 9eef8c2e06..2bb00f0d2c 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -288,7 +288,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed // Fetch and execute the block trace taskCh for task := range taskCh { var ( - signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number()) + signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time()) blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil) ) // Trace all the transactions contained within @@ -544,7 +544,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config var ( roots []common.Hash - signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) chainConfig = api.backend.ChainConfig() vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) @@ -623,7 +623,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac blockHash = block.Hash() is158 = api.backend.ChainConfig().IsEIP158(block.Number()) blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) - signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) results = make([]*txTraceResult, len(txs)) ) for i, tx := range txs { @@ -656,7 +656,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat txs = block.Transactions() blockHash = block.Hash() blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) - signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) results = make([]*txTraceResult, len(txs)) pend sync.WaitGroup ) @@ -765,7 +765,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Execute transaction, either tracing all or just the requested one var ( dumps []string - signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) chainConfig = api.backend.ChainConfig() vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) canon = true diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 6343021038..8f4f88b003 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -169,7 +169,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block return nil, vm.BlockContext{}, statedb, release, nil } // Recompute transactions up to the target index. - signer := types.MakeSigner(b.chainConfig, block.Number()) + signer := types.MakeSigner(b.chainConfig, block.Number(), block.Time()) for idx, tx := range block.Transactions() { msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) txContext := core.NewEVMTxContext(msg) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index e517d436af..bf1c31c08d 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -121,7 +121,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { } // Configure a blockchain with the given prestate var ( - signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) + signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) origin, _ = signer.Sender(tx) txContext = vm.TxContext{ Origin: origin, @@ -218,7 +218,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { b.Fatalf("failed to parse testcase input: %v", err) } - signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) + signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 16c01de25c..85e95401a2 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -85,7 +85,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { return fmt.Errorf("failed to parse testcase input: %v", err) } - signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) + signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) origin, _ := signer.Sender(tx) txContext := vm.TxContext{ Origin: origin, diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 5fc99dd124..991da10b3a 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -92,7 +92,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { } // Configure a blockchain with the given prestate var ( - signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) + signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) origin, _ = signer.Sender(tx) txContext = vm.TxContext{ Origin: origin, diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index b7ad30a6ea..f1041d6a50 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1305,8 +1305,8 @@ type RPCTransaction struct { // newRPCTransaction returns a transaction that will serialize to the RPC // representation, with the given location metadata set (if available). -func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction { - signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber)) +func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction { + signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) from, _ := types.Sender(signer, tx) v, r, s := tx.RawSignatureValues() result := &RPCTransaction{ @@ -1358,13 +1358,17 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber // NewRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation func NewRPCPendingTransaction(tx *types.Transaction, current *types.Header, config *params.ChainConfig) *RPCTransaction { - var baseFee *big.Int - blockNumber := uint64(0) + var ( + baseFee *big.Int + blockNumber = uint64(0) + blockTime = uint64(0) + ) if current != nil { baseFee = misc.CalcBaseFee(config, current) blockNumber = current.Number.Uint64() + blockTime = current.Time } - return newRPCTransaction(tx, common.Hash{}, blockNumber, 0, baseFee, config) + return newRPCTransaction(tx, common.Hash{}, blockNumber, blockTime, 0, baseFee, config) } // newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. @@ -1373,7 +1377,7 @@ func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *param if index >= uint64(len(txs)) { return nil } - return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index, b.BaseFee(), config) + return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), b.Time(), index, b.BaseFee(), config) } // newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. @@ -1585,7 +1589,7 @@ func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.H if err != nil { return nil, err } - return newRPCTransaction(tx, blockHash, blockNumber, index, header.BaseFee, s.b.ChainConfig()), nil + return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, s.b.ChainConfig()), nil } // No finalized transaction, try to retrieve it from the pool if tx := s.b.GetPoolTransaction(hash); tx != nil { @@ -1621,7 +1625,10 @@ func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common. // as per specification. return nil, nil } - + header, err := s.b.HeaderByHash(ctx, blockHash) + if err != nil { + return nil, err + } receipts, err := s.b.GetReceipts(ctx, blockHash) if err != nil { return nil, err @@ -1632,8 +1639,7 @@ func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common. receipt := receipts[index] // Derive the sender. - bigblock := new(big.Int).SetUint64(blockNumber) - signer := types.MakeSigner(s.b.ChainConfig(), bigblock) + signer := types.MakeSigner(s.b.ChainConfig(), header.Number, header.Time) from, _ := types.Sender(signer, tx) fields := map[string]interface{}{ @@ -1697,7 +1703,8 @@ func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c return common.Hash{}, err } // Print a log with full tx details for manual investigations and interventions - signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number) + head := b.CurrentBlock() + signer := types.MakeSigner(b.ChainConfig(), head.Number, head.Time) from, err := types.Sender(signer, tx) if err != nil { return common.Hash{}, err diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 762dc8337d..205e23e847 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -51,7 +51,7 @@ func TestTransaction_RoundTripRpcJSON(t *testing.T) { } // rpcTransaction - rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, nil, config) + rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config) if data, err := json.Marshal(rpcTx); err != nil { t.Fatalf("test %d: marshalling failed; %v", i, err) } else if err = tx2.UnmarshalJSON(data); err != nil { diff --git a/les/downloader/queue_test.go b/les/downloader/queue_test.go index 44b2208595..6bffa90219 100644 --- a/les/downloader/queue_test.go +++ b/les/downloader/queue_test.go @@ -41,7 +41,7 @@ func makeChain(n int, seed byte, parent *types.Block, empty bool) ([]*types.Bloc block.SetCoinbase(common.Address{seed}) // Add one tx to every secondblock if !empty && i%2 == 0 { - signer := types.MakeSigner(params.TestChainConfig, block.Number()) + signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp()) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) if err != nil { panic(err) diff --git a/les/downloader/testchain_test.go b/les/downloader/testchain_test.go index 400eec94e7..dff0844cb8 100644 --- a/les/downloader/testchain_test.go +++ b/les/downloader/testchain_test.go @@ -131,7 +131,7 @@ func (tc *testChain) generate(n int, seed byte, parent *types.Block, heavy bool) } // Include transactions to the miner to make blocks more interesting. if parent == tc.genesis && i%22 == 0 { - signer := types.MakeSigner(params.TestChainConfig, block.Number()) + signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp()) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) if err != nil { panic(err) diff --git a/les/fetcher/block_fetcher_test.go b/les/fetcher/block_fetcher_test.go index caff7a3b35..95ca65916d 100644 --- a/les/fetcher/block_fetcher_test.go +++ b/les/fetcher/block_fetcher_test.go @@ -57,7 +57,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common // If the block number is multiple of 3, send a bonus transaction to the miner if parent == genesis && i%3 == 0 { - signer := types.MakeSigner(params.TestChainConfig, block.Number()) + signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp()) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) if err != nil { panic(err) diff --git a/les/handler_test.go b/les/handler_test.go index c397092596..6d0b171443 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -371,7 +371,7 @@ func testGetReceipt(t *testing.T, protocol int) { block := bc.GetBlockByNumber(i) hashes = append(hashes, block.Hash()) - receipts = append(receipts, rawdb.ReadReceipts(server.db, block.Hash(), block.NumberU64(), bc.Config())) + receipts = append(receipts, rawdb.ReadReceipts(server.db, block.Hash(), block.NumberU64(), block.Time(), bc.Config())) } // Send the hash request and verify the response sendRequest(rawPeer.app, GetReceiptsMsg, 42, hashes) diff --git a/les/odr_test.go b/les/odr_test.go index 90b7cd08d7..2db9acd433 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -68,7 +68,9 @@ func odrGetReceipts(ctx context.Context, db ethdb.Database, config *params.Chain var receipts types.Receipts if bc != nil { if number := rawdb.ReadHeaderNumber(db, bhash); number != nil { - receipts = rawdb.ReadReceipts(db, bhash, *number, config) + if header := rawdb.ReadHeader(db, bhash, *number); header != nil { + receipts = rawdb.ReadReceipts(db, bhash, *number, header.Time, config) + } } } else { if number := rawdb.ReadHeaderNumber(db, bhash); number != nil { diff --git a/les/state_accessor.go b/les/state_accessor.go index 030d6b5a50..9a8214ac2f 100644 --- a/les/state_accessor.go +++ b/les/state_accessor.go @@ -57,7 +57,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types. return nil, vm.BlockContext{}, statedb, release, nil } // Recompute transactions up to the target index. - signer := types.MakeSigner(leth.blockchain.Config(), block.Number()) + signer := types.MakeSigner(leth.blockchain.Config(), block.Number(), block.Time()) for idx, tx := range block.Transactions() { // Assemble the transaction call message and return if the requested offset msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) diff --git a/light/odr_test.go b/light/odr_test.go index 173298bb77..811dd97de3 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -131,9 +131,10 @@ func TestOdrGetReceiptsLes2(t *testing.T) { testChainOdr(t, 1, odrGetReceipts) } func odrGetReceipts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { var receipts types.Receipts if bc != nil { - number := rawdb.ReadHeaderNumber(db, bhash) - if number != nil { - receipts = rawdb.ReadReceipts(db, bhash, *number, bc.Config()) + if number := rawdb.ReadHeaderNumber(db, bhash); number != nil { + if header := rawdb.ReadHeader(db, bhash, *number); header != nil { + receipts = rawdb.ReadReceipts(db, bhash, *number, header.Time, bc.Config()) + } } } else { number := rawdb.ReadHeaderNumber(db, bhash) diff --git a/light/odr_util.go b/light/odr_util.go index 786b54132a..37a1b7a633 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -175,7 +175,7 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num genesis := rawdb.ReadCanonicalHash(odr.Database(), 0) config := rawdb.ReadChainConfig(odr.Database(), genesis) - if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.BaseFee(), block.Transactions()); err != nil { + if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), block.Transactions()); err != nil { return nil, err } rawdb.WriteReceipts(odr.Database(), hash, number, receipts) diff --git a/miner/worker.go b/miner/worker.go index c481239d40..9afc65ab1d 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -801,7 +801,7 @@ func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase co // Note the passed coinbase may be different with header.Coinbase. env := &environment{ - signer: types.MakeSigner(w.chainConfig, header.Number), + signer: types.MakeSigner(w.chainConfig, header.Number, header.Time), state: state, coinbase: coinbase, ancestors: mapset.NewSet[common.Hash](), diff --git a/params/protocol_params.go b/params/protocol_params.go index ab5ed13c06..1fb258c1fc 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -160,6 +160,7 @@ const ( RefundQuotient uint64 = 2 RefundQuotientEIP3529 uint64 = 5 + BlobTxDataGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size) BlobTxMinDataGasprice = 1 // Minimum gas price for data blobs BlobTxDataGaspriceUpdateFraction = 2225652 // Controls the maximum rate of change for data gas price ) From d3ece3a07ca5617476f11e909904c847bc096714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 21 Apr 2023 19:24:18 +0300 Subject: [PATCH 067/988] cmd/utils, node: switch to Pebble as the default db if none exists (#27136) * cmd/utils, node: switch to Pebble as the default db if none exists * node: fall back to LevelDB on platforms not supporting Pebble * core/rawdb, node: default to Pebble at the node level * cmd/geth: fix some tests explicitly using leveldb * ethdb/pebble: allow double closes, makes tests simpler --- cmd/geth/dao_test.go | 2 +- cmd/geth/genesis_test.go | 4 ++-- cmd/utils/flags.go | 4 ++-- core/rawdb/database.go | 27 ++++++++++++++++++++------- ethdb/pebble/pebble.go | 17 ++++++++++------- node/defaults.go | 16 +++++++--------- 6 files changed, 42 insertions(+), 28 deletions(-) diff --git a/cmd/geth/dao_test.go b/cmd/geth/dao_test.go index 0701a2d5a2..5af78116f0 100644 --- a/cmd/geth/dao_test.go +++ b/cmd/geth/dao_test.go @@ -121,7 +121,7 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc } // Retrieve the DAO config flag from the database path := filepath.Join(datadir, "geth", "chaindata") - db, err := rawdb.NewLevelDBDatabase(path, 0, 0, "", false) + db, err := rawdb.NewPebbleDBDatabase(path, 0, 0, "", false) if err != nil { t.Fatalf("test %d: failed to open test database: %v", test, err) } diff --git a/cmd/geth/genesis_test.go b/cmd/geth/genesis_test.go index 8e379b867a..d88346c93f 100644 --- a/cmd/geth/genesis_test.go +++ b/cmd/geth/genesis_test.go @@ -146,8 +146,8 @@ func TestCustomBackend(t *testing.T) { return nil } for i, tt := range []backendTest{ - { // When not specified, it should default to leveldb - execArgs: []string{"--db.engine", "leveldb"}, + { // When not specified, it should default to pebble + execArgs: []string{"--db.engine", "pebble"}, execExpect: "0x0000000000001338", }, { // Explicit leveldb diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 08de71ee83..e9b6320ad7 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -101,8 +101,8 @@ var ( } DBEngineFlag = &cli.StringFlag{ Name: "db.engine", - Usage: "Backing database implementation to use ('leveldb' or 'pebble')", - Value: "leveldb", + Usage: "Backing database implementation to use ('pebble' or 'leveldb')", + Value: node.DefaultConfig.DBEngine, Category: flags.EthCategory, } AncientFlag = &flags.DirectoryFlag{ diff --git a/core/rawdb/database.go b/core/rawdb/database.go index b8cc36a811..e864bcb2e8 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -358,9 +358,15 @@ type OpenOptions struct { // // type == null type != null // +---------------------------------------- -// db is non-existent | leveldb default | specified type -// db is existent | from db | specified type (if compatible) +// db is non-existent | pebble default | specified type +// db is existent | from db | specified type (if compatible) func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) { + // Reject any unsupported database type + if len(o.Type) != 0 && o.Type != dbLeveldb && o.Type != dbPebble { + return nil, fmt.Errorf("unknown db.engine %v", o.Type) + } + // Retrieve any pre-existing database's type and use that or the requested one + // as long as there's no conflict between the two types existingDb := hasPreexistingDb(o.Directory) if len(existingDb) != 0 && len(o.Type) != 0 && o.Type != existingDb { return nil, fmt.Errorf("db.engine choice was %v but found pre-existing %v database in specified data directory", o.Type, existingDb) @@ -373,12 +379,19 @@ func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) { return nil, errors.New("db.engine 'pebble' not supported on this platform") } } - if len(o.Type) != 0 && o.Type != dbLeveldb { - return nil, fmt.Errorf("unknown db.engine %v", o.Type) + if o.Type == dbLeveldb || existingDb == dbLeveldb { + log.Info("Using leveldb as the backing database") + return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) + } + // No pre-existing database, no user-requested one either. Default to Pebble + // on supported platforms and LevelDB on anything else. + if PebbleEnabled { + log.Info("Defaulting to pebble as the backing database") + return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) + } else { + log.Info("Defaulting to leveldb as the backing database") + return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) } - log.Info("Using leveldb as the backing database") - // Use leveldb, either as default (no explicit choice), or pre-existing, or chosen explicitly - return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) } // Open opens both a disk-based key-value database such as leveldb or pebble, but also diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 7c01b879b8..5be4c1af73 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -222,14 +222,17 @@ func (d *Database) Close() error { d.quitLock.Lock() defer d.quitLock.Unlock() - if d.quitChan != nil { - errc := make(chan error) - d.quitChan <- errc - if err := <-errc; err != nil { - d.log.Error("Metrics collection failed", "err", err) - } - d.quitChan = nil + // Allow double closing, simplifies things + if d.quitChan == nil { + return nil + } + errc := make(chan error) + d.quitChan <- errc + if err := <-errc; err != nil { + d.log.Error("Metrics collection failed", "err", err) } + d.quitChan = nil + return d.db.Close() } diff --git a/node/defaults.go b/node/defaults.go index 96ebed81c5..fcfbc934bf 100644 --- a/node/defaults.go +++ b/node/defaults.go @@ -28,14 +28,12 @@ import ( ) const ( - DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server - DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server - DefaultWSHost = "localhost" // Default host interface for the websocket RPC server - DefaultWSPort = 8546 // Default TCP port for the websocket RPC server - DefaultGraphQLHost = "localhost" // Default host interface for the GraphQL server - DefaultGraphQLPort = 8547 // Default TCP port for the GraphQL server - DefaultAuthHost = "localhost" // Default host interface for the authenticated apis - DefaultAuthPort = 8551 // Default port for the authenticated apis + DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server + DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server + DefaultWSHost = "localhost" // Default host interface for the websocket RPC server + DefaultWSPort = 8546 // Default TCP port for the websocket RPC server + DefaultAuthHost = "localhost" // Default host interface for the authenticated apis + DefaultAuthPort = 8551 // Default port for the authenticated apis ) var ( @@ -64,7 +62,7 @@ var DefaultConfig = Config{ MaxPeers: 50, NAT: nat.Any(), }, - DBEngine: "", + DBEngine: "", // Use whatever exists, will default to Pebble if non-existent and supported } // DefaultDataDir is the default data directory to use for the databases and other From 1e556d220c3a40286dd90b37a08bb5fc659ee6ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 24 Apr 2023 09:37:10 +0300 Subject: [PATCH 068/988] all: remove notion of trusted checkpoints in the post-merge world (#27147) * all: remove notion of trusted checkpoints in the post-merge world * light: remove unused function * eth/ethconfig, les: remove unused config option * les: make linter happy --------- Co-authored-by: Gary Rong --- cmd/checkpoint-admin/README.md | 103 ----- cmd/checkpoint-admin/common.go | 120 ----- cmd/checkpoint-admin/exec.go | 311 ------------- cmd/checkpoint-admin/main.go | 96 ---- cmd/checkpoint-admin/status.go | 60 --- contracts/checkpointoracle/contract/oracle.go | 428 ------------------ .../checkpointoracle/contract/oracle.sol | 174 ------- contracts/checkpointoracle/oracle.go | 97 ---- contracts/checkpointoracle/oracle_test.go | 342 -------------- eth/backend.go | 5 - eth/downloader/downloader.go | 27 +- eth/downloader/downloader_test.go | 41 +- eth/ethconfig/config.go | 19 +- eth/ethconfig/gen_config.go | 23 +- eth/handler.go | 105 +---- eth/handler_eth_test.go | 145 ------ eth/sync.go | 13 +- les/api.go | 61 +-- les/checkpointoracle/oracle.go | 170 ------- les/client.go | 14 +- les/client_handler.go | 11 +- les/commons.go | 72 +-- les/fetcher_test.go | 100 ---- les/peer.go | 18 - les/server.go | 11 - les/sync.go | 150 +----- les/sync_test.go | 311 +------------ les/test_helper.go | 68 +-- light/lightchain.go | 53 +-- light/lightchain_test.go | 6 +- light/odr.go | 13 +- light/odr_test.go | 2 +- light/odr_util.go | 24 - light/txpool_test.go | 2 +- params/config.go | 141 ------ 35 files changed, 65 insertions(+), 3271 deletions(-) delete mode 100644 cmd/checkpoint-admin/README.md delete mode 100644 cmd/checkpoint-admin/common.go delete mode 100644 cmd/checkpoint-admin/exec.go delete mode 100644 cmd/checkpoint-admin/main.go delete mode 100644 cmd/checkpoint-admin/status.go delete mode 100644 contracts/checkpointoracle/contract/oracle.go delete mode 100644 contracts/checkpointoracle/contract/oracle.sol delete mode 100644 contracts/checkpointoracle/oracle.go delete mode 100644 contracts/checkpointoracle/oracle_test.go delete mode 100644 les/checkpointoracle/oracle.go diff --git a/cmd/checkpoint-admin/README.md b/cmd/checkpoint-admin/README.md deleted file mode 100644 index 1067ead056..0000000000 --- a/cmd/checkpoint-admin/README.md +++ /dev/null @@ -1,103 +0,0 @@ -## Checkpoint-admin - -Checkpoint-admin is a tool for updating checkpoint oracle status. It provides a series of functions including deploying checkpoint oracle contract, signing for new checkpoints, and updating checkpoints in the checkpoint oracle contract. - -### Checkpoint - -In the LES protocol, there is an important concept called checkpoint. In simple terms, whenever a certain number of blocks are generated on the blockchain, a new checkpoint is generated which contains some important information such as - -* Block hash at checkpoint -* Canonical hash trie root at checkpoint -* Bloom trie root at checkpoint - -*For a more detailed introduction to checkpoint, please see the LES [spec](https://github.com/ethereum/devp2p/blob/master/caps/les.md).* - -Using this information, light clients can skip all historical block headers when synchronizing data and start synchronization from this checkpoint. Therefore, as long as the light client can obtain some latest and correct checkpoints, the amount of data and time for synchronization will be greatly reduced. - -However, from a security perspective, the most critical step in a synchronization algorithm based on checkpoints is to determine whether the checkpoint used by the light client is correct. Otherwise, all blockchain data synchronized based on this checkpoint may be wrong. For this we provide two different ways to ensure the correctness of the checkpoint used by the light client. - -#### Hardcoded checkpoint - -There are several hardcoded checkpoints in the [source code](https://github.com/ethereum/go-ethereum/blob/master/params/config.go#L38) of the go-ethereum project. These checkpoints are updated by go-ethereum developers when new versions of software are released. Because light client users trust Geth developers to some extent, hardcoded checkpoints in the code can also be considered correct. - -#### Checkpoint oracle - -Hardcoded checkpoints can solve the problem of verifying the correctness of checkpoints (although this is a more centralized solution). But the pain point of this solution is that developers can only update checkpoints when a new version of software is released. In addition, light client users usually do not keep the Geth version they use always up to date. So hardcoded checkpoints used by users are generally stale. Therefore, it still needs to download a large amount of blockchain data during synchronization. - -Checkpoint oracle is a more flexible solution. In simple terms, this is a smart contract that is deployed on the blockchain. The smart contract records several designated trusted signers. Whenever enough trusted signers have issued their signatures for the same checkpoint, it can be considered that the checkpoint has been authenticated by the signers. Checkpoints authenticated by trusted signers can be considered correct. - -So this way, even without updating the software version, as long as the trusted signers regularly update the checkpoint in oracle on time, the light client can always use the latest and verified checkpoint for data synchronization. - -### Usage - -Checkpoint-admin is a command line tool designed for checkpoint oracle. Users can easily deploy contracts and update checkpoints through this tool. - -#### Install - -```shell -go get github.com/ethereum/go-ethereum/cmd/checkpoint-admin -``` - -#### Deploy - -Deploy checkpoint oracle contract. `--signers` indicates the specified trusted signer, and `--threshold` indicates the minimum number of signatures required by trusted signers to update a checkpoint. - -```shell -checkpoint-admin deploy --rpc --clef --signer --signers --threshold 1 -``` - -It is worth noting that checkpoint-admin only supports clef as a signer for transactions and plain text(checkpoint). For more clef usage, please see the clef [tutorial](https://geth.ethereum.org/docs/tools/clef/tutorial) . - -#### Sign - -Checkpoint-admin provides two different modes of signing. You can automatically obtain the current stable checkpoint and sign it interactively, and you can also use the information provided by the command line flags to sign checkpoint offline. - -**Interactive mode** - -```shell -checkpoint-admin sign --clef --signer --rpc -``` - -*It is worth noting that the connected Geth node can be a fullnode or a light client. If it is fullnode, you must enable the LES protocol. E.G. add `--light.serv 50` to the startup command line flags*. - -**Offline mode** - -```shell -checkpoint-admin sign --clef --signer --index --hash --oracle -``` - -*CHECKPOINT_HASH is obtained based on this [calculation method](https://github.com/ethereum/go-ethereum/blob/master/params/config.go#L251).* - -#### Publish - -Collect enough signatures from different trusted signers for the same checkpoint and submit them to oracle to update the "authenticated" checkpoint in the contract. - -```shell -checkpoint-admin publish --clef --rpc --signer --index --signatures -``` - -#### Status query - -Check the latest status of checkpoint oracle. - -```shell -checkpoint-admin status --rpc -``` - -### Enable checkpoint oracle in your private network - -Currently, only the Ethereum mainnet and the default supported test networks (rinkeby, goerli) activate this feature. If you want to activate this feature in your private network, you can overwrite the relevant checkpoint oracle settings through the configuration file after deploying the oracle contract. - -* Get your node configuration file `geth dumpconfig OTHER_COMMAND_LINE_OPTIONS > config.toml` -* Edit the configuration file and add the following information - -```toml -[Eth.CheckpointOracle] -Address = CHECKPOINT_ORACLE_ADDRESS -Signers = [TRUSTED_SIGNER_1, ..., TRUSTED_SIGNER_N] -Threshold = THRESHOLD -``` - -* Start geth with the modified configuration file - -*In the private network, all fullnodes and light clients need to be started using the same checkpoint oracle settings.* \ No newline at end of file diff --git a/cmd/checkpoint-admin/common.go b/cmd/checkpoint-admin/common.go deleted file mode 100644 index f86ac24f06..0000000000 --- a/cmd/checkpoint-admin/common.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "strconv" - - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/external" - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts/checkpointoracle" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rpc" - "github.com/urfave/cli/v2" -) - -// newClient creates a client with specified remote URL. -func newClient(ctx *cli.Context) *ethclient.Client { - client, err := ethclient.Dial(ctx.String(nodeURLFlag.Name)) - if err != nil { - utils.Fatalf("Failed to connect to Ethereum node: %v", err) - } - return client -} - -// newRPCClient creates a rpc client with specified node URL. -func newRPCClient(url string) *rpc.Client { - client, err := rpc.Dial(url) - if err != nil { - utils.Fatalf("Failed to connect to Ethereum node: %v", err) - } - return client -} - -// getContractAddr retrieves the register contract address through -// rpc request. -func getContractAddr(client *rpc.Client) common.Address { - var addr string - if err := client.Call(&addr, "les_getCheckpointContractAddress"); err != nil { - utils.Fatalf("Failed to fetch checkpoint oracle address: %v", err) - } - return common.HexToAddress(addr) -} - -// getCheckpoint retrieves the specified checkpoint or the latest one -// through rpc request. -func getCheckpoint(ctx *cli.Context, client *rpc.Client) *params.TrustedCheckpoint { - var checkpoint *params.TrustedCheckpoint - - if ctx.IsSet(indexFlag.Name) { - var result [3]string - index := uint64(ctx.Int64(indexFlag.Name)) - if err := client.Call(&result, "les_getCheckpoint", index); err != nil { - utils.Fatalf("Failed to get local checkpoint %v, please ensure the les API is exposed", err) - } - checkpoint = ¶ms.TrustedCheckpoint{ - SectionIndex: index, - SectionHead: common.HexToHash(result[0]), - CHTRoot: common.HexToHash(result[1]), - BloomRoot: common.HexToHash(result[2]), - } - } else { - var result [4]string - err := client.Call(&result, "les_latestCheckpoint") - if err != nil { - utils.Fatalf("Failed to get local checkpoint %v, please ensure the les API is exposed", err) - } - index, err := strconv.ParseUint(result[0], 0, 64) - if err != nil { - utils.Fatalf("Failed to parse checkpoint index %v", err) - } - checkpoint = ¶ms.TrustedCheckpoint{ - SectionIndex: index, - SectionHead: common.HexToHash(result[1]), - CHTRoot: common.HexToHash(result[2]), - BloomRoot: common.HexToHash(result[3]), - } - } - return checkpoint -} - -// newContract creates a registrar contract instance with specified -// contract address or the default contracts for mainnet or testnet. -func newContract(client *rpc.Client) (common.Address, *checkpointoracle.CheckpointOracle) { - addr := getContractAddr(client) - if addr == (common.Address{}) { - utils.Fatalf("No specified registrar contract address") - } - contract, err := checkpointoracle.NewCheckpointOracle(addr, ethclient.NewClient(client)) - if err != nil { - utils.Fatalf("Failed to setup registrar contract %s: %v", addr, err) - } - return addr, contract -} - -// newClefSigner sets up a clef backend and returns a clef transaction signer. -func newClefSigner(ctx *cli.Context) *bind.TransactOpts { - clef, err := external.NewExternalSigner(ctx.String(clefURLFlag.Name)) - if err != nil { - utils.Fatalf("Failed to create clef signer %v", err) - } - return bind.NewClefTransactor(clef, accounts.Account{Address: common.HexToAddress(ctx.String(signerFlag.Name))}) -} diff --git a/cmd/checkpoint-admin/exec.go b/cmd/checkpoint-admin/exec.go deleted file mode 100644 index cb67d0306d..0000000000 --- a/cmd/checkpoint-admin/exec.go +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "context" - "encoding/binary" - "fmt" - "math/big" - "strings" - "time" - - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/contracts/checkpointoracle" - "github.com/ethereum/go-ethereum/contracts/checkpointoracle/contract" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rpc" - "github.com/urfave/cli/v2" -) - -var commandDeploy = &cli.Command{ - Name: "deploy", - Usage: "Deploy a new checkpoint oracle contract", - Flags: []cli.Flag{ - nodeURLFlag, - clefURLFlag, - signerFlag, - signersFlag, - thresholdFlag, - }, - Action: deploy, -} - -var commandSign = &cli.Command{ - Name: "sign", - Usage: "Sign the checkpoint with the specified key", - Flags: []cli.Flag{ - nodeURLFlag, - clefURLFlag, - signerFlag, - indexFlag, - hashFlag, - oracleFlag, - }, - Action: sign, -} - -var commandPublish = &cli.Command{ - Name: "publish", - Usage: "Publish a checkpoint into the oracle", - Flags: []cli.Flag{ - nodeURLFlag, - clefURLFlag, - signerFlag, - indexFlag, - signaturesFlag, - }, - Action: publish, -} - -// deploy deploys the checkpoint registrar contract. -// -// Note the network where the contract is deployed depends on -// the network where the connected node is located. -func deploy(ctx *cli.Context) error { - // Gather all the addresses that should be permitted to sign - var addrs []common.Address - for _, account := range strings.Split(ctx.String(signersFlag.Name), ",") { - if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) { - utils.Fatalf("Invalid account in --signers: '%s'", trimmed) - } - addrs = append(addrs, common.HexToAddress(account)) - } - // Retrieve and validate the signing threshold - needed := ctx.Int(thresholdFlag.Name) - if needed == 0 || needed > len(addrs) { - utils.Fatalf("Invalid signature threshold %d", needed) - } - // Print a summary to ensure the user understands what they're signing - fmt.Printf("Deploying new checkpoint oracle:\n\n") - for i, addr := range addrs { - fmt.Printf("Admin %d => %s\n", i+1, addr.Hex()) - } - fmt.Printf("\nSignatures needed to publish: %d\n", needed) - - // setup clef signer, create an abigen transactor and an RPC client - transactor, client := newClefSigner(ctx), newClient(ctx) - - // Deploy the checkpoint oracle - fmt.Println("Sending deploy request to Clef...") - oracle, tx, _, err := contract.DeployCheckpointOracle(transactor, client, addrs, big.NewInt(int64(params.CheckpointFrequency)), - big.NewInt(int64(params.CheckpointProcessConfirmations)), big.NewInt(int64(needed))) - if err != nil { - utils.Fatalf("Failed to deploy checkpoint oracle %v", err) - } - log.Info("Deployed checkpoint oracle", "address", oracle, "tx", tx.Hash().Hex()) - - return nil -} - -// sign creates the signature for specific checkpoint -// with local key. Only contract admins have the permission to -// sign checkpoint. -func sign(ctx *cli.Context) error { - var ( - offline bool // The indicator whether we sign checkpoint by offline. - chash common.Hash - cindex uint64 - address common.Address - - node *rpc.Client - oracle *checkpointoracle.CheckpointOracle - ) - if !ctx.IsSet(nodeURLFlag.Name) { - // Offline mode signing - offline = true - if !ctx.IsSet(hashFlag.Name) { - utils.Fatalf("Please specify the checkpoint hash (--hash) to sign in offline mode") - } - chash = common.HexToHash(ctx.String(hashFlag.Name)) - - if !ctx.IsSet(indexFlag.Name) { - utils.Fatalf("Please specify checkpoint index (--index) to sign in offline mode") - } - cindex = ctx.Uint64(indexFlag.Name) - - if !ctx.IsSet(oracleFlag.Name) { - utils.Fatalf("Please specify oracle address (--oracle) to sign in offline mode") - } - address = common.HexToAddress(ctx.String(oracleFlag.Name)) - } else { - // Interactive mode signing, retrieve the data from the remote node - node = newRPCClient(ctx.String(nodeURLFlag.Name)) - - checkpoint := getCheckpoint(ctx, node) - chash, cindex, address = checkpoint.Hash(), checkpoint.SectionIndex, getContractAddr(node) - - // Check the validity of checkpoint - reqCtx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second) - defer cancelFn() - - head, err := ethclient.NewClient(node).HeaderByNumber(reqCtx, nil) - if err != nil { - return err - } - num := head.Number.Uint64() - if num < ((cindex+1)*params.CheckpointFrequency + params.CheckpointProcessConfirmations) { - utils.Fatalf("Invalid future checkpoint") - } - _, oracle = newContract(node) - latest, _, h, err := oracle.Contract().GetLatestCheckpoint(nil) - if err != nil { - return err - } - if cindex < latest { - utils.Fatalf("Checkpoint is too old") - } - if cindex == latest && (latest != 0 || h.Uint64() != 0) { - utils.Fatalf("Stale checkpoint, latest registered %d, given %d", latest, cindex) - } - } - var ( - signature string - signer string - ) - // isAdmin checks whether the specified signer is admin. - isAdmin := func(addr common.Address) error { - signers, err := oracle.Contract().GetAllAdmin(nil) - if err != nil { - return err - } - for _, s := range signers { - if s == addr { - return nil - } - } - return fmt.Errorf("signer %v is not the admin", addr.Hex()) - } - // Print to the user the data thy are about to sign - fmt.Printf("Oracle => %s\n", address.Hex()) - fmt.Printf("Index %4d => %s\n", cindex, chash.Hex()) - - // Sign checkpoint in clef mode. - signer = ctx.String(signerFlag.Name) - - if !offline { - if err := isAdmin(common.HexToAddress(signer)); err != nil { - return err - } - } - clef := newRPCClient(ctx.String(clefURLFlag.Name)) - p := make(map[string]string) - buf := make([]byte, 8) - binary.BigEndian.PutUint64(buf, cindex) - p["address"] = address.Hex() - p["message"] = hexutil.Encode(append(buf, chash.Bytes()...)) - - fmt.Println("Sending signing request to Clef...") - if err := clef.Call(&signature, "account_signData", accounts.MimetypeDataWithValidator, signer, p); err != nil { - utils.Fatalf("Failed to sign checkpoint, err %v", err) - } - fmt.Printf("Signer => %s\n", signer) - fmt.Printf("Signature => %s\n", signature) - return nil -} - -// sighash calculates the hash of the data to sign for the checkpoint oracle. -func sighash(index uint64, oracle common.Address, hash common.Hash) []byte { - buf := make([]byte, 8) - binary.BigEndian.PutUint64(buf, index) - - data := append([]byte{0x19, 0x00}, append(oracle[:], append(buf, hash[:]...)...)...) - return crypto.Keccak256(data) -} - -// ecrecover calculates the sender address from a sighash and signature combo. -func ecrecover(sighash []byte, sig []byte) common.Address { - sig[64] -= 27 - defer func() { sig[64] += 27 }() - - signer, err := crypto.SigToPub(sighash, sig) - if err != nil { - utils.Fatalf("Failed to recover sender from signature %x: %v", sig, err) - } - return crypto.PubkeyToAddress(*signer) -} - -// publish registers the specified checkpoint which generated by connected node -// with a authorised private key. -func publish(ctx *cli.Context) error { - // Print the checkpoint oracle's current status to make sure we're interacting - // with the correct network and contract. - status(ctx) - - // Gather the signatures from the CLI - var sigs [][]byte - for _, sig := range strings.Split(ctx.String(signaturesFlag.Name), ",") { - trimmed := strings.TrimPrefix(strings.TrimSpace(sig), "0x") - if len(trimmed) != 130 { - utils.Fatalf("Invalid signature in --signature: '%s'", trimmed) - } else { - sigs = append(sigs, common.Hex2Bytes(trimmed)) - } - } - // Retrieve the checkpoint we want to sign to sort the signatures - var ( - client = newRPCClient(ctx.String(nodeURLFlag.Name)) - addr, oracle = newContract(client) - checkpoint = getCheckpoint(ctx, client) - sighash = sighash(checkpoint.SectionIndex, addr, checkpoint.Hash()) - ) - for i := 0; i < len(sigs); i++ { - for j := i + 1; j < len(sigs); j++ { - signerA := ecrecover(sighash, sigs[i]) - signerB := ecrecover(sighash, sigs[j]) - if bytes.Compare(signerA.Bytes(), signerB.Bytes()) > 0 { - sigs[i], sigs[j] = sigs[j], sigs[i] - } - } - } - // Retrieve recent header info to protect replay attack - reqCtx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second) - defer cancelFn() - - head, err := ethclient.NewClient(client).HeaderByNumber(reqCtx, nil) - if err != nil { - return err - } - num := head.Number.Uint64() - recent, err := ethclient.NewClient(client).HeaderByNumber(reqCtx, big.NewInt(int64(num-128))) - if err != nil { - return err - } - // Print a summary of the operation that's going to be performed - fmt.Printf("Publishing %d => %s:\n\n", checkpoint.SectionIndex, checkpoint.Hash().Hex()) - for i, sig := range sigs { - fmt.Printf("Signer %d => %s\n", i+1, ecrecover(sighash, sig).Hex()) - } - fmt.Println() - fmt.Printf("Sentry number => %d\nSentry hash => %s\n", recent.Number, recent.Hash().Hex()) - - // Publish the checkpoint into the oracle - fmt.Println("Sending publish request to Clef...") - tx, err := oracle.RegisterCheckpoint(newClefSigner(ctx), checkpoint.SectionIndex, checkpoint.Hash().Bytes(), recent.Number, recent.Hash(), sigs) - if err != nil { - utils.Fatalf("Register contract failed %v", err) - } - log.Info("Successfully registered checkpoint", "tx", tx.Hash().Hex()) - return nil -} diff --git a/cmd/checkpoint-admin/main.go b/cmd/checkpoint-admin/main.go deleted file mode 100644 index ca0bae7375..0000000000 --- a/cmd/checkpoint-admin/main.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// checkpoint-admin is a utility that can be used to query checkpoint information -// and register stable checkpoints into an oracle contract. -package main - -import ( - "fmt" - "os" - - "github.com/ethereum/go-ethereum/common/fdlimit" - "github.com/ethereum/go-ethereum/internal/flags" - "github.com/ethereum/go-ethereum/log" - "github.com/urfave/cli/v2" -) - -var app = flags.NewApp("ethereum checkpoint helper tool") - -func init() { - app.Commands = []*cli.Command{ - commandStatus, - commandDeploy, - commandSign, - commandPublish, - } - app.Flags = []cli.Flag{ - oracleFlag, - nodeURLFlag, - } -} - -// Commonly used command line flags. -var ( - indexFlag = &cli.Int64Flag{ - Name: "index", - Usage: "Checkpoint index (query latest from remote node if not specified)", - } - hashFlag = &cli.StringFlag{ - Name: "hash", - Usage: "Checkpoint hash (query latest from remote node if not specified)", - } - oracleFlag = &cli.StringFlag{ - Name: "oracle", - Usage: "Checkpoint oracle address (query from remote node if not specified)", - } - thresholdFlag = &cli.Int64Flag{ - Name: "threshold", - Usage: "Minimal number of signatures required to approve a checkpoint", - } - nodeURLFlag = &cli.StringFlag{ - Name: "rpc", - Value: "http://localhost:8545", - Usage: "The rpc endpoint of a local or remote geth node", - } - clefURLFlag = &cli.StringFlag{ - Name: "clef", - Value: "http://localhost:8550", - Usage: "The rpc endpoint of clef", - } - signerFlag = &cli.StringFlag{ - Name: "signer", - Usage: "Signer address for clef signing", - } - signersFlag = &cli.StringFlag{ - Name: "signers", - Usage: "Comma separated accounts of trusted checkpoint signers", - } - signaturesFlag = &cli.StringFlag{ - Name: "signatures", - Usage: "Comma separated checkpoint signatures to submit", - } -) - -func main() { - log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - fdlimit.Raise(2048) - - if err := app.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} diff --git a/cmd/checkpoint-admin/status.go b/cmd/checkpoint-admin/status.go deleted file mode 100644 index bec97aed12..0000000000 --- a/cmd/checkpoint-admin/status.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/urfave/cli/v2" -) - -var commandStatus = &cli.Command{ - Name: "status", - Usage: "Fetches the signers and checkpoint status of the oracle contract", - Flags: []cli.Flag{ - nodeURLFlag, - }, - Action: status, -} - -// status fetches the admin list of specified registrar contract. -func status(ctx *cli.Context) error { - // Create a wrapper around the checkpoint oracle contract - addr, oracle := newContract(newRPCClient(ctx.String(nodeURLFlag.Name))) - fmt.Printf("Oracle => %s\n", addr.Hex()) - fmt.Println() - - // Retrieve the list of authorized signers (admins) - admins, err := oracle.Contract().GetAllAdmin(nil) - if err != nil { - return err - } - for i, admin := range admins { - fmt.Printf("Admin %d => %s\n", i+1, admin.Hex()) - } - fmt.Println() - - // Retrieve the latest checkpoint - index, checkpoint, height, err := oracle.Contract().GetLatestCheckpoint(nil) - if err != nil { - return err - } - fmt.Printf("Checkpoint (published at #%d) %d => %s\n", height, index, common.Hash(checkpoint).Hex()) - - return nil -} diff --git a/contracts/checkpointoracle/contract/oracle.go b/contracts/checkpointoracle/contract/oracle.go deleted file mode 100644 index a4a308f5c5..0000000000 --- a/contracts/checkpointoracle/contract/oracle.go +++ /dev/null @@ -1,428 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package contract - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// CheckpointOracleABI is the input ABI used to generate the binding from. -const CheckpointOracleABI = "[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_adminlist\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"_sectionSize\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_processConfirms\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_threshold\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"checkpointHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"NewCheckpointVote\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"GetAllAdmin\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GetLatestCheckpoint\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_recentNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"_recentHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"_hash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"_sectionIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint8[]\",\"name\":\"v\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"r\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"s\",\"type\":\"bytes32[]\"}],\"name\":\"SetCheckpoint\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" - -// CheckpointOracleFuncSigs maps the 4-byte function signature to its string representation. -var CheckpointOracleFuncSigs = map[string]string{ - "45848dfc": "GetAllAdmin()", - "4d6a304c": "GetLatestCheckpoint()", - "d459fc46": "SetCheckpoint(uint256,bytes32,bytes32,uint64,uint8[],bytes32[],bytes32[])", -} - -// CheckpointOracleBin is the compiled bytecode used for deploying new contracts. -var CheckpointOracleBin = "0x608060405234801561001057600080fd5b506040516108703803806108708339818101604052608081101561003357600080fd5b810190808051604051939291908464010000000082111561005357600080fd5b90830190602082018581111561006857600080fd5b825186602082028301116401000000008211171561008557600080fd5b82525081516020918201928201910280838360005b838110156100b257818101518382015260200161009a565b50505050919091016040908152602083015190830151606090930151909450919250600090505b84518110156101855760016000808784815181106100f357fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550600185828151811061014057fe5b60209081029190910181015182546001808201855560009485529290932090920180546001600160a01b0319166001600160a01b0390931692909217909155016100d9565b50600592909255600655600755506106ce806101a26000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806345848dfc146100465780634d6a304c1461009e578063d459fc46146100cf575b600080fd5b61004e6102b0565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561008a578181015183820152602001610072565b505050509050019250505060405180910390f35b6100a6610365565b6040805167ffffffffffffffff9094168452602084019290925282820152519081900360600190f35b61029c600480360360e08110156100e557600080fd5b81359160208101359160408201359167ffffffffffffffff6060820135169181019060a08101608082013564010000000081111561012257600080fd5b82018360208201111561013457600080fd5b8035906020019184602083028401116401000000008311171561015657600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156101a657600080fd5b8201836020820111156101b857600080fd5b803590602001918460208302840111640100000000831117156101da57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561022a57600080fd5b82018360208201111561023c57600080fd5b8035906020019184602083028401116401000000008311171561025e57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610380945050505050565b604080519115158252519081900360200190f35b600154606090819067ffffffffffffffff811180156102ce57600080fd5b506040519080825280602002602001820160405280156102f8578160200160208202803683370190505b50905060005b60015481101561035f576001818154811061031557fe5b9060005260206000200160009054906101000a90046001600160a01b031682828151811061033f57fe5b6001600160a01b03909216602092830291909101909101526001016102fe565b50905090565b60025460045460035467ffffffffffffffff90921691909192565b3360009081526020819052604081205460ff1661039c57600080fd5b868840146103a957600080fd5b82518451146103b757600080fd5b81518451146103c557600080fd5b6006546005548660010167ffffffffffffffff1602014310156103ea5750600061068d565b60025467ffffffffffffffff908116908616101561040a5750600061068d565b60025467ffffffffffffffff868116911614801561043c575067ffffffffffffffff851615158061043c575060035415155b156104495750600061068d565b856104565750600061068d565b60408051601960f81b6020808301919091526000602183018190523060601b60228401526001600160c01b031960c08a901b166036840152603e8084018b905284518085039091018152605e909301909352815191012090805b86518110156106875760006001848984815181106104ca57fe5b60200260200101518985815181106104de57fe5b60200260200101518986815181106104f257fe5b602002602001015160405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610551573d6000803e3d6000fd5b505060408051601f1901516001600160a01b03811660009081526020819052919091205490925060ff16905061058657600080fd5b826001600160a01b0316816001600160a01b0316116105a457600080fd5b8092508867ffffffffffffffff167fce51ffa16246bcaf0899f6504f473cd0114f430f566cef71ab7e03d3dde42a418b8a85815181106105e057fe5b60200260200101518a86815181106105f457fe5b60200260200101518a878151811061060857fe5b6020026020010151604051808581526020018460ff1660ff16815260200183815260200182815260200194505050505060405180910390a2600754826001011061067e5750505060048790555050436003556002805467ffffffffffffffff191667ffffffffffffffff8616179055600161068d565b506001016104b0565b50600080fd5b97965050505050505056fea26469706673582212202ddf9eda76bf59c0fc65584c0b22d84ecef2c703765de60439596d6ac34c2b7264736f6c634300060b0033" - -// DeployCheckpointOracle deploys a new Ethereum contract, binding an instance of CheckpointOracle to it. -func DeployCheckpointOracle(auth *bind.TransactOpts, backend bind.ContractBackend, _adminlist []common.Address, _sectionSize *big.Int, _processConfirms *big.Int, _threshold *big.Int) (common.Address, *types.Transaction, *CheckpointOracle, error) { - parsed, err := abi.JSON(strings.NewReader(CheckpointOracleABI)) - if err != nil { - return common.Address{}, nil, nil, err - } - - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(CheckpointOracleBin), backend, _adminlist, _sectionSize, _processConfirms, _threshold) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &CheckpointOracle{CheckpointOracleCaller: CheckpointOracleCaller{contract: contract}, CheckpointOracleTransactor: CheckpointOracleTransactor{contract: contract}, CheckpointOracleFilterer: CheckpointOracleFilterer{contract: contract}}, nil -} - -// CheckpointOracle is an auto generated Go binding around an Ethereum contract. -type CheckpointOracle struct { - CheckpointOracleCaller // Read-only binding to the contract - CheckpointOracleTransactor // Write-only binding to the contract - CheckpointOracleFilterer // Log filterer for contract events -} - -// CheckpointOracleCaller is an auto generated read-only Go binding around an Ethereum contract. -type CheckpointOracleCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// CheckpointOracleTransactor is an auto generated write-only Go binding around an Ethereum contract. -type CheckpointOracleTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// CheckpointOracleFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type CheckpointOracleFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// CheckpointOracleSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type CheckpointOracleSession struct { - Contract *CheckpointOracle // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// CheckpointOracleCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type CheckpointOracleCallerSession struct { - Contract *CheckpointOracleCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// CheckpointOracleTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type CheckpointOracleTransactorSession struct { - Contract *CheckpointOracleTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// CheckpointOracleRaw is an auto generated low-level Go binding around an Ethereum contract. -type CheckpointOracleRaw struct { - Contract *CheckpointOracle // Generic contract binding to access the raw methods on -} - -// CheckpointOracleCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type CheckpointOracleCallerRaw struct { - Contract *CheckpointOracleCaller // Generic read-only contract binding to access the raw methods on -} - -// CheckpointOracleTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type CheckpointOracleTransactorRaw struct { - Contract *CheckpointOracleTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewCheckpointOracle creates a new instance of CheckpointOracle, bound to a specific deployed contract. -func NewCheckpointOracle(address common.Address, backend bind.ContractBackend) (*CheckpointOracle, error) { - contract, err := bindCheckpointOracle(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &CheckpointOracle{CheckpointOracleCaller: CheckpointOracleCaller{contract: contract}, CheckpointOracleTransactor: CheckpointOracleTransactor{contract: contract}, CheckpointOracleFilterer: CheckpointOracleFilterer{contract: contract}}, nil -} - -// NewCheckpointOracleCaller creates a new read-only instance of CheckpointOracle, bound to a specific deployed contract. -func NewCheckpointOracleCaller(address common.Address, caller bind.ContractCaller) (*CheckpointOracleCaller, error) { - contract, err := bindCheckpointOracle(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &CheckpointOracleCaller{contract: contract}, nil -} - -// NewCheckpointOracleTransactor creates a new write-only instance of CheckpointOracle, bound to a specific deployed contract. -func NewCheckpointOracleTransactor(address common.Address, transactor bind.ContractTransactor) (*CheckpointOracleTransactor, error) { - contract, err := bindCheckpointOracle(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &CheckpointOracleTransactor{contract: contract}, nil -} - -// NewCheckpointOracleFilterer creates a new log filterer instance of CheckpointOracle, bound to a specific deployed contract. -func NewCheckpointOracleFilterer(address common.Address, filterer bind.ContractFilterer) (*CheckpointOracleFilterer, error) { - contract, err := bindCheckpointOracle(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &CheckpointOracleFilterer{contract: contract}, nil -} - -// bindCheckpointOracle binds a generic wrapper to an already deployed contract. -func bindCheckpointOracle(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(CheckpointOracleABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_CheckpointOracle *CheckpointOracleRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _CheckpointOracle.Contract.CheckpointOracleCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_CheckpointOracle *CheckpointOracleRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _CheckpointOracle.Contract.CheckpointOracleTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_CheckpointOracle *CheckpointOracleRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _CheckpointOracle.Contract.CheckpointOracleTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_CheckpointOracle *CheckpointOracleCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _CheckpointOracle.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_CheckpointOracle *CheckpointOracleTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _CheckpointOracle.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_CheckpointOracle *CheckpointOracleTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _CheckpointOracle.Contract.contract.Transact(opts, method, params...) -} - -// GetAllAdmin is a free data retrieval call binding the contract method 0x45848dfc. -// -// Solidity: function GetAllAdmin() view returns(address[]) -func (_CheckpointOracle *CheckpointOracleCaller) GetAllAdmin(opts *bind.CallOpts) ([]common.Address, error) { - var out []interface{} - err := _CheckpointOracle.contract.Call(opts, &out, "GetAllAdmin") - - if err != nil { - return *new([]common.Address), err - } - - out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) - - return out0, err - -} - -// GetAllAdmin is a free data retrieval call binding the contract method 0x45848dfc. -// -// Solidity: function GetAllAdmin() view returns(address[]) -func (_CheckpointOracle *CheckpointOracleSession) GetAllAdmin() ([]common.Address, error) { - return _CheckpointOracle.Contract.GetAllAdmin(&_CheckpointOracle.CallOpts) -} - -// GetAllAdmin is a free data retrieval call binding the contract method 0x45848dfc. -// -// Solidity: function GetAllAdmin() view returns(address[]) -func (_CheckpointOracle *CheckpointOracleCallerSession) GetAllAdmin() ([]common.Address, error) { - return _CheckpointOracle.Contract.GetAllAdmin(&_CheckpointOracle.CallOpts) -} - -// GetLatestCheckpoint is a free data retrieval call binding the contract method 0x4d6a304c. -// -// Solidity: function GetLatestCheckpoint() view returns(uint64, bytes32, uint256) -func (_CheckpointOracle *CheckpointOracleCaller) GetLatestCheckpoint(opts *bind.CallOpts) (uint64, [32]byte, *big.Int, error) { - var out []interface{} - err := _CheckpointOracle.contract.Call(opts, &out, "GetLatestCheckpoint") - - if err != nil { - return *new(uint64), *new([32]byte), *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) - out1 := *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) - out2 := *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - - return out0, out1, out2, err - -} - -// GetLatestCheckpoint is a free data retrieval call binding the contract method 0x4d6a304c. -// -// Solidity: function GetLatestCheckpoint() view returns(uint64, bytes32, uint256) -func (_CheckpointOracle *CheckpointOracleSession) GetLatestCheckpoint() (uint64, [32]byte, *big.Int, error) { - return _CheckpointOracle.Contract.GetLatestCheckpoint(&_CheckpointOracle.CallOpts) -} - -// GetLatestCheckpoint is a free data retrieval call binding the contract method 0x4d6a304c. -// -// Solidity: function GetLatestCheckpoint() view returns(uint64, bytes32, uint256) -func (_CheckpointOracle *CheckpointOracleCallerSession) GetLatestCheckpoint() (uint64, [32]byte, *big.Int, error) { - return _CheckpointOracle.Contract.GetLatestCheckpoint(&_CheckpointOracle.CallOpts) -} - -// SetCheckpoint is a paid mutator transaction binding the contract method 0xd459fc46. -// -// Solidity: function SetCheckpoint(uint256 _recentNumber, bytes32 _recentHash, bytes32 _hash, uint64 _sectionIndex, uint8[] v, bytes32[] r, bytes32[] s) returns(bool) -func (_CheckpointOracle *CheckpointOracleTransactor) SetCheckpoint(opts *bind.TransactOpts, _recentNumber *big.Int, _recentHash [32]byte, _hash [32]byte, _sectionIndex uint64, v []uint8, r [][32]byte, s [][32]byte) (*types.Transaction, error) { - return _CheckpointOracle.contract.Transact(opts, "SetCheckpoint", _recentNumber, _recentHash, _hash, _sectionIndex, v, r, s) -} - -// SetCheckpoint is a paid mutator transaction binding the contract method 0xd459fc46. -// -// Solidity: function SetCheckpoint(uint256 _recentNumber, bytes32 _recentHash, bytes32 _hash, uint64 _sectionIndex, uint8[] v, bytes32[] r, bytes32[] s) returns(bool) -func (_CheckpointOracle *CheckpointOracleSession) SetCheckpoint(_recentNumber *big.Int, _recentHash [32]byte, _hash [32]byte, _sectionIndex uint64, v []uint8, r [][32]byte, s [][32]byte) (*types.Transaction, error) { - return _CheckpointOracle.Contract.SetCheckpoint(&_CheckpointOracle.TransactOpts, _recentNumber, _recentHash, _hash, _sectionIndex, v, r, s) -} - -// SetCheckpoint is a paid mutator transaction binding the contract method 0xd459fc46. -// -// Solidity: function SetCheckpoint(uint256 _recentNumber, bytes32 _recentHash, bytes32 _hash, uint64 _sectionIndex, uint8[] v, bytes32[] r, bytes32[] s) returns(bool) -func (_CheckpointOracle *CheckpointOracleTransactorSession) SetCheckpoint(_recentNumber *big.Int, _recentHash [32]byte, _hash [32]byte, _sectionIndex uint64, v []uint8, r [][32]byte, s [][32]byte) (*types.Transaction, error) { - return _CheckpointOracle.Contract.SetCheckpoint(&_CheckpointOracle.TransactOpts, _recentNumber, _recentHash, _hash, _sectionIndex, v, r, s) -} - -// CheckpointOracleNewCheckpointVoteIterator is returned from FilterNewCheckpointVote and is used to iterate over the raw logs and unpacked data for NewCheckpointVote events raised by the CheckpointOracle contract. -type CheckpointOracleNewCheckpointVoteIterator struct { - Event *CheckpointOracleNewCheckpointVote // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *CheckpointOracleNewCheckpointVoteIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(CheckpointOracleNewCheckpointVote) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(CheckpointOracleNewCheckpointVote) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *CheckpointOracleNewCheckpointVoteIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *CheckpointOracleNewCheckpointVoteIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// CheckpointOracleNewCheckpointVote represents a NewCheckpointVote event raised by the CheckpointOracle contract. -type CheckpointOracleNewCheckpointVote struct { - Index uint64 - CheckpointHash [32]byte - V uint8 - R [32]byte - S [32]byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterNewCheckpointVote is a free log retrieval operation binding the contract event 0xce51ffa16246bcaf0899f6504f473cd0114f430f566cef71ab7e03d3dde42a41. -// -// Solidity: event NewCheckpointVote(uint64 indexed index, bytes32 checkpointHash, uint8 v, bytes32 r, bytes32 s) -func (_CheckpointOracle *CheckpointOracleFilterer) FilterNewCheckpointVote(opts *bind.FilterOpts, index []uint64) (*CheckpointOracleNewCheckpointVoteIterator, error) { - - var indexRule []interface{} - for _, indexItem := range index { - indexRule = append(indexRule, indexItem) - } - - logs, sub, err := _CheckpointOracle.contract.FilterLogs(opts, "NewCheckpointVote", indexRule) - if err != nil { - return nil, err - } - return &CheckpointOracleNewCheckpointVoteIterator{contract: _CheckpointOracle.contract, event: "NewCheckpointVote", logs: logs, sub: sub}, nil -} - -// WatchNewCheckpointVote is a free log subscription operation binding the contract event 0xce51ffa16246bcaf0899f6504f473cd0114f430f566cef71ab7e03d3dde42a41. -// -// Solidity: event NewCheckpointVote(uint64 indexed index, bytes32 checkpointHash, uint8 v, bytes32 r, bytes32 s) -func (_CheckpointOracle *CheckpointOracleFilterer) WatchNewCheckpointVote(opts *bind.WatchOpts, sink chan<- *CheckpointOracleNewCheckpointVote, index []uint64) (event.Subscription, error) { - - var indexRule []interface{} - for _, indexItem := range index { - indexRule = append(indexRule, indexItem) - } - - logs, sub, err := _CheckpointOracle.contract.WatchLogs(opts, "NewCheckpointVote", indexRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(CheckpointOracleNewCheckpointVote) - if err := _CheckpointOracle.contract.UnpackLog(event, "NewCheckpointVote", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseNewCheckpointVote is a log parse operation binding the contract event 0xce51ffa16246bcaf0899f6504f473cd0114f430f566cef71ab7e03d3dde42a41. -// -// Solidity: event NewCheckpointVote(uint64 indexed index, bytes32 checkpointHash, uint8 v, bytes32 r, bytes32 s) -func (_CheckpointOracle *CheckpointOracleFilterer) ParseNewCheckpointVote(log types.Log) (*CheckpointOracleNewCheckpointVote, error) { - event := new(CheckpointOracleNewCheckpointVote) - if err := _CheckpointOracle.contract.UnpackLog(event, "NewCheckpointVote", log); err != nil { - return nil, err - } - return event, nil -} diff --git a/contracts/checkpointoracle/contract/oracle.sol b/contracts/checkpointoracle/contract/oracle.sol deleted file mode 100644 index 65bac09d28..0000000000 --- a/contracts/checkpointoracle/contract/oracle.sol +++ /dev/null @@ -1,174 +0,0 @@ -pragma solidity ^0.6.0; - -/** - * @title CheckpointOracle - * @author Gary Rong, Martin Swende - * @dev Implementation of the blockchain checkpoint registrar. - */ -contract CheckpointOracle { - /* - Events - */ - - // NewCheckpointVote is emitted when a new checkpoint proposal receives a vote. - event NewCheckpointVote(uint64 indexed index, bytes32 checkpointHash, uint8 v, bytes32 r, bytes32 s); - - /* - Public Functions - */ - constructor(address[] memory _adminlist, uint _sectionSize, uint _processConfirms, uint _threshold) public { - for (uint i = 0; i < _adminlist.length; i++) { - admins[_adminlist[i]] = true; - adminList.push(_adminlist[i]); - } - sectionSize = _sectionSize; - processConfirms = _processConfirms; - threshold = _threshold; - } - - /** - * @dev Get latest stable checkpoint information. - * @return section index - * @return checkpoint hash - * @return block height associated with checkpoint - */ - function GetLatestCheckpoint() - view - public - returns(uint64, bytes32, uint) { - return (sectionIndex, hash, height); - } - - // SetCheckpoint sets a new checkpoint. It accepts a list of signatures - // @_recentNumber: a recent blocknumber, for replay protection - // @_recentHash : the hash of `_recentNumber` - // @_hash : the hash to set at _sectionIndex - // @_sectionIndex : the section index to set - // @v : the list of v-values - // @r : the list or r-values - // @s : the list of s-values - function SetCheckpoint( - uint _recentNumber, - bytes32 _recentHash, - bytes32 _hash, - uint64 _sectionIndex, - uint8[] memory v, - bytes32[] memory r, - bytes32[] memory s) - public - returns (bool) - { - // Ensure the sender is authorized. - require(admins[msg.sender]); - - // These checks replay protection, so it cannot be replayed on forks, - // accidentally or intentionally - require(blockhash(_recentNumber) == _recentHash); - - // Ensure the batch of signatures are valid. - require(v.length == r.length); - require(v.length == s.length); - - // Filter out "future" checkpoint. - if (block.number < (_sectionIndex+1)*sectionSize+processConfirms) { - return false; - } - // Filter out "old" announcement - if (_sectionIndex < sectionIndex) { - return false; - } - // Filter out "stale" announcement - if (_sectionIndex == sectionIndex && (_sectionIndex != 0 || height != 0)) { - return false; - } - // Filter out "invalid" announcement - if (_hash == ""){ - return false; - } - - // EIP 191 style signatures - // - // Arguments when calculating hash to validate - // 1: byte(0x19) - the initial 0x19 byte - // 2: byte(0) - the version byte (data with intended validator) - // 3: this - the validator address - // -- Application specific data - // 4 : checkpoint section_index(uint64) - // 5 : checkpoint hash (bytes32) - // hash = keccak256(checkpoint_index, section_head, cht_root, bloom_root) - bytes32 signedHash = keccak256(abi.encodePacked(byte(0x19), byte(0), this, _sectionIndex, _hash)); - - address lastVoter = address(0); - - // In order for us not to have to maintain a mapping of who has already - // voted, and we don't want to count a vote twice, the signatures must - // be submitted in strict ordering. - for (uint idx = 0; idx < v.length; idx++){ - address signer = ecrecover(signedHash, v[idx], r[idx], s[idx]); - require(admins[signer]); - require(uint256(signer) > uint256(lastVoter)); - lastVoter = signer; - emit NewCheckpointVote(_sectionIndex, _hash, v[idx], r[idx], s[idx]); - - // Sufficient signatures present, update latest checkpoint. - if (idx+1 >= threshold){ - hash = _hash; - height = block.number; - sectionIndex = _sectionIndex; - return true; - } - } - // We shouldn't wind up here, reverting un-emits the events - revert(); - } - - /** - * @dev Get all admin addresses - * @return address list - */ - function GetAllAdmin() - public - view - returns(address[] memory) - { - address[] memory ret = new address[](adminList.length); - for (uint i = 0; i < adminList.length; i++) { - ret[i] = adminList[i]; - } - return ret; - } - - /* - Fields - */ - // A map of admin users who have the permission to update CHT and bloom Trie root - mapping(address => bool) admins; - - // A list of admin users so that we can obtain all admin users. - address[] adminList; - - // Latest stored section id - uint64 sectionIndex; - - // The block height associated with latest registered checkpoint. - uint height; - - // The hash of latest registered checkpoint. - bytes32 hash; - - // The frequency for creating a checkpoint - // - // The default value should be the same as the checkpoint size(32768) in the ethereum. - uint sectionSize; - - // The number of confirmations needed before a checkpoint can be registered. - // We have to make sure the checkpoint registered will not be invalid due to - // chain reorg. - // - // The default value should be the same as the checkpoint process confirmations(256) - // in the ethereum. - uint processConfirms; - - // The required signatures to finalize a stable checkpoint. - uint threshold; -} diff --git a/contracts/checkpointoracle/oracle.go b/contracts/checkpointoracle/oracle.go deleted file mode 100644 index dec01db244..0000000000 --- a/contracts/checkpointoracle/oracle.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package checkpointoracle is a an on-chain light client checkpoint oracle. -package checkpointoracle - -//go:generate solc contract/oracle.sol --combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize -o ./ --overwrite -//go:generate go run ../../cmd/abigen --pkg contract --out contract/oracle.go --combined-json ./combined.json - -import ( - "errors" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts/checkpointoracle/contract" - "github.com/ethereum/go-ethereum/core/types" -) - -// CheckpointOracle is a Go wrapper around an on-chain checkpoint oracle contract. -type CheckpointOracle struct { - address common.Address - contract *contract.CheckpointOracle -} - -// NewCheckpointOracle binds checkpoint contract and returns a registrar instance. -func NewCheckpointOracle(contractAddr common.Address, backend bind.ContractBackend) (*CheckpointOracle, error) { - c, err := contract.NewCheckpointOracle(contractAddr, backend) - if err != nil { - return nil, err - } - return &CheckpointOracle{address: contractAddr, contract: c}, nil -} - -// ContractAddr returns the address of contract. -func (oracle *CheckpointOracle) ContractAddr() common.Address { - return oracle.address -} - -// Contract returns the underlying contract instance. -func (oracle *CheckpointOracle) Contract() *contract.CheckpointOracle { - return oracle.contract -} - -// LookupCheckpointEvents searches checkpoint event for specific section in the -// given log batches. -func (oracle *CheckpointOracle) LookupCheckpointEvents(blockLogs [][]*types.Log, section uint64, hash common.Hash) []*contract.CheckpointOracleNewCheckpointVote { - var votes []*contract.CheckpointOracleNewCheckpointVote - - for _, logs := range blockLogs { - for _, log := range logs { - event, err := oracle.contract.ParseNewCheckpointVote(*log) - if err != nil { - continue - } - if event.Index == section && event.CheckpointHash == hash { - votes = append(votes, event) - } - } - } - return votes -} - -// RegisterCheckpoint registers the checkpoint with a batch of associated signatures -// that are collected off-chain and sorted by lexicographical order. -// -// Notably all signatures given should be transformed to "ethereum style" which transforms -// v from 0/1 to 27/28 according to the yellow paper. -func (oracle *CheckpointOracle) RegisterCheckpoint(opts *bind.TransactOpts, index uint64, hash []byte, rnum *big.Int, rhash [32]byte, sigs [][]byte) (*types.Transaction, error) { - var ( - r [][32]byte - s [][32]byte - v []uint8 - ) - for i := 0; i < len(sigs); i++ { - if len(sigs[i]) != 65 { - return nil, errors.New("invalid signature") - } - r = append(r, common.BytesToHash(sigs[i][:32])) - s = append(s, common.BytesToHash(sigs[i][32:64])) - v = append(v, sigs[i][64]) - } - return oracle.contract.SetCheckpoint(opts, rnum, rhash, common.BytesToHash(hash), index, v, r, s) -} diff --git a/contracts/checkpointoracle/oracle_test.go b/contracts/checkpointoracle/oracle_test.go deleted file mode 100644 index 61dd8aec79..0000000000 --- a/contracts/checkpointoracle/oracle_test.go +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package checkpointoracle - -import ( - "bytes" - "crypto/ecdsa" - "encoding/binary" - "errors" - "math/big" - "reflect" - "sort" - "testing" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts/checkpointoracle/contract" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/params" -) - -var ( - emptyHash = [32]byte{} - - checkpoint0 = params.TrustedCheckpoint{ - SectionIndex: 0, - SectionHead: common.HexToHash("0x7fa3c32f996c2bfb41a1a65b3d8ea3e0a33a1674cde43678ad6f4235e764d17d"), - CHTRoot: common.HexToHash("0x98fc5d3de23a0fecebad236f6655533c157d26a1aedcd0852a514dc1169e6350"), - BloomRoot: common.HexToHash("0x99b5adb52b337fe25e74c1c6d3835b896bd638611b3aebddb2317cce27a3f9fa"), - } - checkpoint1 = params.TrustedCheckpoint{ - SectionIndex: 1, - SectionHead: common.HexToHash("0x2d4dee68102125e59b0cc61b176bd89f0d12b3b91cfaf52ef8c2c82fb920c2d2"), - CHTRoot: common.HexToHash("0x7d428008ece3b4c4ef5439f071930aad0bb75108d381308df73beadcd01ded95"), - BloomRoot: common.HexToHash("0x652571f7736de17e7bbb427ac881474da684c6988a88bf51b10cca9a2ee148f4"), - } - checkpoint2 = params.TrustedCheckpoint{ - SectionIndex: 2, - SectionHead: common.HexToHash("0x61c0de578c0115b1dff8ef39aa600588c7c6ecb8a2f102003d7cf4c4146e9291"), - CHTRoot: common.HexToHash("0x407a08a407a2bc3838b74ca3eb206903c9c8a186ccf5ef14af07794efff1970b"), - BloomRoot: common.HexToHash("0x058b4161f558ce295a92925efc57f34f9210d5a30088d7475c183e0d3e58f5ac"), - } -) - -var ( - // The block frequency for creating checkpoint(only used in test) - sectionSize = big.NewInt(512) - - // The number of confirmations needed to generate a checkpoint(only used in test). - processConfirms = big.NewInt(4) -) - -// validateOperation executes the operation, watches and delivers all events fired by the backend and ensures the -// correctness by assert function. -func validateOperation(t *testing.T, c *contract.CheckpointOracle, backend *backends.SimulatedBackend, operation func(), - assert func(<-chan *contract.CheckpointOracleNewCheckpointVote) error, opName string) { - // Watch all events and deliver them to assert function - var ( - sink = make(chan *contract.CheckpointOracleNewCheckpointVote) - sub, _ = c.WatchNewCheckpointVote(nil, sink, nil) - ) - defer func() { - // Close all subscribers - sub.Unsubscribe() - }() - operation() - - // flush pending block - backend.Commit() - if err := assert(sink); err != nil { - t.Errorf("operation {%s} failed, err %s", opName, err) - } -} - -// validateEvents checks that the correct number of contract events -// fired by contract backend. -func validateEvents(target int, sink interface{}) (bool, []reflect.Value) { - chanval := reflect.ValueOf(sink) - chantyp := chanval.Type() - if chantyp.Kind() != reflect.Chan || chantyp.ChanDir()&reflect.RecvDir == 0 { - return false, nil - } - count := 0 - var recv []reflect.Value - timeout := time.After(1 * time.Second) - cases := []reflect.SelectCase{{Chan: chanval, Dir: reflect.SelectRecv}, {Chan: reflect.ValueOf(timeout), Dir: reflect.SelectRecv}} - for { - chose, v, _ := reflect.Select(cases) - if chose == 1 { - // Not enough event received - return false, nil - } - count += 1 - recv = append(recv, v) - if count == target { - break - } - } - done := time.After(50 * time.Millisecond) - cases = cases[:1] - cases = append(cases, reflect.SelectCase{Chan: reflect.ValueOf(done), Dir: reflect.SelectRecv}) - chose, _, _ := reflect.Select(cases) - // If chose equal 0, it means receiving redundant events. - return chose == 1, recv -} - -func signCheckpoint(addr common.Address, privateKey *ecdsa.PrivateKey, index uint64, hash common.Hash) []byte { - // EIP 191 style signatures - // - // Arguments when calculating hash to validate - // 1: byte(0x19) - the initial 0x19 byte - // 2: byte(0) - the version byte (data with intended validator) - // 3: this - the validator address - // -- Application specific data - // 4 : checkpoint section_index(uint64) - // 5 : checkpoint hash (bytes32) - // hash = keccak256(checkpoint_index, section_head, cht_root, bloom_root) - buf := make([]byte, 8) - binary.BigEndian.PutUint64(buf, index) - data := append([]byte{0x19, 0x00}, append(addr.Bytes(), append(buf, hash.Bytes()...)...)...) - sig, _ := crypto.Sign(crypto.Keccak256(data), privateKey) - sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper - return sig -} - -// assertSignature verifies whether the recovered signers are equal with expected. -func assertSignature(addr common.Address, index uint64, hash [32]byte, r, s [32]byte, v uint8, expect common.Address) bool { - buf := make([]byte, 8) - binary.BigEndian.PutUint64(buf, index) - data := append([]byte{0x19, 0x00}, append(addr.Bytes(), append(buf, hash[:]...)...)...) - pubkey, err := crypto.Ecrecover(crypto.Keccak256(data), append(r[:], append(s[:], v-27)...)) - if err != nil { - return false - } - var signer common.Address - copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) - return bytes.Equal(signer.Bytes(), expect.Bytes()) -} - -type Account struct { - key *ecdsa.PrivateKey - addr common.Address -} -type Accounts []Account - -func (a Accounts) Len() int { return len(a) } -func (a Accounts) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a Accounts) Less(i, j int) bool { return bytes.Compare(a[i].addr.Bytes(), a[j].addr.Bytes()) < 0 } - -func TestCheckpointRegister(t *testing.T) { - // Initialize test accounts - var accounts Accounts - for i := 0; i < 3; i++ { - key, _ := crypto.GenerateKey() - addr := crypto.PubkeyToAddress(key.PublicKey) - accounts = append(accounts, Account{key: key, addr: addr}) - } - sort.Sort(accounts) - - // Deploy registrar contract - contractBackend := backends.NewSimulatedBackend( - core.GenesisAlloc{ - accounts[0].addr: {Balance: big.NewInt(10000000000000000)}, - accounts[1].addr: {Balance: big.NewInt(10000000000000000)}, - accounts[2].addr: {Balance: big.NewInt(10000000000000000)}, - }, 10000000, - ) - defer contractBackend.Close() - - transactOpts, _ := bind.NewKeyedTransactorWithChainID(accounts[0].key, big.NewInt(1337)) - - // 3 trusted signers, threshold 2 - contractAddr, _, c, err := contract.DeployCheckpointOracle(transactOpts, contractBackend, []common.Address{accounts[0].addr, accounts[1].addr, accounts[2].addr}, sectionSize, processConfirms, big.NewInt(2)) - if err != nil { - t.Error("Failed to deploy registrar contract", err) - } - contractBackend.Commit() - - // getRecent returns block height and hash of the head parent. - getRecent := func() (*big.Int, common.Hash) { - parentNumber := new(big.Int).Sub(contractBackend.Blockchain().CurrentHeader().Number, big.NewInt(1)) - parentHash := contractBackend.Blockchain().CurrentHeader().ParentHash - return parentNumber, parentHash - } - // collectSig generates specified number signatures. - collectSig := func(index uint64, hash common.Hash, n int, unauthorized *ecdsa.PrivateKey) (v []uint8, r [][32]byte, s [][32]byte) { - for i := 0; i < n; i++ { - sig := signCheckpoint(contractAddr, accounts[i].key, index, hash) - if unauthorized != nil { - sig = signCheckpoint(contractAddr, unauthorized, index, hash) - } - r = append(r, common.BytesToHash(sig[:32])) - s = append(s, common.BytesToHash(sig[32:64])) - v = append(v, sig[64]) - } - return v, r, s - } - // insertEmptyBlocks inserts a batch of empty blocks to blockchain. - insertEmptyBlocks := func(number int) { - for i := 0; i < number; i++ { - contractBackend.Commit() - } - } - // assert checks whether the current contract status is same with - // the expected. - assert := func(index uint64, hash [32]byte, height *big.Int) error { - lindex, lhash, lheight, err := c.GetLatestCheckpoint(nil) - if err != nil { - return err - } - if lindex != index { - return errors.New("latest checkpoint index mismatch") - } - if !bytes.Equal(lhash[:], hash[:]) { - return errors.New("latest checkpoint hash mismatch") - } - if lheight.Cmp(height) != 0 { - return errors.New("latest checkpoint height mismatch") - } - return nil - } - - // Test future checkpoint registration - validateOperation(t, c, contractBackend, func() { - number, hash := getRecent() - v, r, s := collectSig(0, checkpoint0.Hash(), 2, nil) - c.SetCheckpoint(transactOpts, number, hash, checkpoint0.Hash(), 0, v, r, s) - }, func(events <-chan *contract.CheckpointOracleNewCheckpointVote) error { - return assert(0, emptyHash, big.NewInt(0)) - }, "test future checkpoint registration") - - insertEmptyBlocks(int(sectionSize.Uint64() + processConfirms.Uint64())) - - // Test transaction replay protection - validateOperation(t, c, contractBackend, func() { - number, _ := getRecent() - v, r, s := collectSig(0, checkpoint0.Hash(), 2, nil) - hash := common.HexToHash("deadbeef") - c.SetCheckpoint(transactOpts, number, hash, checkpoint0.Hash(), 0, v, r, s) - }, func(events <-chan *contract.CheckpointOracleNewCheckpointVote) error { - return assert(0, emptyHash, big.NewInt(0)) - }, "test transaction replay protection") - - // Test unauthorized signature checking - validateOperation(t, c, contractBackend, func() { - number, hash := getRecent() - u, _ := crypto.GenerateKey() - v, r, s := collectSig(0, checkpoint0.Hash(), 2, u) - c.SetCheckpoint(transactOpts, number, hash, checkpoint0.Hash(), 0, v, r, s) - }, func(events <-chan *contract.CheckpointOracleNewCheckpointVote) error { - return assert(0, emptyHash, big.NewInt(0)) - }, "test unauthorized signature checking") - - // Test un-multi-signature checkpoint registration - validateOperation(t, c, contractBackend, func() { - number, hash := getRecent() - v, r, s := collectSig(0, checkpoint0.Hash(), 1, nil) - c.SetCheckpoint(transactOpts, number, hash, checkpoint0.Hash(), 0, v, r, s) - }, func(events <-chan *contract.CheckpointOracleNewCheckpointVote) error { - return assert(0, emptyHash, big.NewInt(0)) - }, "test un-multi-signature checkpoint registration") - - // Test valid checkpoint registration - validateOperation(t, c, contractBackend, func() { - number, hash := getRecent() - v, r, s := collectSig(0, checkpoint0.Hash(), 2, nil) - c.SetCheckpoint(transactOpts, number, hash, checkpoint0.Hash(), 0, v, r, s) - }, func(events <-chan *contract.CheckpointOracleNewCheckpointVote) error { - if valid, recv := validateEvents(2, events); !valid { - return errors.New("receive incorrect number of events") - } else { - for i := 0; i < len(recv); i++ { - event := recv[i].Interface().(*contract.CheckpointOracleNewCheckpointVote) - if !assertSignature(contractAddr, event.Index, event.CheckpointHash, event.R, event.S, event.V, accounts[i].addr) { - return errors.New("recover signer failed") - } - } - } - number, _ := getRecent() - return assert(0, checkpoint0.Hash(), number.Add(number, big.NewInt(1))) - }, "test valid checkpoint registration") - - distance := 3*sectionSize.Uint64() + processConfirms.Uint64() - contractBackend.Blockchain().CurrentHeader().Number.Uint64() - insertEmptyBlocks(int(distance)) - - // Test uncontinuous checkpoint registration - validateOperation(t, c, contractBackend, func() { - number, hash := getRecent() - v, r, s := collectSig(2, checkpoint2.Hash(), 2, nil) - c.SetCheckpoint(transactOpts, number, hash, checkpoint2.Hash(), 2, v, r, s) - }, func(events <-chan *contract.CheckpointOracleNewCheckpointVote) error { - if valid, recv := validateEvents(2, events); !valid { - return errors.New("receive incorrect number of events") - } else { - for i := 0; i < len(recv); i++ { - event := recv[i].Interface().(*contract.CheckpointOracleNewCheckpointVote) - if !assertSignature(contractAddr, event.Index, event.CheckpointHash, event.R, event.S, event.V, accounts[i].addr) { - return errors.New("recover signer failed") - } - } - } - number, _ := getRecent() - return assert(2, checkpoint2.Hash(), number.Add(number, big.NewInt(1))) - }, "test uncontinuous checkpoint registration") - - // Test old checkpoint registration - validateOperation(t, c, contractBackend, func() { - number, hash := getRecent() - v, r, s := collectSig(1, checkpoint1.Hash(), 2, nil) - c.SetCheckpoint(transactOpts, number, hash, checkpoint1.Hash(), 1, v, r, s) - }, func(events <-chan *contract.CheckpointOracleNewCheckpointVote) error { - number, _ := getRecent() - return assert(2, checkpoint2.Hash(), number) - }, "test uncontinuous checkpoint registration") - - // Test stale checkpoint registration - validateOperation(t, c, contractBackend, func() { - number, hash := getRecent() - v, r, s := collectSig(2, checkpoint2.Hash(), 2, nil) - c.SetCheckpoint(transactOpts, number, hash, checkpoint2.Hash(), 2, v, r, s) - }, func(events <-chan *contract.CheckpointOracleNewCheckpointVote) error { - number, _ := getRecent() - return assert(2, checkpoint2.Hash(), number.Sub(number, big.NewInt(1))) - }, "test stale checkpoint registration") -} diff --git a/eth/backend.go b/eth/backend.go index 6368c0e03c..105a8e8977 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -211,10 +211,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { // Permit the downloader to use the trie cache allowance during fast sync cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit - checkpoint := config.Checkpoint - if checkpoint == nil { - checkpoint = params.TrustedCheckpoints[eth.blockchain.Genesis().Hash()] - } if eth.handler, err = newHandler(&handlerConfig{ Database: chainDb, Chain: eth.blockchain, @@ -224,7 +220,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { Sync: config.SyncMode, BloomCache: uint64(cacheLimit), EventMux: eth.eventMux, - Checkpoint: checkpoint, RequiredBlocks: config.RequiredBlocks, }); err != nil { return nil, err diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index a3d8a21060..1e2022ba7b 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -101,10 +101,9 @@ type Downloader struct { mode atomic.Uint32 // Synchronisation mode defining the strategy used (per sync cycle), use d.getMode() to get the SyncMode mux *event.TypeMux // Event multiplexer to announce sync operation events - checkpoint uint64 // Checkpoint block number to enforce head against (e.g. snap sync) - genesis uint64 // Genesis block number to limit sync to (e.g. light client CHT) - queue *queue // Scheduler for selecting the hashes to download - peers *peerSet // Set of active peers from which download can proceed + genesis uint64 // Genesis block number to limit sync to (e.g. light client CHT) + queue *queue // Scheduler for selecting the hashes to download + peers *peerSet // Set of active peers from which download can proceed stateDB ethdb.Database // Database to state sync into (and deduplicate via) @@ -219,14 +218,13 @@ type BlockChain interface { } // New creates a new downloader to fetch hashes and blocks from remote peers. -func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func()) *Downloader { +func New(stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func()) *Downloader { if lightchain == nil { lightchain = chain } dl := &Downloader{ stateDB: stateDb, mux: mux, - checkpoint: checkpoint, queue: newQueue(blockCacheMaxItems, blockCacheInitialItems), peers: newPeerSet(), blockchain: chain, @@ -593,11 +591,9 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * d.ancientLimit = 0 } } else { - // Legacy sync, use any hardcoded checkpoints or the best announcement - // we have from the remote peer. TODO(karalabe): Drop this pathway. - if d.checkpoint != 0 && d.checkpoint > fullMaxForkAncestry+1 { - d.ancientLimit = d.checkpoint - } else if height > fullMaxForkAncestry+1 { + // Legacy sync, use the best announcement we have from the remote peer. + // TODO(karalabe): Drop this pathway. + if height > fullMaxForkAncestry+1 { d.ancientLimit = height - fullMaxForkAncestry - 1 } else { d.ancientLimit = 0 @@ -742,13 +738,10 @@ func (d *Downloader) fetchHead(p *peerConnection) (head *types.Header, pivot *ty if len(headers) == 0 || len(headers) > fetch { return nil, nil, fmt.Errorf("%w: returned headers %d != requested %d", errBadPeer, len(headers), fetch) } - // The first header needs to be the head, validate against the checkpoint - // and request. If only 1 header was returned, make sure there's no pivot - // or there was not one requested. + // The first header needs to be the head, validate against the request. If + // only 1 header was returned, make sure there's no pivot or there was not + // one requested. head = headers[0] - if (mode == SnapSync || mode == LightSync) && head.Number.Uint64() < d.checkpoint { - return nil, nil, fmt.Errorf("%w: remote head %d below checkpoint %d", errUnsyncedPeer, head.Number, d.checkpoint) - } if len(headers) == 1 { if mode == SnapSync && head.Number.Uint64() > uint64(fsMinFullBlocks) { return nil, nil, fmt.Errorf("%w: no pivot included along head header", errBadPeer) diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 37f7a76704..06c22afff0 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -17,7 +17,6 @@ package downloader import ( - "errors" "fmt" "math/big" "os" @@ -82,7 +81,7 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester { chain: chain, peers: make(map[string]*downloadTesterPeer), } - tester.downloader = New(0, db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, success) + tester.downloader = New(db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, success) return tester } @@ -1409,44 +1408,6 @@ func TestRemoteHeaderRequestSpan(t *testing.T) { } } -// Tests that peers below a pre-configured checkpoint block are prevented from -// being fast-synced from, avoiding potential cheap eclipse attacks. -func TestCheckpointEnforcement66Full(t *testing.T) { testCheckpointEnforcement(t, eth.ETH66, FullSync) } -func TestCheckpointEnforcement66Snap(t *testing.T) { testCheckpointEnforcement(t, eth.ETH66, SnapSync) } -func TestCheckpointEnforcement66Light(t *testing.T) { - testCheckpointEnforcement(t, eth.ETH66, LightSync) -} -func TestCheckpointEnforcement67Full(t *testing.T) { testCheckpointEnforcement(t, eth.ETH67, FullSync) } -func TestCheckpointEnforcement67Snap(t *testing.T) { testCheckpointEnforcement(t, eth.ETH67, SnapSync) } -func TestCheckpointEnforcement67Light(t *testing.T) { - testCheckpointEnforcement(t, eth.ETH67, LightSync) -} - -func testCheckpointEnforcement(t *testing.T, protocol uint, mode SyncMode) { - // Create a new tester with a particular hard coded checkpoint block - tester := newTester(t) - defer tester.terminate() - - tester.downloader.checkpoint = uint64(fsMinFullBlocks) + 256 - chain := testChainBase.shorten(int(tester.downloader.checkpoint) - 1) - - // Attempt to sync with the peer and validate the result - tester.newPeer("peer", protocol, chain.blocks[1:]) - - var expect error - if mode == SnapSync || mode == LightSync { - expect = errUnsyncedPeer - } - if err := tester.sync("peer", nil, mode); !errors.Is(err, expect) { - t.Fatalf("block sync error mismatch: have %v, want %v", err, expect) - } - if mode == SnapSync || mode == LightSync { - assertOwnChain(t, tester, 1) - } else { - assertOwnChain(t, tester, len(chain.blocks)) - } -} - // Tests that peers below a pre-configured checkpoint block are prevented from // being fast-synced from, avoiding potential cheap eclipse attacks. func TestBeaconSync66Full(t *testing.T) { testBeaconSync(t, eth.ETH66, FullSync) } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index db686c5d08..3d26cf69a2 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -141,13 +141,12 @@ type Config struct { RequiredBlocks map[uint64]common.Hash `toml:"-"` // Light client options - LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests - LightIngress int `toml:",omitempty"` // Incoming bandwidth limit for light servers - LightEgress int `toml:",omitempty"` // Outgoing bandwidth limit for light servers - LightPeers int `toml:",omitempty"` // Maximum number of LES client peers - LightNoPrune bool `toml:",omitempty"` // Whether to disable light chain pruning - LightNoSyncServe bool `toml:",omitempty"` // Whether to serve light clients before syncing - SyncFromCheckpoint bool `toml:",omitempty"` // Whether to sync the header chain from the configured checkpoint + LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests + LightIngress int `toml:",omitempty"` // Incoming bandwidth limit for light servers + LightEgress int `toml:",omitempty"` // Outgoing bandwidth limit for light servers + LightPeers int `toml:",omitempty"` // Maximum number of LES client peers + LightNoPrune bool `toml:",omitempty"` // Whether to disable light chain pruning + LightNoSyncServe bool `toml:",omitempty"` // Whether to serve light clients before syncing // Ultra Light client options UltraLightServers []string `toml:",omitempty"` // List of trusted ultra light servers @@ -199,12 +198,6 @@ type Config struct { // send-transaction variants. The unit is ether. RPCTxFeeCap float64 - // Checkpoint is a hardcoded checkpoint which can be nil. - Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` - - // CheckpointOracle is the configuration for checkpoint oracle. - CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - // OverrideShanghai (TODO: remove after the fork) OverrideShanghai *uint64 `toml:",omitempty"` } diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index b7255a242e..3ab4340144 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -12,7 +12,6 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/miner" - "github.com/ethereum/go-ethereum/params" ) // MarshalTOML marshals as TOML. @@ -33,7 +32,6 @@ func (c Config) MarshalTOML() (interface{}, error) { LightPeers int `toml:",omitempty"` LightNoPrune bool `toml:",omitempty"` LightNoSyncServe bool `toml:",omitempty"` - SyncFromCheckpoint bool `toml:",omitempty"` UltraLightServers []string `toml:",omitempty"` UltraLightFraction int `toml:",omitempty"` UltraLightOnlyAnnounce bool `toml:",omitempty"` @@ -58,9 +56,7 @@ func (c Config) MarshalTOML() (interface{}, error) { RPCGasCap uint64 RPCEVMTimeout time.Duration RPCTxFeeCap float64 - Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` - CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - OverrideShanghai *uint64 `toml:",omitempty"` + OverrideShanghai *uint64 `toml:",omitempty"` } var enc Config enc.Genesis = c.Genesis @@ -78,7 +74,6 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.LightPeers = c.LightPeers enc.LightNoPrune = c.LightNoPrune enc.LightNoSyncServe = c.LightNoSyncServe - enc.SyncFromCheckpoint = c.SyncFromCheckpoint enc.UltraLightServers = c.UltraLightServers enc.UltraLightFraction = c.UltraLightFraction enc.UltraLightOnlyAnnounce = c.UltraLightOnlyAnnounce @@ -103,8 +98,6 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCGasCap = c.RPCGasCap enc.RPCEVMTimeout = c.RPCEVMTimeout enc.RPCTxFeeCap = c.RPCTxFeeCap - enc.Checkpoint = c.Checkpoint - enc.CheckpointOracle = c.CheckpointOracle enc.OverrideShanghai = c.OverrideShanghai return &enc, nil } @@ -127,7 +120,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { LightPeers *int `toml:",omitempty"` LightNoPrune *bool `toml:",omitempty"` LightNoSyncServe *bool `toml:",omitempty"` - SyncFromCheckpoint *bool `toml:",omitempty"` UltraLightServers []string `toml:",omitempty"` UltraLightFraction *int `toml:",omitempty"` UltraLightOnlyAnnounce *bool `toml:",omitempty"` @@ -152,9 +144,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { RPCGasCap *uint64 RPCEVMTimeout *time.Duration RPCTxFeeCap *float64 - Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` - CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - OverrideShanghai *uint64 `toml:",omitempty"` + OverrideShanghai *uint64 `toml:",omitempty"` } var dec Config if err := unmarshal(&dec); err != nil { @@ -205,9 +195,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.LightNoSyncServe != nil { c.LightNoSyncServe = *dec.LightNoSyncServe } - if dec.SyncFromCheckpoint != nil { - c.SyncFromCheckpoint = *dec.SyncFromCheckpoint - } if dec.UltraLightServers != nil { c.UltraLightServers = dec.UltraLightServers } @@ -280,12 +267,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.RPCTxFeeCap != nil { c.RPCTxFeeCap = *dec.RPCTxFeeCap } - if dec.Checkpoint != nil { - c.Checkpoint = dec.Checkpoint - } - if dec.CheckpointOracle != nil { - c.CheckpointOracle = dec.CheckpointOracle - } if dec.OverrideShanghai != nil { c.OverrideShanghai = dec.OverrideShanghai } diff --git a/eth/handler.go b/eth/handler.go index 83df6ff2eb..71ed6b227d 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -38,7 +38,6 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/params" ) const ( @@ -77,16 +76,15 @@ type txPool interface { // handlerConfig is the collection of initialization parameters to create a full // node network handler. type handlerConfig struct { - Database ethdb.Database // Database for direct sync insertions - Chain *core.BlockChain // Blockchain to serve data from - TxPool txPool // Transaction pool to propagate from - Merger *consensus.Merger // The manager for eth1/2 transition - Network uint64 // Network identifier to adfvertise - Sync downloader.SyncMode // Whether to snap or full sync - BloomCache uint64 // Megabytes to alloc for snap sync bloom - EventMux *event.TypeMux // Legacy event mux, deprecate for `feed` - Checkpoint *params.TrustedCheckpoint // Hard coded checkpoint for sync challenges - RequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges + Database ethdb.Database // Database for direct sync insertions + Chain *core.BlockChain // Blockchain to serve data from + TxPool txPool // Transaction pool to propagate from + Merger *consensus.Merger // The manager for eth1/2 transition + Network uint64 // Network identifier to adfvertise + Sync downloader.SyncMode // Whether to snap or full sync + BloomCache uint64 // Megabytes to alloc for snap sync bloom + EventMux *event.TypeMux // Legacy event mux, deprecate for `feed` + RequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges } type handler struct { @@ -96,9 +94,6 @@ type handler struct { snapSync uint32 // Flag whether snap sync is enabled (gets disabled if we already have blocks) acceptTxs uint32 // Flag whether we're considered synchronised (enables transaction processing) - checkpointNumber uint64 // Block number for the sync progress validator to cross reference - checkpointHash common.Hash // Block hash for the sync progress validator to cross reference - database ethdb.Database txpool txPool chain *core.BlockChain @@ -166,11 +161,6 @@ func newHandler(config *handlerConfig) (*handler, error) { h.snapSync = uint32(1) } } - // If we have trusted checkpoints, enforce them on the chain - if config.Checkpoint != nil { - h.checkpointNumber = (config.Checkpoint.SectionIndex+1)*params.CHTFrequency - 1 - h.checkpointHash = config.Checkpoint.SectionHead - } // If sync succeeds, pass a callback to potentially disable snap sync mode // and enable transaction propagation. success := func() { @@ -180,19 +170,12 @@ func newHandler(config *handlerConfig) (*handler, error) { log.Info("Snap sync complete, auto disabling") atomic.StoreUint32(&h.snapSync, 0) } - // If we've successfully finished a sync cycle and passed any required - // checkpoint, enable accepting transactions from the network - head := h.chain.CurrentBlock() - if head.Number.Uint64() >= h.checkpointNumber { - // Checkpoint passed, sanity check the timestamp to have a fallback mechanism - // for non-checkpointed (number = 0) private networks. - if head.Time >= uint64(time.Now().AddDate(0, -1, 0).Unix()) { - atomic.StoreUint32(&h.acceptTxs, 1) - } - } + // If we've successfully finished a sync cycle, accept transactions from + // the network + atomic.StoreUint32(&h.acceptTxs, 1) } // Construct the downloader (long sync) - h.downloader = downloader.New(h.checkpointNumber, config.Database, h.eventMux, h.chain, nil, h.removePeer, success) + h.downloader = downloader.New(config.Database, h.eventMux, h.chain, nil, h.removePeer, success) if ttd := h.chain.Config().TerminalTotalDifficulty; ttd != nil { if h.chain.Config().TerminalTotalDifficultyPassed { log.Info("Chain post-merge, sync via beacon client") @@ -244,16 +227,6 @@ func newHandler(config *handlerConfig) (*handler, error) { log.Warn("Unexpected insertion activity", ctx...) return 0, errors.New("unexpected behavior after transition") } - // If sync hasn't reached the checkpoint yet, deny importing weird blocks. - // - // Ideally we would also compare the head block's timestamp and similarly reject - // the propagated block if the head is too old. Unfortunately there is a corner - // case when starting new networks, where the genesis might be ancient (0 unix) - // which would prevent full nodes from accepting it. - if h.chain.CurrentBlock().Number.Uint64() < h.checkpointNumber { - log.Warn("Unsynced yet, discarded propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash()) - return 0, nil - } // If snap sync is running, deny importing weird blocks. This is a problematic // clause when starting up a new network, because snap-syncing miners might not // accept each others' blocks until a restart. Unfortunately we haven't figured @@ -387,58 +360,6 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { dead := make(chan struct{}) defer close(dead) - // If we have a trusted CHT, reject all peers below that (avoid fast sync eclipse) - if h.checkpointHash != (common.Hash{}) { - // Request the peer's checkpoint header for chain height/weight validation - resCh := make(chan *eth.Response) - - req, err := peer.RequestHeadersByNumber(h.checkpointNumber, 1, 0, false, resCh) - if err != nil { - return err - } - // Start a timer to disconnect if the peer doesn't reply in time - go func() { - // Ensure the request gets cancelled in case of error/drop - defer req.Close() - - timeout := time.NewTimer(syncChallengeTimeout) - defer timeout.Stop() - - select { - case res := <-resCh: - headers := ([]*types.Header)(*res.Res.(*eth.BlockHeadersPacket)) - if len(headers) == 0 { - // If we're doing a snap sync, we must enforce the checkpoint - // block to avoid eclipse attacks. Unsynced nodes are welcome - // to connect after we're done joining the network. - if atomic.LoadUint32(&h.snapSync) == 1 { - peer.Log().Warn("Dropping unsynced node during sync", "addr", peer.RemoteAddr(), "type", peer.Name()) - res.Done <- errors.New("unsynced node cannot serve sync") - return - } - res.Done <- nil - return - } - // Validate the header and either drop the peer or continue - if len(headers) > 1 { - res.Done <- errors.New("too many headers in checkpoint response") - return - } - if headers[0].Hash() != h.checkpointHash { - res.Done <- errors.New("checkpoint hash mismatch") - return - } - res.Done <- nil - - case <-timeout.C: - peer.Log().Warn("Checkpoint challenge timed out, dropping", "addr", peer.RemoteAddr(), "type", peer.Name()) - h.removePeer(peer.ID()) - - case <-dead: - // Peer handler terminated, abort all goroutines - } - }() - } // If we have any explicit peer required block hashes, request them for number, hash := range h.requiredBlocks { resCh := make(chan *eth.Response) diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 9f0dd8ec5d..d51d01de9e 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -19,8 +19,6 @@ package eth import ( "fmt" "math/big" - "math/rand" - "sync/atomic" "testing" "time" @@ -38,7 +36,6 @@ import ( "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rlp" ) // testEthHandler is a mock event handler to listen for inbound network requests @@ -459,148 +456,6 @@ func testTransactionPropagation(t *testing.T, protocol uint) { } } -// Tests that post eth protocol handshake, clients perform a mutual checkpoint -// challenge to validate each other's chains. Hash mismatches, or missing ones -// during a fast sync should lead to the peer getting dropped. -func TestCheckpointChallenge(t *testing.T) { - tests := []struct { - syncmode downloader.SyncMode - checkpoint bool - timeout bool - empty bool - match bool - drop bool - }{ - // If checkpointing is not enabled locally, don't challenge and don't drop - {downloader.FullSync, false, false, false, false, false}, - {downloader.SnapSync, false, false, false, false, false}, - - // If checkpointing is enabled locally and remote response is empty, only drop during fast sync - {downloader.FullSync, true, false, true, false, false}, - {downloader.SnapSync, true, false, true, false, true}, // Special case, fast sync, unsynced peer - - // If checkpointing is enabled locally and remote response mismatches, always drop - {downloader.FullSync, true, false, false, false, true}, - {downloader.SnapSync, true, false, false, false, true}, - - // If checkpointing is enabled locally and remote response matches, never drop - {downloader.FullSync, true, false, false, true, false}, - {downloader.SnapSync, true, false, false, true, false}, - - // If checkpointing is enabled locally and remote times out, always drop - {downloader.FullSync, true, true, false, true, true}, - {downloader.SnapSync, true, true, false, true, true}, - } - for _, tt := range tests { - t.Run(fmt.Sprintf("sync %v checkpoint %v timeout %v empty %v match %v", tt.syncmode, tt.checkpoint, tt.timeout, tt.empty, tt.match), func(t *testing.T) { - testCheckpointChallenge(t, tt.syncmode, tt.checkpoint, tt.timeout, tt.empty, tt.match, tt.drop) - }) - } -} - -func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpoint bool, timeout bool, empty bool, match bool, drop bool) { - // Reduce the checkpoint handshake challenge timeout - defer func(old time.Duration) { syncChallengeTimeout = old }(syncChallengeTimeout) - syncChallengeTimeout = 250 * time.Millisecond - - // Create a test handler and inject a CHT into it. The injection is a bit - // ugly, but it beats creating everything manually just to avoid reaching - // into the internals a bit. - handler := newTestHandler() - defer handler.close() - - if syncmode == downloader.SnapSync { - atomic.StoreUint32(&handler.handler.snapSync, 1) - } else { - atomic.StoreUint32(&handler.handler.snapSync, 0) - } - var response *types.Header - if checkpoint { - number := (uint64(rand.Intn(500))+1)*params.CHTFrequency - 1 - response = &types.Header{Number: big.NewInt(int64(number)), Extra: []byte("valid")} - - handler.handler.checkpointNumber = number - handler.handler.checkpointHash = response.Hash() - } - - // Create a challenger peer and a challenged one. - p2pLocal, p2pRemote := p2p.MsgPipe() - defer p2pLocal.Close() - defer p2pRemote.Close() - - local := eth.NewPeer(eth.ETH66, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pLocal), p2pLocal, handler.txpool) - remote := eth.NewPeer(eth.ETH66, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pRemote), p2pRemote, handler.txpool) - defer local.Close() - defer remote.Close() - - handlerDone := make(chan struct{}) - go func() { - defer close(handlerDone) - handler.handler.runEthPeer(local, func(peer *eth.Peer) error { - return eth.Handle((*ethHandler)(handler.handler), peer) - }) - }() - - // Run the handshake locally to avoid spinning up a remote handler. - var ( - genesis = handler.chain.Genesis() - head = handler.chain.CurrentBlock() - td = handler.chain.GetTd(head.Hash(), head.Number.Uint64()) - ) - if err := remote.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil { - t.Fatalf("failed to run protocol handshake") - } - // Connect a new peer and check that we receive the checkpoint challenge. - if checkpoint { - msg, err := p2pRemote.ReadMsg() - if err != nil { - t.Fatalf("failed to read checkpoint challenge: %v", err) - } - request := new(eth.GetBlockHeadersPacket66) - if err := msg.Decode(request); err != nil { - t.Fatalf("failed to decode checkpoint challenge: %v", err) - } - query := request.GetBlockHeadersPacket - if query.Origin.Number != response.Number.Uint64() || query.Amount != 1 || query.Skip != 0 || query.Reverse { - t.Fatalf("challenge mismatch: have [%d, %d, %d, %v] want [%d, %d, %d, %v]", - query.Origin.Number, query.Amount, query.Skip, query.Reverse, - response.Number.Uint64(), 1, 0, false) - } - // Create a block to reply to the challenge if no timeout is simulated. - if !timeout { - if empty { - if err := remote.ReplyBlockHeadersRLP(request.RequestId, []rlp.RawValue{}); err != nil { - t.Fatalf("failed to answer challenge: %v", err) - } - } else if match { - responseRlp, _ := rlp.EncodeToBytes(response) - if err := remote.ReplyBlockHeadersRLP(request.RequestId, []rlp.RawValue{responseRlp}); err != nil { - t.Fatalf("failed to answer challenge: %v", err) - } - } else { - responseRlp, _ := rlp.EncodeToBytes(&types.Header{Number: response.Number}) - if err := remote.ReplyBlockHeadersRLP(request.RequestId, []rlp.RawValue{responseRlp}); err != nil { - t.Fatalf("failed to answer challenge: %v", err) - } - } - } - } - // Wait until the test timeout passes to ensure proper cleanup - time.Sleep(syncChallengeTimeout + 300*time.Millisecond) - - // Verify that the remote peer is maintained or dropped. - if drop { - <-handlerDone - if peers := handler.handler.peers.len(); peers != 0 { - t.Fatalf("peer count mismatch: have %d, want %d", peers, 0) - } - } else { - if peers := handler.handler.peers.len(); peers != 1 { - t.Fatalf("peer count mismatch: have %d, want %d", peers, 1) - } - } -} - // Tests that blocks are broadcast to a sqrt number of peers only. func TestBroadcastBlock1Peer(t *testing.T) { testBroadcastBlock(t, 1, 1) } func TestBroadcastBlock2Peers(t *testing.T) { testBroadcastBlock(t, 2, 1) } diff --git a/eth/sync.go b/eth/sync.go index 6d764ef482..e56d470cfc 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -260,16 +260,11 @@ func (h *handler) doSync(op *chainSyncOp) error { log.Info("Snap sync complete, auto disabling") atomic.StoreUint32(&h.snapSync, 0) } - // If we've successfully finished a sync cycle and passed any required checkpoint, - // enable accepting transactions from the network. + // If we've successfully finished a sync cycle, enable accepting transactions + // from the network. + atomic.StoreUint32(&h.acceptTxs, 1) + head := h.chain.CurrentBlock() - if head.Number.Uint64() >= h.checkpointNumber { - // Checkpoint passed, sanity check the timestamp to have a fallback mechanism - // for non-checkpointed (number = 0) private networks. - if head.Time >= uint64(time.Now().AddDate(0, -1, 0).Unix()) { - atomic.StoreUint32(&h.acceptTxs, 1) - } - } if head.Number.Uint64() > 0 { // We've completed a sync cycle, notify all peers of new state. This path is // essential in star-topology networks where a gateway node needs to notify diff --git a/les/api.go b/les/api.go index 3b21b635ac..e8490f7b0f 100644 --- a/les/api.go +++ b/les/api.go @@ -21,17 +21,12 @@ import ( "fmt" "time" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/mclock" vfs "github.com/ethereum/go-ethereum/les/vflux/server" "github.com/ethereum/go-ethereum/p2p/enode" ) -var ( - errNoCheckpoint = errors.New("no local checkpoint provided") - errNotActivated = errors.New("checkpoint registrar is not activated") - errUnknownBenchmarkType = errors.New("unknown benchmark type") -) +var errUnknownBenchmarkType = errors.New("unknown benchmark type") // LightServerAPI provides an API to access the LES light server. type LightServerAPI struct { @@ -352,57 +347,3 @@ func (api *DebugAPI) FreezeClient(node string) error { return fmt.Errorf("client %064x is not connected", id[:]) } } - -// LightAPI provides an API to access the LES light server or light client. -type LightAPI struct { - backend *lesCommons -} - -// NewLightAPI creates a new LES service API. -func NewLightAPI(backend *lesCommons) *LightAPI { - return &LightAPI{backend: backend} -} - -// LatestCheckpoint returns the latest local checkpoint package. -// -// The checkpoint package consists of 4 strings: -// -// result[0], hex encoded latest section index -// result[1], 32 bytes hex encoded latest section head hash -// result[2], 32 bytes hex encoded latest section canonical hash trie root hash -// result[3], 32 bytes hex encoded latest section bloom trie root hash -func (api *LightAPI) LatestCheckpoint() ([4]string, error) { - var res [4]string - cp := api.backend.latestLocalCheckpoint() - if cp.Empty() { - return res, errNoCheckpoint - } - res[0] = hexutil.EncodeUint64(cp.SectionIndex) - res[1], res[2], res[3] = cp.SectionHead.Hex(), cp.CHTRoot.Hex(), cp.BloomRoot.Hex() - return res, nil -} - -// GetCheckpoint returns the specific local checkpoint package. -// -// The checkpoint package consists of 3 strings: -// -// result[0], 32 bytes hex encoded latest section head hash -// result[1], 32 bytes hex encoded latest section canonical hash trie root hash -// result[2], 32 bytes hex encoded latest section bloom trie root hash -func (api *LightAPI) GetCheckpoint(index uint64) ([3]string, error) { - var res [3]string - cp := api.backend.localCheckpoint(index) - if cp.Empty() { - return res, errNoCheckpoint - } - res[0], res[1], res[2] = cp.SectionHead.Hex(), cp.CHTRoot.Hex(), cp.BloomRoot.Hex() - return res, nil -} - -// GetCheckpointContractAddress returns the contract contract address in hex format. -func (api *LightAPI) GetCheckpointContractAddress() (string, error) { - if api.backend.oracle == nil { - return "", errNotActivated - } - return api.backend.oracle.Contract().ContractAddr().Hex(), nil -} diff --git a/les/checkpointoracle/oracle.go b/les/checkpointoracle/oracle.go deleted file mode 100644 index 6ad1ea2938..0000000000 --- a/les/checkpointoracle/oracle.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2020 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package checkpointoracle is a wrapper of checkpoint oracle contract with -// additional rules defined. This package can be used both in LES client or -// server side for offering oracle related APIs. -package checkpointoracle - -import ( - "encoding/binary" - "sync" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts/checkpointoracle" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" -) - -// CheckpointOracle is responsible for offering the latest stable checkpoint -// generated and announced by the contract admins on-chain. The checkpoint can -// be verified by clients locally during the checkpoint syncing. -type CheckpointOracle struct { - config *params.CheckpointOracleConfig - contract *checkpointoracle.CheckpointOracle - - running int32 // Flag whether the contract backend is set or not - getLocal func(uint64) params.TrustedCheckpoint // Function used to retrieve local checkpoint - - checkMu sync.Mutex // Mutex to sync access to the fields below - lastCheckTime time.Time // Time we last checked the checkpoint - lastCheckPoint *params.TrustedCheckpoint // The last stable checkpoint - lastCheckPointHeight uint64 // The height of last stable checkpoint -} - -// New creates a checkpoint oracle handler with given configs and callback. -func New(config *params.CheckpointOracleConfig, getLocal func(uint64) params.TrustedCheckpoint) *CheckpointOracle { - return &CheckpointOracle{ - config: config, - getLocal: getLocal, - } -} - -// Start binds the contract backend, initializes the oracle instance -// and marks the status as available. -func (oracle *CheckpointOracle) Start(backend bind.ContractBackend) { - contract, err := checkpointoracle.NewCheckpointOracle(oracle.config.Address, backend) - if err != nil { - log.Error("Oracle contract binding failed", "err", err) - return - } - if !atomic.CompareAndSwapInt32(&oracle.running, 0, 1) { - log.Error("Already bound and listening to registrar") - return - } - oracle.contract = contract -} - -// IsRunning returns an indicator whether the oracle is running. -func (oracle *CheckpointOracle) IsRunning() bool { - return atomic.LoadInt32(&oracle.running) == 1 -} - -// Contract returns the underlying raw checkpoint oracle contract. -func (oracle *CheckpointOracle) Contract() *checkpointoracle.CheckpointOracle { - return oracle.contract -} - -// StableCheckpoint returns the stable checkpoint which was generated by local -// indexers and announced by trusted signers. -func (oracle *CheckpointOracle) StableCheckpoint() (*params.TrustedCheckpoint, uint64) { - oracle.checkMu.Lock() - defer oracle.checkMu.Unlock() - if time.Since(oracle.lastCheckTime) < 1*time.Minute { - return oracle.lastCheckPoint, oracle.lastCheckPointHeight - } - // Look it up properly - // Retrieve the latest checkpoint from the contract, abort if empty - latest, hash, height, err := oracle.contract.Contract().GetLatestCheckpoint(nil) - oracle.lastCheckTime = time.Now() - if err != nil || (latest == 0 && hash == [32]byte{}) { - oracle.lastCheckPointHeight = 0 - oracle.lastCheckPoint = nil - return oracle.lastCheckPoint, oracle.lastCheckPointHeight - } - local := oracle.getLocal(latest) - - // The following scenarios may occur: - // - // * local node is out of sync so that it doesn't have the - // checkpoint which registered in the contract. - // * local checkpoint doesn't match with the registered one. - // - // In both cases, no stable checkpoint will be returned. - if local.HashEqual(hash) { - oracle.lastCheckPointHeight = height.Uint64() - oracle.lastCheckPoint = &local - return oracle.lastCheckPoint, oracle.lastCheckPointHeight - } - return nil, 0 -} - -// VerifySigners recovers the signer addresses according to the signature and -// checks whether there are enough approvals to finalize the checkpoint. -func (oracle *CheckpointOracle) VerifySigners(index uint64, hash [32]byte, signatures [][]byte) (bool, []common.Address) { - // Short circuit if the given signatures doesn't reach the threshold. - if len(signatures) < int(oracle.config.Threshold) { - return false, nil - } - var ( - signers []common.Address - checked = make(map[common.Address]struct{}) - ) - for i := 0; i < len(signatures); i++ { - if len(signatures[i]) != 65 { - continue - } - // EIP 191 style signatures - // - // Arguments when calculating hash to validate - // 1: byte(0x19) - the initial 0x19 byte - // 2: byte(0) - the version byte (data with intended validator) - // 3: this - the validator address - // -- Application specific data - // 4 : checkpoint section_index (uint64) - // 5 : checkpoint hash (bytes32) - // hash = keccak256(checkpoint_index, section_head, cht_root, bloom_root) - buf := make([]byte, 8) - binary.BigEndian.PutUint64(buf, index) - data := append([]byte{0x19, 0x00}, append(oracle.config.Address.Bytes(), append(buf, hash[:]...)...)...) - signatures[i][64] -= 27 // Transform V from 27/28 to 0/1 according to the yellow paper for verification. - pubkey, err := crypto.Ecrecover(crypto.Keccak256(data), signatures[i]) - if err != nil { - return false, nil - } - var signer common.Address - copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) - if _, exist := checked[signer]; exist { - continue - } - for _, s := range oracle.config.Signers { - if s == signer { - signers = append(signers, signer) - checked[signer] = struct{}{} - } - } - } - threshold := oracle.config.Threshold - if uint64(len(signers)) < threshold { - log.Warn("Not enough signers to approve checkpoint", "signers", len(signers), "threshold", threshold) - return false, nil - } - return true, signers -} diff --git a/les/client.go b/les/client.go index 9ac85ecdac..9b75f07bd8 100644 --- a/les/client.go +++ b/les/client.go @@ -150,21 +150,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { leth.bloomTrieIndexer = light.NewBloomTrieIndexer(chainDb, leth.odr, params.BloomBitsBlocksClient, params.BloomTrieFrequency, config.LightNoPrune) leth.odr.SetIndexers(leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer) - checkpoint := config.Checkpoint - if checkpoint == nil { - checkpoint = params.TrustedCheckpoints[genesisHash] - } // Note: NewLightChain adds the trusted checkpoint so it needs an ODR with // indexers already set but not started yet - if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint); err != nil { + if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine); err != nil { return nil, err } leth.chainReader = leth.blockchain leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) - // Set up checkpoint oracle. - leth.oracle = leth.setupOracle(stack, genesisHash, config) - // Note: AddChildIndexer starts the update process for the child leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer) leth.chtIndexer.Start(leth.blockchain) @@ -191,7 +184,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { } leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) - leth.handler = newClientHandler(config.UltraLightServers, config.UltraLightFraction, checkpoint, leth) + leth.handler = newClientHandler(config.UltraLightServers, config.UltraLightFraction, leth) if leth.handler.ulc != nil { log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.handler.ulc.keys), "minTrustedFraction", leth.handler.ulc.fraction) leth.blockchain.DisableCheckFreq() @@ -309,9 +302,6 @@ func (s *LightEthereum) APIs() []rpc.API { }, { Namespace: "net", Service: s.netRPCService, - }, { - Namespace: "les", - Service: NewLightAPI(&s.lesCommons), }, { Namespace: "vflux", Service: s.serverPool.API(), diff --git a/les/client_handler.go b/les/client_handler.go index cce99d41dc..25a508d42d 100644 --- a/les/client_handler.go +++ b/les/client_handler.go @@ -33,7 +33,6 @@ import ( "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/params" ) // clientHandler is responsible for receiving and processing all incoming server @@ -41,7 +40,6 @@ import ( type clientHandler struct { ulc *ulc forkFilter forkid.Filter - checkpoint *params.TrustedCheckpoint fetcher *lightFetcher downloader *downloader.Downloader backend *LightEthereum @@ -54,10 +52,9 @@ type clientHandler struct { syncEnd func(header *types.Header) // Hook called when the syncing is done } -func newClientHandler(ulcServers []string, ulcFraction int, checkpoint *params.TrustedCheckpoint, backend *LightEthereum) *clientHandler { +func newClientHandler(ulcServers []string, ulcFraction int, backend *LightEthereum) *clientHandler { handler := &clientHandler{ forkFilter: forkid.NewFilter(backend.blockchain), - checkpoint: checkpoint, backend: backend, closeCh: make(chan struct{}), } @@ -69,12 +66,8 @@ func newClientHandler(ulcServers []string, ulcFraction int, checkpoint *params.T handler.ulc = ulc log.Info("Enable ultra light client mode") } - var height uint64 - if checkpoint != nil { - height = (checkpoint.SectionIndex+1)*params.CHTFrequency - 1 - } handler.fetcher = newLightFetcher(backend.blockchain, backend.engine, backend.peers, handler.ulc, backend.chainDb, backend.reqDist, handler.synchronise) - handler.downloader = downloader.New(height, backend.chainDb, backend.eventMux, nil, backend.blockchain, handler.removePeer) + handler.downloader = downloader.New(0, backend.chainDb, backend.eventMux, nil, backend.blockchain, handler.removePeer) handler.backend.peers.subscribe((*downloaderPeerNotify)(handler)) return handler } diff --git a/les/commons.go b/les/commons.go index 860175c8ca..b35d6b51d0 100644 --- a/les/commons.go +++ b/les/commons.go @@ -26,12 +26,8 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/les/checkpointoracle" "github.com/ethereum/go-ethereum/light" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" @@ -54,7 +50,6 @@ type lesCommons struct { chainDb, lesDb ethdb.Database chainReader chainReader chtIndexer, bloomTrieIndexer *core.ChainIndexer - oracle *checkpointoracle.CheckpointOracle closeCh chan struct{} wg sync.WaitGroup @@ -63,12 +58,11 @@ type lesCommons struct { // NodeInfo represents a short summary of the Ethereum sub-protocol metadata // known about the host peer. type NodeInfo struct { - Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Rinkeby=4, Goerli=5) - Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain - Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block - Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules - Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block - CHT params.TrustedCheckpoint `json:"cht"` // Trused CHT checkpoint for fast catchup + Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Rinkeby=4, Goerli=5) + Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain + Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block + Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules + Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block } // makeProtocols creates protocol descriptors for the given LES versions. @@ -101,61 +95,5 @@ func (c *lesCommons) nodeInfo() interface{} { Genesis: c.genesis, Config: c.chainConfig, Head: hash, - CHT: c.latestLocalCheckpoint(), } } - -// latestLocalCheckpoint finds the common stored section index and returns a set -// of post-processed trie roots (CHT and BloomTrie) associated with the appropriate -// section index and head hash as a local checkpoint package. -func (c *lesCommons) latestLocalCheckpoint() params.TrustedCheckpoint { - sections, _, _ := c.chtIndexer.Sections() - sections2, _, _ := c.bloomTrieIndexer.Sections() - // Cap the section index if the two sections are not consistent. - if sections > sections2 { - sections = sections2 - } - if sections == 0 { - // No checkpoint information can be provided. - return params.TrustedCheckpoint{} - } - return c.localCheckpoint(sections - 1) -} - -// localCheckpoint returns a set of post-processed trie roots (CHT and BloomTrie) -// associated with the appropriate head hash by specific section index. -// -// The returned checkpoint is only the checkpoint generated by the local indexers, -// not the stable checkpoint registered in the registrar contract. -func (c *lesCommons) localCheckpoint(index uint64) params.TrustedCheckpoint { - sectionHead := c.chtIndexer.SectionHead(index) - return params.TrustedCheckpoint{ - SectionIndex: index, - SectionHead: sectionHead, - CHTRoot: light.GetChtRoot(c.chainDb, index, sectionHead), - BloomRoot: light.GetBloomTrieRoot(c.chainDb, index, sectionHead), - } -} - -// setupOracle sets up the checkpoint oracle contract client. -func (c *lesCommons) setupOracle(node *node.Node, genesis common.Hash, ethconfig *ethconfig.Config) *checkpointoracle.CheckpointOracle { - config := ethconfig.CheckpointOracle - if config == nil { - // Try loading default config. - config = params.CheckpointOracles[genesis] - } - if config == nil { - log.Info("Checkpoint oracle is not enabled") - return nil - } - if config.Address == (common.Address{}) || uint64(len(config.Signers)) < config.Threshold { - log.Warn("Invalid checkpoint oracle config") - return nil - } - oracle := checkpointoracle.New(config, c.localCheckpoint) - rpcClient, _ := node.Attach() - client := ethclient.NewClient(rpcClient) - oracle.Start(client) - log.Info("Configured checkpoint oracle", "address", config.Address, "signers", len(config.Signers), "threshold", config.Threshold) - return oracle -} diff --git a/les/fetcher_test.go b/les/fetcher_test.go index 2f3a80aa5b..7c523f797e 100644 --- a/les/fetcher_test.go +++ b/les/fetcher_test.go @@ -25,8 +25,6 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/light" - "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" ) @@ -149,104 +147,6 @@ func testGappedAnnouncements(t *testing.T, protocol int) { verifyChainHeight(t, c.handler.fetcher, 5) } -func TestTrustedAnnouncementsLes2(t *testing.T) { testTrustedAnnouncement(t, 2) } -func TestTrustedAnnouncementsLes3(t *testing.T) { testTrustedAnnouncement(t, 3) } - -func testTrustedAnnouncement(t *testing.T, protocol int) { - //log.Root().SetHandler(log.LvlFilterHandler(log.LvlDebug, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - var ( - servers []*testServer - teardowns []func() - nodes []*enode.Node - ids []string - cpeers []*clientPeer - - config = light.TestServerIndexerConfig - waitIndexers = func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { - for { - cs, _, _ := cIndexer.Sections() - bts, _, _ := btIndexer.Sections() - if cs >= 2 && bts >= 2 { - break - } - time.Sleep(10 * time.Millisecond) - } - } - ) - for i := 0; i < 4; i++ { - s, n, teardown := newTestServerPeer(t, int(2*config.ChtSize+config.ChtConfirms), protocol, waitIndexers) - - servers = append(servers, s) - nodes = append(nodes, n) - teardowns = append(teardowns, teardown) - - // A half of them are trusted servers. - if i < 2 { - ids = append(ids, n.String()) - } - } - netconfig := testnetConfig{ - protocol: protocol, - nopruning: true, - ulcServers: ids, - ulcFraction: 60, - } - _, c, teardown := newClientServerEnv(t, netconfig) - defer teardown() - defer func() { - for i := 0; i < len(teardowns); i++ { - teardowns[i]() - } - }() - - // Register the assembled checkpoint as hardcoded one. - head := servers[0].chtIndexer.SectionHead(0) - cp := ¶ms.TrustedCheckpoint{ - SectionIndex: 0, - SectionHead: head, - CHTRoot: light.GetChtRoot(servers[0].db, 0, head), - BloomRoot: light.GetBloomTrieRoot(servers[0].db, 0, head), - } - c.handler.checkpoint = cp - c.handler.backend.blockchain.AddTrustedCheckpoint(cp) - - // Connect all server instances. - for i := 0; i < len(servers); i++ { - _, cp, err := connect(servers[i].handler, nodes[i].ID(), c.handler, protocol, true) - if err != nil { - t.Fatalf("connect server and client failed, err %s", err) - } - cpeers = append(cpeers, cp) - } - newHead := make(chan *types.Header, 1) - c.handler.fetcher.newHeadHook = func(header *types.Header) { newHead <- header } - - check := func(height []uint64, expected uint64, callback func()) { - for i := 0; i < len(height); i++ { - for j := 0; j < len(servers); j++ { - h := servers[j].backend.Blockchain().GetHeaderByNumber(height[i]) - hash, number := h.Hash(), h.Number.Uint64() - td := rawdb.ReadTd(servers[j].db, hash, number) - - // Sign the announcement if necessary. - announce := announceData{hash, number, td, 0, nil} - p := cpeers[j] - if p.announceType == announceTypeSigned { - announce.sign(servers[j].handler.server.privateKey) - } - p.sendAnnounce(announce) - } - } - if callback != nil { - callback() - } - verifyChainHeight(t, c.handler.fetcher, expected) - } - check([]uint64{1}, 1, func() { <-newHead }) // Sequential announcements - check([]uint64{config.ChtSize + config.ChtConfirms}, config.ChtSize+config.ChtConfirms, func() { <-newHead }) // ULC-style light syncing, rollback untrusted headers - check([]uint64{2*config.ChtSize + config.ChtConfirms}, 2*config.ChtSize+config.ChtConfirms, func() { <-newHead }) // Sync the whole chain. -} - func TestInvalidAnnouncesLES2(t *testing.T) { testInvalidAnnounces(t, lpv2) } func TestInvalidAnnouncesLES3(t *testing.T) { testInvalidAnnounces(t, lpv3) } func TestInvalidAnnouncesLES4(t *testing.T) { testInvalidAnnounces(t, lpv4) } diff --git a/les/peer.go b/les/peer.go index deda052a3b..100cc7e4f1 100644 --- a/les/peer.go +++ b/les/peer.go @@ -39,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" ) @@ -345,10 +344,6 @@ type serverPeer struct { stateSince, stateRecent uint64 // The range of state server peer can serve. txHistory uint64 // The length of available tx history, 0 means all, 1 means disabled - // Advertised checkpoint fields - checkpointNumber uint64 // The block height which the checkpoint is registered. - checkpoint params.TrustedCheckpoint // The advertised checkpoint sent by server. - fcServer *flowcontrol.ServerNode // Client side mirror token bucket. vtLock sync.Mutex nodeValueTracker *vfc.NodeValueTracker @@ -661,9 +656,6 @@ func (p *serverPeer) Handshake(genesis common.Hash, forkid forkid.ID, forkFilter p.fcServer = flowcontrol.NewServerNode(sParams, &mclock.System{}) p.fcCosts = MRC.decode(ProtocolLengths[uint(p.version)]) - recv.get("checkpoint/value", &p.checkpoint) - recv.get("checkpoint/registerHeight", &p.checkpointNumber) - if !p.onlyAnnounce { for msgCode := range reqAvgTimeCost { if p.fcCosts[msgCode] == nil { @@ -1046,16 +1038,6 @@ func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, ge *lists = (*lists).add("flowControl/MRC", costList) p.fcCosts = costList.decode(ProtocolLengths[uint(p.version)]) p.fcParams = server.defParams - - // Add advertised checkpoint and register block height which - // client can verify the checkpoint validity. - if server.oracle != nil && server.oracle.IsRunning() { - cp, height := server.oracle.StableCheckpoint() - if cp != nil { - *lists = (*lists).add("checkpoint/value", cp) - *lists = (*lists).add("checkpoint/registerHeight", height) - } - } }, func(recv keyValueMap) error { p.server = recv.get("flowControl/MRR", nil) == nil if p.server { diff --git a/les/server.go b/les/server.go index 06bbc30fb0..d84856c7fb 100644 --- a/les/server.go +++ b/les/server.go @@ -117,7 +117,6 @@ func NewLesServer(node *node.Node, e ethBackend, config *ethconfig.Config) (*Les } srv.handler = newServerHandler(srv, e.BlockChain(), e.ChainDb(), e.TxPool(), issync) srv.costTracker, srv.minCapacity = newCostTracker(e.ChainDb(), config) - srv.oracle = srv.setupOracle(node, e.BlockChain().Genesis().Hash(), config) // Initialize the bloom trie indexer. e.BloomIndexer().AddChildIndexer(srv.bloomTrieIndexer) @@ -142,12 +141,6 @@ func NewLesServer(node *node.Node, e ethBackend, config *ethconfig.Config) (*Les srv.clientPool.Start() srv.clientPool.SetDefaultFactors(defaultPosFactors, defaultNegFactors) srv.vfluxServer.Register(srv.clientPool, "les", "Ethereum light client service") - - checkpoint := srv.latestLocalCheckpoint() - if !checkpoint.Empty() { - log.Info("Loaded latest checkpoint", "section", checkpoint.SectionIndex, "head", checkpoint.SectionHead, - "chtroot", checkpoint.CHTRoot, "bloomroot", checkpoint.BloomRoot) - } srv.chtIndexer.Start(e.BlockChain()) node.RegisterProtocols(srv.Protocols()) @@ -158,10 +151,6 @@ func NewLesServer(node *node.Node, e ethBackend, config *ethconfig.Config) (*Les func (s *LesServer) APIs() []rpc.API { return []rpc.API{ - { - Namespace: "les", - Service: NewLightAPI(&s.lesCommons), - }, { Namespace: "les", Service: NewLightServerAPI(s), diff --git a/les/sync.go b/les/sync.go index 31cd06ca70..bd06077aae 100644 --- a/les/sync.go +++ b/les/sync.go @@ -17,76 +17,14 @@ package les import ( - "context" - "errors" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/les/downloader" - "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" ) -var errInvalidCheckpoint = errors.New("invalid advertised checkpoint") - -const ( - // lightSync starts syncing from the current highest block. - // If the chain is empty, syncing the entire header chain. - lightSync = iota - - // legacyCheckpointSync starts syncing from a hardcoded checkpoint. - legacyCheckpointSync - - // checkpointSync starts syncing from a checkpoint signed by trusted - // signer or hardcoded checkpoint for compatibility. - checkpointSync -) - -// validateCheckpoint verifies the advertised checkpoint by peer is valid or not. -// -// Each network has several hard-coded checkpoint signer addresses. Only the -// checkpoint issued by the specified signer is considered valid. -// -// In addition to the checkpoint registered in the registrar contract, there are -// several legacy hardcoded checkpoints in our codebase. These checkpoints are -// also considered as valid. -func (h *clientHandler) validateCheckpoint(peer *serverPeer) error { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - - // Fetch the block header corresponding to the checkpoint registration. - wrapPeer := &peerConnection{handler: h, peer: peer} - header, err := wrapPeer.RetrieveSingleHeaderByNumber(ctx, peer.checkpointNumber) - if err != nil { - return err - } - // Fetch block logs associated with the block header. - logs, err := light.GetUntrustedBlockLogs(ctx, h.backend.odr, header) - if err != nil { - return err - } - events := h.backend.oracle.Contract().LookupCheckpointEvents(logs, peer.checkpoint.SectionIndex, peer.checkpoint.Hash()) - if len(events) == 0 { - return errInvalidCheckpoint - } - var ( - index = events[0].Index - hash = events[0].CheckpointHash - signatures [][]byte - ) - for _, event := range events { - signatures = append(signatures, append(event.R[:], append(event.S[:], event.V)...)) - } - valid, signers := h.backend.oracle.VerifySigners(index, hash, signatures) - if !valid { - return errInvalidCheckpoint - } - log.Warn("Verified advertised checkpoint", "peer", peer.id, "signers", len(signers)) - return nil -} - // synchronise tries to sync up our local chain with a remote peer. func (h *clientHandler) synchronise(peer *serverPeer) { // Short circuit if the peer is nil. @@ -99,99 +37,13 @@ func (h *clientHandler) synchronise(peer *serverPeer) { if currentTd != nil && peer.Td().Cmp(currentTd) < 0 { return } - // Recap the checkpoint. The light client may be connected to several different - // versions of the server. - // (1) Old version server which can not provide stable checkpoint in the - // handshake packet. - // => Use local checkpoint or empty checkpoint - // (2) New version server but simple checkpoint syncing is not enabled - // (e.g. mainnet, new testnet or private network) - // => Use local checkpoint or empty checkpoint - // (3) New version server but the provided stable checkpoint is even lower - // than the local one. - // => Use local checkpoint - // (4) New version server with valid and higher stable checkpoint - // => Use provided checkpoint - var ( - local bool - checkpoint = &peer.checkpoint - ) - if h.checkpoint != nil && h.checkpoint.SectionIndex >= peer.checkpoint.SectionIndex { - local, checkpoint = true, h.checkpoint - } - // Replace the checkpoint with locally configured one If it's required by - // users. Nil checkpoint means synchronization from the scratch. - if h.backend.config.SyncFromCheckpoint { - local, checkpoint = true, h.backend.config.Checkpoint - if h.backend.config.Checkpoint == nil { - checkpoint = ¶ms.TrustedCheckpoint{} - } - } - // Determine whether we should run checkpoint syncing or normal light syncing. - // - // Here has four situations that we will disable the checkpoint syncing: - // - // 1. The checkpoint is empty - // 2. The latest head block of the local chain is above the checkpoint. - // 3. The checkpoint is local(replaced with local checkpoint) - // 4. For some networks the checkpoint syncing is not activated. - mode := checkpointSync - switch { - case checkpoint.Empty(): - mode = lightSync - log.Debug("Disable checkpoint syncing", "reason", "empty checkpoint") - case latest.Number.Uint64() >= (checkpoint.SectionIndex+1)*h.backend.iConfig.ChtSize-1: - mode = lightSync - log.Debug("Disable checkpoint syncing", "reason", "local chain beyond the checkpoint") - case local: - mode = legacyCheckpointSync - log.Debug("Disable checkpoint syncing", "reason", "checkpoint is hardcoded") - case h.backend.oracle == nil || !h.backend.oracle.IsRunning(): - if h.checkpoint == nil { - mode = lightSync // Downgrade to light sync unfortunately. - } else { - checkpoint = h.checkpoint - mode = legacyCheckpointSync - } - log.Debug("Disable checkpoint syncing", "reason", "checkpoint syncing is not activated") - } - - // Notify testing framework if syncing has completed(for testing purpose). + // Notify testing framework if syncing has completed (for testing purpose). defer func() { if h.syncEnd != nil { h.syncEnd(h.backend.blockchain.CurrentHeader()) } }() - start := time.Now() - if mode == checkpointSync || mode == legacyCheckpointSync { - // Validate the advertised checkpoint - if mode == checkpointSync { - if err := h.validateCheckpoint(peer); err != nil { - log.Debug("Failed to validate checkpoint", "reason", err) - h.removePeer(peer.id) - return - } - h.backend.blockchain.AddTrustedCheckpoint(checkpoint) - } - log.Debug("Checkpoint syncing start", "peer", peer.id, "checkpoint", checkpoint.SectionIndex) - - // Fetch the start point block header. - // - // For the ethash consensus engine, the start header is the block header - // of the checkpoint. - // - // For the clique consensus engine, the start header is the block header - // of the latest epoch covered by checkpoint. - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - if !checkpoint.Empty() && !h.backend.blockchain.SyncCheckpoint(ctx, checkpoint) { - log.Debug("Sync checkpoint failed") - h.removePeer(peer.id) - return - } - } - if h.syncStart != nil { h.syncStart(h.backend.blockchain.CurrentHeader()) } diff --git a/les/sync_test.go b/les/sync_test.go index 3fc2a9c154..356a88ffbe 100644 --- a/les/sync_test.go +++ b/les/sync_test.go @@ -18,30 +18,18 @@ package les import ( "fmt" - "math/big" "testing" "time" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/light" - "github.com/ethereum/go-ethereum/params" ) // Test light syncing which will download all headers from genesis. -func TestLightSyncingLes3(t *testing.T) { testCheckpointSyncing(t, lpv3, 0) } +func TestLightSyncingLes3(t *testing.T) { testSyncing(t, lpv3) } -// Test legacy checkpoint syncing which will download tail headers -// based on a hardcoded checkpoint. -func TestLegacyCheckpointSyncingLes3(t *testing.T) { testCheckpointSyncing(t, lpv3, 1) } - -// Test checkpoint syncing which will download tail headers based -// on a verified checkpoint. -func TestCheckpointSyncingLes3(t *testing.T) { testCheckpointSyncing(t, lpv3, 2) } - -func testCheckpointSyncing(t *testing.T, protocol int, syncMode int) { +func testSyncing(t *testing.T, protocol int) { config := light.TestServerIndexerConfig waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { @@ -66,46 +54,6 @@ func testCheckpointSyncing(t *testing.T, protocol int, syncMode int) { expected := config.ChtSize + config.ChtConfirms - // Checkpoint syncing or legacy checkpoint syncing. - if syncMode == 1 || syncMode == 2 { - // Assemble checkpoint 0 - s, _, head := server.chtIndexer.Sections() - cp := ¶ms.TrustedCheckpoint{ - SectionIndex: 0, - SectionHead: head, - CHTRoot: light.GetChtRoot(server.db, s-1, head), - BloomRoot: light.GetBloomTrieRoot(server.db, s-1, head), - } - if syncMode == 1 { - // Register the assembled checkpoint as hardcoded one. - client.handler.checkpoint = cp - client.handler.backend.blockchain.AddTrustedCheckpoint(cp) - } else { - // Register the assembled checkpoint into oracle. - header := server.backend.Blockchain().CurrentHeader() - - data := append([]byte{0x19, 0x00}, append(oracleAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...) - sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey) - sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper - auth, _ := bind.NewKeyedTransactorWithChainID(signerKey, big.NewInt(1337)) - if _, err := server.handler.server.oracle.Contract().RegisterCheckpoint(auth, cp.SectionIndex, cp.Hash().Bytes(), new(big.Int).Sub(header.Number, big.NewInt(1)), header.ParentHash, [][]byte{sig}); err != nil { - t.Error("register checkpoint failed", err) - } - server.backend.Commit() - - // Wait for the checkpoint registration - for { - _, hash, _, err := server.handler.server.oracle.Contract().Contract().GetLatestCheckpoint(nil) - if err != nil || hash == [32]byte{} { - time.Sleep(10 * time.Millisecond) - continue - } - break - } - expected += 1 - } - } - done := make(chan error) client.handler.syncEnd = func(header *types.Header) { if header.Number.Uint64() == expected { @@ -133,258 +81,3 @@ func testCheckpointSyncing(t *testing.T, protocol int, syncMode int) { t.Error("checkpoint syncing timeout") } } - -func TestMissOracleBackendLES3(t *testing.T) { testMissOracleBackend(t, true, lpv3) } -func TestMissOracleBackendNoCheckpointLES3(t *testing.T) { testMissOracleBackend(t, false, lpv3) } - -func testMissOracleBackend(t *testing.T, hasCheckpoint bool, protocol int) { - config := light.TestServerIndexerConfig - - waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { - for { - cs, _, _ := cIndexer.Sections() - bts, _, _ := btIndexer.Sections() - if cs >= 1 && bts >= 1 { - break - } - time.Sleep(10 * time.Millisecond) - } - } - // Generate 128+1 blocks (totally 1 CHT section) - netconfig := testnetConfig{ - blocks: int(config.ChtSize + config.ChtConfirms), - protocol: protocol, - indexFn: waitIndexers, - nopruning: true, - } - server, client, tearDown := newClientServerEnv(t, netconfig) - defer tearDown() - - expected := config.ChtSize + config.ChtConfirms - - s, _, head := server.chtIndexer.Sections() - cp := ¶ms.TrustedCheckpoint{ - SectionIndex: 0, - SectionHead: head, - CHTRoot: light.GetChtRoot(server.db, s-1, head), - BloomRoot: light.GetBloomTrieRoot(server.db, s-1, head), - } - // Register the assembled checkpoint into oracle. - header := server.backend.Blockchain().CurrentHeader() - - data := append([]byte{0x19, 0x00}, append(oracleAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...) - sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey) - sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper - auth, _ := bind.NewKeyedTransactorWithChainID(signerKey, big.NewInt(1337)) - if _, err := server.handler.server.oracle.Contract().RegisterCheckpoint(auth, cp.SectionIndex, cp.Hash().Bytes(), new(big.Int).Sub(header.Number, big.NewInt(1)), header.ParentHash, [][]byte{sig}); err != nil { - t.Error("register checkpoint failed", err) - } - server.backend.Commit() - - // Wait for the checkpoint registration - for { - _, hash, _, err := server.handler.server.oracle.Contract().Contract().GetLatestCheckpoint(nil) - if err != nil || hash == [32]byte{} { - time.Sleep(100 * time.Millisecond) - continue - } - break - } - expected += 1 - - // Explicitly set the oracle as nil. In normal use case it can happen - // that user wants to unlock something which blocks the oracle backend - // initialisation. But at the same time syncing starts. - // - // See https://github.com/ethereum/go-ethereum/issues/20097 for more detail. - // - // In this case, client should run light sync or legacy checkpoint sync - // if hardcoded checkpoint is configured. - client.handler.backend.oracle = nil - - // For some private networks it can happen checkpoint syncing is enabled - // but there is no hardcoded checkpoint configured. - if hasCheckpoint { - client.handler.checkpoint = cp - client.handler.backend.blockchain.AddTrustedCheckpoint(cp) - } - - done := make(chan error) - client.handler.syncEnd = func(header *types.Header) { - if header.Number.Uint64() == expected { - done <- nil - } else { - done <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expected, header.Number) - } - } - // Create connected peer pair. - if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler, false); err != nil { - t.Fatalf("Failed to connect testing peers %v", err) - } - select { - case err := <-done: - if err != nil { - t.Error("sync failed", err) - } - return - case <-time.NewTimer(10 * time.Second).C: - t.Error("checkpoint syncing timeout") - } -} - -func TestSyncFromConfiguredCheckpointLES3(t *testing.T) { testSyncFromConfiguredCheckpoint(t, lpv3) } - -func testSyncFromConfiguredCheckpoint(t *testing.T, protocol int) { - config := light.TestServerIndexerConfig - - waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { - for { - cs, _, _ := cIndexer.Sections() - bts, _, _ := btIndexer.Sections() - if cs >= 2 && bts >= 2 { - break - } - time.Sleep(10 * time.Millisecond) - } - } - // Generate 256+1 blocks (totally 2 CHT sections) - netconfig := testnetConfig{ - blocks: int(2*config.ChtSize + config.ChtConfirms), - protocol: protocol, - indexFn: waitIndexers, - nopruning: true, - } - server, client, tearDown := newClientServerEnv(t, netconfig) - defer tearDown() - - // Configure the local checkpoint(the first section) - head := server.handler.blockchain.GetHeaderByNumber(config.ChtSize - 1).Hash() - cp := ¶ms.TrustedCheckpoint{ - SectionIndex: 0, - SectionHead: head, - CHTRoot: light.GetChtRoot(server.db, 0, head), - BloomRoot: light.GetBloomTrieRoot(server.db, 0, head), - } - client.handler.backend.config.SyncFromCheckpoint = true - client.handler.backend.config.Checkpoint = cp - client.handler.checkpoint = cp - client.handler.backend.blockchain.AddTrustedCheckpoint(cp) - - var ( - start = make(chan error, 1) - end = make(chan error, 1) - expectStart = config.ChtSize - 1 - expectEnd = 2*config.ChtSize + config.ChtConfirms - ) - client.handler.syncStart = func(header *types.Header) { - if header.Number.Uint64() == expectStart { - start <- nil - } else { - start <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectStart, header.Number) - } - } - client.handler.syncEnd = func(header *types.Header) { - if header.Number.Uint64() == expectEnd { - end <- nil - } else { - end <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectEnd, header.Number) - } - } - // Create connected peer pair. - if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler, false); err != nil { - t.Fatalf("Failed to connect testing peers %v", err) - } - - select { - case err := <-start: - if err != nil { - t.Error("sync failed", err) - } - return - case <-time.NewTimer(10 * time.Second).C: - t.Error("checkpoint syncing timeout") - } - - select { - case err := <-end: - if err != nil { - t.Error("sync failed", err) - } - return - case <-time.NewTimer(10 * time.Second).C: - t.Error("checkpoint syncing timeout") - } -} - -func TestSyncAll(t *testing.T) { testSyncAll(t, lpv3) } - -func testSyncAll(t *testing.T, protocol int) { - config := light.TestServerIndexerConfig - - waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { - for { - cs, _, _ := cIndexer.Sections() - bts, _, _ := btIndexer.Sections() - if cs >= 2 && bts >= 2 { - break - } - time.Sleep(10 * time.Millisecond) - } - } - // Generate 256+1 blocks (totally 2 CHT sections) - netconfig := testnetConfig{ - blocks: int(2*config.ChtSize + config.ChtConfirms), - protocol: protocol, - indexFn: waitIndexers, - nopruning: true, - } - server, client, tearDown := newClientServerEnv(t, netconfig) - defer tearDown() - - client.handler.backend.config.SyncFromCheckpoint = true - - var ( - start = make(chan error, 1) - end = make(chan error, 1) - expectStart = uint64(0) - expectEnd = 2*config.ChtSize + config.ChtConfirms - ) - client.handler.syncStart = func(header *types.Header) { - if header.Number.Uint64() == expectStart { - start <- nil - } else { - start <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectStart, header.Number) - } - } - client.handler.syncEnd = func(header *types.Header) { - if header.Number.Uint64() == expectEnd { - end <- nil - } else { - end <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectEnd, header.Number) - } - } - // Create connected peer pair. - if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler, false); err != nil { - t.Fatalf("Failed to connect testing peers %v", err) - } - - select { - case err := <-start: - if err != nil { - t.Error("sync failed", err) - } - return - case <-time.NewTimer(10 * time.Second).C: - t.Error("checkpoint syncing timeout") - } - - select { - case err := <-end: - if err != nil { - t.Error("sync failed", err) - } - return - case <-time.NewTimer(10 * time.Second).C: - t.Error("checkpoint syncing timeout") - } -} diff --git a/les/test_helper.go b/les/test_helper.go index 714bc7b3f6..70f78498d4 100644 --- a/les/test_helper.go +++ b/les/test_helper.go @@ -29,13 +29,11 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/ethash" - "github.com/ethereum/go-ethereum/contracts/checkpointoracle/contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/forkid" "github.com/ethereum/go-ethereum/core/rawdb" @@ -45,7 +43,6 @@ import ( "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/les/checkpointoracle" "github.com/ethereum/go-ethereum/les/flowcontrol" vfs "github.com/ethereum/go-ethereum/les/vflux/server" "github.com/ethereum/go-ethereum/light" @@ -72,18 +69,11 @@ var ( testEventEmitterCode = common.Hex2Bytes("60606040523415600e57600080fd5b7f57050ab73f6b9ebdd9f76b8d4997793f48cf956e965ee070551b9ca0bb71584e60405160405180910390a160358060476000396000f3006060604052600080fd00a165627a7a723058203f727efcad8b5811f8cb1fc2620ce5e8c63570d697aef968172de296ea3994140029") // Checkpoint oracle relative fields - oracleAddr common.Address signerKey, _ = crypto.GenerateKey() signerAddr = crypto.PubkeyToAddress(signerKey.PublicKey) ) var ( - // The block frequency for creating checkpoint(only used in test) - sectionSize = big.NewInt(128) - - // The number of confirmations needed to generate a checkpoint(only used in test). - processConfirms = big.NewInt(1) - // The token bucket buffer limit for testing purpose. testBufLimit = uint64(1000000) @@ -117,11 +107,7 @@ func prepare(n int, backend *backends.SimulatedBackend) { case 0: // Builtin-block // number: 1 - // txs: 2 - - // deploy checkpoint contract - auth, _ := bind.NewKeyedTransactorWithChainID(bankKey, big.NewInt(1337)) - oracleAddr, _, _, _ = contract.DeployCheckpointOracle(auth, backend, []common.Address{signerAddr}, sectionSize, processConfirms, big.NewInt(1)) + // txs: 1 // bankUser transfers some ether to user1 nonce, _ := backend.PendingNonceAt(ctx, bankAddr) @@ -201,28 +187,10 @@ func newTestClientHandler(backend *backends.SimulatedBackend, odr *LesOdr, index GasLimit: 100000000, BaseFee: big.NewInt(params.InitialBaseFee), } - oracle *checkpointoracle.CheckpointOracle ) genesis := gspec.MustCommit(db) - chain, _ := light.NewLightChain(odr, gspec.Config, engine, nil) - if indexers != nil { - checkpointConfig := ¶ms.CheckpointOracleConfig{ - Address: crypto.CreateAddress(bankAddr, 0), - Signers: []common.Address{signerAddr}, - Threshold: 1, - } - getLocal := func(index uint64) params.TrustedCheckpoint { - chtIndexer := indexers[0] - sectionHead := chtIndexer.SectionHead(index) - return params.TrustedCheckpoint{ - SectionIndex: index, - SectionHead: sectionHead, - CHTRoot: light.GetChtRoot(db, index, sectionHead), - BloomRoot: light.GetBloomTrieRoot(db, index, sectionHead), - } - } - oracle = checkpointoracle.New(checkpointConfig, getLocal) - } + chain, _ := light.NewLightChain(odr, gspec.Config, engine) + client := &LightEthereum{ lesCommons: lesCommons{ genesis: genesis.Hash(), @@ -230,7 +198,6 @@ func newTestClientHandler(backend *backends.SimulatedBackend, odr *LesOdr, index chainConfig: params.AllEthashProtocolChanges, iConfig: light.TestClientIndexerConfig, chainDb: db, - oracle: oracle, chainReader: chain, closeCh: make(chan struct{}), }, @@ -243,11 +210,8 @@ func newTestClientHandler(backend *backends.SimulatedBackend, odr *LesOdr, index eventMux: evmux, merger: consensus.NewMerger(rawdb.NewMemoryDatabase()), } - client.handler = newClientHandler(ulcServers, ulcFraction, nil, client) + client.handler = newClientHandler(ulcServers, ulcFraction, client) - if client.oracle != nil { - client.oracle.Start(backend) - } client.handler.start() return client.handler, func() { client.handler.stop() @@ -262,7 +226,6 @@ func newTestServerHandler(blocks int, indexers []*core.ChainIndexer, db ethdb.Da GasLimit: 100000000, BaseFee: big.NewInt(params.InitialBaseFee), } - oracle *checkpointoracle.CheckpointOracle ) genesis := gspec.MustCommit(db) @@ -273,24 +236,7 @@ func newTestServerHandler(blocks int, indexers []*core.ChainIndexer, db ethdb.Da txpoolConfig := txpool.DefaultConfig txpoolConfig.Journal = "" txpool := txpool.NewTxPool(txpoolConfig, gspec.Config, simulation.Blockchain()) - if indexers != nil { - checkpointConfig := ¶ms.CheckpointOracleConfig{ - Address: crypto.CreateAddress(bankAddr, 0), - Signers: []common.Address{signerAddr}, - Threshold: 1, - } - getLocal := func(index uint64) params.TrustedCheckpoint { - chtIndexer := indexers[0] - sectionHead := chtIndexer.SectionHead(index) - return params.TrustedCheckpoint{ - SectionIndex: index, - SectionHead: sectionHead, - CHTRoot: light.GetChtRoot(db, index, sectionHead), - BloomRoot: light.GetBloomTrieRoot(db, index, sectionHead), - } - } - oracle = checkpointoracle.New(checkpointConfig, getLocal) - } + server := &LesServer{ lesCommons: lesCommons{ genesis: genesis.Hash(), @@ -299,7 +245,6 @@ func newTestServerHandler(blocks int, indexers []*core.ChainIndexer, db ethdb.Da iConfig: light.TestServerIndexerConfig, chainDb: db, chainReader: simulation.Blockchain(), - oracle: oracle, closeCh: make(chan struct{}), }, peers: newClientPeerSet(), @@ -316,9 +261,6 @@ func newTestServerHandler(blocks int, indexers []*core.ChainIndexer, db ethdb.Da server.clientPool.Start() server.clientPool.SetLimits(10000, 10000) // Assign enough capacity for clientpool server.handler = newServerHandler(server, simulation.Blockchain(), db, txpool, func() bool { return true }) - if server.oracle != nil { - server.oracle.Start(simulation) - } server.servingQueue.setThreads(4) server.handler.start() closer := func() { server.Stop() } diff --git a/light/lightchain.go b/light/lightchain.go index f42c904f57..24999f52b0 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -78,7 +78,7 @@ type LightChain struct { // NewLightChain returns a fully initialised light chain using information // available in the database. It initialises the default Ethereum header // validator. -func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine, checkpoint *params.TrustedCheckpoint) (*LightChain, error) { +func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine) (*LightChain, error) { bc := &LightChain{ chainDb: odr.Database(), indexerConfig: odr.IndexerConfig(), @@ -99,9 +99,6 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. if bc.genesisBlock == nil { return nil, core.ErrNoGenesis } - if checkpoint != nil { - bc.AddTrustedCheckpoint(checkpoint) - } if err := bc.loadLastState(); err != nil { return nil, err } @@ -116,22 +113,6 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. return bc, nil } -// AddTrustedCheckpoint adds a trusted checkpoint to the blockchain -func (lc *LightChain) AddTrustedCheckpoint(cp *params.TrustedCheckpoint) { - if lc.odr.ChtIndexer() != nil { - StoreChtRoot(lc.chainDb, cp.SectionIndex, cp.SectionHead, cp.CHTRoot) - lc.odr.ChtIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) - } - if lc.odr.BloomTrieIndexer() != nil { - StoreBloomTrieRoot(lc.chainDb, cp.SectionIndex, cp.SectionHead, cp.BloomRoot) - lc.odr.BloomTrieIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) - } - if lc.odr.BloomIndexer() != nil { - lc.odr.BloomIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) - } - log.Info("Added trusted checkpoint", "block", (cp.SectionIndex+1)*lc.indexerConfig.ChtSize-1, "hash", cp.SectionHead) -} - func (lc *LightChain) getProcInterrupt() bool { return atomic.LoadInt32(&lc.procInterrupt) == 1 } @@ -520,38 +501,6 @@ func (lc *LightChain) GetHeaderByNumberOdr(ctx context.Context, number uint64) ( // Config retrieves the header chain's chain configuration. func (lc *LightChain) Config() *params.ChainConfig { return lc.hc.Config() } -// SyncCheckpoint fetches the checkpoint point block header according to -// the checkpoint provided by the remote peer. -// -// Note if we are running the clique, fetches the last epoch snapshot header -// which covered by checkpoint. -func (lc *LightChain) SyncCheckpoint(ctx context.Context, checkpoint *params.TrustedCheckpoint) bool { - // Ensure the remote checkpoint head is ahead of us - head := lc.CurrentHeader().Number.Uint64() - - latest := (checkpoint.SectionIndex+1)*lc.indexerConfig.ChtSize - 1 - if clique := lc.hc.Config().Clique; clique != nil { - latest -= latest % clique.Epoch // epoch snapshot for clique - } - if head >= latest { - return true - } - // Retrieve the latest useful header and update to it - if header, err := GetHeaderByNumber(ctx, lc.odr, latest); header != nil && err == nil { - lc.chainmu.Lock() - defer lc.chainmu.Unlock() - - // Ensure the chain didn't move past the latest block while retrieving it - if lc.hc.CurrentHeader().Number.Uint64() < header.Number.Uint64() { - log.Info("Updated latest header based on CHT", "number", header.Number, "hash", header.Hash(), "age", common.PrettyAge(time.Unix(int64(header.Time), 0))) - rawdb.WriteHeadHeaderHash(lc.chainDb, header.Hash()) - lc.hc.SetCurrentHeader(header) - } - return true - } - return false -} - // LockChain locks the chain mutex for reading so that multiple canonical hashes can be // retrieved while it is guaranteed that they belong to the same version of the chain func (lc *LightChain) LockChain() { diff --git a/light/lightchain_test.go b/light/lightchain_test.go index d19713dc2f..905d522552 100644 --- a/light/lightchain_test.go +++ b/light/lightchain_test.go @@ -56,7 +56,7 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) { db := rawdb.NewMemoryDatabase() gspec := core.Genesis{Config: params.TestChainConfig} genesis := gspec.MustCommit(db) - blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker(), nil) + blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker()) // Create and inject the requested chain if n == 0 { @@ -76,7 +76,7 @@ func newTestLightChain() *LightChain { Config: params.TestChainConfig, } gspec.MustCommit(db) - lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker(), nil) + lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker()) if err != nil { panic(err) } @@ -347,7 +347,7 @@ func TestReorgBadHeaderHashes(t *testing.T) { defer func() { delete(core.BadHashes, headers[3].Hash()) }() // Create a new LightChain and check that it rolled back the state. - ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker(), nil) + ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker()) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } diff --git a/light/odr.go b/light/odr.go index f998dbe584..d331d3c9b5 100644 --- a/light/odr.go +++ b/light/odr.go @@ -125,18 +125,15 @@ func (req *BlockRequest) StoreResult(db ethdb.Database) { // ReceiptsRequest is the ODR request type for retrieving receipts. type ReceiptsRequest struct { - Untrusted bool // Indicator whether the result retrieved is trusted or not - Hash common.Hash - Number uint64 - Header *types.Header - Receipts types.Receipts + Hash common.Hash + Number uint64 + Header *types.Header + Receipts types.Receipts } // StoreResult stores the retrieved data in local database func (req *ReceiptsRequest) StoreResult(db ethdb.Database) { - if !req.Untrusted { - rawdb.WriteReceipts(db, req.Hash, req.Number, req.Receipts) - } + rawdb.WriteReceipts(db, req.Hash, req.Number, req.Receipts) } // ChtRequest is the ODR request type for retrieving header by Canonical Hash Trie diff --git a/light/odr_test.go b/light/odr_test.go index 811dd97de3..5c15ae5afe 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -284,7 +284,7 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { gspec.MustCommit(ldb) odr := &testOdr{sdb: sdb, ldb: ldb, serverState: blockchain.StateCache(), indexerConfig: TestClientIndexerConfig} - lightchain, err := NewLightChain(odr, gspec.Config, ethash.NewFullFaker(), nil) + lightchain, err := NewLightChain(odr, gspec.Config, ethash.NewFullFaker()) if err != nil { t.Fatal(err) } diff --git a/light/odr_util.go b/light/odr_util.go index 37a1b7a633..8e2047f006 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -197,30 +197,6 @@ func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number return logs, nil } -// GetUntrustedBlockLogs retrieves the logs generated by the transactions included in a -// block. The retrieved logs are regarded as untrusted and will not be stored in the -// database. This function should only be used in light client checkpoint syncing. -func GetUntrustedBlockLogs(ctx context.Context, odr OdrBackend, header *types.Header) ([][]*types.Log, error) { - // Retrieve the potentially incomplete receipts from disk or network - hash, number := header.Hash(), header.Number.Uint64() - receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number) - if receipts == nil { - r := &ReceiptsRequest{Hash: hash, Number: number, Header: header, Untrusted: true} - if err := odr.Retrieve(ctx, r); err != nil { - return nil, err - } - receipts = r.Receipts - // Untrusted receipts won't be stored in the database. Therefore - // derived fields computation is unnecessary. - } - // Return the logs without deriving any computed fields on the receipts - logs := make([][]*types.Log, len(receipts)) - for i, receipt := range receipts { - logs[i] = receipt.Logs - } - return logs, nil -} - // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to // the given bit index and section indexes. func GetBloomBits(ctx context.Context, odr OdrBackend, bit uint, sections []uint64) ([][]byte, error) { diff --git a/light/txpool_test.go b/light/txpool_test.go index 0770088063..02f982d9af 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -103,7 +103,7 @@ func TestTxPool(t *testing.T) { discard: make(chan int, 1), mined: make(chan int, 1), } - lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil) + lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker()) txPermanent = 50 pool := NewTxPool(params.TestChainConfig, lightchain, relay) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) diff --git a/params/config.go b/params/config.go index 82d00bc8f5..9ea2b150b0 100644 --- a/params/config.go +++ b/params/config.go @@ -17,12 +17,10 @@ package params import ( - "encoding/binary" "fmt" "math/big" "github.com/ethereum/go-ethereum/common" - "golang.org/x/crypto/sha3" ) // Genesis hashes to enforce below configs on. @@ -33,23 +31,6 @@ var ( GoerliGenesisHash = common.HexToHash("0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a") ) -// TrustedCheckpoints associates each known checkpoint with the genesis hash of -// the chain it belongs to. -var TrustedCheckpoints = map[common.Hash]*TrustedCheckpoint{ - MainnetGenesisHash: MainnetTrustedCheckpoint, - SepoliaGenesisHash: SepoliaTrustedCheckpoint, - RinkebyGenesisHash: RinkebyTrustedCheckpoint, - GoerliGenesisHash: GoerliTrustedCheckpoint, -} - -// CheckpointOracles associates each known checkpoint oracles with the genesis hash of -// the chain it belongs to. -var CheckpointOracles = map[common.Hash]*CheckpointOracleConfig{ - MainnetGenesisHash: MainnetCheckpointOracle, - RinkebyGenesisHash: RinkebyCheckpointOracle, - GoerliGenesisHash: GoerliCheckpointOracle, -} - func newUint64(val uint64) *uint64 { return &val } var ( @@ -78,28 +59,6 @@ var ( ShanghaiTime: newUint64(1681338455), Ethash: new(EthashConfig), } - - // MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network. - MainnetTrustedCheckpoint = &TrustedCheckpoint{ - SectionIndex: 506, - SectionHead: common.HexToHash("0x3d1a139a6fc7764211236ef7c64d9e8c1fe55b358d7414e25277bac1144486cd"), - CHTRoot: common.HexToHash("0xef7fc3321a239a54238593bdf68d82933d903cb533b0d03228a8d958cd35ea77"), - BloomRoot: common.HexToHash("0x51d7bfe7c6397b1caa8b1cb046de4aeaf7e7fbd3fb6c726b60bf750de78809e8"), - } - - // MainnetCheckpointOracle contains a set of configs for the main network oracle. - MainnetCheckpointOracle = &CheckpointOracleConfig{ - Address: common.HexToAddress("0x9a9070028361F7AAbeB3f2F2Dc07F82C4a98A02a"), - Signers: []common.Address{ - common.HexToAddress("0x1b2C260efc720BE89101890E4Db589b44E950527"), // Peter - common.HexToAddress("0x78d1aD571A1A09D60D9BBf25894b44e4C8859595"), // Martin - common.HexToAddress("0x286834935f4A8Cfb4FF4C77D5770C2775aE2b0E7"), // Zsolt - common.HexToAddress("0xb86e2B0Ab5A4B1373e40c51A7C712c70Ba2f9f8E"), // Gary - common.HexToAddress("0x0DF8fa387C602AE62559cC4aFa4972A7045d6707"), // Guillaume - }, - Threshold: 2, - } - // SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network. SepoliaChainConfig = &ChainConfig{ ChainID: big.NewInt(11155111), @@ -122,15 +81,6 @@ var ( ShanghaiTime: newUint64(1677557088), Ethash: new(EthashConfig), } - - // SepoliaTrustedCheckpoint contains the light client trusted checkpoint for the Sepolia test network. - SepoliaTrustedCheckpoint = &TrustedCheckpoint{ - SectionIndex: 55, - SectionHead: common.HexToHash("0xb70ea113ab4db9d6e015c5b55d486713f60c40bda666121914a71ce3aec53a75"), - CHTRoot: common.HexToHash("0x206456d8847b66aaf427ed551f55e24cff90241bdb0a02583c761bf8164f78e4"), - BloomRoot: common.HexToHash("0x4369228d59a8fe285fee874c636531091e659b3b1294bb978eb159860a1cede2"), - } - // RinkebyChainConfig contains the chain parameters to run a node on the Rinkeby test network. RinkebyChainConfig = &ChainConfig{ ChainID: big.NewInt(4), @@ -153,27 +103,6 @@ var ( Epoch: 30000, }, } - - // RinkebyTrustedCheckpoint contains the light client trusted checkpoint for the Rinkeby test network. - RinkebyTrustedCheckpoint = &TrustedCheckpoint{ - SectionIndex: 373, - SectionHead: common.HexToHash("0x09f6d8f0d08d61025ccf4578dc214220b78013841470d445ed86faab4a5a885a"), - CHTRoot: common.HexToHash("0xef72902b944a111e9fdfee5fb69a5e46f68bf11a1f0bd430321f92d6b66987df"), - BloomRoot: common.HexToHash("0xd0120268729c51dd6fa2714f7f88527adfecbdb08592c671233ad2e0ad7cd835"), - } - - // RinkebyCheckpointOracle contains a set of configs for the Rinkeby test network oracle. - RinkebyCheckpointOracle = &CheckpointOracleConfig{ - Address: common.HexToAddress("0xebe8eFA441B9302A0d7eaECc277c09d20D684540"), - Signers: []common.Address{ - common.HexToAddress("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3"), // Peter - common.HexToAddress("0x78d1aD571A1A09D60D9BBf25894b44e4C8859595"), // Martin - common.HexToAddress("0x286834935f4A8Cfb4FF4C77D5770C2775aE2b0E7"), // Zsolt - common.HexToAddress("0xb86e2B0Ab5A4B1373e40c51A7C712c70Ba2f9f8E"), // Gary - }, - Threshold: 2, - } - // GoerliChainConfig contains the chain parameters to run a node on the Görli test network. GoerliChainConfig = &ChainConfig{ ChainID: big.NewInt(5), @@ -199,28 +128,6 @@ var ( Epoch: 30000, }, } - - // GoerliTrustedCheckpoint contains the light client trusted checkpoint for the Görli test network. - GoerliTrustedCheckpoint = &TrustedCheckpoint{ - SectionIndex: 229, - SectionHead: common.HexToHash("0xc5a7b57cb4af7b3d4cc251ac5f29acaac94e7464365358e7ad26129083b7729a"), - CHTRoot: common.HexToHash("0x54c0d5c756d9c48eda26ea13c2a49c2e31f1cb7dfb01514ddc49f3d24272c77e"), - BloomRoot: common.HexToHash("0xd681970a496f6187d089f8c8665a3587b5a78212d79b6ceef97c0dabd0188e56"), - } - - // GoerliCheckpointOracle contains a set of configs for the Goerli test network oracle. - GoerliCheckpointOracle = &CheckpointOracleConfig{ - Address: common.HexToAddress("0x18CA0E045F0D772a851BC7e48357Bcaab0a0795D"), - Signers: []common.Address{ - common.HexToAddress("0x4769bcaD07e3b938B7f43EB7D278Bc7Cb9efFb38"), // Peter - common.HexToAddress("0x78d1aD571A1A09D60D9BBf25894b44e4C8859595"), // Martin - common.HexToAddress("0x286834935f4A8Cfb4FF4C77D5770C2775aE2b0E7"), // Zsolt - common.HexToAddress("0xb86e2B0Ab5A4B1373e40c51A7C712c70Ba2f9f8E"), // Gary - common.HexToAddress("0x0DF8fa387C602AE62559cC4aFa4972A7045d6707"), // Guillaume - }, - Threshold: 2, - } - // AllEthashProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Ethash consensus. AllEthashProtocolChanges = &ChainConfig{ @@ -347,54 +254,6 @@ var NetworkNames = map[string]string{ SepoliaChainConfig.ChainID.String(): "sepolia", } -// TrustedCheckpoint represents a set of post-processed trie roots (CHT and -// BloomTrie) associated with the appropriate section index and head hash. It is -// used to start light syncing from this checkpoint and avoid downloading the -// entire header chain while still being able to securely access old headers/logs. -type TrustedCheckpoint struct { - SectionIndex uint64 `json:"sectionIndex"` - SectionHead common.Hash `json:"sectionHead"` - CHTRoot common.Hash `json:"chtRoot"` - BloomRoot common.Hash `json:"bloomRoot"` -} - -// HashEqual returns an indicator comparing the itself hash with given one. -func (c *TrustedCheckpoint) HashEqual(hash common.Hash) bool { - if c.Empty() { - return hash == common.Hash{} - } - return c.Hash() == hash -} - -// Hash returns the hash of checkpoint's four key fields(index, sectionHead, chtRoot and bloomTrieRoot). -func (c *TrustedCheckpoint) Hash() common.Hash { - var sectionIndex [8]byte - binary.BigEndian.PutUint64(sectionIndex[:], c.SectionIndex) - - w := sha3.NewLegacyKeccak256() - w.Write(sectionIndex[:]) - w.Write(c.SectionHead[:]) - w.Write(c.CHTRoot[:]) - w.Write(c.BloomRoot[:]) - - var h common.Hash - w.Sum(h[:0]) - return h -} - -// Empty returns an indicator whether the checkpoint is regarded as empty. -func (c *TrustedCheckpoint) Empty() bool { - return c.SectionHead == (common.Hash{}) || c.CHTRoot == (common.Hash{}) || c.BloomRoot == (common.Hash{}) -} - -// CheckpointOracleConfig represents a set of checkpoint contract(which acts as an oracle) -// config which used for light client checkpoint syncing. -type CheckpointOracleConfig struct { - Address common.Address `json:"address"` - Signers []common.Address `json:"signers"` - Threshold uint64 `json:"threshold"` -} - // ChainConfig is the core config which determines the blockchain settings. // // ChainConfig is stored in the database on a per block basis. This means From bbcb5ea37b31c48a59f9aa5fad3fd22233c8a2ae Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 24 Apr 2023 15:38:52 +0800 Subject: [PATCH 069/988] core, trie: rework trie database (#26813) * core, trie: rework trie database * trie: fix comment --- trie/committer.go | 40 +++-- trie/database.go | 366 +++++++++++--------------------------------- trie/iterator.go | 11 +- trie/node.go | 13 ++ trie/node_enc.go | 23 --- trie/nodeset.go | 24 +-- trie/proof.go | 7 +- trie/stacktrie.go | 12 +- trie/trie.go | 4 +- trie/trie_reader.go | 39 +---- 10 files changed, 152 insertions(+), 387 deletions(-) diff --git a/trie/committer.go b/trie/committer.go index 9f978873a8..af5f5f1a17 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -142,12 +142,10 @@ func (c *committer) store(path []byte, n node) node { // We have the hash already, estimate the RLP encoding-size of the node. // The size is used for mem tracking, does not need to be exact var ( - size = estimateSize(n) nhash = common.BytesToHash(hash) mnode = &memoryNode{ hash: nhash, - node: simplifyNode(n), - size: uint16(size), + node: nodeToBytes(n), } ) // Collect the dirty node to nodeset for return. @@ -166,31 +164,29 @@ func (c *committer) store(path []byte, n node) node { return hash } -// estimateSize estimates the size of an rlp-encoded node, without actually -// rlp-encoding it (zero allocs). This method has been experimentally tried, and with a trie -// with 1000 leaves, the only errors above 1% are on small shortnodes, where this -// method overestimates by 2 or 3 bytes (e.g. 37 instead of 35) -func estimateSize(n node) int { +// mptResolver the children resolver in merkle-patricia-tree. +type mptResolver struct{} + +// ForEach implements childResolver, decodes the provided node and +// traverses the children inside. +func (resolver mptResolver) forEach(node []byte, onChild func(common.Hash)) { + forGatherChildren(mustDecodeNodeUnsafe(nil, node), onChild) +} + +// forGatherChildren traverses the node hierarchy and invokes the callback +// for all the hashnode children. +func forGatherChildren(n node, onChild func(hash common.Hash)) { switch n := n.(type) { case *shortNode: - // A short node contains a compacted key, and a value. - return 3 + len(n.Key) + estimateSize(n.Val) + forGatherChildren(n.Val, onChild) case *fullNode: - // A full node contains up to 16 hashes (some nils), and a key - s := 3 for i := 0; i < 16; i++ { - if child := n.Children[i]; child != nil { - s += estimateSize(child) - } else { - s++ - } + forGatherChildren(n.Children[i], onChild) } - return s - case valueNode: - return 1 + len(n) case hashNode: - return 1 + len(n) + onChild(common.BytesToHash(n)) + case valueNode, nil: default: - panic(fmt.Sprintf("node type %T", n)) + panic(fmt.Sprintf("unknown node type: %T", n)) } } diff --git a/trie/database.go b/trie/database.go index 200ed3674b..c1f7ddd756 100644 --- a/trie/database.go +++ b/trie/database.go @@ -18,8 +18,6 @@ package trie import ( "errors" - "fmt" - "io" "reflect" "runtime" "sync" @@ -59,6 +57,12 @@ var ( memcacheCommitSizeMeter = metrics.NewRegisteredMeter("trie/memcache/commit/size", nil) ) +// childResolver defines the required method to decode the provided +// trie node and iterate the children on top. +type childResolver interface { + forEach(node []byte, onChild func(common.Hash)) +} + // Database is an intermediate write layer between the trie data structures and // the disk database. The aim is to accumulate trie writes in-memory and only // periodically flush a couple tries to disk, garbage collecting the remainder. @@ -68,7 +72,8 @@ var ( // behind this split design is to provide read access to RPC handlers and sync // servers even while the trie is executing expensive garbage collection. type Database struct { - diskdb ethdb.Database // Persistent storage for matured trie nodes + diskdb ethdb.Database // Persistent storage for matured trie nodes + resolver childResolver // The handler to resolve children of nodes cleans *fastcache.Cache // GC friendly memory cache of clean node RLPs dirties map[common.Hash]*cachedNode // Data and references relationships of dirty trie nodes @@ -90,55 +95,14 @@ type Database struct { lock sync.RWMutex } -// rawNode is a simple binary blob used to differentiate between collapsed trie -// nodes and already encoded RLP binary blobs (while at the same time store them -// in the same cache fields). -type rawNode []byte - -func (n rawNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } -func (n rawNode) fstring(ind string) string { panic("this should never end up in a live trie") } - -func (n rawNode) EncodeRLP(w io.Writer) error { - _, err := w.Write(n) - return err -} - -// rawFullNode represents only the useful data content of a full node, with the -// caches and flags stripped out to minimize its data storage. This type honors -// the same RLP encoding as the original parent. -type rawFullNode [17]node - -func (n rawFullNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } -func (n rawFullNode) fstring(ind string) string { panic("this should never end up in a live trie") } - -func (n rawFullNode) EncodeRLP(w io.Writer) error { - eb := rlp.NewEncoderBuffer(w) - n.encode(eb) - return eb.Flush() -} - -// rawShortNode represents only the useful data content of a short node, with the -// caches and flags stripped out to minimize its data storage. This type honors -// the same RLP encoding as the original parent. -type rawShortNode struct { - Key []byte - Val node -} - -func (n rawShortNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } -func (n rawShortNode) fstring(ind string) string { panic("this should never end up in a live trie") } - // cachedNode is all the information we know about a single cached trie node // in the memory database write layer. type cachedNode struct { - node node // Cached collapsed trie node, or raw rlp data - size uint16 // Byte size of the useful cached data - - parents uint32 // Number of live nodes referencing this one - children map[common.Hash]uint16 // External children referenced by this node - - flushPrev common.Hash // Previous node in the flush-list - flushNext common.Hash // Next node in the flush-list + node []byte // Encoded node blob + parents uint32 // Number of live nodes referencing this one + external map[common.Hash]struct{} // The set of external children + flushPrev common.Hash // Previous node in the flush-list + flushNext common.Hash // Next node in the flush-list } // cachedNodeSize is the raw size of a cachedNode data structure without any @@ -146,121 +110,14 @@ type cachedNode struct { // than not counting them. var cachedNodeSize = int(reflect.TypeOf(cachedNode{}).Size()) -// cachedNodeChildrenSize is the raw size of an initialized but empty external -// reference map. -const cachedNodeChildrenSize = 48 - -// rlp returns the raw rlp encoded blob of the cached trie node, either directly -// from the cache, or by regenerating it from the collapsed node. -func (n *cachedNode) rlp() []byte { - if node, ok := n.node.(rawNode); ok { - return node - } - return nodeToBytes(n.node) -} - -// obj returns the decoded and expanded trie node, either directly from the cache, -// or by regenerating it from the rlp encoded blob. -func (n *cachedNode) obj(hash common.Hash) node { - if node, ok := n.node.(rawNode); ok { - // The raw-blob format nodes are loaded either from the - // clean cache or the database, they are all in their own - // copy and safe to use unsafe decoder. - return mustDecodeNodeUnsafe(hash[:], node) - } - return expandNode(hash[:], n.node) -} - -// forChilds invokes the callback for all the tracked children of this node, +// forChildren invokes the callback for all the tracked children of this node, // both the implicit ones from inside the node as well as the explicit ones // from outside the node. -func (n *cachedNode) forChilds(onChild func(hash common.Hash)) { - for child := range n.children { +func (n *cachedNode) forChildren(resolver childResolver, onChild func(hash common.Hash)) { + for child := range n.external { onChild(child) } - if _, ok := n.node.(rawNode); !ok { - forGatherChildren(n.node, onChild) - } -} - -// forGatherChildren traverses the node hierarchy of a collapsed storage node and -// invokes the callback for all the hashnode children. -func forGatherChildren(n node, onChild func(hash common.Hash)) { - switch n := n.(type) { - case *rawShortNode: - forGatherChildren(n.Val, onChild) - case rawFullNode: - for i := 0; i < 16; i++ { - forGatherChildren(n[i], onChild) - } - case hashNode: - onChild(common.BytesToHash(n)) - case valueNode, nil, rawNode: - default: - panic(fmt.Sprintf("unknown node type: %T", n)) - } -} - -// simplifyNode traverses the hierarchy of an expanded memory node and discards -// all the internal caches, returning a node that only contains the raw data. -func simplifyNode(n node) node { - switch n := n.(type) { - case *shortNode: - // Short nodes discard the flags and cascade - return &rawShortNode{Key: n.Key, Val: simplifyNode(n.Val)} - - case *fullNode: - // Full nodes discard the flags and cascade - node := rawFullNode(n.Children) - for i := 0; i < len(node); i++ { - if node[i] != nil { - node[i] = simplifyNode(node[i]) - } - } - return node - - case valueNode, hashNode, rawNode: - return n - - default: - panic(fmt.Sprintf("unknown node type: %T", n)) - } -} - -// expandNode traverses the node hierarchy of a collapsed storage node and converts -// all fields and keys into expanded memory form. -func expandNode(hash hashNode, n node) node { - switch n := n.(type) { - case *rawShortNode: - // Short nodes need key and child expansion - return &shortNode{ - Key: compactToHex(n.Key), - Val: expandNode(nil, n.Val), - flags: nodeFlag{ - hash: hash, - }, - } - - case rawFullNode: - // Full nodes need child expansion - node := &fullNode{ - flags: nodeFlag{ - hash: hash, - }, - } - for i := 0; i < len(node.Children); i++ { - if n[i] != nil { - node.Children[i] = expandNode(nil, n[i]) - } - } - return node - - case valueNode, hashNode: - return n - - default: - panic(fmt.Sprintf("unknown node type: %T", n)) - } + resolver.forEach(n.node, onChild) } // Config defines all necessary options for database. @@ -293,34 +150,31 @@ func NewDatabaseWithConfig(diskdb ethdb.Database, config *Config) *Database { if config != nil && config.Preimages { preimage = newPreimageStore(diskdb) } - db := &Database{ - diskdb: diskdb, - cleans: cleans, - dirties: map[common.Hash]*cachedNode{{}: { - children: make(map[common.Hash]uint16), - }}, + return &Database{ + diskdb: diskdb, + resolver: mptResolver{}, + cleans: cleans, + dirties: make(map[common.Hash]*cachedNode), preimages: preimage, } - return db } // insert inserts a simplified trie node into the memory database. // All nodes inserted by this function will be reference tracked // and in theory should only used for **trie nodes** insertion. -func (db *Database) insert(hash common.Hash, size int, node node) { +func (db *Database) insert(hash common.Hash, node []byte) { // If the node's already cached, skip if _, ok := db.dirties[hash]; ok { return } - memcacheDirtyWriteMeter.Mark(int64(size)) + memcacheDirtyWriteMeter.Mark(int64(len(node))) // Create the cached entry for this node entry := &cachedNode{ node: node, - size: uint16(size), flushPrev: db.newest, } - entry.forChilds(func(child common.Hash) { + entry.forChildren(db.resolver, func(child common.Hash) { if c := db.dirties[child]; c != nil { c.parents++ } @@ -333,48 +187,7 @@ func (db *Database) insert(hash common.Hash, size int, node node) { } else { db.dirties[db.newest].flushNext, db.newest = hash, hash } - db.dirtiesSize += common.StorageSize(common.HashLength + entry.size) -} - -// node retrieves a cached trie node from memory, or returns nil if none can be -// found in the memory cache. -func (db *Database) node(hash common.Hash) node { - // Retrieve the node from the clean cache if available - if db.cleans != nil { - if enc := db.cleans.Get(nil, hash[:]); enc != nil { - memcacheCleanHitMeter.Mark(1) - memcacheCleanReadMeter.Mark(int64(len(enc))) - - // The returned value from cache is in its own copy, - // safe to use mustDecodeNodeUnsafe for decoding. - return mustDecodeNodeUnsafe(hash[:], enc) - } - } - // Retrieve the node from the dirty cache if available - db.lock.RLock() - dirty := db.dirties[hash] - db.lock.RUnlock() - - if dirty != nil { - memcacheDirtyHitMeter.Mark(1) - memcacheDirtyReadMeter.Mark(int64(dirty.size)) - return dirty.obj(hash) - } - memcacheDirtyMissMeter.Mark(1) - - // Content unavailable in memory, attempt to retrieve from disk - enc, err := db.diskdb.Get(hash[:]) - if err != nil || enc == nil { - return nil - } - if db.cleans != nil { - db.cleans.Set(hash[:], enc) - memcacheCleanMissMeter.Mark(1) - memcacheCleanWriteMeter.Mark(int64(len(enc))) - } - // The returned value from database is in its own copy, - // safe to use mustDecodeNodeUnsafe for decoding. - return mustDecodeNodeUnsafe(hash[:], enc) + db.dirtiesSize += common.StorageSize(common.HashLength + len(node)) } // Node retrieves an encoded cached trie node from memory. If it cannot be found @@ -399,8 +212,8 @@ func (db *Database) Node(hash common.Hash) ([]byte, error) { if dirty != nil { memcacheDirtyHitMeter.Mark(1) - memcacheDirtyReadMeter.Mark(int64(dirty.size)) - return dirty.rlp(), nil + memcacheDirtyReadMeter.Mark(int64(len(dirty.node))) + return dirty.node, nil } memcacheDirtyMissMeter.Mark(1) @@ -426,9 +239,7 @@ func (db *Database) Nodes() []common.Hash { var hashes = make([]common.Hash, 0, len(db.dirties)) for hash := range db.dirties { - if hash != (common.Hash{}) { // Special case for "root" references/nodes - hashes = append(hashes, hash) - } + hashes = append(hashes, hash) } return hashes } @@ -451,18 +262,22 @@ func (db *Database) reference(child common.Hash, parent common.Hash) { if !ok { return } - // If the reference already exists, only duplicate for roots - if db.dirties[parent].children == nil { - db.dirties[parent].children = make(map[common.Hash]uint16) - db.childrenSize += cachedNodeChildrenSize - } else if _, ok = db.dirties[parent].children[child]; ok && parent != (common.Hash{}) { + // The reference is for state root, increase the reference counter. + if parent == (common.Hash{}) { + node.parents += 1 return } - node.parents++ - db.dirties[parent].children[child]++ - if db.dirties[parent].children[child] == 1 { - db.childrenSize += common.HashLength + 2 // uint16 counter + // The reference is for external storage trie, don't duplicate if + // the reference is already existent. + if db.dirties[parent].external == nil { + db.dirties[parent].external = make(map[common.Hash]struct{}) + } + if _, ok := db.dirties[parent].external[child]; ok { + return } + node.parents++ + db.dirties[parent].external[child] = struct{}{} + db.childrenSize += common.HashLength } // Dereference removes an existing reference from a root node. @@ -476,7 +291,7 @@ func (db *Database) Dereference(root common.Hash) { defer db.lock.Unlock() nodes, storage, start := len(db.dirties), db.dirtiesSize, time.Now() - db.dereference(root, common.Hash{}) + db.dereference(root) db.gcnodes += uint64(nodes - len(db.dirties)) db.gcsize += storage - db.dirtiesSize @@ -491,23 +306,13 @@ func (db *Database) Dereference(root common.Hash) { } // dereference is the private locked version of Dereference. -func (db *Database) dereference(child common.Hash, parent common.Hash) { - // Dereference the parent-child - node := db.dirties[parent] - - if node.children != nil && node.children[child] > 0 { - node.children[child]-- - if node.children[child] == 0 { - delete(node.children, child) - db.childrenSize -= (common.HashLength + 2) // uint16 counter - } - } - // If the child does not exist, it's a previously committed node. - node, ok := db.dirties[child] +func (db *Database) dereference(hash common.Hash) { + // If the node does not exist, it's a previously committed node. + node, ok := db.dirties[hash] if !ok { return } - // If there are no more references to the child, delete it and cascade + // If there are no more references to the node, delete it and cascade if node.parents > 0 { // This is a special cornercase where a node loaded from disk (i.e. not in the // memcache any more) gets reinjected as a new node (short node split into full, @@ -517,25 +322,29 @@ func (db *Database) dereference(child common.Hash, parent common.Hash) { } if node.parents == 0 { // Remove the node from the flush-list - switch child { + switch hash { case db.oldest: db.oldest = node.flushNext - db.dirties[node.flushNext].flushPrev = common.Hash{} + if node.flushNext != (common.Hash{}) { + db.dirties[node.flushNext].flushPrev = common.Hash{} + } case db.newest: db.newest = node.flushPrev - db.dirties[node.flushPrev].flushNext = common.Hash{} + if node.flushPrev != (common.Hash{}) { + db.dirties[node.flushPrev].flushNext = common.Hash{} + } default: db.dirties[node.flushPrev].flushNext = node.flushNext db.dirties[node.flushNext].flushPrev = node.flushPrev } // Dereference all children and delete the node - node.forChilds(func(hash common.Hash) { - db.dereference(hash, child) + node.forChildren(db.resolver, func(child common.Hash) { + db.dereference(child) }) - delete(db.dirties, child) - db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) - if node.children != nil { - db.childrenSize -= cachedNodeChildrenSize + delete(db.dirties, hash) + db.dirtiesSize -= common.StorageSize(common.HashLength + len(node.node)) + if node.external != nil { + db.childrenSize -= common.StorageSize(len(node.external) * common.HashLength) } } } @@ -556,8 +365,8 @@ func (db *Database) Cap(limit common.StorageSize) error { // db.dirtiesSize only contains the useful data in the cache, but when reporting // the total memory consumption, the maintenance metadata is also needed to be // counted. - size := db.dirtiesSize + common.StorageSize((len(db.dirties)-1)*cachedNodeSize) - size += db.childrenSize - common.StorageSize(len(db.dirties[common.Hash{}].children)*(common.HashLength+2)) + size := db.dirtiesSize + common.StorageSize(len(db.dirties)*cachedNodeSize) + size += db.childrenSize // If the preimage cache got large enough, push to disk. If it's still small // leave for later to deduplicate writes. @@ -571,7 +380,7 @@ func (db *Database) Cap(limit common.StorageSize) error { for size > limit && oldest != (common.Hash{}) { // Fetch the oldest referenced node and push into the batch node := db.dirties[oldest] - rawdb.WriteLegacyTrieNode(batch, oldest, node.rlp()) + rawdb.WriteLegacyTrieNode(batch, oldest, node.node) // If we exceeded the ideal batch size, commit and reset if batch.ValueSize() >= ethdb.IdealBatchSize { @@ -584,9 +393,9 @@ func (db *Database) Cap(limit common.StorageSize) error { // Iterate to the next flush item, or abort if the size cap was achieved. Size // is the total size, including the useful cached data (hash -> blob), the // cache item metadata, as well as external children mappings. - size -= common.StorageSize(common.HashLength + int(node.size) + cachedNodeSize) - if node.children != nil { - size -= common.StorageSize(cachedNodeChildrenSize + len(node.children)*(common.HashLength+2)) + size -= common.StorageSize(common.HashLength + len(node.node) + cachedNodeSize) + if node.external != nil { + size -= common.StorageSize(len(node.external) * common.HashLength) } oldest = node.flushNext } @@ -604,9 +413,9 @@ func (db *Database) Cap(limit common.StorageSize) error { delete(db.dirties, db.oldest) db.oldest = node.flushNext - db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) - if node.children != nil { - db.childrenSize -= common.StorageSize(cachedNodeChildrenSize + len(node.children)*(common.HashLength+2)) + db.dirtiesSize -= common.StorageSize(common.HashLength + len(node.node)) + if node.external != nil { + db.childrenSize -= common.StorageSize(len(node.external) * common.HashLength) } } if db.oldest != (common.Hash{}) { @@ -694,7 +503,9 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane return nil } var err error - node.forChilds(func(child common.Hash) { + + // Dereference all children and delete the node + node.forChildren(db.resolver, func(child common.Hash) { if err == nil { err = db.commit(child, batch, uncacher) } @@ -703,7 +514,7 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane return err } // If we've reached an optimal batch size, commit and start over - rawdb.WriteLegacyTrieNode(batch, hash, node.rlp()) + rawdb.WriteLegacyTrieNode(batch, hash, node.node) if batch.ValueSize() >= ethdb.IdealBatchSize { if err := batch.Write(); err != nil { return err @@ -742,19 +553,23 @@ func (c *cleaner) Put(key []byte, rlp []byte) error { switch hash { case c.db.oldest: c.db.oldest = node.flushNext - c.db.dirties[node.flushNext].flushPrev = common.Hash{} + if node.flushNext != (common.Hash{}) { + c.db.dirties[node.flushNext].flushPrev = common.Hash{} + } case c.db.newest: c.db.newest = node.flushPrev - c.db.dirties[node.flushPrev].flushNext = common.Hash{} + if node.flushPrev != (common.Hash{}) { + c.db.dirties[node.flushPrev].flushNext = common.Hash{} + } default: c.db.dirties[node.flushPrev].flushNext = node.flushNext c.db.dirties[node.flushNext].flushPrev = node.flushPrev } // Remove the node from the dirty cache delete(c.db.dirties, hash) - c.db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) - if node.children != nil { - c.db.childrenSize -= common.StorageSize(cachedNodeChildrenSize + len(node.children)*(common.HashLength+2)) + c.db.dirtiesSize -= common.StorageSize(common.HashLength + len(node.node)) + if node.external != nil { + c.db.childrenSize -= common.StorageSize(len(node.external) * common.HashLength) } // Move the flushed node into the clean cache to prevent insta-reloads if c.db.cleans != nil { @@ -796,7 +611,7 @@ func (db *Database) Update(nodes *MergedNodeSet) error { if n.isDeleted() { return // ignore deletion } - db.insert(n.hash, int(n.size), n.node) + db.insert(n.hash, n.node) }) } // Link up the account trie and storage trie if the node points @@ -824,13 +639,12 @@ func (db *Database) Size() (common.StorageSize, common.StorageSize) { // db.dirtiesSize only contains the useful data in the cache, but when reporting // the total memory consumption, the maintenance metadata is also needed to be // counted. - var metadataSize = common.StorageSize((len(db.dirties) - 1) * cachedNodeSize) - var metarootRefs = common.StorageSize(len(db.dirties[common.Hash{}].children) * (common.HashLength + 2)) + var metadataSize = common.StorageSize(len(db.dirties) * cachedNodeSize) var preimageSize common.StorageSize if db.preimages != nil { preimageSize = db.preimages.size() } - return db.dirtiesSize + db.childrenSize + metadataSize - metarootRefs, preimageSize + return db.dirtiesSize + db.childrenSize + metadataSize, preimageSize } // GetReader retrieves a node reader belonging to the given state root. @@ -848,15 +662,9 @@ func newHashReader(db *Database) *hashReader { return &hashReader{db: db} } -// Node retrieves the trie node with the given node hash. -// No error will be returned if the node is not found. -func (reader *hashReader) Node(_ common.Hash, _ []byte, hash common.Hash) (node, error) { - return reader.db.node(hash), nil -} - -// NodeBlob retrieves the RLP-encoded trie node blob with the given node hash. +// Node retrieves the RLP-encoded trie node blob with the given node hash. // No error will be returned if the node is not found. -func (reader *hashReader) NodeBlob(_ common.Hash, _ []byte, hash common.Hash) ([]byte, error) { +func (reader *hashReader) Node(_ common.Hash, _ []byte, hash common.Hash) ([]byte, error) { blob, _ := reader.db.Node(hash) return blob, nil } diff --git a/trie/iterator.go b/trie/iterator.go index f42beec4ab..6f054a7245 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -387,7 +387,14 @@ func (it *nodeIterator) resolveHash(hash hashNode, path []byte) (node, error) { // loaded blob will be tracked, while it's not required here since // all loaded nodes won't be linked to trie at all and track nodes // may lead to out-of-memory issue. - return it.trie.reader.node(path, common.BytesToHash(hash)) + blob, err := it.trie.reader.node(path, common.BytesToHash(hash)) + if err != nil { + return nil, err + } + // The raw-blob format nodes are loaded either from the + // clean cache or the database, they are all in their own + // copy and safe to use unsafe decoder. + return mustDecodeNodeUnsafe(hash, blob), nil } func (it *nodeIterator) resolveBlob(hash hashNode, path []byte) ([]byte, error) { @@ -401,7 +408,7 @@ func (it *nodeIterator) resolveBlob(hash hashNode, path []byte) ([]byte, error) // loaded blob will be tracked, while it's not required here since // all loaded nodes won't be linked to trie at all and track nodes // may lead to out-of-memory issue. - return it.trie.reader.nodeBlob(path, common.BytesToHash(hash)) + return it.trie.reader.node(path, common.BytesToHash(hash)) } func (st *nodeIteratorState) resolve(it *nodeIterator, path []byte) error { diff --git a/trie/node.go b/trie/node.go index 6ce6551ded..15bbf62f1c 100644 --- a/trie/node.go +++ b/trie/node.go @@ -99,6 +99,19 @@ func (n valueNode) fstring(ind string) string { return fmt.Sprintf("%x ", []byte(n)) } +// rawNode is a simple binary blob used to differentiate between collapsed trie +// nodes and already encoded RLP binary blobs (while at the same time store them +// in the same cache fields). +type rawNode []byte + +func (n rawNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } +func (n rawNode) fstring(ind string) string { panic("this should never end up in a live trie") } + +func (n rawNode) EncodeRLP(w io.Writer) error { + _, err := w.Write(n) + return err +} + // mustDecodeNode is a wrapper of decodeNode and panic if any error is encountered. func mustDecodeNode(hash, buf []byte) node { n, err := decodeNode(hash, buf) diff --git a/trie/node_enc.go b/trie/node_enc.go index cade35b707..1b2eca682f 100644 --- a/trie/node_enc.go +++ b/trie/node_enc.go @@ -59,29 +59,6 @@ func (n valueNode) encode(w rlp.EncoderBuffer) { w.WriteBytes(n) } -func (n rawFullNode) encode(w rlp.EncoderBuffer) { - offset := w.List() - for _, c := range n { - if c != nil { - c.encode(w) - } else { - w.Write(rlp.EmptyString) - } - } - w.ListEnd(offset) -} - -func (n *rawShortNode) encode(w rlp.EncoderBuffer) { - offset := w.List() - w.WriteBytes(n.Key) - if n.Val != nil { - n.Val.encode(w) - } else { - w.Write(rlp.EmptyString) - } - w.ListEnd(offset) -} - func (n rawNode) encode(w rlp.EncoderBuffer) { w.Write(n) } diff --git a/trie/nodeset.go b/trie/nodeset.go index 99e4a80fa8..fc2111375f 100644 --- a/trie/nodeset.go +++ b/trie/nodeset.go @@ -18,7 +18,6 @@ package trie import ( "fmt" - "reflect" "sort" "strings" @@ -28,41 +27,28 @@ import ( // memoryNode is all the information we know about a single cached trie node // in the memory. type memoryNode struct { - hash common.Hash // Node hash, computed by hashing rlp value, empty for deleted nodes - size uint16 // Byte size of the useful cached data, 0 for deleted nodes - node node // Cached collapsed trie node, or raw rlp data, nil for deleted nodes + hash common.Hash // Node hash by hashing node blob, empty for deleted nodes + node []byte // Encoded node blob, nil for deleted nodes } -// memoryNodeSize is the raw size of a memoryNode data structure without any -// node data included. It's an approximate size, but should be a lot better -// than not counting them. -// nolint:unused -var memoryNodeSize = int(reflect.TypeOf(memoryNode{}).Size()) - // memorySize returns the total memory size used by this node. // nolint:unused func (n *memoryNode) memorySize(pathlen int) int { - return int(n.size) + memoryNodeSize + pathlen + return len(n.node) + common.HashLength + pathlen } // rlp returns the raw rlp encoded blob of the cached trie node, either directly // from the cache, or by regenerating it from the collapsed node. // nolint:unused func (n *memoryNode) rlp() []byte { - if node, ok := n.node.(rawNode); ok { - return node - } - return nodeToBytes(n.node) + return n.node } // obj returns the decoded and expanded trie node, either directly from the cache, // or by regenerating it from the rlp encoded blob. // nolint:unused func (n *memoryNode) obj() node { - if node, ok := n.node.(rawNode); ok { - return mustDecodeNode(n.hash[:], node) - } - return expandNode(n.hash[:], n.node) + return mustDecodeNode(n.hash[:], n.node) } // isDeleted returns the indicator if the node is marked as deleted. diff --git a/trie/proof.go b/trie/proof.go index 65df7577b9..a25263d82e 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -64,12 +64,15 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) e // loaded blob will be tracked, while it's not required here since // all loaded nodes won't be linked to trie at all and track nodes // may lead to out-of-memory issue. - var err error - tn, err = t.reader.node(prefix, common.BytesToHash(n)) + blob, err := t.reader.node(prefix, common.BytesToHash(n)) if err != nil { log.Error("Unhandled trie error in Trie.Prove", "err", err) return err } + // The raw-blob format nodes are loaded either from the + // clean cache or the database, they are all in their own + // copy and safe to use unsafe decoder. + tn = mustDecodeNodeUnsafe(n, blob) default: panic(fmt.Sprintf("%T: invalid node: %v", tn, tn)) } diff --git a/trie/stacktrie.go b/trie/stacktrie.go index 030d2a596c..ee1ce28291 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -420,17 +420,17 @@ func (st *StackTrie) hashRec(hasher *hasher, path []byte) { return case branchNode: - var nodes rawFullNode + var nodes fullNode for i, child := range st.children { if child == nil { - nodes[i] = nilValueNode + nodes.Children[i] = nilValueNode continue } child.hashRec(hasher, append(path, byte(i))) if len(child.val) < 32 { - nodes[i] = rawNode(child.val) + nodes.Children[i] = rawNode(child.val) } else { - nodes[i] = hashNode(child.val) + nodes.Children[i] = hashNode(child.val) } // Release child back to pool. @@ -444,7 +444,7 @@ func (st *StackTrie) hashRec(hasher *hasher, path []byte) { case extNode: st.children[0].hashRec(hasher, append(path, st.key...)) - n := rawShortNode{Key: hexToCompact(st.key)} + n := shortNode{Key: hexToCompact(st.key)} if len(st.children[0].val) < 32 { n.Val = rawNode(st.children[0].val) } else { @@ -460,7 +460,7 @@ func (st *StackTrie) hashRec(hasher *hasher, path []byte) { case leafNode: st.key = append(st.key, byte(16)) - n := rawShortNode{Key: hexToCompact(st.key), Val: valueNode(st.val)} + n := shortNode{Key: hexToCompact(st.key), Val: valueNode(st.val)} n.encode(hasher.encbuf) encodedNode = hasher.encodedBytes() diff --git a/trie/trie.go b/trie/trie.go index 4b6f6a55bb..18504dc5bc 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -212,7 +212,7 @@ func (t *Trie) getNode(origNode node, path []byte, pos int) (item []byte, newnod if hash == nil { return nil, origNode, 0, errors.New("non-consensus node") } - blob, err := t.reader.nodeBlob(path, common.BytesToHash(hash)) + blob, err := t.reader.node(path, common.BytesToHash(hash)) return blob, origNode, 1, err } // Path still needs to be traversed, descend into children @@ -549,7 +549,7 @@ func (t *Trie) resolve(n node, prefix []byte) (node, error) { // node's original value. The rlp-encoded blob is preferred to be loaded from // database because it's easy to decode node while complex to encode node to blob. func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { - blob, err := t.reader.nodeBlob(prefix, common.BytesToHash(n)) + blob, err := t.reader.node(prefix, common.BytesToHash(n)) if err != nil { return nil, err } diff --git a/trie/trie_reader.go b/trie/trie_reader.go index 14186159b7..e3f98a8061 100644 --- a/trie/trie_reader.go +++ b/trie/trie_reader.go @@ -22,17 +22,12 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// Reader wraps the Node and NodeBlob method of a backing trie store. +// Reader wraps the Node method of a backing trie store. type Reader interface { - // Node retrieves the trie node with the provided trie identifier, hexary - // node path and the corresponding node hash. - // No error will be returned if the node is not found. - Node(owner common.Hash, path []byte, hash common.Hash) (node, error) - - // NodeBlob retrieves the RLP-encoded trie node blob with the provided trie - // identifier, hexary node path and the corresponding node hash. - // No error will be returned if the node is not found. - NodeBlob(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) + // Node retrieves the RLP-encoded trie node blob with the provided trie + // identifier, node path and the corresponding node hash. No error will + // be returned if the node is not found. + Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) } // NodeReader wraps all the necessary functions for accessing trie node. @@ -65,30 +60,10 @@ func newEmptyReader() *trieReader { return &trieReader{} } -// node retrieves the trie node with the provided trie node information. -// An MissingNodeError will be returned in case the node is not found or -// any error is encountered. -func (r *trieReader) node(path []byte, hash common.Hash) (node, error) { - // Perform the logics in tests for preventing trie node access. - if r.banned != nil { - if _, ok := r.banned[string(path)]; ok { - return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} - } - } - if r.reader == nil { - return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} - } - node, err := r.reader.Node(r.owner, path, hash) - if err != nil || node == nil { - return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path, err: err} - } - return node, nil -} - // node retrieves the rlp-encoded trie node with the provided trie node // information. An MissingNodeError will be returned in case the node is // not found or any error is encountered. -func (r *trieReader) nodeBlob(path []byte, hash common.Hash) ([]byte, error) { +func (r *trieReader) node(path []byte, hash common.Hash) ([]byte, error) { // Perform the logics in tests for preventing trie node access. if r.banned != nil { if _, ok := r.banned[string(path)]; ok { @@ -98,7 +73,7 @@ func (r *trieReader) nodeBlob(path []byte, hash common.Hash) ([]byte, error) { if r.reader == nil { return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} } - blob, err := r.reader.NodeBlob(r.owner, path, hash) + blob, err := r.reader.Node(r.owner, path, hash) if err != nil || len(blob) == 0 { return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path, err: err} } From f541cad272087d6633122d9f955881c8597a510f Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 25 Apr 2023 18:06:50 +0800 Subject: [PATCH 070/988] eth: use new atomic types (#27137) --- eth/backend.go | 7 +++-- eth/fetcher/block_fetcher_test.go | 44 +++++++++++++++---------------- eth/gasprice/feehistory.go | 10 +++---- eth/handler.go | 20 +++++++------- eth/handler_eth.go | 3 +-- eth/handler_eth_test.go | 6 ++--- eth/protocols/snap/sync.go | 14 +++++----- eth/sync.go | 9 +++---- eth/sync_test.go | 7 +++-- 9 files changed, 58 insertions(+), 62 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 105a8e8977..24ae08502a 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -23,7 +23,6 @@ import ( "math/big" "runtime" "sync" - "sync/atomic" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" @@ -437,7 +436,7 @@ func (s *Ethereum) StartMining(threads int) error { } // If mining is started, we can disable the transaction rejection mechanism // introduced to speed sync times. - atomic.StoreUint32(&s.handler.acceptTxs, 1) + s.handler.acceptTxs.Store(true) go s.miner.Start() } @@ -469,8 +468,8 @@ func (s *Ethereum) Engine() consensus.Engine { return s.engine } func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } func (s *Ethereum) IsListening() bool { return true } // Always listening func (s *Ethereum) Downloader() *downloader.Downloader { return s.handler.downloader } -func (s *Ethereum) Synced() bool { return atomic.LoadUint32(&s.handler.acceptTxs) == 1 } -func (s *Ethereum) SetSynced() { atomic.StoreUint32(&s.handler.acceptTxs, 1) } +func (s *Ethereum) Synced() bool { return s.handler.acceptTxs.Load() } +func (s *Ethereum) SetSynced() { s.handler.acceptTxs.Store(true) } func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning } func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } func (s *Ethereum) Merger() *consensus.Merger { return s.merger } diff --git a/eth/fetcher/block_fetcher_test.go b/eth/fetcher/block_fetcher_test.go index 0553add4f1..520fc9c7b7 100644 --- a/eth/fetcher/block_fetcher_test.go +++ b/eth/fetcher/block_fetcher_test.go @@ -413,13 +413,13 @@ func testConcurrentAnnouncements(t *testing.T, light bool) { secondHeaderFetcher := tester.makeHeaderFetcher("second", blocks, -gatherSlack) secondBodyFetcher := tester.makeBodyFetcher("second", blocks, 0) - counter := uint32(0) + var counter atomic.Uint32 firstHeaderWrapper := func(hash common.Hash, sink chan *eth.Response) (*eth.Request, error) { - atomic.AddUint32(&counter, 1) + counter.Add(1) return firstHeaderFetcher(hash, sink) } secondHeaderWrapper := func(hash common.Hash, sink chan *eth.Response) (*eth.Request, error) { - atomic.AddUint32(&counter, 1) + counter.Add(1) return secondHeaderFetcher(hash, sink) } // Iteratively announce blocks until all are imported @@ -446,8 +446,8 @@ func testConcurrentAnnouncements(t *testing.T, light bool) { verifyImportDone(t, imported) // Make sure no blocks were retrieved twice - if int(counter) != targetBlocks { - t.Fatalf("retrieval count mismatch: have %v, want %v", counter, targetBlocks) + if c := int(counter.Load()); c != targetBlocks { + t.Fatalf("retrieval count mismatch: have %v, want %v", c, targetBlocks) } verifyChainHeight(t, tester, uint64(len(hashes)-1)) } @@ -513,9 +513,9 @@ func testPendingDeduplication(t *testing.T, light bool) { bodyFetcher := tester.makeBodyFetcher("repeater", blocks, 0) delay := 50 * time.Millisecond - counter := uint32(0) + var counter atomic.Uint32 headerWrapper := func(hash common.Hash, sink chan *eth.Response) (*eth.Request, error) { - atomic.AddUint32(&counter, 1) + counter.Add(1) // Simulate a long running fetch resink := make(chan *eth.Response) @@ -545,8 +545,8 @@ func testPendingDeduplication(t *testing.T, light bool) { time.Sleep(delay) // Check that all blocks were imported and none fetched twice - if int(counter) != 1 { - t.Fatalf("retrieval count mismatch: have %v, want %v", counter, 1) + if c := counter.Load(); c != 1 { + t.Fatalf("retrieval count mismatch: have %v, want %v", c, 1) } verifyChainHeight(t, tester, 1) } @@ -632,9 +632,9 @@ func TestImportDeduplication(t *testing.T) { headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack) bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) - counter := uint32(0) + var counter atomic.Uint32 tester.fetcher.insertChain = func(blocks types.Blocks) (int, error) { - atomic.AddUint32(&counter, uint32(len(blocks))) + counter.Add(uint32(len(blocks))) return tester.insertChain(blocks) } // Instrument the fetching and imported events @@ -655,8 +655,8 @@ func TestImportDeduplication(t *testing.T) { tester.fetcher.Enqueue("valid", blocks[hashes[1]]) verifyImportCount(t, imported, 2) - if counter != 2 { - t.Fatalf("import invocation count mismatch: have %v, want %v", counter, 2) + if c := counter.Load(); c != 2 { + t.Fatalf("import invocation count mismatch: have %v, want %v", c, 2) } } @@ -853,13 +853,13 @@ func TestHashMemoryExhaustionAttack(t *testing.T) { // Create a tester with instrumented import hooks tester := newTester(false) - imported, announces := make(chan interface{}), int32(0) + imported, announces := make(chan interface{}), atomic.Int32{} tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { imported <- block } tester.fetcher.announceChangeHook = func(hash common.Hash, added bool) { if added { - atomic.AddInt32(&announces, 1) + announces.Add(1) } else { - atomic.AddInt32(&announces, -1) + announces.Add(-1) } } // Create a valid chain and an infinite junk chain @@ -879,7 +879,7 @@ func TestHashMemoryExhaustionAttack(t *testing.T) { } tester.fetcher.Notify("attacker", attack[i], 1 /* don't distance drop */, time.Now(), attackerHeaderFetcher, attackerBodyFetcher) } - if count := atomic.LoadInt32(&announces); count != hashLimit+maxQueueDist { + if count := announces.Load(); count != hashLimit+maxQueueDist { t.Fatalf("queued announce count mismatch: have %d, want %d", count, hashLimit+maxQueueDist) } // Wait for fetches to complete @@ -900,13 +900,13 @@ func TestBlockMemoryExhaustionAttack(t *testing.T) { // Create a tester with instrumented import hooks tester := newTester(false) - imported, enqueued := make(chan interface{}), int32(0) + imported, enqueued := make(chan interface{}), atomic.Int32{} tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { imported <- block } tester.fetcher.queueChangeHook = func(hash common.Hash, added bool) { if added { - atomic.AddInt32(&enqueued, 1) + enqueued.Add(1) } else { - atomic.AddInt32(&enqueued, -1) + enqueued.Add(-1) } } // Create a valid chain and a batch of dangling (but in range) blocks @@ -924,7 +924,7 @@ func TestBlockMemoryExhaustionAttack(t *testing.T) { tester.fetcher.Enqueue("attacker", block) } time.Sleep(200 * time.Millisecond) - if queued := atomic.LoadInt32(&enqueued); queued != blockLimit { + if queued := enqueued.Load(); queued != blockLimit { t.Fatalf("queued block count mismatch: have %d, want %d", queued, blockLimit) } // Queue up a batch of valid blocks, and check that a new peer is allowed to do so @@ -932,7 +932,7 @@ func TestBlockMemoryExhaustionAttack(t *testing.T) { tester.fetcher.Enqueue("valid", blocks[hashes[len(hashes)-3-i]]) } time.Sleep(100 * time.Millisecond) - if queued := atomic.LoadInt32(&enqueued); queued != blockLimit+maxQueueDist-1 { + if queued := enqueued.Load(); queued != blockLimit+maxQueueDist-1 { t.Fatalf("queued block count mismatch: have %d, want %d", queued, blockLimit+maxQueueDist-1) } // Insert the missing piece (and sanity check the import) diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 82edf9a7fb..ee0b0ebcca 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -251,10 +251,10 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL } oldestBlock := lastBlock + 1 - blocks - var ( - next = oldestBlock - results = make(chan *blockFees, blocks) - ) + var next atomic.Uint64 + next.Store(oldestBlock) + results := make(chan *blockFees, blocks) + percentileKey := make([]byte, 8*len(rewardPercentiles)) for i, p := range rewardPercentiles { binary.LittleEndian.PutUint64(percentileKey[i*8:(i+1)*8], math.Float64bits(p)) @@ -263,7 +263,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL go func() { for { // Retrieve the next block number to fetch with this goroutine - blockNumber := atomic.AddUint64(&next, 1) - 1 + blockNumber := next.Add(1) - 1 if blockNumber > lastBlock { return } diff --git a/eth/handler.go b/eth/handler.go index 71ed6b227d..d4c538e6fe 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -91,8 +91,8 @@ type handler struct { networkID uint64 forkFilter forkid.Filter // Fork ID filter, constant across the lifetime of the node - snapSync uint32 // Flag whether snap sync is enabled (gets disabled if we already have blocks) - acceptTxs uint32 // Flag whether we're considered synchronised (enables transaction processing) + snapSync atomic.Bool // Flag whether snap sync is enabled (gets disabled if we already have blocks) + acceptTxs atomic.Bool // Flag whether we're considered synchronised (enables transaction processing) database ethdb.Database txpool txPool @@ -149,7 +149,7 @@ func newHandler(config *handlerConfig) (*handler, error) { // In these cases however it's safe to reenable snap sync. fullBlock, snapBlock := h.chain.CurrentBlock(), h.chain.CurrentSnapBlock() if fullBlock.Number.Uint64() == 0 && snapBlock.Number.Uint64() > 0 { - h.snapSync = uint32(1) + h.snapSync.Store(true) log.Warn("Switch sync mode from full sync to snap sync") } } else { @@ -158,7 +158,7 @@ func newHandler(config *handlerConfig) (*handler, error) { log.Warn("Switch sync mode from snap sync to full sync") } else { // If snap sync was requested and our database is empty, grant it - h.snapSync = uint32(1) + h.snapSync.Store(true) } } // If sync succeeds, pass a callback to potentially disable snap sync mode @@ -166,13 +166,13 @@ func newHandler(config *handlerConfig) (*handler, error) { success := func() { // If we were running snap sync and it finished, disable doing another // round on next sync cycle - if atomic.LoadUint32(&h.snapSync) == 1 { + if h.snapSync.Load() { log.Info("Snap sync complete, auto disabling") - atomic.StoreUint32(&h.snapSync, 0) + h.snapSync.Store(false) } // If we've successfully finished a sync cycle, accept transactions from // the network - atomic.StoreUint32(&h.acceptTxs, 1) + h.acceptTxs.Store(true) } // Construct the downloader (long sync) h.downloader = downloader.New(config.Database, h.eventMux, h.chain, nil, h.removePeer, success) @@ -232,7 +232,7 @@ func newHandler(config *handlerConfig) (*handler, error) { // accept each others' blocks until a restart. Unfortunately we haven't figured // out a way yet where nodes can decide unilaterally whether the network is new // or not. This should be fixed if we figure out a solution. - if atomic.LoadUint32(&h.snapSync) == 1 { + if h.snapSync.Load() { log.Warn("Snap syncing, discarded propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash()) return 0, nil } @@ -261,7 +261,7 @@ func newHandler(config *handlerConfig) (*handler, error) { } n, err := h.chain.InsertChain(blocks) if err == nil { - atomic.StoreUint32(&h.acceptTxs, 1) // Mark initial sync done on any fetcher import + h.acceptTxs.Store(true) // Mark initial sync done on any fetcher import } return n, err } @@ -310,7 +310,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { return err } reject := false // reserved peer slots - if atomic.LoadUint32(&h.snapSync) == 1 { + if h.snapSync.Load() { if snap == nil { // If we are running snap-sync, we want to reserve roughly half the peer // slots for peers supporting the snap protocol. diff --git a/eth/handler_eth.go b/eth/handler_eth.go index 4ed6335769..00be022d9e 100644 --- a/eth/handler_eth.go +++ b/eth/handler_eth.go @@ -19,7 +19,6 @@ package eth import ( "fmt" "math/big" - "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -52,7 +51,7 @@ func (h *ethHandler) PeerInfo(id enode.ID) interface{} { // AcceptTxs retrieves whether transaction processing is enabled on the node // or if inbound transactions should simply be dropped. func (h *ethHandler) AcceptTxs() bool { - return atomic.LoadUint32(&h.acceptTxs) == 1 + return h.acceptTxs.Load() } // Handle is invoked from a peer's message handler when it receives a new remote diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index d51d01de9e..fd7df23403 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -248,7 +248,7 @@ func testRecvTransactions(t *testing.T, protocol uint) { handler := newTestHandler() defer handler.close() - handler.handler.acceptTxs = 1 // mark synced to accept transactions + handler.handler.acceptTxs.Store(true) // mark synced to accept transactions txs := make(chan core.NewTxsEvent) sub := handler.txpool.SubscribeNewTxsEvent(txs) @@ -394,7 +394,7 @@ func testTransactionPropagation(t *testing.T, protocol uint) { // to receive them. We need multiple sinks since a one-to-one peering would // broadcast all transactions without announcement. source := newTestHandler() - source.handler.snapSync = 0 // Avoid requiring snap, otherwise some will be dropped below + source.handler.snapSync.Store(false) // Avoid requiring snap, otherwise some will be dropped below defer source.close() sinks := make([]*testHandler, 10) @@ -402,7 +402,7 @@ func testTransactionPropagation(t *testing.T, protocol uint) { sinks[i] = newTestHandler() defer sinks[i].close() - sinks[i].handler.acceptTxs = 1 // mark synced to accept transactions + sinks[i].handler.acceptTxs.Store(true) // mark synced to accept transactions } // Interconnect all the sink handlers with the source handler for i, sink := range sinks { diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 13279fd96c..e99eb88436 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -449,10 +449,10 @@ type Syncer struct { trienodeHealReqs map[uint64]*trienodeHealRequest // Trie node requests currently running bytecodeHealReqs map[uint64]*bytecodeHealRequest // Bytecode requests currently running - trienodeHealRate float64 // Average heal rate for processing trie node data - trienodeHealPend uint64 // Number of trie nodes currently pending for processing - trienodeHealThrottle float64 // Divisor for throttling the amount of trienode heal data requested - trienodeHealThrottled time.Time // Timestamp the last time the throttle was updated + trienodeHealRate float64 // Average heal rate for processing trie node data + trienodeHealPend atomic.Uint64 // Number of trie nodes currently pending for processing + trienodeHealThrottle float64 // Divisor for throttling the amount of trienode heal data requested + trienodeHealThrottled time.Time // Timestamp the last time the throttle was updated trienodeHealSynced uint64 // Number of state trie nodes downloaded trienodeHealBytes common.StorageSize // Number of state trie bytes persisted to disk @@ -2189,7 +2189,7 @@ func (s *Syncer) processTrienodeHealResponse(res *trienodeHealResponse) { // HR(N) = (1-MI)^N*(OR-NR) + NR s.trienodeHealRate = gomath.Pow(1-trienodeHealRateMeasurementImpact, float64(fills))*(s.trienodeHealRate-rate) + rate - pending := atomic.LoadUint64(&s.trienodeHealPend) + pending := s.trienodeHealPend.Load() if time.Since(s.trienodeHealThrottled) > time.Second { // Periodically adjust the trie node throttler if float64(pending) > 2*s.trienodeHealRate { @@ -2776,9 +2776,9 @@ func (s *Syncer) OnTrieNodes(peer SyncPeer, id uint64, trienodes [][]byte) error return errors.New("unexpected healing trienode") } // Response validated, send it to the scheduler for filling - atomic.AddUint64(&s.trienodeHealPend, fills) + s.trienodeHealPend.Add(fills) defer func() { - atomic.AddUint64(&s.trienodeHealPend, ^(fills - 1)) + s.trienodeHealPend.Add(^(fills - 1)) }() response := &trienodeHealResponse{ paths: req.paths, diff --git a/eth/sync.go b/eth/sync.go index e56d470cfc..ace1071143 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -19,7 +19,6 @@ package eth import ( "errors" "math/big" - "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -205,7 +204,7 @@ func peerToSyncOp(mode downloader.SyncMode, p *eth.Peer) *chainSyncOp { func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) { // If we're in snap sync mode, return that directly - if atomic.LoadUint32(&cs.handler.snapSync) == 1 { + if cs.handler.snapSync.Load() { block := cs.handler.chain.CurrentSnapBlock() td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64()) return downloader.SnapSync, td @@ -256,13 +255,13 @@ func (h *handler) doSync(op *chainSyncOp) error { if err != nil { return err } - if atomic.LoadUint32(&h.snapSync) == 1 { + if h.snapSync.Load() { log.Info("Snap sync complete, auto disabling") - atomic.StoreUint32(&h.snapSync, 0) + h.snapSync.Store(false) } // If we've successfully finished a sync cycle, enable accepting transactions // from the network. - atomic.StoreUint32(&h.acceptTxs, 1) + h.acceptTxs.Store(true) head := h.chain.CurrentBlock() if head.Number.Uint64() > 0 { diff --git a/eth/sync_test.go b/eth/sync_test.go index 0b9f9e1bba..b5e00298b9 100644 --- a/eth/sync_test.go +++ b/eth/sync_test.go @@ -17,7 +17,6 @@ package eth import ( - "sync/atomic" "testing" "time" @@ -39,14 +38,14 @@ func testSnapSyncDisabling(t *testing.T, ethVer uint, snapVer uint) { // Create an empty handler and ensure it's in snap sync mode empty := newTestHandler() - if atomic.LoadUint32(&empty.handler.snapSync) == 0 { + if !empty.handler.snapSync.Load() { t.Fatalf("snap sync disabled on pristine blockchain") } defer empty.close() // Create a full handler and ensure snap sync ends up disabled full := newTestHandlerWithBlocks(1024) - if atomic.LoadUint32(&full.handler.snapSync) == 1 { + if full.handler.snapSync.Load() { t.Fatalf("snap sync not disabled on non-empty blockchain") } defer full.close() @@ -91,7 +90,7 @@ func testSnapSyncDisabling(t *testing.T, ethVer uint, snapVer uint) { if err := empty.handler.doSync(op); err != nil { t.Fatal("sync failed:", err) } - if atomic.LoadUint32(&empty.handler.snapSync) == 1 { + if empty.handler.snapSync.Load() { t.Fatalf("snap sync not disabled after successful synchronisation") } } From f8f95346f9ba42f33c95fdba214bab163e9a322b Mon Sep 17 00:00:00 2001 From: Exca-DK <85954505+Exca-DK@users.noreply.github.com> Date: Tue, 25 Apr 2023 12:12:34 +0200 Subject: [PATCH 071/988] p2p/discover: add traffic metrics (#27008) Co-authored-by: Exca-DK Co-authored-by: rjl493456442 --- p2p/discover/metrics.go | 65 +++++++++++++++++++++++++++++++++++++++++ p2p/discover/v4_udp.go | 2 +- p2p/discover/v5_udp.go | 2 +- 3 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 p2p/discover/metrics.go diff --git a/p2p/discover/metrics.go b/p2p/discover/metrics.go new file mode 100644 index 0000000000..bf1a2fa2b8 --- /dev/null +++ b/p2p/discover/metrics.go @@ -0,0 +1,65 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package discover + +import ( + "net" + + "github.com/ethereum/go-ethereum/metrics" +) + +const ( + moduleName = "discover" + // ingressMeterName is the prefix of the per-packet inbound metrics. + ingressMeterName = moduleName + "/ingress" + + // egressMeterName is the prefix of the per-packet outbound metrics. + egressMeterName = moduleName + "/egress" +) + +var ( + ingressTrafficMeter = metrics.NewRegisteredMeter(ingressMeterName, nil) + egressTrafficMeter = metrics.NewRegisteredMeter(egressMeterName, nil) +) + +// meteredConn is a wrapper around a net.UDPConn that meters both the +// inbound and outbound network traffic. +type meteredUdpConn struct { + UDPConn +} + +func newMeteredConn(conn UDPConn) UDPConn { + // Short circuit if metrics are disabled + if !metrics.Enabled { + return conn + } + return &meteredUdpConn{UDPConn: conn} +} + +// Read delegates a network read to the underlying connection, bumping the udp ingress traffic meter along the way. +func (c *meteredUdpConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) { + n, addr, err = c.UDPConn.ReadFromUDP(b) + ingressTrafficMeter.Mark(int64(n)) + return n, addr, err +} + +// Write delegates a network write to the underlying connection, bumping the udp egress traffic meter along the way. +func (c *meteredUdpConn) WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) { + n, err = c.UDPConn.WriteToUDP(b, addr) + egressTrafficMeter.Mark(int64(n)) + return n, err +} diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 67cd2c004c..21fee9c793 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -130,7 +130,7 @@ func ListenV4(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) { cfg = cfg.withDefaults() closeCtx, cancel := context.WithCancel(context.Background()) t := &UDPv4{ - conn: c, + conn: newMeteredConn(c), priv: cfg.PrivateKey, netrestrict: cfg.NetRestrict, localNode: ln, diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 38f5b3b652..dadacb528b 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -142,7 +142,7 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { cfg = cfg.withDefaults() t := &UDPv5{ // static fields - conn: conn, + conn: newMeteredConn(conn), localNode: ln, db: ln.Database(), netrestrict: cfg.NetRestrict, From 9a12cc99de0e02baf9ba3d4d7e328215e41c0cce Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 25 Apr 2023 07:27:28 -0400 Subject: [PATCH 072/988] cmd/geth: remove DAO fork test (#27161) * cmd/geth: fix test to not use explicit db * cmd/geth: remove dao-test --- cmd/geth/dao_test.go | 152 ------------------------------------------- 1 file changed, 152 deletions(-) delete mode 100644 cmd/geth/dao_test.go diff --git a/cmd/geth/dao_test.go b/cmd/geth/dao_test.go deleted file mode 100644 index 5af78116f0..0000000000 --- a/cmd/geth/dao_test.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "math/big" - "os" - "path/filepath" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/params" -) - -// Genesis block for nodes which don't care about the DAO fork (i.e. not configured) -var daoOldGenesis = `{ - "alloc" : {}, - "coinbase" : "0x0000000000000000000000000000000000000000", - "difficulty" : "0x20000", - "extraData" : "", - "gasLimit" : "0x2fefd8", - "nonce" : "0x0000000000000042", - "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp" : "0x00", - "config" : { - "homesteadBlock" : 0 - } -}` - -// Genesis block for nodes which actively oppose the DAO fork -var daoNoForkGenesis = `{ - "alloc" : {}, - "coinbase" : "0x0000000000000000000000000000000000000000", - "difficulty" : "0x20000", - "extraData" : "", - "gasLimit" : "0x2fefd8", - "nonce" : "0x0000000000000042", - "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp" : "0x00", - "config" : { - "homesteadBlock" : 0, - "daoForkBlock" : 314, - "daoForkSupport" : false - } -}` - -// Genesis block for nodes which actively support the DAO fork -var daoProForkGenesis = `{ - "alloc" : {}, - "coinbase" : "0x0000000000000000000000000000000000000000", - "difficulty" : "0x20000", - "extraData" : "", - "gasLimit" : "0x2fefd8", - "nonce" : "0x0000000000000042", - "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp" : "0x00", - "config" : { - "homesteadBlock" : 0, - "daoForkBlock" : 314, - "daoForkSupport" : true - } -}` - -var daoGenesisHash = common.HexToHash("5e1fc79cb4ffa4739177b5408045cd5d51c6cf766133f23f7cd72ee1f8d790e0") -var daoGenesisForkBlock = big.NewInt(314) - -// TestDAOForkBlockNewChain tests that the DAO hard-fork number and the nodes support/opposition is correctly -// set in the database after various initialization procedures and invocations. -func TestDAOForkBlockNewChain(t *testing.T) { - for i, arg := range []struct { - genesis string - expectBlock *big.Int - expectVote bool - }{ - // Test DAO Default Mainnet - {"", params.MainnetChainConfig.DAOForkBlock, true}, - // test DAO Init Old Privnet - {daoOldGenesis, nil, false}, - // test DAO Default No Fork Privnet - {daoNoForkGenesis, daoGenesisForkBlock, false}, - // test DAO Default Pro Fork Privnet - {daoProForkGenesis, daoGenesisForkBlock, true}, - } { - testDAOForkBlockNewChain(t, i, arg.genesis, arg.expectBlock, arg.expectVote) - } -} - -func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBlock *big.Int, expectVote bool) { - // Create a temporary data directory to use and inspect later - datadir := t.TempDir() - - // Start a Geth instance with the requested flags set and immediately terminate - if genesis != "" { - json := filepath.Join(datadir, "genesis.json") - if err := os.WriteFile(json, []byte(genesis), 0600); err != nil { - t.Fatalf("test %d: failed to write genesis file: %v", test, err) - } - runGeth(t, "--datadir", datadir, "--networkid", "1337", "init", json).WaitExit() - } else { - // Force chain initialization - args := []string{"--port", "0", "--networkid", "1337", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--datadir", datadir} - runGeth(t, append(args, []string{"--exec", "2+2", "console"}...)...).WaitExit() - } - // Retrieve the DAO config flag from the database - path := filepath.Join(datadir, "geth", "chaindata") - db, err := rawdb.NewPebbleDBDatabase(path, 0, 0, "", false) - if err != nil { - t.Fatalf("test %d: failed to open test database: %v", test, err) - } - defer db.Close() - - genesisHash := common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") - if genesis != "" { - genesisHash = daoGenesisHash - } - config := rawdb.ReadChainConfig(db, genesisHash) - if config == nil { - t.Errorf("test %d: failed to retrieve chain config: %v", test, err) - return // we want to return here, the other checks can't make it past this point (nil panic). - } - // Validate the DAO hard-fork block number against the expected value - if config.DAOForkBlock == nil { - if expectBlock != nil { - t.Errorf("test %d: dao hard-fork block mismatch: have nil, want %v", test, expectBlock) - } - } else if expectBlock == nil { - t.Errorf("test %d: dao hard-fork block mismatch: have %v, want nil", test, config.DAOForkBlock) - } else if config.DAOForkBlock.Cmp(expectBlock) != 0 { - t.Errorf("test %d: dao hard-fork block mismatch: have %v, want %v", test, config.DAOForkBlock, expectBlock) - } - if config.DAOForkSupport != expectVote { - t.Errorf("test %d: dao hard-fork support mismatch: have %v, want %v", test, config.DAOForkSupport, expectVote) - } -} From 2f98dd3838bc5e6de462d128b7cce776a2abcf83 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 25 Apr 2023 14:02:54 +0200 Subject: [PATCH 073/988] graphql: encode Long values as hex (#26894) This is a breaking GraphQL API change. All numeric values are now encoded as hex strings. The motivation for this change is matching JSON-RPC outputs more closely. Numbers in query parameters are accepted as both decimal integers and hex strings. --- graphql/graphql.go | 109 ++++++++++++++++++++-------------------- graphql/graphql_test.go | 30 +++++------ graphql/schema.go | 20 ++++---- 3 files changed, 78 insertions(+), 81 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 45a1f7a2aa..ce3ca171cf 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -24,6 +24,7 @@ import ( "math/big" "sort" "strconv" + "strings" "sync" "github.com/ethereum/go-ethereum" @@ -54,16 +55,16 @@ func (b *Long) UnmarshalGraphQL(input interface{}) error { switch input := input.(type) { case string: // uncomment to support hex values - //if strings.HasPrefix(input, "0x") { - // // apply leniency and support hex representations of longs. - // value, err := hexutil.DecodeUint64(input) - // *b = Long(value) - // return err - //} else { - value, err := strconv.ParseInt(input, 10, 64) - *b = Long(value) - return err - //} + if strings.HasPrefix(input, "0x") { + // apply leniency and support hex representations of longs. + value, err := hexutil.DecodeUint64(input) + *b = Long(value) + return err + } else { + value, err := strconv.ParseInt(input, 10, 64) + *b = Long(value) + return err + } case int32: *b = Long(input) case int64: @@ -156,8 +157,8 @@ func (l *Log) Account(ctx context.Context, args BlockNumberArgs) *Account { } } -func (l *Log) Index(ctx context.Context) int32 { - return int32(l.log.Index) +func (l *Log) Index(ctx context.Context) hexutil.Uint64 { + return hexutil.Uint64(l.log.Index) } func (l *Log) Topics(ctx context.Context) []common.Hash { @@ -391,7 +392,7 @@ func (t *Transaction) Block(ctx context.Context) (*Block, error) { return block, nil } -func (t *Transaction) Index(ctx context.Context) (*int32, error) { +func (t *Transaction) Index(ctx context.Context) (*hexutil.Uint64, error) { _, block, err := t.resolve(ctx) if err != nil { return nil, err @@ -400,7 +401,7 @@ func (t *Transaction) Index(ctx context.Context) (*int32, error) { if block == nil { return nil, nil } - index := int32(t.index) + index := hexutil.Uint64(t.index) return &index, nil } @@ -421,7 +422,7 @@ func (t *Transaction) getReceipt(ctx context.Context) (*types.Receipt, error) { return receipts[t.index], nil } -func (t *Transaction) Status(ctx context.Context) (*Long, error) { +func (t *Transaction) Status(ctx context.Context) (*hexutil.Uint64, error) { receipt, err := t.getReceipt(ctx) if err != nil || receipt == nil { return nil, err @@ -429,25 +430,25 @@ func (t *Transaction) Status(ctx context.Context) (*Long, error) { if len(receipt.PostState) != 0 { return nil, nil } - ret := Long(receipt.Status) + ret := hexutil.Uint64(receipt.Status) return &ret, nil } -func (t *Transaction) GasUsed(ctx context.Context) (*Long, error) { +func (t *Transaction) GasUsed(ctx context.Context) (*hexutil.Uint64, error) { receipt, err := t.getReceipt(ctx) if err != nil || receipt == nil { return nil, err } - ret := Long(receipt.GasUsed) + ret := hexutil.Uint64(receipt.GasUsed) return &ret, nil } -func (t *Transaction) CumulativeGasUsed(ctx context.Context) (*Long, error) { +func (t *Transaction) CumulativeGasUsed(ctx context.Context) (*hexutil.Uint64, error) { receipt, err := t.getReceipt(ctx) if err != nil || receipt == nil { return nil, err } - ret := Long(receipt.CumulativeGasUsed) + ret := hexutil.Uint64(receipt.CumulativeGasUsed) return &ret, nil } @@ -503,12 +504,12 @@ func (t *Transaction) getLogs(ctx context.Context, hash common.Hash) (*[]*Log, e return &ret, nil } -func (t *Transaction) Type(ctx context.Context) (*int32, error) { +func (t *Transaction) Type(ctx context.Context) (*hexutil.Uint64, error) { tx, _, err := t.resolve(ctx) if err != nil { return nil, err } - txType := int32(tx.Type()) + txType := hexutil.Uint64(tx.Type()) return &txType, nil } @@ -649,13 +650,13 @@ func (b *Block) resolveReceipts(ctx context.Context) ([]*types.Receipt, error) { return receipts, nil } -func (b *Block) Number(ctx context.Context) (Long, error) { +func (b *Block) Number(ctx context.Context) (hexutil.Uint64, error) { header, err := b.resolveHeader(ctx) if err != nil { return 0, err } - return Long(header.Number.Uint64()), nil + return hexutil.Uint64(header.Number.Uint64()), nil } func (b *Block) Hash(ctx context.Context) (common.Hash, error) { @@ -664,20 +665,20 @@ func (b *Block) Hash(ctx context.Context) (common.Hash, error) { return b.hash, nil } -func (b *Block) GasLimit(ctx context.Context) (Long, error) { +func (b *Block) GasLimit(ctx context.Context) (hexutil.Uint64, error) { header, err := b.resolveHeader(ctx) if err != nil { return 0, err } - return Long(header.GasLimit), nil + return hexutil.Uint64(header.GasLimit), nil } -func (b *Block) GasUsed(ctx context.Context) (Long, error) { +func (b *Block) GasUsed(ctx context.Context) (hexutil.Uint64, error) { header, err := b.resolveHeader(ctx) if err != nil { return 0, err } - return Long(header.GasUsed), nil + return hexutil.Uint64(header.GasUsed), nil } func (b *Block) BaseFeePerGas(ctx context.Context) (*hexutil.Big, error) { @@ -793,12 +794,12 @@ func (b *Block) OmmerHash(ctx context.Context) (common.Hash, error) { return header.UncleHash, nil } -func (b *Block) OmmerCount(ctx context.Context) (*int32, error) { +func (b *Block) OmmerCount(ctx context.Context) (*hexutil.Uint64, error) { block, err := b.resolve(ctx) if err != nil || block == nil { return nil, err } - count := int32(len(block.Uncles())) + count := hexutil.Uint64(len(block.Uncles())) return &count, err } @@ -869,7 +870,7 @@ type BlockNumberArgs struct { // TODO: Ideally we could use input unions to allow the query to specify the // block parameter by hash, block number, or tag but input unions aren't part of the // standard GraphQL schema SDL yet, see: https://github.com/graphql/graphql-spec/issues/488 - Block *hexutil.Uint64 + Block *Long } // NumberOr returns the provided block number argument, or the "current" block number or hash if none @@ -900,12 +901,12 @@ func (b *Block) Miner(ctx context.Context, args BlockNumberArgs) (*Account, erro }, nil } -func (b *Block) TransactionCount(ctx context.Context) (*int32, error) { +func (b *Block) TransactionCount(ctx context.Context) (*hexutil.Uint64, error) { block, err := b.resolve(ctx) if err != nil || block == nil { return nil, err } - count := int32(len(block.Transactions())) + count := hexutil.Uint64(len(block.Transactions())) return &count, err } @@ -927,7 +928,7 @@ func (b *Block) Transactions(ctx context.Context) (*[]*Transaction, error) { return &ret, nil } -func (b *Block) TransactionAt(ctx context.Context, args struct{ Index int32 }) (*Transaction, error) { +func (b *Block) TransactionAt(ctx context.Context, args struct{ Index Long }) (*Transaction, error) { block, err := b.resolve(ctx) if err != nil || block == nil { return nil, err @@ -946,7 +947,7 @@ func (b *Block) TransactionAt(ctx context.Context, args struct{ Index int32 }) ( }, nil } -func (b *Block) OmmerAt(ctx context.Context, args struct{ Index int32 }) (*Block, error) { +func (b *Block) OmmerAt(ctx context.Context, args struct{ Index Long }) (*Block, error) { block, err := b.resolve(ctx) if err != nil || block == nil { return nil, err @@ -1037,7 +1038,7 @@ func (b *Block) Account(ctx context.Context, args struct { type CallData struct { From *common.Address // The Ethereum address the call is from. To *common.Address // The Ethereum address the call is to. - Gas *hexutil.Uint64 // The amount of gas provided for the call. + Gas *Long // The amount of gas provided for the call. GasPrice *hexutil.Big // The price of each unit of gas, in wei. MaxFeePerGas *hexutil.Big // The max price of each unit of gas, in wei (1559). MaxPriorityFeePerGas *hexutil.Big // The max tip of each unit of gas, in wei (1559). @@ -1047,20 +1048,20 @@ type CallData struct { // CallResult encapsulates the result of an invocation of the `call` accessor. type CallResult struct { - data hexutil.Bytes // The return data from the call - gasUsed Long // The amount of gas used - status Long // The return status of the call - 0 for failure or 1 for success. + data hexutil.Bytes // The return data from the call + gasUsed hexutil.Uint64 // The amount of gas used + status hexutil.Uint64 // The return status of the call - 0 for failure or 1 for success. } func (c *CallResult) Data() hexutil.Bytes { return c.data } -func (c *CallResult) GasUsed() Long { +func (c *CallResult) GasUsed() hexutil.Uint64 { return c.gasUsed } -func (c *CallResult) Status() Long { +func (c *CallResult) Status() hexutil.Uint64 { return c.status } @@ -1071,32 +1072,31 @@ func (b *Block) Call(ctx context.Context, args struct { if err != nil { return nil, err } - status := Long(1) + status := hexutil.Uint64(1) if result.Failed() { status = 0 } return &CallResult{ data: result.ReturnData, - gasUsed: Long(result.UsedGas), + gasUsed: hexutil.Uint64(result.UsedGas), status: status, }, nil } func (b *Block) EstimateGas(ctx context.Context, args struct { Data ethapi.TransactionArgs -}) (Long, error) { - gas, err := ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, b.r.backend.RPCGasCap()) - return Long(gas), err +}) (hexutil.Uint64, error) { + return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, b.r.backend.RPCGasCap()) } type Pending struct { r *Resolver } -func (p *Pending) TransactionCount(ctx context.Context) (int32, error) { +func (p *Pending) TransactionCount(ctx context.Context) (hexutil.Uint64, error) { txs, err := p.r.backend.GetPoolTransactions() - return int32(len(txs)), err + return hexutil.Uint64(len(txs)), err } func (p *Pending) Transactions(ctx context.Context) (*[]*Transaction, error) { @@ -1135,24 +1135,23 @@ func (p *Pending) Call(ctx context.Context, args struct { if err != nil { return nil, err } - status := Long(1) + status := hexutil.Uint64(1) if result.Failed() { status = 0 } return &CallResult{ data: result.ReturnData, - gasUsed: Long(result.UsedGas), + gasUsed: hexutil.Uint64(result.UsedGas), status: status, }, nil } func (p *Pending) EstimateGas(ctx context.Context, args struct { Data ethapi.TransactionArgs -}) (Long, error) { +}) (hexutil.Uint64, error) { pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) - gas, err := ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, pendingBlockNr, p.r.backend.RPCGasCap()) - return Long(gas), err + return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, pendingBlockNr, p.r.backend.RPCGasCap()) } // Resolver is the top-level object in the GraphQL hierarchy. @@ -1260,8 +1259,8 @@ func (r *Resolver) SendRawTransaction(ctx context.Context, args struct{ Data hex // FilterCriteria encapsulates the arguments to `logs` on the root resolver object. type FilterCriteria struct { - FromBlock *hexutil.Uint64 // beginning of the queried range, nil means genesis block - ToBlock *hexutil.Uint64 // end of the range, nil means latest block + FromBlock *Long // beginning of the queried range, nil means genesis block + ToBlock *Long // end of the range, nil means latest block Addresses *[]common.Address // restricts matches to events created by specific contracts // The Topic list restricts matches to particular event topics. Each event has a list diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 9354eac0f3..00ad4f0211 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -80,17 +80,17 @@ func TestGraphQLBlockSerialization(t *testing.T) { }{ { // Should return latest block body: `{"query": "{block{number}}","variables": null}`, - want: `{"data":{"block":{"number":10}}}`, + want: `{"data":{"block":{"number":"0xa"}}}`, code: 200, }, { // Should return info about latest block body: `{"query": "{block{number,gasUsed,gasLimit}}","variables": null}`, - want: `{"data":{"block":{"number":10,"gasUsed":0,"gasLimit":11500000}}}`, + want: `{"data":{"block":{"number":"0xa","gasUsed":"0x0","gasLimit":"0xaf79e0"}}}`, code: 200, }, { body: `{"query": "{block(number:0){number,gasUsed,gasLimit}}","variables": null}`, - want: `{"data":{"block":{"number":0,"gasUsed":0,"gasLimit":11500000}}}`, + want: `{"data":{"block":{"number":"0x0","gasUsed":"0x0","gasLimit":"0xaf79e0"}}}`, code: 200, }, { @@ -105,7 +105,7 @@ func TestGraphQLBlockSerialization(t *testing.T) { }, { body: `{"query": "{block(number:\"0\"){number,gasUsed,gasLimit}}","variables": null}`, - want: `{"data":{"block":{"number":0,"gasUsed":0,"gasLimit":11500000}}}`, + want: `{"data":{"block":{"number":"0x0","gasUsed":"0x0","gasLimit":"0xaf79e0"}}}`, code: 200, }, { @@ -119,14 +119,10 @@ func TestGraphQLBlockSerialization(t *testing.T) { code: 200, }, { - body: `{"query": "{block(number:\"0xbad\"){number,gasUsed,gasLimit}}","variables": null}`, - want: `{"errors":[{"message":"strconv.ParseInt: parsing \"0xbad\": invalid syntax"}],"data":{}}`, - code: 400, - }, - { // hex strings are currently not supported. If that's added to the spec, this test will need to change body: `{"query": "{block(number:\"0x0\"){number,gasUsed,gasLimit}}","variables": null}`, - want: `{"errors":[{"message":"strconv.ParseInt: parsing \"0x0\": invalid syntax"}],"data":{}}`, - code: 400, + want: `{"data":{"block":{"number":"0x0","gasUsed":"0x0","gasLimit":"0xaf79e0"}}}`, + //want: `{"errors":[{"message":"strconv.ParseInt: parsing \"0x0\": invalid syntax"}],"data":{}}`, + code: 200, }, { body: `{"query": "{block(number:\"a\"){number,gasUsed,gasLimit}}","variables": null}`, @@ -141,13 +137,13 @@ func TestGraphQLBlockSerialization(t *testing.T) { // should return `estimateGas` as decimal { body: `{"query": "{block{ estimateGas(data:{}) }}"}`, - want: `{"data":{"block":{"estimateGas":53000}}}`, + want: `{"data":{"block":{"estimateGas":"0xcf08"}}}`, code: 200, }, // should return `status` as decimal { body: `{"query": "{block {number call (data : {from : \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\", to: \"0x6295ee1b4f6dd65047762f924ecd367c17eabf8f\", data :\"0x12a7b914\"}){data status}}}"}`, - want: `{"data":{"block":{"number":10,"call":{"data":"0x","status":1}}}}`, + want: `{"data":{"block":{"number":"0xa","call":{"data":"0x","status":"0x1"}}}}`, code: 200, }, } { @@ -231,7 +227,7 @@ func TestGraphQLBlockSerializationEIP2718(t *testing.T) { }{ { body: `{"query": "{block {number transactions { from { address } to { address } value hash type accessList { address storageKeys } index}}}"}`, - want: `{"data":{"block":{"number":1,"transactions":[{"from":{"address":"0x71562b71999873db5b286df957af199ec94617f7"},"to":{"address":"0x0000000000000000000000000000000000000dad"},"value":"0x64","hash":"0xd864c9d7d37fade6b70164740540c06dd58bb9c3f6b46101908d6339db6a6a7b","type":0,"accessList":[],"index":0},{"from":{"address":"0x71562b71999873db5b286df957af199ec94617f7"},"to":{"address":"0x0000000000000000000000000000000000000dad"},"value":"0x32","hash":"0x19b35f8187b4e15fb59a9af469dca5dfa3cd363c11d372058c12f6482477b474","type":1,"accessList":[{"address":"0x0000000000000000000000000000000000000dad","storageKeys":["0x0000000000000000000000000000000000000000000000000000000000000000"]}],"index":1}]}}}`, + want: `{"data":{"block":{"number":"0x1","transactions":[{"from":{"address":"0x71562b71999873db5b286df957af199ec94617f7"},"to":{"address":"0x0000000000000000000000000000000000000dad"},"value":"0x64","hash":"0xd864c9d7d37fade6b70164740540c06dd58bb9c3f6b46101908d6339db6a6a7b","type":"0x0","accessList":[],"index":"0x0"},{"from":{"address":"0x71562b71999873db5b286df957af199ec94617f7"},"to":{"address":"0x0000000000000000000000000000000000000dad"},"value":"0x32","hash":"0x19b35f8187b4e15fb59a9af469dca5dfa3cd363c11d372058c12f6482477b474","type":"0x1","accessList":[{"address":"0x0000000000000000000000000000000000000dad","storageKeys":["0x0000000000000000000000000000000000000000000000000000000000000000"]}],"index":"0x1"}]}}}`, code: 200, }, } { @@ -327,17 +323,17 @@ func TestGraphQLConcurrentResolvers(t *testing.T) { // Multiple txes of a block race to set/retrieve receipts of a block. { body: "{block { transactions { status gasUsed } } }", - want: `{"block":{"transactions":[{"status":1,"gasUsed":21768},{"status":1,"gasUsed":21768},{"status":1,"gasUsed":21768}]}}`, + want: `{"block":{"transactions":[{"status":"0x1","gasUsed":"0x5508"},{"status":"0x1","gasUsed":"0x5508"},{"status":"0x1","gasUsed":"0x5508"}]}}`, }, // Multiple fields of block race to resolve header and body. { body: "{ block { number hash gasLimit ommerCount transactionCount totalDifficulty } }", - want: fmt.Sprintf(`{"block":{"number":1,"hash":"%s","gasLimit":11500000,"ommerCount":0,"transactionCount":3,"totalDifficulty":"0x200000"}}`, chain[len(chain)-1].Hash()), + want: fmt.Sprintf(`{"block":{"number":"0x1","hash":"%s","gasLimit":"0xaf79e0","ommerCount":"0x0","transactionCount":"0x3","totalDifficulty":"0x200000"}}`, chain[len(chain)-1].Hash()), }, // Multiple fields of a block race to resolve the header and body. { body: fmt.Sprintf(`{ transaction(hash: "%s") { block { number hash gasLimit ommerCount transactionCount } } }`, tx.Hash()), - want: fmt.Sprintf(`{"transaction":{"block":{"number":1,"hash":"%s","gasLimit":11500000,"ommerCount":0,"transactionCount":3}}}`, chain[len(chain)-1].Hash()), + want: fmt.Sprintf(`{"transaction":{"block":{"number":"0x1","hash":"%s","gasLimit":"0xaf79e0","ommerCount":"0x0","transactionCount":"0x3"}}}`, chain[len(chain)-1].Hash()), }, // Account fields race the resolve the state object. { diff --git a/graphql/schema.go b/graphql/schema.go index ff3919be74..e4ce7b9afc 100644 --- a/graphql/schema.go +++ b/graphql/schema.go @@ -28,7 +28,9 @@ const schema string = ` # Strings may be either decimal or 0x-prefixed hexadecimal. Output values are all # 0x-prefixed hexadecimal. scalar BigInt - # Long is a 64 bit unsigned integer. + # Long is a 64 bit unsigned integer. Input is accepted as either a JSON number or as a string. + # Strings may be either decimal or 0x-prefixed hexadecimal. Output values are all + # 0x-prefixed hexadecimal. scalar Long schema { @@ -57,7 +59,7 @@ const schema string = ` # Log is an Ethereum event log. type Log { # Index is the index of this log in the block. - index: Int! + index: Long! # Account is the account which generated this log - this will always # be a contract account. account(block: Long): Account! @@ -83,7 +85,7 @@ const schema string = ` nonce: Long! # Index is the index of this transaction in the parent block. This will # be null if the transaction has not yet been mined. - index: Int + index: Long # From is the account that sent this transaction - this will always be # an externally owned account. from(block: Long): Account! @@ -138,7 +140,7 @@ const schema string = ` s: BigInt! v: BigInt! # Envelope transaction support - type: Int + type: Long accessList: [AccessTuple!] # Raw is the canonical encoding of the transaction. # For legacy transactions, it returns the RLP encoding. @@ -183,7 +185,7 @@ const schema string = ` transactionsRoot: Bytes32! # TransactionCount is the number of transactions in this block. if # transactions are not available for this block, this field will be null. - transactionCount: Int + transactionCount: Long # StateRoot is the keccak256 hash of the state trie after this block was processed. stateRoot: Bytes32! # ReceiptsRoot is the keccak256 hash of the trie of transaction receipts in this block. @@ -214,7 +216,7 @@ const schema string = ` totalDifficulty: BigInt! # OmmerCount is the number of ommers (AKA uncles) associated with this # block. If ommers are unavailable, this field will be null. - ommerCount: Int + ommerCount: Long # Ommers is a list of ommer (AKA uncle) blocks associated with this block. # If ommers are unavailable, this field will be null. Depending on your # node, the transactions, transactionAt, transactionCount, ommers, @@ -222,7 +224,7 @@ const schema string = ` ommers: [Block] # OmmerAt returns the ommer (AKA uncle) at the specified index. If ommers # are unavailable, or the index is out of bounds, this field will be null. - ommerAt(index: Int!): Block + ommerAt(index: Long!): Block # OmmerHash is the keccak256 hash of all the ommers (AKA uncles) # associated with this block. ommerHash: Bytes32! @@ -232,7 +234,7 @@ const schema string = ` # TransactionAt returns the transaction at the specified index. If # transactions are unavailable for this block, or if the index is out of # bounds, this field will be null. - transactionAt(index: Int!): Transaction + transactionAt(index: Long!): Transaction # Logs returns a filtered set of logs from this block. logs(filter: BlockFilterCriteria!): [Log!]! # Account fetches an Ethereum account at the current block's state. @@ -317,7 +319,7 @@ const schema string = ` # Pending represents the current pending state. type Pending { # TransactionCount is the number of transactions in the pending state. - transactionCount: Int! + transactionCount: Long! # Transactions is a list of transactions in the current pending state. transactions: [Transaction!] # Account fetches an Ethereum account for the pending state. From b1113aa07ee554575be9276b862fd786d1db52be Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 25 Apr 2023 15:15:43 +0200 Subject: [PATCH 074/988] eth: fix crash on querying finalized block (#27162) eth: fix crash on querying nil finalized block --- eth/api_backend.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/eth/api_backend.go b/eth/api_backend.go index ac160b0736..0e4521173b 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -134,6 +134,9 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe return nil, errors.New("'finalized' tag not supported on pre-merge network") } header := b.eth.blockchain.CurrentFinalBlock() + if header == nil { + return nil, errors.New("finalized block not found") + } return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } if number == rpc.SafeBlockNumber { @@ -141,6 +144,9 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe return nil, errors.New("'safe' tag not supported on pre-merge network") } header := b.eth.blockchain.CurrentSafeBlock() + if header == nil { + return nil, errors.New("safe block not found") + } return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil From 5d3f5805d50c0630b0f68af21b82635880fe03ec Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 26 Apr 2023 14:01:54 +0800 Subject: [PATCH 075/988] trie: add node type common package (#27160) * trie: add node type common package In trie/types package, a few node wrappers are defined, which will be used in both trie package, trie/snap package, etc. Therefore, a standalone common package is created to put these stuffs. * trie: rename trie/types to trie/trienode --- trie/committer.go | 25 +++++---- trie/database.go | 7 +-- trie/nodeset.go | 117 +++++++++++------------------------------- trie/tracer.go | 10 ++-- trie/trie.go | 4 +- trie/trie_test.go | 19 +++---- trie/trienode/node.go | 67 ++++++++++++++++++++++++ 7 files changed, 133 insertions(+), 116 deletions(-) create mode 100644 trie/trienode/node.go diff --git a/trie/committer.go b/trie/committer.go index af5f5f1a17..805d4a3143 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -20,6 +20,7 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/trie/trienode" ) // leaf represents a trie leaf node @@ -33,13 +34,15 @@ type leaf struct { // insertion order. type committer struct { nodes *NodeSet + tracer *tracer collectLeaf bool } // newCommitter creates a new committer or picks one from the pool. -func newCommitter(nodeset *NodeSet, collectLeaf bool) *committer { +func newCommitter(nodeset *NodeSet, tracer *tracer, collectLeaf bool) *committer { return &committer{ nodes: nodeset, + tracer: tracer, collectLeaf: collectLeaf, } } @@ -134,22 +137,22 @@ func (c *committer) store(path []byte, n node) node { // The node is embedded in its parent, in other words, this node // will not be stored in the database independently, mark it as // deleted only if the node was existent in database before. - if _, ok := c.nodes.accessList[string(path)]; ok { - c.nodes.markDeleted(path) + prev, ok := c.tracer.accessList[string(path)] + if ok { + c.nodes.addNode(path, trienode.NewWithPrev(common.Hash{}, nil, prev)) } return n } - // We have the hash already, estimate the RLP encoding-size of the node. - // The size is used for mem tracking, does not need to be exact + // Collect the dirty node to nodeset for return. var ( nhash = common.BytesToHash(hash) - mnode = &memoryNode{ - hash: nhash, - node: nodeToBytes(n), - } + node = trienode.NewWithPrev( + nhash, + nodeToBytes(n), + c.tracer.accessList[string(path)], + ) ) - // Collect the dirty node to nodeset for return. - c.nodes.markUpdated(path, mnode) + c.nodes.addNode(path, node) // Collect the corresponding leaf node if it's required. We don't check // full node since it's impossible to store value in fullNode. The key diff --git a/trie/database.go b/trie/database.go index c1f7ddd756..c105c730a2 100644 --- a/trie/database.go +++ b/trie/database.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie/trienode" ) var ( @@ -607,11 +608,11 @@ func (db *Database) Update(nodes *MergedNodeSet) error { } for _, owner := range order { subset := nodes.sets[owner] - subset.forEachWithOrder(func(path string, n *memoryNode) { - if n.isDeleted() { + subset.forEachWithOrder(func(path string, n *trienode.Node) { + if n.IsDeleted() { return // ignore deletion } - db.insert(n.hash, n.node) + db.insert(n.Hash, n.Blob) }) } // Link up the account trie and storage trie if the node points diff --git a/trie/nodeset.go b/trie/nodeset.go index fc2111375f..4ebbb3329c 100644 --- a/trie/nodeset.go +++ b/trie/nodeset.go @@ -22,89 +22,37 @@ import ( "strings" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/trie/trienode" ) -// memoryNode is all the information we know about a single cached trie node -// in the memory. -type memoryNode struct { - hash common.Hash // Node hash by hashing node blob, empty for deleted nodes - node []byte // Encoded node blob, nil for deleted nodes -} - -// memorySize returns the total memory size used by this node. -// nolint:unused -func (n *memoryNode) memorySize(pathlen int) int { - return len(n.node) + common.HashLength + pathlen -} - -// rlp returns the raw rlp encoded blob of the cached trie node, either directly -// from the cache, or by regenerating it from the collapsed node. -// nolint:unused -func (n *memoryNode) rlp() []byte { - return n.node -} - -// obj returns the decoded and expanded trie node, either directly from the cache, -// or by regenerating it from the rlp encoded blob. -// nolint:unused -func (n *memoryNode) obj() node { - return mustDecodeNode(n.hash[:], n.node) -} - -// isDeleted returns the indicator if the node is marked as deleted. -func (n *memoryNode) isDeleted() bool { - return n.hash == (common.Hash{}) -} - -// nodeWithPrev wraps the memoryNode with the previous node value. -// nolint: unused -type nodeWithPrev struct { - *memoryNode - prev []byte // RLP-encoded previous value, nil means it's non-existent -} - -// unwrap returns the internal memoryNode object. -// nolint:unused -func (n *nodeWithPrev) unwrap() *memoryNode { - return n.memoryNode -} - -// memorySize returns the total memory size used by this node. It overloads -// the function in memoryNode by counting the size of previous value as well. -// nolint: unused -func (n *nodeWithPrev) memorySize(pathlen int) int { - return n.memoryNode.memorySize(pathlen) + len(n.prev) -} - // NodeSet contains all dirty nodes collected during the commit operation. // Each node is keyed by path. It's not thread-safe to use. type NodeSet struct { - owner common.Hash // the identifier of the trie - nodes map[string]*memoryNode // the set of dirty nodes(inserted, updated, deleted) - leaves []*leaf // the list of dirty leaves - updates int // the count of updated and inserted nodes - deletes int // the count of deleted nodes - - // The list of accessed nodes, which records the original node value. - // The origin value is expected to be nil for newly inserted node - // and is expected to be non-nil for other types(updated, deleted). - accessList map[string][]byte + owner common.Hash // the identifier of the trie + leaves []*leaf // the list of dirty leaves + updates int // the count of updated and inserted nodes + deletes int // the count of deleted nodes + + // The set of all dirty nodes. Dirty nodes include newly inserted nodes, + // deleted nodes and updated nodes. The original value of the newly + // inserted node must be nil, and the original value of the other two + // types must be non-nil. + nodes map[string]*trienode.WithPrev } // NewNodeSet initializes an empty node set to be used for tracking dirty nodes // from a specific account or storage trie. The owner is zero for the account // trie and the owning account address hash for storage tries. -func NewNodeSet(owner common.Hash, accessList map[string][]byte) *NodeSet { +func NewNodeSet(owner common.Hash) *NodeSet { return &NodeSet{ - owner: owner, - nodes: make(map[string]*memoryNode), - accessList: accessList, + owner: owner, + nodes: make(map[string]*trienode.WithPrev), } } // forEachWithOrder iterates the dirty nodes with the order from bottom to top, // right to left, nodes with the longest path will be iterated first. -func (set *NodeSet) forEachWithOrder(callback func(path string, n *memoryNode)) { +func (set *NodeSet) forEachWithOrder(callback func(path string, n *trienode.Node)) { var paths sort.StringSlice for path := range set.nodes { paths = append(paths, path) @@ -112,23 +60,21 @@ func (set *NodeSet) forEachWithOrder(callback func(path string, n *memoryNode)) // Bottom-up, longest path first sort.Sort(sort.Reverse(paths)) for _, path := range paths { - callback(path, set.nodes[path]) + callback(path, set.nodes[path].Unwrap()) } } -// markUpdated marks the node as dirty(newly-inserted or updated). -func (set *NodeSet) markUpdated(path []byte, node *memoryNode) { - set.nodes[string(path)] = node - set.updates += 1 -} - -// markDeleted marks the node as deleted. -func (set *NodeSet) markDeleted(path []byte) { - set.nodes[string(path)] = &memoryNode{} - set.deletes += 1 +// addNode adds the provided dirty node into set. +func (set *NodeSet) addNode(path []byte, n *trienode.WithPrev) { + if n.IsDeleted() { + set.deletes += 1 + } else { + set.updates += 1 + } + set.nodes[string(path)] = n } -// addLeaf collects the provided leaf node into set. +// addLeaf adds the provided leaf node into set. func (set *NodeSet) addLeaf(node *leaf) { set.leaves = append(set.leaves, node) } @@ -143,7 +89,7 @@ func (set *NodeSet) Size() (int, int) { func (set *NodeSet) Hashes() []common.Hash { var ret []common.Hash for _, node := range set.nodes { - ret = append(ret, node.hash) + ret = append(ret, node.Hash) } return ret } @@ -155,18 +101,17 @@ func (set *NodeSet) Summary() string { if set.nodes != nil { for path, n := range set.nodes { // Deletion - if n.isDeleted() { - fmt.Fprintf(out, " [-]: %x prev: %x\n", path, set.accessList[path]) + if n.IsDeleted() { + fmt.Fprintf(out, " [-]: %x prev: %x\n", path, n.Prev) continue } // Insertion - origin, ok := set.accessList[path] - if !ok { - fmt.Fprintf(out, " [+]: %x -> %v\n", path, n.hash) + if len(n.Prev) == 0 { + fmt.Fprintf(out, " [+]: %x -> %v\n", path, n.Hash) continue } // Update - fmt.Fprintf(out, " [*]: %x -> %v prev: %x\n", path, n.hash, origin) + fmt.Fprintf(out, " [*]: %x -> %v prev: %x\n", path, n.Hash, n.Prev) } } for _, n := range set.leaves { diff --git a/trie/tracer.go b/trie/tracer.go index a27e371c7a..04b2f12bf6 100644 --- a/trie/tracer.go +++ b/trie/tracer.go @@ -16,7 +16,10 @@ package trie -import "github.com/ethereum/go-ethereum/common" +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/trie/trienode" +) // tracer tracks the changes of trie nodes. During the trie operations, // some nodes can be deleted from the trie, while these deleted nodes @@ -117,9 +120,10 @@ func (t *tracer) markDeletions(set *NodeSet) { // It's possible a few deleted nodes were embedded // in their parent before, the deletions can be no // effect by deleting nothing, filter them out. - if _, ok := set.accessList[path]; !ok { + prev, ok := t.accessList[path] + if !ok { continue } - set.markDeleted([]byte(path)) + set.addNode([]byte(path), trienode.NewWithPrev(common.Hash{}, nil, prev)) } } diff --git a/trie/trie.go b/trie/trie.go index 18504dc5bc..14685c3df8 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -574,7 +574,7 @@ func (t *Trie) Hash() common.Hash { func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { defer t.tracer.reset() - nodes := NewNodeSet(t.owner, t.tracer.accessList) + nodes := NewNodeSet(t.owner) t.tracer.markDeletions(nodes) // Trie is empty and can be classified into two types of situations: @@ -595,7 +595,7 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { t.root = hashedNode return rootHash, nil } - t.root = newCommitter(nodes, collectLeaf).Commit(t.root) + t.root = newCommitter(nodes, t.tracer, collectLeaf).Commit(t.root) return rootHash, nodes } diff --git a/trie/trie_test.go b/trie/trie_test.go index 82ead8b441..a03a68283d 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -408,39 +408,36 @@ func verifyAccessList(old *Trie, new *Trie, set *NodeSet) error { // Check insertion set for path := range inserts { n, ok := set.nodes[path] - if !ok || n.isDeleted() { + if !ok || n.IsDeleted() { return errors.New("expect new node") } - _, ok = set.accessList[path] - if ok { + if len(n.Prev) > 0 { return errors.New("unexpected origin value") } } // Check deletion set for path, blob := range deletes { n, ok := set.nodes[path] - if !ok || !n.isDeleted() { + if !ok || !n.IsDeleted() { return errors.New("expect deleted node") } - v, ok := set.accessList[path] - if !ok { + if len(n.Prev) == 0 { return errors.New("expect origin value") } - if !bytes.Equal(v, blob) { + if !bytes.Equal(n.Prev, blob) { return errors.New("invalid origin value") } } // Check update set for path, blob := range updates { n, ok := set.nodes[path] - if !ok || n.isDeleted() { + if !ok || n.IsDeleted() { return errors.New("expect updated node") } - v, ok := set.accessList[path] - if !ok { + if len(n.Prev) == 0 { return errors.New("expect origin value") } - if !bytes.Equal(v, blob) { + if !bytes.Equal(n.Prev, blob) { return errors.New("invalid origin value") } } diff --git a/trie/trienode/node.go b/trie/trienode/node.go new file mode 100644 index 0000000000..5ebfea8896 --- /dev/null +++ b/trie/trienode/node.go @@ -0,0 +1,67 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see + +package trienode + +import "github.com/ethereum/go-ethereum/common" + +// Node is a wrapper which contains the encoded blob of the trie node and its +// unique hash identifier. It is general enough that can be used to represent +// trie nodes corresponding to different trie implementations. +type Node struct { + Hash common.Hash // Node hash, empty for deleted node + Blob []byte // Encoded node blob, nil for the deleted node +} + +// Size returns the total memory size used by this node. +func (n *Node) Size() int { + return len(n.Blob) + common.HashLength +} + +// IsDeleted returns the indicator if the node is marked as deleted. +func (n *Node) IsDeleted() bool { + return n.Hash == (common.Hash{}) +} + +// WithPrev wraps the Node with the previous node value attached. +type WithPrev struct { + *Node + Prev []byte // Encoded original value, nil means it's non-existent +} + +// Unwrap returns the internal Node object. +func (n *WithPrev) Unwrap() *Node { + return n.Node +} + +// Size returns the total memory size used by this node. It overloads +// the function in Node by counting the size of previous value as well. +func (n *WithPrev) Size() int { + return n.Node.Size() + len(n.Prev) +} + +// New constructs a node with provided node information. +func New(hash common.Hash, blob []byte) *Node { + return &Node{Hash: hash, Blob: blob} +} + +// NewWithPrev constructs a node with provided node information. +func NewWithPrev(hash common.Hash, blob []byte, prev []byte) *WithPrev { + return &WithPrev{ + Node: New(hash, blob), + Prev: prev, + } +} From f8aa62353666a6368fb3f1a378bd0a82d1542052 Mon Sep 17 00:00:00 2001 From: Roberto Bayardo Date: Tue, 25 Apr 2023 23:37:11 -0700 Subject: [PATCH 076/988] core/types: fix discrepancy in receipt.EffectiveGasPrice json encoding tags (#27114) Regenerate receipt json code to remove omit empty. Previously, there was a discrepancy between the generated code and the source. --------- Co-authored-by: lightclient@protonmail.com Co-authored-by: Martin Holst Swende --- cmd/evm/t8n_test.go | 7 +-- cmd/evm/testdata/1/exp.json | 1 + cmd/evm/testdata/13/exp2.json | 2 + cmd/evm/testdata/23/exp.json | 1 + cmd/evm/testdata/24/exp.json | 2 + cmd/evm/testdata/25/exp.json | 1 + cmd/evm/testdata/3/exp.json | 1 + core/types/gen_receipt_json.go | 4 +- core/types/receipt.go | 3 +- core/types/receipt_test.go | 83 ++++++++++++++++++++++++---------- 10 files changed, 76 insertions(+), 29 deletions(-) diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index 067660c7e7..0ef3fac409 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -275,7 +275,8 @@ func TestT8n(t *testing.T) { tt.Run("evm-test", args...) // Compare the expected output, if provided if tc.expOut != "" { - want, err := os.ReadFile(fmt.Sprintf("%v/%v", tc.base, tc.expOut)) + file := fmt.Sprintf("%v/%v", tc.base, tc.expOut) + want, err := os.ReadFile(file) if err != nil { t.Fatalf("test %d: could not read expected output: %v", i, err) } @@ -283,9 +284,9 @@ func TestT8n(t *testing.T) { ok, err := cmpJson(have, want) switch { case err != nil: - t.Fatalf("test %d, json parsing failed: %v", i, err) + t.Fatalf("test %d, file %v: json parsing failed: %v", i, file, err) case !ok: - t.Fatalf("test %d: output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want)) + t.Fatalf("test %d, file %v: output wrong, have \n%v\nwant\n%v\n", i, file, string(have), string(want)) } } tt.WaitExit() diff --git a/cmd/evm/testdata/1/exp.json b/cmd/evm/testdata/1/exp.json index 7d3805012d..d1351e5b76 100644 --- a/cmd/evm/testdata/1/exp.json +++ b/cmd/evm/testdata/1/exp.json @@ -28,6 +28,7 @@ "transactionHash": "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673", "contractAddress": "0x0000000000000000000000000000000000000000", "gasUsed": "0x5208", + "effectiveGasPrice": null, "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x0" } diff --git a/cmd/evm/testdata/13/exp2.json b/cmd/evm/testdata/13/exp2.json index cbad6552c1..babce35929 100644 --- a/cmd/evm/testdata/13/exp2.json +++ b/cmd/evm/testdata/13/exp2.json @@ -16,6 +16,7 @@ "transactionHash": "0xa98a24882ea90916c6a86da650fbc6b14238e46f0af04a131ce92be897507476", "contractAddress": "0x0000000000000000000000000000000000000000", "gasUsed": "0x84d0", + "effectiveGasPrice": null, "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x0" }, @@ -29,6 +30,7 @@ "transactionHash": "0x36bad80acce7040c45fd32764b5c2b2d2e6f778669fb41791f73f546d56e739a", "contractAddress": "0x0000000000000000000000000000000000000000", "gasUsed": "0x84d0", + "effectiveGasPrice": null, "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x1" } diff --git a/cmd/evm/testdata/23/exp.json b/cmd/evm/testdata/23/exp.json index e51f37d9c7..22dde0a27c 100644 --- a/cmd/evm/testdata/23/exp.json +++ b/cmd/evm/testdata/23/exp.json @@ -15,6 +15,7 @@ "transactionHash": "0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81", "contractAddress": "0x0000000000000000000000000000000000000000", "gasUsed": "0x520b", + "effectiveGasPrice": null, "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x0" } diff --git a/cmd/evm/testdata/24/exp.json b/cmd/evm/testdata/24/exp.json index d8cec59d6a..ac571d149b 100644 --- a/cmd/evm/testdata/24/exp.json +++ b/cmd/evm/testdata/24/exp.json @@ -31,6 +31,7 @@ "transactionHash": "0x92ea4a28224d033afb20e0cc2b290d4c7c2d61f6a4800a680e4e19ac962ee941", "contractAddress": "0x0000000000000000000000000000000000000000", "gasUsed": "0xa861", + "effectiveGasPrice": null, "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x0" }, @@ -43,6 +44,7 @@ "transactionHash": "0x16b1d912f1d664f3f60f4e1b5f296f3c82a64a1a253117b4851d18bc03c4f1da", "contractAddress": "0x0000000000000000000000000000000000000000", "gasUsed": "0x5aa5", + "effectiveGasPrice": null, "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x1" } diff --git a/cmd/evm/testdata/25/exp.json b/cmd/evm/testdata/25/exp.json index a9c310a1e1..1cb521794c 100644 --- a/cmd/evm/testdata/25/exp.json +++ b/cmd/evm/testdata/25/exp.json @@ -27,6 +27,7 @@ "transactionHash": "0x92ea4a28224d033afb20e0cc2b290d4c7c2d61f6a4800a680e4e19ac962ee941", "contractAddress": "0x0000000000000000000000000000000000000000", "gasUsed": "0x5208", + "effectiveGasPrice": null, "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x0" } diff --git a/cmd/evm/testdata/3/exp.json b/cmd/evm/testdata/3/exp.json index 71b3d2f559..7230dca2cf 100644 --- a/cmd/evm/testdata/3/exp.json +++ b/cmd/evm/testdata/3/exp.json @@ -28,6 +28,7 @@ "transactionHash": "0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81", "contractAddress": "0x0000000000000000000000000000000000000000", "gasUsed": "0x521f", + "effectiveGasPrice": null, "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x0" } diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go index 8d85dd5b9c..d83be14477 100644 --- a/core/types/gen_receipt_json.go +++ b/core/types/gen_receipt_json.go @@ -25,7 +25,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) { TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress common.Address `json:"contractAddress"` GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice,omitempty"` + EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice"` BlockHash common.Hash `json:"blockHash,omitempty"` BlockNumber *hexutil.Big `json:"blockNumber,omitempty"` TransactionIndex hexutil.Uint `json:"transactionIndex"` @@ -59,7 +59,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { TxHash *common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress *common.Address `json:"contractAddress"` GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice,omitempty"` + EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice"` BlockHash *common.Hash `json:"blockHash,omitempty"` BlockNumber *hexutil.Big `json:"blockNumber,omitempty"` TransactionIndex *hexutil.Uint `json:"transactionIndex"` diff --git a/core/types/receipt.go b/core/types/receipt.go index 6300886c05..8fc9ec9894 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -62,7 +62,7 @@ type Receipt struct { TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress common.Address `json:"contractAddress"` GasUsed uint64 `json:"gasUsed" gencodec:"required"` - EffectiveGasPrice *big.Int `json:"effectiveGasPrice"` + EffectiveGasPrice *big.Int `json:"effectiveGasPrice"` // required, but tag omitted for backwards compatibility // Inclusion information: These fields provide information about the inclusion of the // transaction corresponding to this receipt. @@ -77,6 +77,7 @@ type receiptMarshaling struct { Status hexutil.Uint64 CumulativeGasUsed hexutil.Uint64 GasUsed hexutil.Uint64 + EffectiveGasPrice *hexutil.Big BlockNumber *hexutil.Big TransactionIndex hexutil.Uint } diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index 00031ad563..168f36208b 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -82,27 +82,15 @@ var ( }, Type: DynamicFeeTxType, } -) - -func TestDecodeEmptyTypedReceipt(t *testing.T) { - input := []byte{0x80} - var r Receipt - err := rlp.DecodeBytes(input, &r) - if err != errShortTypedReceipt { - t.Fatal("wrong error:", err) - } -} -// Tests that receipt data can be correctly derived from the contextual infos -func TestDeriveFields(t *testing.T) { // Create a few transactions to have receipts for - to2 := common.HexToAddress("0x2") - to3 := common.HexToAddress("0x3") - to4 := common.HexToAddress("0x4") - to5 := common.HexToAddress("0x5") - to6 := common.HexToAddress("0x6") - to7 := common.HexToAddress("0x7") - txs := Transactions{ + to2 = common.HexToAddress("0x2") + to3 = common.HexToAddress("0x3") + to4 = common.HexToAddress("0x4") + to5 = common.HexToAddress("0x5") + to6 = common.HexToAddress("0x6") + to7 = common.HexToAddress("0x7") + txs = Transactions{ NewTx(&LegacyTx{ Nonce: 1, Value: big.NewInt(1), @@ -161,18 +149,19 @@ func TestDeriveFields(t *testing.T) { }), } - blockNumber := big.NewInt(1) - blockTime := uint64(2) - blockHash := common.BytesToHash([]byte{0x03, 0x14}) + blockNumber = big.NewInt(1) + blockTime = uint64(2) + blockHash = common.BytesToHash([]byte{0x03, 0x14}) // Create the corresponding receipts - receipts := Receipts{ + receipts = Receipts{ &Receipt{ Status: ReceiptStatusFailed, CumulativeGasUsed: 1, Logs: []*Log{ { Address: common.BytesToAddress([]byte{0x11}), + Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")}, // derived fields: BlockNumber: blockNumber.Uint64(), TxHash: txs[0].Hash(), @@ -182,6 +171,7 @@ func TestDeriveFields(t *testing.T) { }, { Address: common.BytesToAddress([]byte{0x01, 0x11}), + Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")}, // derived fields: BlockNumber: blockNumber.Uint64(), TxHash: txs[0].Hash(), @@ -205,6 +195,7 @@ func TestDeriveFields(t *testing.T) { Logs: []*Log{ { Address: common.BytesToAddress([]byte{0x22}), + Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")}, // derived fields: BlockNumber: blockNumber.Uint64(), TxHash: txs[1].Hash(), @@ -214,6 +205,7 @@ func TestDeriveFields(t *testing.T) { }, { Address: common.BytesToAddress([]byte{0x02, 0x22}), + Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")}, // derived fields: BlockNumber: blockNumber.Uint64(), TxHash: txs[1].Hash(), @@ -296,7 +288,19 @@ func TestDeriveFields(t *testing.T) { TransactionIndex: 6, }, } +) + +func TestDecodeEmptyTypedReceipt(t *testing.T) { + input := []byte{0x80} + var r Receipt + err := rlp.DecodeBytes(input, &r) + if err != errShortTypedReceipt { + t.Fatal("wrong error:", err) + } +} +// Tests that receipt data can be correctly derived from the contextual infos +func TestDeriveFields(t *testing.T) { // Re-derive receipts. basefee := big.NewInt(1000) derivedReceipts := clearComputedFieldsOnReceipts(receipts) @@ -310,6 +314,7 @@ func TestDeriveFields(t *testing.T) { if err != nil { t.Fatal("error marshaling input receipts:", err) } + r2, err := json.MarshalIndent(derivedReceipts, "", " ") if err != nil { t.Fatal("error marshaling derived receipts:", err) @@ -320,6 +325,38 @@ func TestDeriveFields(t *testing.T) { } } +// Test that we can marshal/unmarshal receipts to/from json without errors. +// This also confirms that our test receipts contain all the required fields. +func TestReceiptJSON(t *testing.T) { + for i := range receipts { + b, err := receipts[i].MarshalJSON() + if err != nil { + t.Fatal("error marshaling receipt to json:", err) + } + r := Receipt{} + err = r.UnmarshalJSON(b) + if err != nil { + t.Fatal("error unmarshaling receipt from json:", err) + } + } +} + +// Test we can still parse receipt without EffectiveGasPrice for backwards compatibility, even +// though it is required per the spec. +func TestEffectiveGasPriceNotRequired(t *testing.T) { + r := *receipts[0] + r.EffectiveGasPrice = nil + b, err := r.MarshalJSON() + if err != nil { + t.Fatal("error marshaling receipt to json:", err) + } + r2 := Receipt{} + err = r2.UnmarshalJSON(b) + if err != nil { + t.Fatal("error unmarshaling receipt from json:", err) + } +} + // TestTypedReceiptEncodingDecoding reproduces a flaw that existed in the receipt // rlp decoder, which failed due to a shadowing error. func TestTypedReceiptEncodingDecoding(t *testing.T) { From 25f9977f2d29e2db93ab4799e94e0f26482380d4 Mon Sep 17 00:00:00 2001 From: Stephen Guo Date: Wed, 26 Apr 2023 16:19:56 +0800 Subject: [PATCH 077/988] les: use atomic type (#27168) --- les/client_handler.go | 5 ++--- les/peer.go | 26 +++++++++++++------------- les/server_handler.go | 5 ++--- les/test_helper.go | 7 +++---- les/ulc_test.go | 3 +-- 5 files changed, 21 insertions(+), 25 deletions(-) diff --git a/les/client_handler.go b/les/client_handler.go index 25a508d42d..6e7d88fc5a 100644 --- a/les/client_handler.go +++ b/les/client_handler.go @@ -21,7 +21,6 @@ import ( "math/big" "math/rand" "sync" - "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -144,8 +143,8 @@ func (h *clientHandler) handle(p *serverPeer, noInitAnnounce bool) error { } // Mark the peer starts to be served. - atomic.StoreUint32(&p.serving, 1) - defer atomic.StoreUint32(&p.serving, 0) + p.serving.Store(true) + defer p.serving.Store(false) // Spawn a main loop to handle all incoming messages. for { diff --git a/les/peer.go b/les/peer.go index 100cc7e4f1..909d912e94 100644 --- a/les/peer.go +++ b/les/peer.go @@ -121,13 +121,13 @@ type peerCommons struct { *p2p.Peer rw p2p.MsgReadWriter - id string // Peer identity. - version int // Protocol version negotiated. - network uint64 // Network ID being on. - frozen uint32 // Flag whether the peer is frozen. - announceType uint64 // New block announcement type. - serving uint32 // The status indicates the peer is served. - headInfo blockInfo // Last announced block information. + id string // Peer identity. + version int // Protocol version negotiated. + network uint64 // Network ID being on. + frozen atomic.Bool // Flag whether the peer is frozen. + announceType uint64 // New block announcement type. + serving atomic.Bool // The status indicates the peer is served. + headInfo blockInfo // Last announced block information. // Background task queue for caching peer tasks and executing in order. sendQueue *utils.ExecQueue @@ -143,7 +143,7 @@ type peerCommons struct { // isFrozen returns true if the client is frozen or the server has put our // client in frozen state func (p *peerCommons) isFrozen() bool { - return atomic.LoadUint32(&p.frozen) != 0 + return p.frozen.Load() } // canQueue returns an indicator whether the peer can queue an operation. @@ -398,7 +398,7 @@ func (p *serverPeer) rejectUpdate(size uint64) bool { // freeze processes Stop messages from the given server and set the status as // frozen. func (p *serverPeer) freeze() { - if atomic.CompareAndSwapUint32(&p.frozen, 0, 1) { + if p.frozen.CompareAndSwap(false, true) { p.sendQueue.Clear() } } @@ -406,7 +406,7 @@ func (p *serverPeer) freeze() { // unfreeze processes Resume messages from the given server and set the status // as unfrozen. func (p *serverPeer) unfreeze() { - atomic.StoreUint32(&p.frozen, 0) + p.frozen.Store(false) } // sendRequest send a request to the server based on the given message type @@ -823,11 +823,11 @@ func (p *clientPeer) freeze() { if p.version < lpv3 { // if Stop/Resume is not supported then just drop the peer after setting // its frozen status permanently - atomic.StoreUint32(&p.frozen, 1) + p.frozen.Store(true) p.Peer.Disconnect(p2p.DiscUselessPeer) return } - if atomic.SwapUint32(&p.frozen, 1) == 0 { + if !p.frozen.Swap(true) { go func() { p.sendStop() time.Sleep(freezeTimeBase + time.Duration(rand.Int63n(int64(freezeTimeRandom)))) @@ -840,7 +840,7 @@ func (p *clientPeer) freeze() { time.Sleep(freezeCheckPeriod) continue } - atomic.StoreUint32(&p.frozen, 0) + p.frozen.Store(false) p.sendResume(bufValue) return } diff --git a/les/server_handler.go b/les/server_handler.go index 39c7ace1c9..418974c37c 100644 --- a/les/server_handler.go +++ b/les/server_handler.go @@ -19,7 +19,6 @@ package les import ( "errors" "sync" - "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -164,8 +163,8 @@ func (h *serverHandler) handle(p *clientPeer) error { }() // Mark the peer as being served. - atomic.StoreUint32(&p.serving, 1) - defer atomic.StoreUint32(&p.serving, 0) + p.serving.Store(true) + defer p.serving.Store(false) // Spawn a main loop to handle all incoming messages. for { diff --git a/les/test_helper.go b/les/test_helper.go index 70f78498d4..ead97ddd17 100644 --- a/les/test_helper.go +++ b/les/test_helper.go @@ -25,7 +25,6 @@ import ( "crypto/rand" "fmt" "math/big" - "sync/atomic" "testing" "time" @@ -380,7 +379,7 @@ func newTestPeerPair(name string, version int, server *serverHandler, client *cl return nil, nil, fmt.Errorf("failed to establish protocol connection %v", err) default: } - if atomic.LoadUint32(&peer1.serving) == 1 && atomic.LoadUint32(&peer2.serving) == 1 { + if peer1.serving.Load() && peer2.serving.Load() { break } time.Sleep(50 * time.Millisecond) @@ -441,7 +440,7 @@ func (client *testClient) newRawPeer(t *testing.T, name string, version int, rec return nil, nil, nil default: } - if atomic.LoadUint32(&peer.serving) == 1 { + if peer.serving.Load() { break } time.Sleep(50 * time.Millisecond) @@ -505,7 +504,7 @@ func (server *testServer) newRawPeer(t *testing.T, name string, version int) (*t return nil, nil, nil default: } - if atomic.LoadUint32(&peer.serving) == 1 { + if peer.serving.Load() { break } time.Sleep(50 * time.Millisecond) diff --git a/les/ulc_test.go b/les/ulc_test.go index 9a29a24cee..791bc28853 100644 --- a/les/ulc_test.go +++ b/les/ulc_test.go @@ -20,7 +20,6 @@ import ( "crypto/rand" "fmt" "net" - "sync/atomic" "testing" "time" @@ -136,7 +135,7 @@ func connect(server *serverHandler, serverId enode.ID, client *clientHandler, pr return nil, nil, fmt.Errorf("failed to establish protocol connection %v", err) default: } - if atomic.LoadUint32(&peer1.serving) == 1 && atomic.LoadUint32(&peer2.serving) == 1 { + if peer1.serving.Load() && peer2.serving.Load() { break } time.Sleep(50 * time.Millisecond) From 306d17749c3f04816435026071830d4932b3390d Mon Sep 17 00:00:00 2001 From: Stephen Guo Date: Wed, 26 Apr 2023 16:21:47 +0800 Subject: [PATCH 078/988] light: use atomic type (#27169) * light: use atomic type * light: use a suitable name for the stopped switch in LightChain --- light/lightchain.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/light/lightchain.go b/light/lightchain.go index 24999f52b0..e2d236fb83 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -70,9 +70,9 @@ type LightChain struct { wg sync.WaitGroup // Atomic boolean switches: - running int32 // whether LightChain is running or stopped - procInterrupt int32 // interrupts chain insert - disableCheckFreq int32 // disables header verification + stopped atomic.Bool // whether LightChain is stopped or running + procInterrupt atomic.Bool // interrupts chain insert + disableCheckFreq atomic.Bool // disables header verification } // NewLightChain returns a fully initialised light chain using information @@ -114,7 +114,7 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. } func (lc *LightChain) getProcInterrupt() bool { - return atomic.LoadInt32(&lc.procInterrupt) == 1 + return lc.procInterrupt.Load() } // Odr returns the ODR backend of the chain @@ -302,7 +302,7 @@ func (lc *LightChain) GetBlockByNumber(ctx context.Context, number uint64) (*typ // Stop stops the blockchain service. If any imports are currently in progress // it will abort them using the procInterrupt. func (lc *LightChain) Stop() { - if !atomic.CompareAndSwapInt32(&lc.running, 0, 1) { + if !lc.stopped.CompareAndSwap(false, true) { return } close(lc.quit) @@ -315,7 +315,7 @@ func (lc *LightChain) Stop() { // errInsertionInterrupted as soon as possible. Insertion is permanently disabled after // calling this method. func (lc *LightChain) StopInsert() { - atomic.StoreInt32(&lc.procInterrupt, 1) + lc.procInterrupt.Store(true) } // Rollback is designed to remove a chain of links from the database that aren't @@ -393,7 +393,7 @@ func (lc *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (i if len(chain) == 0 { return 0, nil } - if atomic.LoadInt32(&lc.disableCheckFreq) == 1 { + if lc.disableCheckFreq.Load() { checkFreq = 0 } start := time.Now() @@ -541,10 +541,10 @@ func (lc *LightChain) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) // DisableCheckFreq disables header validation. This is used for ultralight mode. func (lc *LightChain) DisableCheckFreq() { - atomic.StoreInt32(&lc.disableCheckFreq, 1) + lc.disableCheckFreq.Store(true) } // EnableCheckFreq enables header validation. func (lc *LightChain) EnableCheckFreq() { - atomic.StoreInt32(&lc.disableCheckFreq, 0) + lc.disableCheckFreq.Store(false) } From 66c0c4e5174a0b231727f27c7ad48624189ecc62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 26 Apr 2023 18:17:37 +0300 Subject: [PATCH 079/988] cmd, eth, les: replace Shanghai override flag with Cancun (#27171) --- cmd/geth/config.go | 6 +++--- cmd/geth/main.go | 2 +- cmd/utils/flags.go | 6 +++--- core/genesis.go | 6 +++--- eth/backend.go | 4 ++-- eth/ethconfig/config.go | 4 ++-- eth/ethconfig/gen_config.go | 10 +++++----- les/client.go | 4 ++-- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 0b856d1c1b..ad7fd4d714 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -158,9 +158,9 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { // makeFullNode loads geth configuration and creates the Ethereum backend. func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { stack, cfg := makeConfigNode(ctx) - if ctx.IsSet(utils.OverrideShanghai.Name) { - v := ctx.Uint64(utils.OverrideShanghai.Name) - cfg.Eth.OverrideShanghai = &v + if ctx.IsSet(utils.OverrideCancun.Name) { + v := ctx.Uint64(utils.OverrideCancun.Name) + cfg.Eth.OverrideCancun = &v } backend, eth := utils.RegisterEthService(stack, &cfg.Eth) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index f55adb1449..799493e67d 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -64,7 +64,7 @@ var ( utils.NoUSBFlag, utils.USBFlag, utils.SmartCardDaemonPathFlag, - utils.OverrideShanghai, + utils.OverrideCancun, utils.EnablePersonal, utils.EthashCacheDirFlag, utils.EthashCachesInMemoryFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index e9b6320ad7..ba9916d93b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -268,9 +268,9 @@ var ( Value: 2048, Category: flags.EthCategory, } - OverrideShanghai = &cli.Uint64Flag{ - Name: "override.shanghai", - Usage: "Manually specify the Shanghai fork timestamp, overriding the bundled setting", + OverrideCancun = &cli.Uint64Flag{ + Name: "override.cancun", + Usage: "Manually specify the Cancun fork timestamp, overriding the bundled setting", Category: flags.EthCategory, } // Light server and client settings diff --git a/core/genesis.go b/core/genesis.go index 269c1486d3..e1682ebebb 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -267,7 +267,7 @@ func (e *GenesisMismatchError) Error() string { // ChainOverrides contains the changes to chain config. type ChainOverrides struct { - OverrideShanghai *uint64 + OverrideCancun *uint64 } // SetupGenesisBlock writes or updates the genesis block in db. @@ -293,8 +293,8 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen } applyOverrides := func(config *params.ChainConfig) { if config != nil { - if overrides != nil && overrides.OverrideShanghai != nil { - config.ShanghaiTime = overrides.OverrideShanghai + if overrides != nil && overrides.OverrideCancun != nil { + config.CancunTime = overrides.OverrideCancun } } } diff --git a/eth/backend.go b/eth/backend.go index 24ae08502a..21c0deaa2d 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -194,8 +194,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { ) // Override the chain config with provided settings. var overrides core.ChainOverrides - if config.OverrideShanghai != nil { - overrides.OverrideShanghai = config.OverrideShanghai + if config.OverrideCancun != nil { + overrides.OverrideCancun = config.OverrideCancun } eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) if err != nil { diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 3d26cf69a2..3279d9a1b2 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -198,8 +198,8 @@ type Config struct { // send-transaction variants. The unit is ether. RPCTxFeeCap float64 - // OverrideShanghai (TODO: remove after the fork) - OverrideShanghai *uint64 `toml:",omitempty"` + // OverrideCancun (TODO: remove after the fork) + OverrideCancun *uint64 `toml:",omitempty"` } // CreateConsensusEngine creates a consensus engine for the given chain configuration. diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 3ab4340144..0070ba4c03 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -56,7 +56,7 @@ func (c Config) MarshalTOML() (interface{}, error) { RPCGasCap uint64 RPCEVMTimeout time.Duration RPCTxFeeCap float64 - OverrideShanghai *uint64 `toml:",omitempty"` + OverrideCancun *uint64 `toml:",omitempty"` } var enc Config enc.Genesis = c.Genesis @@ -98,7 +98,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCGasCap = c.RPCGasCap enc.RPCEVMTimeout = c.RPCEVMTimeout enc.RPCTxFeeCap = c.RPCTxFeeCap - enc.OverrideShanghai = c.OverrideShanghai + enc.OverrideCancun = c.OverrideCancun return &enc, nil } @@ -144,7 +144,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { RPCGasCap *uint64 RPCEVMTimeout *time.Duration RPCTxFeeCap *float64 - OverrideShanghai *uint64 `toml:",omitempty"` + OverrideCancun *uint64 `toml:",omitempty"` } var dec Config if err := unmarshal(&dec); err != nil { @@ -267,8 +267,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.RPCTxFeeCap != nil { c.RPCTxFeeCap = *dec.RPCTxFeeCap } - if dec.OverrideShanghai != nil { - c.OverrideShanghai = dec.OverrideShanghai + if dec.OverrideCancun != nil { + c.OverrideCancun = dec.OverrideCancun } return nil } diff --git a/les/client.go b/les/client.go index 9b75f07bd8..8eb46c2e63 100644 --- a/les/client.go +++ b/les/client.go @@ -94,8 +94,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { return nil, err } var overrides core.ChainOverrides - if config.OverrideShanghai != nil { - overrides.OverrideShanghai = config.OverrideShanghai + if config.OverrideCancun != nil { + overrides.OverrideCancun = config.OverrideCancun } chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, trie.NewDatabase(chainDb), config.Genesis, &overrides) if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { From 8f373227ac481685148019b21ef9e1478d3ba609 Mon Sep 17 00:00:00 2001 From: Delweng Date: Thu, 27 Apr 2023 18:57:29 +0800 Subject: [PATCH 080/988] cmd/geth: make account commands not require datadir lock (#27084) Makes the `geth account ... ` commands usable even if a geth-process is already executing, since the account commands do not read the chaindata, it was not required for those to use the same locking mechanism. --- Signed-off-by: jsvisa Co-authored-by: Martin Holst Swende Co-authored-by: Sina Mahmoodi --- cmd/geth/accountcmd.go | 59 ++++++++++++++++++++++++++---------------- cmd/geth/config.go | 19 +++++++++----- node/config.go | 6 ++--- node/node.go | 2 +- 4 files changed, 53 insertions(+), 33 deletions(-) diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go index a36da7d55f..cc22684e0b 100644 --- a/cmd/geth/accountcmd.go +++ b/cmd/geth/accountcmd.go @@ -188,15 +188,34 @@ nodes. } ) +// makeAccountManager creates an account manager with backends +func makeAccountManager(ctx *cli.Context) *accounts.Manager { + cfg := loadBaseConfig(ctx) + am := accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: cfg.Node.InsecureUnlockAllowed}) + keydir, isEphemeral, err := cfg.Node.GetKeyStoreDir() + if err != nil { + utils.Fatalf("Failed to get the keystore directory: %v", err) + } + if isEphemeral { + utils.Fatalf("Can't use ephemeral directory as keystore path") + } + + if err := setAccountManagerBackends(&cfg.Node, am, keydir); err != nil { + utils.Fatalf("Failed to set account manager backends: %v", err) + } + return am +} + func accountList(ctx *cli.Context) error { - stack, _ := makeConfigNode(ctx) + am := makeAccountManager(ctx) var index int - for _, wallet := range stack.AccountManager().Wallets() { + for _, wallet := range am.Wallets() { for _, account := range wallet.Accounts() { fmt.Printf("Account #%d: {%x} %s\n", index, account.Address, &account.URL) index++ } } + return nil } @@ -258,17 +277,13 @@ func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrErr // accountCreate creates a new account into the keystore defined by the CLI flags. func accountCreate(ctx *cli.Context) error { - cfg := gethConfig{Node: defaultNodeConfig()} - // Load config file. - if file := ctx.String(configFileFlag.Name); file != "" { - if err := loadConfig(file, &cfg); err != nil { - utils.Fatalf("%v", err) - } - } - utils.SetNodeConfig(ctx, &cfg.Node) - keydir, err := cfg.Node.KeyDirConfig() + cfg := loadBaseConfig(ctx) + keydir, isEphemeral, err := cfg.Node.GetKeyStoreDir() if err != nil { - utils.Fatalf("Failed to read configuration: %v", err) + utils.Fatalf("Failed to get the keystore directory: %v", err) + } + if isEphemeral { + utils.Fatalf("Can't use ephemeral directory as keystore path") } scryptN := keystore.StandardScryptN scryptP := keystore.StandardScryptP @@ -300,8 +315,8 @@ func accountUpdate(ctx *cli.Context) error { if ctx.Args().Len() == 0 { utils.Fatalf("No accounts specified to update") } - stack, _ := makeConfigNode(ctx) - backends := stack.AccountManager().Backends(keystore.KeyStoreType) + am := makeAccountManager(ctx) + backends := am.Backends(keystore.KeyStoreType) if len(backends) == 0 { utils.Fatalf("Keystore is not available") } @@ -327,14 +342,14 @@ func importWallet(ctx *cli.Context) error { utils.Fatalf("Could not read wallet file: %v", err) } - stack, _ := makeConfigNode(ctx) - passphrase := utils.GetPassPhraseWithList("", false, 0, utils.MakePasswordList(ctx)) - - backends := stack.AccountManager().Backends(keystore.KeyStoreType) + am := makeAccountManager(ctx) + backends := am.Backends(keystore.KeyStoreType) if len(backends) == 0 { utils.Fatalf("Keystore is not available") } ks := backends[0].(*keystore.KeyStore) + passphrase := utils.GetPassPhraseWithList("", false, 0, utils.MakePasswordList(ctx)) + acct, err := ks.ImportPreSaleKey(keyJSON, passphrase) if err != nil { utils.Fatalf("%v", err) @@ -352,14 +367,14 @@ func accountImport(ctx *cli.Context) error { if err != nil { utils.Fatalf("Failed to load the private key: %v", err) } - stack, _ := makeConfigNode(ctx) - passphrase := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) - - backends := stack.AccountManager().Backends(keystore.KeyStoreType) + am := makeAccountManager(ctx) + backends := am.Backends(keystore.KeyStoreType) if len(backends) == 0 { utils.Fatalf("Keystore is not available") } ks := backends[0].(*keystore.KeyStore) + passphrase := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) + acct, err := ks.ImportECDSA(key, passphrase) if err != nil { utils.Fatalf("Could not create the account: %v", err) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index ad7fd4d714..816762a683 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -26,6 +26,7 @@ import ( "github.com/urfave/cli/v2" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/external" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/scwallet" @@ -119,8 +120,9 @@ func defaultNodeConfig() node.Config { return cfg } -// makeConfigNode loads geth configuration and creates a blank node instance. -func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { +// loadBaseConfig loads the gethConfig based on the given command line +// parameters and config file. +func loadBaseConfig(ctx *cli.Context) gethConfig { // Load defaults. cfg := gethConfig{ Eth: ethconfig.Defaults, @@ -137,12 +139,18 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { // Apply flags. utils.SetNodeConfig(ctx, &cfg.Node) + return cfg +} + +// makeConfigNode loads geth configuration and creates a blank node instance. +func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { + cfg := loadBaseConfig(ctx) stack, err := node.New(&cfg.Node) if err != nil { utils.Fatalf("Failed to create the protocol stack: %v", err) } // Node doesn't by default populate account manager backends - if err := setAccountManagerBackends(stack); err != nil { + if err := setAccountManagerBackends(stack.Config(), stack.AccountManager(), stack.KeyStoreDir()); err != nil { utils.Fatalf("Failed to set account manager backends: %v", err) } @@ -269,10 +277,7 @@ func deprecated(field string) bool { } } -func setAccountManagerBackends(stack *node.Node) error { - conf := stack.Config() - am := stack.AccountManager() - keydir := stack.KeyStoreDir() +func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error { scryptN := keystore.StandardScryptN scryptP := keystore.StandardScryptP if conf.UseLightweightKDF { diff --git a/node/config.go b/node/config.go index 37a7d5837f..35115eaa85 100644 --- a/node/config.go +++ b/node/config.go @@ -448,10 +448,10 @@ func (c *Config) KeyDirConfig() (string, error) { return keydir, err } -// getKeyStoreDir retrieves the key directory and will create +// GetKeyStoreDir retrieves the key directory and will create // and ephemeral one if necessary. -func getKeyStoreDir(conf *Config) (string, bool, error) { - keydir, err := conf.KeyDirConfig() +func (c *Config) GetKeyStoreDir() (string, bool, error) { + keydir, err := c.KeyDirConfig() if err != nil { return "", false, err } diff --git a/node/node.go b/node/node.go index 2f89bc1ad2..e8494ac3b2 100644 --- a/node/node.go +++ b/node/node.go @@ -119,7 +119,7 @@ func New(conf *Config) (*Node, error) { if err := node.openDataDir(); err != nil { return nil, err } - keyDir, isEphem, err := getKeyStoreDir(conf) + keyDir, isEphem, err := conf.GetKeyStoreDir() if err != nil { return nil, err } From 47cdea5ac5f97d275b50bffd25adc12eea0ddd8c Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 28 Apr 2023 11:03:43 +0200 Subject: [PATCH 081/988] p2p/discover: concurrent TALKREQ handling (#27112) This changes TALKREQ message processing to run the handler on separate goroutine, instead of running on the main discv5 dispatcher goroutine. It's better this way because it allows the handler to perform blocking actions. I'm also adding a new method TalkRequestToID here. The method allows implementing a request flow where one node A sends TALKREQ to another node B, and node B later sends a TALKREQ back. With TalkRequestToID, node B does not need the ENR of A to send its request. --- p2p/discover/table_util_test.go | 1 + p2p/discover/v5_talk.go | 113 ++++++++++++++++++++++++++ p2p/discover/v5_udp.go | 137 +++++++++++++++++++------------- p2p/discover/v5_udp_test.go | 23 +++++- p2p/discover/v5wire/msg.go | 4 +- 5 files changed, 220 insertions(+), 58 deletions(-) create mode 100644 p2p/discover/v5_talk.go diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index 77e03ca9e7..217905eb73 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -52,6 +52,7 @@ func newTestTable(t transport) (*Table, *enode.DB) { func nodeAtDistance(base enode.ID, ld int, ip net.IP) *node { var r enr.Record r.Set(enr.IP(ip)) + r.Set(enr.UDP(30303)) return wrapNode(enode.SignNull(&r, idAtDistance(base, ld))) } diff --git a/p2p/discover/v5_talk.go b/p2p/discover/v5_talk.go new file mode 100644 index 0000000000..c1f6787940 --- /dev/null +++ b/p2p/discover/v5_talk.go @@ -0,0 +1,113 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package discover + +import ( + "net" + "sync" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/discover/v5wire" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +// This is a limit for the number of concurrent talk requests. +const maxActiveTalkRequests = 1024 + +// This is the timeout for acquiring a handler execution slot for a talk request. +// The timeout should be short enough to fit within the request timeout. +const talkHandlerLaunchTimeout = 400 * time.Millisecond + +// TalkRequestHandler callback processes a talk request and returns a response. +// +// Note that talk handlers are expected to come up with a response very quickly, within at +// most 200ms or so. If the handler takes longer than that, the remote end may time out +// and wont receive the response. +type TalkRequestHandler func(enode.ID, *net.UDPAddr, []byte) []byte + +type talkSystem struct { + transport *UDPv5 + + mutex sync.Mutex + handlers map[string]TalkRequestHandler + slots chan struct{} + lastLog time.Time + dropCount int +} + +func newTalkSystem(transport *UDPv5) *talkSystem { + t := &talkSystem{ + transport: transport, + handlers: make(map[string]TalkRequestHandler), + slots: make(chan struct{}, maxActiveTalkRequests), + } + for i := 0; i < cap(t.slots); i++ { + t.slots <- struct{}{} + } + return t +} + +// register adds a protocol handler. +func (t *talkSystem) register(protocol string, handler TalkRequestHandler) { + t.mutex.Lock() + t.handlers[protocol] = handler + t.mutex.Unlock() +} + +// handleRequest handles a talk request. +func (t *talkSystem) handleRequest(id enode.ID, addr *net.UDPAddr, req *v5wire.TalkRequest) { + t.mutex.Lock() + handler, ok := t.handlers[req.Protocol] + t.mutex.Unlock() + + if !ok { + resp := &v5wire.TalkResponse{ReqID: req.ReqID} + t.transport.sendResponse(id, addr, resp) + return + } + + // Wait for a slot to become available, then run the handler. + timeout := time.NewTimer(talkHandlerLaunchTimeout) + defer timeout.Stop() + select { + case <-t.slots: + go func() { + defer func() { t.slots <- struct{}{} }() + respMessage := handler(id, addr, req.Message) + resp := &v5wire.TalkResponse{ReqID: req.ReqID, Message: respMessage} + t.transport.sendFromAnotherThread(id, addr, resp) + }() + case <-timeout.C: + // Couldn't get it in time, drop the request. + if time.Since(t.lastLog) > 5*time.Second { + log.Warn("Dropping TALKREQ due to overload", "ndrop", t.dropCount) + t.lastLog = time.Now() + t.dropCount++ + } + case <-t.transport.closeCtx.Done(): + // Transport closed, drop the request. + } +} + +// wait blocks until all active requests have finished, and prevents new request +// handlers from being launched. +func (t *talkSystem) wait() { + for i := 0; i < cap(t.slots); i++ { + <-t.slots + } +} diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index dadacb528b..df5ffcf3b2 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -74,8 +74,7 @@ type UDPv5 struct { logcontext []interface{} // talkreq handler registry - trlock sync.Mutex - trhandlers map[string]TalkRequestHandler + talk *talkSystem // channels into dispatch packetInCh chan ReadPacket @@ -83,6 +82,7 @@ type UDPv5 struct { callCh chan *callV5 callDoneCh chan *callV5 respTimeoutCh chan *callTimeout + sendCh chan sendRequest unhandled chan<- ReadPacket // state of dispatch @@ -98,12 +98,18 @@ type UDPv5 struct { wg sync.WaitGroup } -// TalkRequestHandler callback processes a talk request and optionally returns a reply -type TalkRequestHandler func(enode.ID, *net.UDPAddr, []byte) []byte +type sendRequest struct { + destID enode.ID + destAddr *net.UDPAddr + msg v5wire.Packet +} // callV5 represents a remote procedure call against another node. type callV5 struct { - node *enode.Node + id enode.ID + addr *net.UDPAddr + node *enode.Node // This is required to perform handshakes. + packet v5wire.Packet responseType byte // expected packet type of response reqid []byte @@ -150,12 +156,12 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { log: cfg.Log, validSchemes: cfg.ValidSchemes, clock: cfg.Clock, - trhandlers: make(map[string]TalkRequestHandler), // channels into dispatch packetInCh: make(chan ReadPacket, 1), readNextCh: make(chan struct{}, 1), callCh: make(chan *callV5), callDoneCh: make(chan *callV5), + sendCh: make(chan sendRequest), respTimeoutCh: make(chan *callTimeout), unhandled: cfg.Unhandled, // state of dispatch @@ -163,11 +169,11 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { activeCallByNode: make(map[enode.ID]*callV5), activeCallByAuth: make(map[v5wire.Nonce]*callV5), callQueue: make(map[enode.ID][]*callV5), - // shutdown closeCtx: closeCtx, cancelCloseCtx: cancelCloseCtx, } + t.talk = newTalkSystem(t) tab, err := newTable(t, t.db, cfg.Bootnodes, cfg.Log) if err != nil { return nil, err @@ -186,6 +192,7 @@ func (t *UDPv5) Close() { t.closeOnce.Do(func() { t.cancelCloseCtx() t.conn.Close() + t.talk.wait() t.wg.Wait() t.tab.close() }) @@ -241,15 +248,26 @@ func (t *UDPv5) LocalNode() *enode.LocalNode { // whenever a request for the given protocol is received and should return the response // data or nil. func (t *UDPv5) RegisterTalkHandler(protocol string, handler TalkRequestHandler) { - t.trlock.Lock() - defer t.trlock.Unlock() - t.trhandlers[protocol] = handler + t.talk.register(protocol, handler) } -// TalkRequest sends a talk request to n and waits for a response. +// TalkRequest sends a talk request to a node and waits for a response. func (t *UDPv5) TalkRequest(n *enode.Node, protocol string, request []byte) ([]byte, error) { req := &v5wire.TalkRequest{Protocol: protocol, Message: request} - resp := t.call(n, v5wire.TalkResponseMsg, req) + resp := t.callToNode(n, v5wire.TalkResponseMsg, req) + defer t.callDone(resp) + select { + case respMsg := <-resp.ch: + return respMsg.(*v5wire.TalkResponse).Message, nil + case err := <-resp.err: + return nil, err + } +} + +// TalkRequest sends a talk request to a node and waits for a response. +func (t *UDPv5) TalkRequestToID(id enode.ID, addr *net.UDPAddr, protocol string, request []byte) ([]byte, error) { + req := &v5wire.TalkRequest{Protocol: protocol, Message: request} + resp := t.callToID(id, addr, v5wire.TalkResponseMsg, req) defer t.callDone(resp) select { case respMsg := <-resp.ch: @@ -340,7 +358,7 @@ func lookupDistances(target, dest enode.ID) (dists []uint) { // ping calls PING on a node and waits for a PONG response. func (t *UDPv5) ping(n *enode.Node) (uint64, error) { req := &v5wire.Ping{ENRSeq: t.localNode.Node().Seq()} - resp := t.call(n, v5wire.PongMsg, req) + resp := t.callToNode(n, v5wire.PongMsg, req) defer t.callDone(resp) select { @@ -365,7 +383,7 @@ func (t *UDPv5) RequestENR(n *enode.Node) (*enode.Node, error) { // findnode calls FINDNODE on a node and waits for responses. func (t *UDPv5) findnode(n *enode.Node, distances []uint) ([]*enode.Node, error) { - resp := t.call(n, v5wire.NodesMsg, &v5wire.Findnode{Distances: distances}) + resp := t.callToNode(n, v5wire.NodesMsg, &v5wire.Findnode{Distances: distances}) return t.waitForNodes(resp, distances) } @@ -408,17 +426,17 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s if err != nil { return nil, err } - if err := netutil.CheckRelayIP(c.node.IP(), node.IP()); err != nil { + if err := netutil.CheckRelayIP(c.addr.IP, node.IP()); err != nil { return nil, err } if t.netrestrict != nil && !t.netrestrict.Contains(node.IP()) { return nil, errors.New("not contained in netrestrict list") } - if c.node.UDP() <= 1024 { + if node.UDP() <= 1024 { return nil, errLowPort } if distances != nil { - nd := enode.LogDist(c.node.ID(), node.ID()) + nd := enode.LogDist(c.id, node.ID()) if !containsUint(uint(nd), distances) { return nil, errors.New("does not match any requested distance") } @@ -439,17 +457,28 @@ func containsUint(x uint, xs []uint) bool { return false } -// call sends the given call and sets up a handler for response packets (of message type -// responseType). Responses are dispatched to the call's response channel. -func (t *UDPv5) call(node *enode.Node, responseType byte, packet v5wire.Packet) *callV5 { - c := &callV5{ - node: node, - packet: packet, - responseType: responseType, - reqid: make([]byte, 8), - ch: make(chan v5wire.Packet, 1), - err: make(chan error, 1), - } +// callToNode sends the given call and sets up a handler for response packets (of message +// type responseType). Responses are dispatched to the call's response channel. +func (t *UDPv5) callToNode(n *enode.Node, responseType byte, req v5wire.Packet) *callV5 { + addr := &net.UDPAddr{IP: n.IP(), Port: int(n.UDP())} + c := &callV5{id: n.ID(), addr: addr, node: n} + t.initCall(c, responseType, req) + return c +} + +// callToID is like callToNode, but for cases where the node record is not available. +func (t *UDPv5) callToID(id enode.ID, addr *net.UDPAddr, responseType byte, req v5wire.Packet) *callV5 { + c := &callV5{id: id, addr: addr} + t.initCall(c, responseType, req) + return c +} + +func (t *UDPv5) initCall(c *callV5, responseType byte, packet v5wire.Packet) { + c.packet = packet + c.responseType = responseType + c.reqid = make([]byte, 8) + c.ch = make(chan v5wire.Packet, 1) + c.err = make(chan error, 1) // Assign request ID. crand.Read(c.reqid) packet.SetRequestID(c.reqid) @@ -459,7 +488,6 @@ func (t *UDPv5) call(node *enode.Node, responseType byte, packet v5wire.Packet) case <-t.closeCtx.Done(): c.err <- errClosed } - return c } // callDone tells dispatch that the active call is done. @@ -501,26 +529,27 @@ func (t *UDPv5) dispatch() { for { select { case c := <-t.callCh: - id := c.node.ID() - t.callQueue[id] = append(t.callQueue[id], c) - t.sendNextCall(id) + t.callQueue[c.id] = append(t.callQueue[c.id], c) + t.sendNextCall(c.id) case ct := <-t.respTimeoutCh: - active := t.activeCallByNode[ct.c.node.ID()] + active := t.activeCallByNode[ct.c.id] if ct.c == active && ct.timer == active.timeout { ct.c.err <- errTimeout } case c := <-t.callDoneCh: - id := c.node.ID() - active := t.activeCallByNode[id] + active := t.activeCallByNode[c.id] if active != c { panic("BUG: callDone for inactive call") } c.timeout.Stop() delete(t.activeCallByAuth, c.nonce) - delete(t.activeCallByNode, id) - t.sendNextCall(id) + delete(t.activeCallByNode, c.id) + t.sendNextCall(c.id) + + case r := <-t.sendCh: + t.send(r.destID, r.destAddr, r.msg, nil) case p := <-t.packetInCh: t.handlePacket(p.Data, p.Addr) @@ -590,8 +619,7 @@ func (t *UDPv5) sendCall(c *callV5) { delete(t.activeCallByAuth, c.nonce) } - addr := &net.UDPAddr{IP: c.node.IP(), Port: c.node.UDP()} - newNonce, _ := t.send(c.node.ID(), addr, c.packet, c.challenge) + newNonce, _ := t.send(c.id, c.addr, c.packet, c.challenge) c.nonce = newNonce t.activeCallByAuth[newNonce] = c t.startResponseTimeout(c) @@ -604,6 +632,13 @@ func (t *UDPv5) sendResponse(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.P return err } +func (t *UDPv5) sendFromAnotherThread(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet) { + select { + case t.sendCh <- sendRequest{toID, toAddr, packet}: + case <-t.closeCtx.Done(): + } +} + // send sends a packet to the given node. func (t *UDPv5) send(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet, c *v5wire.Whoareyou) (v5wire.Nonce, error) { addr := toAddr.String() @@ -691,7 +726,7 @@ func (t *UDPv5) handleCallResponse(fromID enode.ID, fromAddr *net.UDPAddr, p v5w t.log.Debug(fmt.Sprintf("Unsolicited/late %s response", p.Name()), "id", fromID, "addr", fromAddr) return false } - if !fromAddr.IP.Equal(ac.node.IP()) || fromAddr.Port != ac.node.UDP() { + if !fromAddr.IP.Equal(ac.addr.IP) || fromAddr.Port != ac.addr.Port { t.log.Debug(fmt.Sprintf("%s from wrong endpoint", p.Name()), "id", fromID, "addr", fromAddr) return false } @@ -733,7 +768,7 @@ func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr *net.UDPAddr) case *v5wire.Nodes: t.handleCallResponse(fromID, fromAddr, p) case *v5wire.TalkRequest: - t.handleTalkRequest(fromID, fromAddr, p) + t.talk.handleRequest(fromID, fromAddr, p) case *v5wire.TalkResponse: t.handleCallResponse(fromID, fromAddr, p) } @@ -763,6 +798,12 @@ func (t *UDPv5) handleWhoareyou(p *v5wire.Whoareyou, fromID enode.ID, fromAddr * return } + if c.node == nil { + // Can't perform handshake because we don't have the ENR. + t.log.Debug("Can't handle "+p.Name(), "addr", fromAddr, "err", "call has no ENR") + c.err <- errors.New("remote wants handshake, but call has no ENR") + return + } // Resend the call that was answered by WHOAREYOU. t.log.Trace("<< "+p.Name(), "id", c.node.ID(), "addr", fromAddr) c.handshakeCount++ @@ -876,17 +917,3 @@ func packNodes(reqid []byte, nodes []*enode.Node) []*v5wire.Nodes { } return resp } - -// handleTalkRequest runs the talk request handler of the requested protocol. -func (t *UDPv5) handleTalkRequest(fromID enode.ID, fromAddr *net.UDPAddr, p *v5wire.TalkRequest) { - t.trlock.Lock() - handler := t.trhandlers[p.Protocol] - t.trlock.Unlock() - - var response []byte - if handler != nil { - response = handler(fromID, fromAddr, p.Message) - } - resp := &v5wire.TalkResponse{ReqID: p.ReqID, Message: response} - t.sendResponse(fromID, fromAddr, resp) -} diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 481bb1cdc3..9aa5f975e8 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -186,7 +186,7 @@ func TestUDPv5_findnodeHandling(t *testing.T) { // This request gets all the distance-253 nodes. test.packetIn(&v5wire.Findnode{ReqID: []byte{4}, Distances: []uint{253}}) - test.expectNodes([]byte{4}, 1, nodes253) + test.expectNodes([]byte{4}, 2, nodes253) // This request gets all the distance-249 nodes and some more at 248 because // the bucket at 249 is not full. @@ -515,6 +515,27 @@ func TestUDPv5_talkRequest(t *testing.T) { if err := <-done; err != nil { t.Fatal(err) } + + // Also check requesting without ENR. + go func() { + _, err := test.udp.TalkRequestToID(remote.ID(), test.remoteaddr, "test", []byte("test request 2")) + done <- err + }() + test.waitPacketOut(func(p *v5wire.TalkRequest, addr *net.UDPAddr, _ v5wire.Nonce) { + if p.Protocol != "test" { + t.Errorf("wrong protocol ID in talk request: %q", p.Protocol) + } + if string(p.Message) != "test request 2" { + t.Errorf("wrong message talk request: %q", p.Message) + } + test.packetInFrom(test.remotekey, test.remoteaddr, &v5wire.TalkResponse{ + ReqID: p.ReqID, + Message: []byte("test response 2"), + }) + }) + if err := <-done; err != nil { + t.Fatal(err) + } } // This test checks that lookupDistances works. diff --git a/p2p/discover/v5wire/msg.go b/p2p/discover/v5wire/msg.go index fb8e1e12c2..401db2f6c5 100644 --- a/p2p/discover/v5wire/msg.go +++ b/p2p/discover/v5wire/msg.go @@ -216,7 +216,7 @@ func (p *TalkRequest) RequestID() []byte { return p.ReqID } func (p *TalkRequest) SetRequestID(id []byte) { p.ReqID = id } func (p *TalkRequest) AppendLogInfo(ctx []interface{}) []interface{} { - return append(ctx, "proto", p.Protocol, "reqid", hexutil.Bytes(p.ReqID), "len", len(p.Message)) + return append(ctx, "proto", p.Protocol, "req", hexutil.Bytes(p.ReqID), "len", len(p.Message)) } func (*TalkResponse) Name() string { return "TALKRESP/v5" } @@ -225,5 +225,5 @@ func (p *TalkResponse) RequestID() []byte { return p.ReqID } func (p *TalkResponse) SetRequestID(id []byte) { p.ReqID = id } func (p *TalkResponse) AppendLogInfo(ctx []interface{}) []interface{} { - return append(ctx, "req", p.ReqID, "len", len(p.Message)) + return append(ctx, "req", hexutil.Bytes(p.ReqID), "len", len(p.Message)) } From c387186f885f9a3492c70282d205fc0a1b141b55 Mon Sep 17 00:00:00 2001 From: ucwong Date: Fri, 28 Apr 2023 13:33:14 -0500 Subject: [PATCH 082/988] eth/ethconfig: go fmt (#27194) --- eth/ethconfig/gen_config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 0070ba4c03..7d7fd32666 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -144,7 +144,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { RPCGasCap *uint64 RPCEVMTimeout *time.Duration RPCTxFeeCap *float64 - OverrideCancun *uint64 `toml:",omitempty"` + OverrideCancun *uint64 `toml:",omitempty"` } var dec Config if err := unmarshal(&dec); err != nil { From a865e28f2866ad8d1df99d2e3924a9c57b47813e Mon Sep 17 00:00:00 2001 From: ucwong Date: Fri, 28 Apr 2023 13:34:08 -0500 Subject: [PATCH 083/988] p2p/discover : typo (#27193) --- p2p/discover/v5_udp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index df5ffcf3b2..50e25b8588 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -264,7 +264,7 @@ func (t *UDPv5) TalkRequest(n *enode.Node, protocol string, request []byte) ([]b } } -// TalkRequest sends a talk request to a node and waits for a response. +// TalkRequestToID sends a talk request to a node and waits for a response. func (t *UDPv5) TalkRequestToID(id enode.ID, addr *net.UDPAddr, protocol string, request []byte) ([]byte, error) { req := &v5wire.TalkRequest{Protocol: protocol, Message: request} resp := t.callToID(id, addr, v5wire.TalkResponseMsg, req) From 52c246fac329bc98bedc94f54612eab4d02e62c2 Mon Sep 17 00:00:00 2001 From: chirag-bgh <76247491+chirag-bgh@users.noreply.github.com> Date: Tue, 2 May 2023 13:54:35 +0530 Subject: [PATCH 084/988] eth/gasprice: fix typo (#27202) --- eth/gasprice/gasprice.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index 7475cef381..a3dd83d79f 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -251,7 +251,7 @@ func (s *txSorter) Less(i, j int) bool { return tip1.Cmp(tip2) < 0 } -// getBlockPrices calculates the lowest transaction gas price in a given block +// getBlockValues calculates the lowest transaction gas price in a given block // and sends it to the result channel. If the block is empty or all transactions // are sent by the miner itself(it doesn't make any sense to include this kind of // transaction prices for sampling), nil gasprice is returned. From ae660096400fa5f4e491bfa93ee62dfae3142a95 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 2 May 2023 10:28:43 +0200 Subject: [PATCH 085/988] internal/ethapi: add block overrides to eth_call (#26414) Adds an optional config parameter to eth_call which allows users to override block context fields (same functionality that was added to traceCall in #24871) --------- Co-authored-by: Martin Holst Swende --- eth/api_backend.go | 9 +- eth/tracers/api.go | 26 +- ethclient/gethclient/gethclient.go | 71 ++++ ethclient/gethclient/gethclient_test.go | 75 ++++ graphql/graphql.go | 4 +- internal/ethapi/api.go | 49 ++- internal/ethapi/api_test.go | 467 +++++++++++++++++++++++ internal/ethapi/backend.go | 2 +- internal/ethapi/transaction_args_test.go | 2 +- internal/web3ext/web3ext.go | 4 +- les/api_backend.go | 5 +- 11 files changed, 674 insertions(+), 40 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index 0e4521173b..959568d294 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -246,12 +246,17 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { +func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) { if vmConfig == nil { vmConfig = b.eth.blockchain.GetVMConfig() } txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) + var context vm.BlockContext + if blockCtx != nil { + context = *blockCtx + } else { + context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) + } return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), state.Error, nil } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 2bb00f0d2c..34f4199a83 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -100,34 +100,10 @@ func NewAPI(backend Backend) *API { return &API{backend: backend} } -type chainContext struct { - api *API - ctx context.Context -} - -func (context *chainContext) Engine() consensus.Engine { - return context.api.backend.Engine() -} - -func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header { - header, err := context.api.backend.HeaderByNumber(context.ctx, rpc.BlockNumber(number)) - if err != nil { - return nil - } - if header.Hash() == hash { - return header - } - header, err = context.api.backend.HeaderByHash(context.ctx, hash) - if err != nil { - return nil - } - return header -} - // chainContext constructs the context reader which is used by the evm for reading // the necessary chain context. func (api *API) chainContext(ctx context.Context) core.ChainContext { - return &chainContext{api: api, ctx: ctx} + return ethapi.NewChainContext(ctx, api.backend) } // blockByNumber is the wrapper of the chain access function offered by the backend. diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index fdcfb9a0ac..718cdfea42 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -143,6 +143,28 @@ func (ec *Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockN return hex, err } +// CallContractWithBlockOverrides executes a message call transaction, which is directly executed +// in the VM of the node, but never mined into the blockchain. +// +// blockNumber selects the block height at which the call runs. It can be nil, in which +// case the code is taken from the latest known block. Note that state from very old +// blocks might not be available. +// +// overrides specifies a map of contract states that should be overwritten before executing +// the message call. +// +// blockOverrides specifies block fields exposed to the EVM that can be overridden for the call. +// +// Please use ethclient.CallContract instead if you don't need the override functionality. +func (ec *Client) CallContractWithBlockOverrides(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int, overrides *map[common.Address]OverrideAccount, blockOverrides BlockOverrides) ([]byte, error) { + var hex hexutil.Bytes + err := ec.c.CallContext( + ctx, &hex, "eth_call", toCallArg(msg), + toBlockNumArg(blockNumber), overrides, blockOverrides, + ) + return hex, err +} + // GCStats retrieves the current garbage collection stats from a geth node. func (ec *Client) GCStats(ctx context.Context) (*debug.GCStats, error) { var result debug.GCStats @@ -265,3 +287,52 @@ func (a OverrideAccount) MarshalJSON() ([]byte, error) { } return json.Marshal(output) } + +// BlockOverrides specifies the set of header fields to override. +type BlockOverrides struct { + // Number overrides the block number. + Number *big.Int + // Difficulty overrides the block difficulty. + Difficulty *big.Int + // Time overrides the block timestamp. Time is applied only when + // it is non-zero. + Time uint64 + // GasLimit overrides the block gas limit. GasLimit is applied only when + // it is non-zero. + GasLimit uint64 + // Coinbase overrides the block coinbase. Coinbase is applied only when + // it is different from the zero address. + Coinbase common.Address + // Random overrides the block extra data which feeds into the RANDOM opcode. + // Random is applied only when it is a non-zero hash. + Random common.Hash + // BaseFee overrides the block base fee. + BaseFee *big.Int +} + +func (o BlockOverrides) MarshalJSON() ([]byte, error) { + type override struct { + Number *hexutil.Big `json:"number,omitempty"` + Difficulty *hexutil.Big `json:"difficulty,omitempty"` + Time hexutil.Uint64 `json:"time,omitempty"` + GasLimit hexutil.Uint64 `json:"gasLimit,omitempty"` + Coinbase *common.Address `json:"coinbase,omitempty"` + Random *common.Hash `json:"random,omitempty"` + BaseFee *hexutil.Big `json:"baseFee,omitempty"` + } + + output := override{ + Number: (*hexutil.Big)(o.Number), + Difficulty: (*hexutil.Big)(o.Difficulty), + Time: hexutil.Uint64(o.Time), + GasLimit: hexutil.Uint64(o.GasLimit), + BaseFee: (*hexutil.Big)(o.BaseFee), + } + if o.Coinbase != (common.Address{}) { + output.Coinbase = &o.Coinbase + } + if o.Random != (common.Hash{}) { + output.Random = &o.Random + } + return json.Marshal(output) +} diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index a9637d182f..87456fd64c 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -127,6 +127,9 @@ func TestGethClient(t *testing.T) { }, { "TestCallContract", func(t *testing.T) { testCallContract(t, client) }, + }, { + "TestCallContractWithBlockOverrides", + func(t *testing.T) { testCallContractWithBlockOverrides(t, client) }, }, // The testaccesslist is a bit time-sensitive: the newTestBackend imports // one block. The `testAcessList` fails if the miner has not yet created a @@ -413,3 +416,75 @@ func TestOverrideAccountMarshal(t *testing.T) { t.Error("want:", expected) } } + +func TestBlockOverridesMarshal(t *testing.T) { + for i, tt := range []struct { + bo BlockOverrides + want string + }{ + { + bo: BlockOverrides{}, + want: `{}`, + }, + { + bo: BlockOverrides{ + Coinbase: common.HexToAddress("0x1111111111111111111111111111111111111111"), + }, + want: `{"coinbase":"0x1111111111111111111111111111111111111111"}`, + }, + { + bo: BlockOverrides{ + Number: big.NewInt(1), + Difficulty: big.NewInt(2), + Time: 3, + GasLimit: 4, + BaseFee: big.NewInt(5), + }, + want: `{"number":"0x1","difficulty":"0x2","time":"0x3","gasLimit":"0x4","baseFee":"0x5"}`, + }, + } { + marshalled, err := json.Marshal(&tt.bo) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if string(marshalled) != tt.want { + t.Errorf("Testcase #%d failed. expected\n%s\ngot\n%s", i, tt.want, string(marshalled)) + } + } +} + +func testCallContractWithBlockOverrides(t *testing.T, client *rpc.Client) { + ec := New(client) + msg := ethereum.CallMsg{ + From: testAddr, + To: &common.Address{}, + Gas: 50000, + GasPrice: big.NewInt(1000000000), + Value: big.NewInt(1), + } + override := OverrideAccount{ + // Returns coinbase address. + Code: common.FromHex("0x41806000526014600cf3"), + } + mapAcc := make(map[common.Address]OverrideAccount) + mapAcc[common.Address{}] = override + res, err := ec.CallContract(context.Background(), msg, big.NewInt(0), &mapAcc) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !bytes.Equal(res, common.FromHex("0x0000000000000000000000000000000000000000")) { + t.Fatalf("unexpected result: %x", res) + } + + // Now test with block overrides + bo := BlockOverrides{ + Coinbase: common.HexToAddress("0x1111111111111111111111111111111111111111"), + } + res, err = ec.CallContractWithBlockOverrides(context.Background(), msg, big.NewInt(0), &mapAcc, bo) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !bytes.Equal(res, common.FromHex("0x1111111111111111111111111111111111111111")) { + t.Fatalf("unexpected result: %x", res) + } +} diff --git a/graphql/graphql.go b/graphql/graphql.go index ce3ca171cf..35ea8643ad 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -1068,7 +1068,7 @@ func (c *CallResult) Status() hexutil.Uint64 { func (b *Block) Call(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (*CallResult, error) { - result, err := ethapi.DoCall(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCEVMTimeout(), b.r.backend.RPCGasCap()) + result, err := ethapi.DoCall(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, nil, b.r.backend.RPCEVMTimeout(), b.r.backend.RPCGasCap()) if err != nil { return nil, err } @@ -1131,7 +1131,7 @@ func (p *Pending) Call(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (*CallResult, error) { pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) - result, err := ethapi.DoCall(ctx, p.r.backend, args.Data, pendingBlockNr, nil, p.r.backend.RPCEVMTimeout(), p.r.backend.RPCGasCap()) + result, err := ethapi.DoCall(ctx, p.r.backend, args.Data, pendingBlockNr, nil, nil, p.r.backend.RPCEVMTimeout(), p.r.backend.RPCGasCap()) if err != nil { return nil, err } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index f1041d6a50..82ca894609 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core" @@ -955,7 +956,39 @@ func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) { } } -func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { +// ChainContextBackend provides methods required to implement ChainContext. +type ChainContextBackend interface { + Engine() consensus.Engine + HeaderByNumber(context.Context, rpc.BlockNumber) (*types.Header, error) +} + +// ChainContext is an implementation of core.ChainContext. It's main use-case +// is instantiating a vm.BlockContext without having access to the BlockChain object. +type ChainContext struct { + b ChainContextBackend + ctx context.Context +} + +// NewChainContext creates a new ChainContext object. +func NewChainContext(ctx context.Context, backend ChainContextBackend) *ChainContext { + return &ChainContext{ctx: ctx, b: backend} +} + +func (context *ChainContext) Engine() consensus.Engine { + return context.b.Engine() +} + +func (context *ChainContext) GetHeader(hash common.Hash, number uint64) *types.Header { + // This method is called to get the hash for a block number when executing the BLOCKHASH + // opcode. Hence no need to search for non-canonical blocks. + header, err := context.b.HeaderByNumber(context.ctx, rpc.BlockNumber(number)) + if err != nil || header.Hash() != hash { + return nil + } + return header +} + +func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) @@ -982,7 +1015,11 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash if err != nil { return nil, err } - evm, vmError, err := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}) + blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) + if blockOverrides != nil { + blockOverrides.Apply(&blockCtx) + } + evm, vmError, err := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, &blockCtx) if err != nil { return nil, err } @@ -1046,8 +1083,8 @@ func (e *revertError) ErrorData() interface{} { // // Note, this function doesn't make and changes in the state/blockchain and is // useful to execute and retrieve values. -func (s *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) { - result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap()) +func (s *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides) (hexutil.Bytes, error) { + result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, blockOverrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap()) if err != nil { return nil, err } @@ -1132,7 +1169,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr executable := func(gas uint64) (bool, *core.ExecutionResult, error) { args.Gas = (*hexutil.Uint64)(&gas) - result, err := DoCall(ctx, b, args, blockNrOrHash, nil, 0, gasCap) + result, err := DoCall(ctx, b, args, blockNrOrHash, nil, nil, 0, gasCap) if err != nil { if errors.Is(err, core.ErrIntrinsicGas) { return true, nil, nil // Special case, raise gas limit @@ -1478,7 +1515,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) config := vm.Config{Tracer: tracer, NoBaseFee: true} - vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config) + vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config, nil) if err != nil { return nil, 0, nil, err } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 205e23e847..39f912a349 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -17,14 +17,34 @@ package ethapi import ( + "bytes" + "context" + "crypto/ecdsa" "encoding/json" + "errors" "math/big" + "reflect" + "sort" "testing" + "time" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus" + "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/rawdb" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" ) func TestTransaction_RoundTripRpcJSON(t *testing.T) { @@ -157,3 +177,450 @@ func allTransactionTypes(addr common.Address, config *params.ChainConfig) []type }, } } + +type testBackend struct { + db ethdb.Database + chain *core.BlockChain +} + +func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend { + var ( + engine = ethash.NewFaker() + backend = &testBackend{ + db: rawdb.NewMemoryDatabase(), + } + cacheConfig = &core.CacheConfig{ + TrieCleanLimit: 256, + TrieDirtyLimit: 256, + TrieTimeLimit: 5 * time.Minute, + SnapshotLimit: 0, + TrieDirtyDisabled: true, // Archive mode + } + ) + // Generate blocks for testing + _, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, generator) + chain, err := core.NewBlockChain(backend.db, cacheConfig, gspec, nil, engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + if n, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + backend.chain = chain + return backend +} + +func (b testBackend) SyncProgress() ethereum.SyncProgress { return ethereum.SyncProgress{} } +func (b testBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { + return big.NewInt(0), nil +} +func (b testBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { + return nil, nil, nil, nil, nil +} +func (b testBackend) ChainDb() ethdb.Database { return b.db } +func (b testBackend) AccountManager() *accounts.Manager { return nil } +func (b testBackend) ExtRPCEnabled() bool { return false } +func (b testBackend) RPCGasCap() uint64 { return 10000000 } +func (b testBackend) RPCEVMTimeout() time.Duration { return time.Second } +func (b testBackend) RPCTxFeeCap() float64 { return 0 } +func (b testBackend) UnprotectedAllowed() bool { return false } +func (b testBackend) SetHead(number uint64) {} +func (b testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { + if number == rpc.LatestBlockNumber { + return b.chain.CurrentBlock(), nil + } + return b.chain.GetHeaderByNumber(uint64(number)), nil +} +func (b testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { + panic("implement me") +} +func (b testBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { + panic("implement me") +} +func (b testBackend) CurrentHeader() *types.Header { panic("implement me") } +func (b testBackend) CurrentBlock() *types.Header { panic("implement me") } +func (b testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { + if number == rpc.LatestBlockNumber { + head := b.chain.CurrentBlock() + return b.chain.GetBlock(head.Hash(), head.Number.Uint64()), nil + } + return b.chain.GetBlockByNumber(uint64(number)), nil +} +func (b testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { + panic("implement me") +} +func (b testBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { + if blockNr, ok := blockNrOrHash.Number(); ok { + return b.BlockByNumber(ctx, blockNr) + } + panic("implement me") +} +func (b testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { + return b.chain.GetBlock(hash, uint64(number.Int64())).Body(), nil +} +func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { + if number == rpc.PendingBlockNumber { + panic("pending state not implemented") + } + header, err := b.HeaderByNumber(ctx, number) + if err != nil { + return nil, nil, err + } + if header == nil { + return nil, nil, errors.New("header not found") + } + stateDb, err := b.chain.StateAt(header.Root) + return stateDb, header, err +} +func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { + if blockNr, ok := blockNrOrHash.Number(); ok { + return b.StateAndHeaderByNumber(ctx, blockNr) + } + panic("only implemented for number") +} +func (b testBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { panic("implement me") } +func (b testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { + panic("implement me") +} +func (b testBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { panic("implement me") } +func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) (*vm.EVM, func() error, error) { + vmError := func() error { return nil } + if vmConfig == nil { + vmConfig = b.chain.GetVMConfig() + } + txContext := core.NewEVMTxContext(msg) + context := core.NewEVMBlockContext(header, b.chain, nil) + if blockContext != nil { + context = *blockContext + } + return vm.NewEVM(context, txContext, state, b.chain.Config(), *vmConfig), vmError, nil +} +func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { + panic("implement me") +} +func (b testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { + panic("implement me") +} +func (b testBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { + panic("implement me") +} +func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { + panic("implement me") +} +func (b testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { + panic("implement me") +} +func (b testBackend) GetPoolTransactions() (types.Transactions, error) { panic("implement me") } +func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("implement me") } +func (b testBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { + panic("implement me") +} +func (b testBackend) Stats() (pending int, queued int) { panic("implement me") } +func (b testBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { + panic("implement me") +} +func (b testBackend) TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) { + panic("implement me") +} +func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.Subscription { + panic("implement me") +} +func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() } +func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() } +func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) { + panic("implement me") +} +func (b testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { + panic("implement me") +} +func (b testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { + panic("implement me") +} +func (b testBackend) SubscribePendingLogsEvent(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) { + panic("implement me") +} + +func TestEstimateGas(t *testing.T) { + t.Parallel() + // Initialize test accounts + var ( + accounts = newAccounts(2) + genesis = &core.Genesis{ + Config: params.TestChainConfig, + Alloc: core.GenesisAlloc{ + accounts[0].addr: {Balance: big.NewInt(params.Ether)}, + accounts[1].addr: {Balance: big.NewInt(params.Ether)}, + }, + } + genBlocks = 10 + signer = types.HomesteadSigner{} + randomAccounts = newAccounts(2) + ) + api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { + // Transfer from account[0] to account[1] + // value: 1000 wei + // fee: 0 wei + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key) + b.AddTx(tx) + })) + var testSuite = []struct { + blockNumber rpc.BlockNumber + call TransactionArgs + expectErr error + want uint64 + }{ + // simple transfer on latest block + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &accounts[0].addr, + To: &accounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + expectErr: nil, + want: 21000, + }, + // simple transfer with insufficient funds on latest block + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &randomAccounts[0].addr, + To: &accounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + expectErr: core.ErrInsufficientFunds, + want: 21000, + }, + // empty create + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{}, + expectErr: nil, + want: 53000, + }, + } + for i, tc := range testSuite { + result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}) + if tc.expectErr != nil { + if err == nil { + t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) + continue + } + if !errors.Is(err, tc.expectErr) { + t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) + } + continue + } + if err != nil { + t.Errorf("test %d: want no error, have %v", i, err) + continue + } + if uint64(result) != tc.want { + t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, uint64(result), tc.want) + } + } +} + +func TestCall(t *testing.T) { + t.Parallel() + // Initialize test accounts + var ( + accounts = newAccounts(3) + genesis = &core.Genesis{ + Config: params.TestChainConfig, + Alloc: core.GenesisAlloc{ + accounts[0].addr: {Balance: big.NewInt(params.Ether)}, + accounts[1].addr: {Balance: big.NewInt(params.Ether)}, + accounts[2].addr: {Balance: big.NewInt(params.Ether)}, + }, + } + genBlocks = 10 + signer = types.HomesteadSigner{} + ) + api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { + // Transfer from account[0] to account[1] + // value: 1000 wei + // fee: 0 wei + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key) + b.AddTx(tx) + })) + randomAccounts := newAccounts(3) + var testSuite = []struct { + blockNumber rpc.BlockNumber + overrides StateOverride + call TransactionArgs + blockOverrides BlockOverrides + expectErr error + want string + }{ + // transfer on genesis + { + blockNumber: rpc.BlockNumber(0), + call: TransactionArgs{ + From: &accounts[0].addr, + To: &accounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + expectErr: nil, + want: "0x", + }, + // transfer on the head + { + blockNumber: rpc.BlockNumber(genBlocks), + call: TransactionArgs{ + From: &accounts[0].addr, + To: &accounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + expectErr: nil, + want: "0x", + }, + // transfer on a non-existent block, error expects + { + blockNumber: rpc.BlockNumber(genBlocks + 1), + call: TransactionArgs{ + From: &accounts[0].addr, + To: &accounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + expectErr: errors.New("header not found"), + }, + // transfer on the latest block + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &accounts[0].addr, + To: &accounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + expectErr: nil, + want: "0x", + }, + // Call which can only succeed if state is state overridden + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &randomAccounts[0].addr, + To: &randomAccounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + overrides: StateOverride{ + randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, + }, + want: "0x", + }, + // Invalid call without state overriding + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &randomAccounts[0].addr, + To: &randomAccounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + expectErr: core.ErrInsufficientFunds, + }, + // Successful simple contract call + // + // // SPDX-License-Identifier: GPL-3.0 + // + // pragma solidity >=0.7.0 <0.8.0; + // + // /** + // * @title Storage + // * @dev Store & retrieve value in a variable + // */ + // contract Storage { + // uint256 public number; + // constructor() { + // number = block.number; + // } + // } + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &randomAccounts[0].addr, + To: &randomAccounts[2].addr, + Data: hex2Bytes("8381f58a"), // call number() + }, + overrides: StateOverride{ + randomAccounts[2].addr: OverrideAccount{ + Code: hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"), + StateDiff: &map[common.Hash]common.Hash{common.Hash{}: common.BigToHash(big.NewInt(123))}, + }, + }, + want: "0x000000000000000000000000000000000000000000000000000000000000007b", + }, + // Block overrides should work + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &accounts[1].addr, + Input: &hexutil.Bytes{ + 0x43, // NUMBER + 0x60, 0x00, 0x52, // MSTORE offset 0 + 0x60, 0x20, 0x60, 0x00, 0xf3, + }, + }, + blockOverrides: BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))}, + want: "0x000000000000000000000000000000000000000000000000000000000000000b", + }, + } + for i, tc := range testSuite { + result, err := api.Call(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) + if tc.expectErr != nil { + if err == nil { + t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) + continue + } + if !errors.Is(err, tc.expectErr) { + // Second try + if !reflect.DeepEqual(err, tc.expectErr) { + t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) + } + } + continue + } + if err != nil { + t.Errorf("test %d: want no error, have %v", i, err) + continue + } + if !reflect.DeepEqual(result.String(), tc.want) { + t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, result.String(), tc.want) + } + } +} + +type Account struct { + key *ecdsa.PrivateKey + addr common.Address +} + +type Accounts []Account + +func (a Accounts) Len() int { return len(a) } +func (a Accounts) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a Accounts) Less(i, j int) bool { return bytes.Compare(a[i].addr.Bytes(), a[j].addr.Bytes()) < 0 } + +func newAccounts(n int) (accounts Accounts) { + for i := 0; i < n; i++ { + key, _ := crypto.GenerateKey() + addr := crypto.PubkeyToAddress(key.PublicKey) + accounts = append(accounts, Account{key: key, addr: addr}) + } + sort.Sort(accounts) + return accounts +} + +func newRPCBalance(balance *big.Int) **hexutil.Big { + rpcBalance := (*hexutil.Big)(balance) + return &rpcBalance +} + +func hex2Bytes(str string) *hexutil.Bytes { + rpcBytes := hexutil.Bytes(common.Hex2Bytes(str)) + return &rpcBytes +} diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 0249c8664d..3e4ee505f3 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -68,7 +68,7 @@ type Backend interface { PendingBlockAndReceipts() (*types.Block, types.Receipts) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) GetTd(ctx context.Context, hash common.Hash) *big.Int - GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) + GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 24c15b7775..124f2164cf 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -305,7 +305,7 @@ func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number return nil, nil } func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { +func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) { return nil, nil, nil } func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 388eed8a2f..3366329643 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -608,8 +608,8 @@ web3._extend({ new web3._extend.Method({ name: 'call', call: 'eth_call', - params: 3, - inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputDefaultBlockNumberFormatter, null], + params: 4, + inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputDefaultBlockNumberFormatter, null, null], }), ], properties: [ diff --git a/les/api_backend.go b/les/api_backend.go index 2d1fccd9ad..86da26da65 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -184,12 +184,15 @@ func (b *LesApiBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { +func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) { if vmConfig == nil { vmConfig = new(vm.Config) } txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(header, b.eth.blockchain, nil) + if blockCtx != nil { + context = *blockCtx + } return vm.NewEVM(context, txContext, state, b.eth.chainConfig, *vmConfig), state.Error, nil } From a9d7cdaf6ecb7c19cd3052e5501a311237be27f8 Mon Sep 17 00:00:00 2001 From: ucwong Date: Tue, 2 May 2023 02:32:27 -0600 Subject: [PATCH 086/988] core/types: go generate (#27196) Fixes a discrepancy between source and generated files, which was introduced when ExcessDataGas was added in https://github.com/ethereum/go-ethereum/pull/27046. --- core/types/gen_header_json.go | 6 ++++++ core/types/gen_header_rlp.go | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index 5c8b81652d..73287257bd 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -33,6 +33,7 @@ func (h Header) MarshalJSON() ([]byte, error) { Nonce BlockNonce `json:"nonce"` BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` + ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"` Hash common.Hash `json:"hash"` } var enc Header @@ -53,6 +54,7 @@ func (h Header) MarshalJSON() ([]byte, error) { enc.Nonce = h.Nonce enc.BaseFee = (*hexutil.Big)(h.BaseFee) enc.WithdrawalsHash = h.WithdrawalsHash + enc.ExcessDataGas = h.ExcessDataGas enc.Hash = h.Hash() return json.Marshal(&enc) } @@ -77,6 +79,7 @@ func (h *Header) UnmarshalJSON(input []byte) error { Nonce *BlockNonce `json:"nonce"` BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` + ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"` } var dec Header if err := json.Unmarshal(input, &dec); err != nil { @@ -145,5 +148,8 @@ func (h *Header) UnmarshalJSON(input []byte) error { if dec.WithdrawalsHash != nil { h.WithdrawalsHash = dec.WithdrawalsHash } + if dec.ExcessDataGas != nil { + h.ExcessDataGas = dec.ExcessDataGas + } return nil } diff --git a/core/types/gen_header_rlp.go b/core/types/gen_header_rlp.go index 7fd2cf8f2d..005f6c2ad4 100644 --- a/core/types/gen_header_rlp.go +++ b/core/types/gen_header_rlp.go @@ -42,7 +42,8 @@ func (obj *Header) EncodeRLP(_w io.Writer) error { w.WriteBytes(obj.Nonce[:]) _tmp1 := obj.BaseFee != nil _tmp2 := obj.WithdrawalsHash != nil - if _tmp1 || _tmp2 { + _tmp3 := obj.ExcessDataGas != nil + if _tmp1 || _tmp2 || _tmp3 { if obj.BaseFee == nil { w.Write(rlp.EmptyString) } else { @@ -52,13 +53,23 @@ func (obj *Header) EncodeRLP(_w io.Writer) error { w.WriteBigInt(obj.BaseFee) } } - if _tmp2 { + if _tmp2 || _tmp3 { if obj.WithdrawalsHash == nil { w.Write([]byte{0x80}) } else { w.WriteBytes(obj.WithdrawalsHash[:]) } } + if _tmp3 { + if obj.ExcessDataGas == nil { + w.Write(rlp.EmptyString) + } else { + if obj.ExcessDataGas.Sign() == -1 { + return rlp.ErrNegativeBigInt + } + w.WriteBigInt(obj.ExcessDataGas) + } + } w.ListEnd(_tmp0) return w.Flush() } From 7d1ebe51b72fa187feee30fac47c276ebd118810 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 2 May 2023 04:36:11 -0400 Subject: [PATCH 087/988] p2p/discover: fix lint nit (#27206) --- p2p/discover/v5_udp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 50e25b8588..6a86e72a50 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -460,7 +460,7 @@ func containsUint(x uint, xs []uint) bool { // callToNode sends the given call and sets up a handler for response packets (of message // type responseType). Responses are dispatched to the call's response channel. func (t *UDPv5) callToNode(n *enode.Node, responseType byte, req v5wire.Packet) *callV5 { - addr := &net.UDPAddr{IP: n.IP(), Port: int(n.UDP())} + addr := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} c := &callV5{id: n.ID(), addr: addr, node: n} t.initCall(c, responseType, req) return c From 7f6c045e0d1dac31444821c84730e718092a64d1 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 2 May 2023 10:56:08 +0200 Subject: [PATCH 088/988] core: remove unused ContractCode method from BlockChain (#27186) --- core/blockchain_reader.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index a04323255c..fd65cb2db3 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -299,12 +299,6 @@ func (bc *BlockChain) TrieNode(hash common.Hash) ([]byte, error) { return bc.stateCache.TrieDB().Node(hash) } -// ContractCode retrieves a blob of data associated with a contract hash -// either from ephemeral in-memory cache, or from persistent storage. -func (bc *BlockChain) ContractCode(hash common.Hash) ([]byte, error) { - return bc.stateCache.ContractCode(common.Hash{}, hash) -} - // ContractCodeWithPrefix retrieves a blob of data associated with a contract // hash either from ephemeral in-memory cache, or from persistent storage. // From 29c33d9bab1f79929d3aa1592ca283374dbfe614 Mon Sep 17 00:00:00 2001 From: David Dzhalaev <72649244+DavidRomanovizc@users.noreply.github.com> Date: Tue, 2 May 2023 11:57:07 +0300 Subject: [PATCH 089/988] graphql, internal: fix typos in comments (#27184) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * âœï¸ Fix typos * âªï¸ Revert changes * Update internal/web3ext/web3ext.go --------- Co-authored-by: Martin Holst Swende --- graphql/graphql.go | 6 +++--- internal/build/util.go | 2 +- internal/debug/trace.go | 2 +- internal/ethapi/api.go | 14 +++++++------- internal/web3ext/web3ext.go | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 35ea8643ad..ac80304f87 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -196,7 +196,7 @@ type Transaction struct { } // resolve returns the internal transaction object, fetching it if needed. -// It also returns the block the tx blongs to, unless it is a pending tx. +// It also returns the block the tx belongs to, unless it is a pending tx. func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, *Block, error) { t.mu.Lock() defer t.mu.Unlock() @@ -1374,9 +1374,9 @@ func (s *SyncState) HealingBytecode() hexutil.Uint64 { return hexutil.Uint64(s.progress.HealingBytecode) } -// Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not +// Syncing returns false in case the node is currently not syncing with the network. It can be up-to-date or has not // yet received the latest block headers from its pears. In case it is synchronizing: -// - startingBlock: block number this node started to synchronise from +// - startingBlock: block number this node started to synchronize from // - currentBlock: block number this node is currently importing // - highestBlock: block number of the highest block header this node has received from peers // - syncedAccounts: number of accounts downloaded diff --git a/internal/build/util.go b/internal/build/util.go index 9a721e9b83..3a0b384e5e 100644 --- a/internal/build/util.go +++ b/internal/build/util.go @@ -127,7 +127,7 @@ func render(tpl *template.Template, outputFile string, outputPerm os.FileMode, x } // UploadSFTP uploads files to a remote host using the sftp command line tool. -// The destination host may be specified either as [user@]host[: or as a URI in +// The destination host may be specified either as [user@]host: or as a URI in // the form sftp://[user@]host[:port]. func UploadSFTP(identityFile, host, dir string, files []string) error { sftp := exec.Command("sftp") diff --git a/internal/debug/trace.go b/internal/debug/trace.go index a273e4a9db..eea8798234 100644 --- a/internal/debug/trace.go +++ b/internal/debug/trace.go @@ -48,7 +48,7 @@ func (h *HandlerT) StartGoTrace(file string) error { return nil } -// StopTrace stops an ongoing trace. +// StopGoTrace stops an ongoing trace. func (h *HandlerT) StopGoTrace() error { h.mu.Lock() defer h.mu.Unlock() diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 82ca894609..dbd27bcae4 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -116,9 +116,9 @@ func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecim return results, nil } -// Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not +// Syncing returns false in case the node is currently not syncing with the network. It can be up-to-date or has not // yet received the latest block headers from its pears. In case it is synchronizing: -// - startingBlock: block number this node started to synchronise from +// - startingBlock: block number this node started to synchronize from // - currentBlock: block number this node is currently importing // - highestBlock: block number of the highest block header this node has received from peers // - pulledStates: number of state entries processed until now @@ -150,7 +150,7 @@ func (s *EthereumAPI) Syncing() (interface{}, error) { }, nil } -// TxPoolAPI offers and API for the transaction pool. It only operates on data that is non confidential. +// TxPoolAPI offers and API for the transaction pool. It only operates on data that is non-confidential. type TxPoolAPI struct { b Backend } @@ -337,7 +337,7 @@ func (s *PersonalAccountAPI) OpenWallet(url string, passphrase *string) error { return wallet.Open(pass) } -// DeriveAccount requests a HD wallet to derive a new account, optionally pinning +// DeriveAccount requests an HD wallet to derive a new account, optionally pinning // it for later reuse. func (s *PersonalAccountAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { wallet, err := s.am.Wallet(url) @@ -712,7 +712,7 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st } // decodeHash parses a hex-encoded 32-byte hash. The input may optionally -// be prefixed by 0x and can have an byte length up to 32. +// be prefixed by 0x and can have a byte length up to 32. func decodeHash(s string) (common.Hash, error) { if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") { s = s[2:] @@ -1438,7 +1438,7 @@ func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash, config *pa } // accessListResult returns an optional accesslist -// Its the result of the `debug_createAccessList` RPC call. +// It's the result of the `debug_createAccessList` RPC call. // It contains an error if the transaction itself failed. type accessListResult struct { Accesslist *types.AccessList `json:"accessList"` @@ -1446,7 +1446,7 @@ type accessListResult struct { GasUsed hexutil.Uint64 `json:"gasUsed"` } -// CreateAccessList creates a EIP-2930 type AccessList for the given transaction. +// CreateAccessList creates an EIP-2930 type AccessList for the given transaction. // Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state. func (s *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) { bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 3366329643..a2fc3b5a90 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// package web3ext contains geth specific web3.js extensions. +// Package web3ext contains geth specific web3.js extensions. package web3ext var Modules = map[string]string{ From ac3418def67355041bdb6fad901899e13feb33a0 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 2 May 2023 14:27:37 +0200 Subject: [PATCH 090/988] accounts/abi: resolve name conflict for methods starting with a number (#26999) This adds logic to prepend 'M' or 'E' to Solidity identifiers when they would otherwise violate Go identifier naming rules. Closes #26972 --------- Co-authored-by: Martin Holst Swende Co-authored-by: Sina Mahmoodi --- accounts/abi/bind/bind.go | 17 ++++++++++++++++- accounts/abi/bind/bind_test.go | 23 +++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index 05cca8e90b..8a54a0e6ef 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -133,12 +133,19 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] // Normalize the method for capital cases and non-anonymous inputs/outputs normalized := original normalizedName := methodNormalizer[lang](alias(aliases, original.Name)) - // Ensure there is no duplicated identifier var identifiers = callIdentifiers if !original.IsConstant() { identifiers = transactIdentifiers } + // Name shouldn't start with a digit. It will make the generated code invalid. + if len(normalizedName) > 0 && unicode.IsDigit(rune(normalizedName[0])) { + normalizedName = fmt.Sprintf("M%s", normalizedName) + normalizedName = abi.ResolveNameConflict(normalizedName, func(name string) bool { + _, ok := identifiers[name] + return ok + }) + } if identifiers[normalizedName] { return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName) } @@ -182,6 +189,14 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] // Ensure there is no duplicated identifier normalizedName := methodNormalizer[lang](alias(aliases, original.Name)) + // Name shouldn't start with a digit. It will make the generated code invalid. + if len(normalizedName) > 0 && unicode.IsDigit(rune(normalizedName[0])) { + normalizedName = fmt.Sprintf("E%s", normalizedName) + normalizedName = abi.ResolveNameConflict(normalizedName, func(name string) bool { + _, ok := eventIdentifiers[name] + return ok + }) + } if eventIdentifiers[normalizedName] { return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName) } diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index cbbce7b308..1069f3d396 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -2038,6 +2038,29 @@ var bindTests = []struct { t.Errorf("error deploying the contract: %v", err) } `, + }, { + name: "NumericMethodName", + contract: ` + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.4.22 <0.9.0; + + contract NumericMethodName { + event _1TestEvent(address _param); + function _1test() public pure {} + function __1test() public pure {} + function __2test() public pure {} + } + `, + bytecode: []string{"0x6080604052348015600f57600080fd5b5060958061001e6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80639d993132146041578063d02767c7146049578063ffa02795146051575b600080fd5b60476059565b005b604f605b565b005b6057605d565b005b565b565b56fea26469706673582212200382ca602dff96a7e2ba54657985e2b4ac423a56abe4a1f0667bc635c4d4371f64736f6c63430008110033"}, + abi: []string{`[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_param","type":"address"}],"name":"_1TestEvent","type":"event"},{"inputs":[],"name":"_1test","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"__1test","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"__2test","outputs":[],"stateMutability":"pure","type":"function"}]`}, + imports: ` + "github.com/ethereum/go-ethereum/common" + `, + tester: ` + if b, err := NewNumericMethodName(common.Address{}, nil); b == nil || err != nil { + t.Fatalf("combined binding (%v) nil or error (%v) not nil", b, nil) + } +`, }, } From dde2da0efb8e9a1812f470bc43254134cd1f8cc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 3 May 2023 12:58:39 +0300 Subject: [PATCH 091/988] all: remove ethash pow, only retain shims needed for consensus and tests (#27178) * all: remove ethash pow, only retain shims needed for consensus and tests * all: thank you linter * all: disallow launching Geth in legacy PoW mode * cmd/env/internal/t8ntool: remove dangling ethash flag --- .../internal/ethtest/testdata/genesis.json | 1 + cmd/evm/internal/t8ntool/block.go | 58 +- cmd/evm/internal/t8ntool/flags.go | 13 - cmd/evm/main.go | 3 - cmd/geth/genesis_test.go | 17 +- cmd/geth/main.go | 19 +- cmd/geth/misccmd.go | 57 - cmd/utils/flags.go | 119 +- consensus/beacon/consensus.go | 10 +- consensus/clique/clique.go | 4 +- consensus/consensus.go | 7 +- consensus/ethash/algorithm.go | 1152 ----------------- consensus/ethash/algorithm_test.go | 815 ------------ consensus/ethash/api.go | 113 -- consensus/ethash/consensus.go | 185 +-- consensus/ethash/ethash.go | 649 +--------- consensus/ethash/ethash_test.go | 177 --- consensus/ethash/mmap_help_linux.go | 35 - consensus/ethash/mmap_help_other.go | 36 - consensus/ethash/sealer.go | 451 ------- consensus/ethash/sealer_test.go | 298 ----- console/console_test.go | 4 - core/block_validator_test.go | 29 +- core/blockchain.go | 28 +- core/blockchain_test.go | 48 +- core/genesis.go | 19 +- core/headerchain.go | 21 +- eth/api.go | 8 +- eth/api_backend.go | 4 +- eth/backend.go | 23 +- eth/catalyst/api_test.go | 2 +- eth/downloader/downloader.go | 27 +- eth/ethconfig/config.go | 83 +- eth/ethconfig/gen_config.go | 7 - eth/handler.go | 2 +- ethclient/ethclient_test.go | 1 - ethclient/gethclient/gethclient_test.go | 1 - graphql/graphql_test.go | 5 +- internal/ethapi/api.go | 10 - les/api_test.go | 2 - les/catalyst/api_test.go | 3 +- les/client.go | 11 +- les/downloader/downloader.go | 27 +- les/downloader/downloader_test.go | 2 +- les/fetcher.go | 11 +- light/lightchain.go | 31 +- light/lightchain_test.go | 14 +- light/odr_test.go | 2 +- light/txpool_test.go | 2 +- miner/miner.go | 15 +- miner/stress/1559/main.go | 264 ---- miner/stress/beacon/main.go | 558 -------- miner/stress/clique/main.go | 2 +- miner/stress/ethash/main.go | 194 --- miner/worker_test.go | 4 - params/config.go | 2 +- tests/block_test_util.go | 9 +- 57 files changed, 210 insertions(+), 5484 deletions(-) delete mode 100644 consensus/ethash/algorithm.go delete mode 100644 consensus/ethash/algorithm_test.go delete mode 100644 consensus/ethash/api.go delete mode 100644 consensus/ethash/ethash_test.go delete mode 100644 consensus/ethash/mmap_help_linux.go delete mode 100644 consensus/ethash/mmap_help_other.go delete mode 100644 consensus/ethash/sealer.go delete mode 100644 consensus/ethash/sealer_test.go delete mode 100644 miner/stress/1559/main.go delete mode 100644 miner/stress/beacon/main.go delete mode 100644 miner/stress/ethash/main.go diff --git a/cmd/devp2p/internal/ethtest/testdata/genesis.json b/cmd/devp2p/internal/ethtest/testdata/genesis.json index d8b5d22502..b4de6e85a5 100644 --- a/cmd/devp2p/internal/ethtest/testdata/genesis.json +++ b/cmd/devp2p/internal/ethtest/testdata/genesis.json @@ -6,6 +6,7 @@ "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 0, + "terminalTotalDifficultyPassed": true, "ethash": {} }, "nonce": "0xdeadbeefdeadbeef", diff --git a/cmd/evm/internal/t8ntool/block.go b/cmd/evm/internal/t8ntool/block.go index 7a9c4b6101..ac3031d6ef 100644 --- a/cmd/evm/internal/t8ntool/block.go +++ b/cmd/evm/internal/t8ntool/block.go @@ -28,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus/clique" - "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" @@ -74,11 +73,9 @@ type bbInput struct { Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` Clique *cliqueInput `json:"clique,omitempty"` - Ethash bool `json:"-"` - EthashDir string `json:"-"` - PowMode ethash.Mode `json:"-"` - Txs []*types.Transaction `json:"-"` - Ommers []*types.Header `json:"-"` + Ethash bool `json:"-"` + Txs []*types.Transaction `json:"-"` + Ommers []*types.Header `json:"-"` } type cliqueInput struct { @@ -162,8 +159,6 @@ func (i *bbInput) ToBlock() *types.Block { // SealBlock seals the given block using the configured engine. func (i *bbInput) SealBlock(block *types.Block) (*types.Block, error) { switch { - case i.Ethash: - return i.sealEthash(block) case i.Clique != nil: return i.sealClique(block) default: @@ -171,33 +166,6 @@ func (i *bbInput) SealBlock(block *types.Block) (*types.Block, error) { } } -// sealEthash seals the given block using ethash. -func (i *bbInput) sealEthash(block *types.Block) (*types.Block, error) { - if i.Header.Nonce != nil { - return nil, NewError(ErrorConfig, fmt.Errorf("sealing with ethash will overwrite provided nonce")) - } - ethashConfig := ethash.Config{ - PowMode: i.PowMode, - DatasetDir: i.EthashDir, - CacheDir: i.EthashDir, - DatasetsInMem: 1, - DatasetsOnDisk: 2, - CachesInMem: 2, - CachesOnDisk: 3, - } - engine := ethash.New(ethashConfig, nil, true) - defer engine.Close() - // Use a buffered chan for results. - // If the testmode is used, the sealer will return quickly, and complain - // "Sealing result is not read by miner" if it cannot write the result. - results := make(chan *types.Block, 1) - if err := engine.Seal(nil, block, results, nil); err != nil { - panic(fmt.Sprintf("failed to seal block: %v", err)) - } - found := <-results - return block.WithSeal(found.Header()), nil -} - // sealClique seals the given block using clique. func (i *bbInput) sealClique(block *types.Block) (*types.Block, error) { // If any clique value overwrites an explicit header value, fail @@ -267,28 +235,8 @@ func readInput(ctx *cli.Context) (*bbInput, error) { withdrawalsStr = ctx.String(InputWithdrawalsFlag.Name) txsStr = ctx.String(InputTxsRlpFlag.Name) cliqueStr = ctx.String(SealCliqueFlag.Name) - ethashOn = ctx.Bool(SealEthashFlag.Name) - ethashDir = ctx.String(SealEthashDirFlag.Name) - ethashMode = ctx.String(SealEthashModeFlag.Name) inputData = &bbInput{} ) - if ethashOn && cliqueStr != "" { - return nil, NewError(ErrorConfig, fmt.Errorf("both ethash and clique sealing specified, only one may be chosen")) - } - if ethashOn { - inputData.Ethash = ethashOn - inputData.EthashDir = ethashDir - switch ethashMode { - case "normal": - inputData.PowMode = ethash.ModeNormal - case "test": - inputData.PowMode = ethash.ModeTest - case "fake": - inputData.PowMode = ethash.ModeFake - default: - return nil, NewError(ErrorConfig, fmt.Errorf("unknown pow mode: %s, supported modes: test, fake, normal", ethashMode)) - } - } if headerStr == stdinSelector || ommersStr == stdinSelector || txsStr == stdinSelector || cliqueStr == stdinSelector { decoder := json.NewDecoder(os.Stdin) if err := decoder.Decode(inputData); err != nil { diff --git a/cmd/evm/internal/t8ntool/flags.go b/cmd/evm/internal/t8ntool/flags.go index 339523593a..de19dbc851 100644 --- a/cmd/evm/internal/t8ntool/flags.go +++ b/cmd/evm/internal/t8ntool/flags.go @@ -125,19 +125,6 @@ var ( Name: "seal.clique", Usage: "Seal block with Clique. `stdin` or file name of where to find the Clique sealing data.", } - SealEthashFlag = &cli.BoolFlag{ - Name: "seal.ethash", - Usage: "Seal block with ethash.", - } - SealEthashDirFlag = &cli.StringFlag{ - Name: "seal.ethash.dir", - Usage: "Path to ethash DAG. If none exists, a new DAG will be generated.", - } - SealEthashModeFlag = &cli.StringFlag{ - Name: "seal.ethash.mode", - Usage: "Defines the type and amount of PoW verification an ethash engine makes.", - Value: "normal", - } RewardFlag = &cli.Int64Flag{ Name: "state.reward", Usage: "Mining reward. Set to -1 to disable", diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 35f3e37ae5..024be62b9c 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -179,9 +179,6 @@ var blockBuilderCommand = &cli.Command{ t8ntool.InputWithdrawalsFlag, t8ntool.InputTxsRlpFlag, t8ntool.SealCliqueFlag, - t8ntool.SealEthashFlag, - t8ntool.SealEthashDirFlag, - t8ntool.SealEthashModeFlag, t8ntool.VerbosityFlag, }, } diff --git a/cmd/geth/genesis_test.go b/cmd/geth/genesis_test.go index d88346c93f..ffe8176b01 100644 --- a/cmd/geth/genesis_test.go +++ b/cmd/geth/genesis_test.go @@ -41,7 +41,9 @@ var customGenesisTests = []struct { "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp" : "0x00", - "config" : {} + "config" : { + "terminalTotalDifficultyPassed": true + } }`, query: "eth.getBlock(0).nonce", result: "0x0000000000001338", @@ -59,9 +61,10 @@ var customGenesisTests = []struct { "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp" : "0x00", "config" : { - "homesteadBlock" : 42, - "daoForkBlock" : 141, - "daoForkSupport" : true + "homesteadBlock" : 42, + "daoForkBlock" : 141, + "daoForkSupport" : true, + "terminalTotalDifficultyPassed" : true } }`, query: "eth.getBlock(0).nonce", @@ -111,8 +114,10 @@ func TestCustomBackend(t *testing.T) { "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp" : "0x00", - "config" : {} - }` + "config" : { + "terminalTotalDifficultyPassed": true + } + }` type backendTest struct { initArgs []string initExpect string diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 799493e67d..bac74f2a6e 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -66,14 +66,6 @@ var ( utils.SmartCardDaemonPathFlag, utils.OverrideCancun, utils.EnablePersonal, - utils.EthashCacheDirFlag, - utils.EthashCachesInMemoryFlag, - utils.EthashCachesOnDiskFlag, - utils.EthashCachesLockMmapFlag, - utils.EthashDatasetDirFlag, - utils.EthashDatasetsInMemoryFlag, - utils.EthashDatasetsOnDiskFlag, - utils.EthashDatasetsLockMmapFlag, utils.TxPoolLocalsFlag, utils.TxPoolNoLocalsFlag, utils.TxPoolJournalFlag, @@ -120,14 +112,11 @@ var ( utils.MaxPeersFlag, utils.MaxPendingPeersFlag, utils.MiningEnabledFlag, - utils.MinerThreadsFlag, - utils.MinerNotifyFlag, utils.MinerGasLimitFlag, utils.MinerGasPriceFlag, utils.MinerEtherbaseFlag, utils.MinerExtraDataFlag, utils.MinerRecommitIntervalFlag, - utils.MinerNoVerifyFlag, utils.MinerNewPayloadTimeout, utils.NATFlag, utils.NoDiscoverFlag, @@ -142,13 +131,11 @@ var ( utils.VMEnableDebugFlag, utils.NetworkIdFlag, utils.EthStatsURLFlag, - utils.FakePoWFlag, utils.NoCompactionFlag, utils.GpoBlocksFlag, utils.GpoPercentileFlag, utils.GpoMaxGasPriceFlag, utils.GpoIgnoreGasPriceFlag, - utils.MinerNotifyFullFlag, configFileFlag, }, utils.NetworkFlags, utils.DatabasePathFlags) @@ -224,8 +211,6 @@ func init() { attachCommand, javascriptCommand, // See misccmd.go: - makecacheCommand, - makedagCommand, versionCommand, versionCheckCommand, licenseCommand, @@ -438,9 +423,7 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon // Set the gas price to the limits from the CLI and start mining gasprice := flags.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) ethBackend.TxPool().SetGasPrice(gasprice) - // start mining - threads := ctx.Int(utils.MinerThreadsFlag.Name) - if err := ethBackend.StartMining(threads); err != nil { + if err := ethBackend.StartMining(); err != nil { utils.Fatalf("Failed to start mining: %v", err) } } diff --git a/cmd/geth/misccmd.go b/cmd/geth/misccmd.go index d8a523c632..f3530c30fb 100644 --- a/cmd/geth/misccmd.go +++ b/cmd/geth/misccmd.go @@ -20,11 +20,8 @@ import ( "fmt" "os" "runtime" - "strconv" "strings" - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" @@ -41,30 +38,6 @@ var ( Usage: "Version to check", Value: version.ClientName(clientIdentifier), } - makecacheCommand = &cli.Command{ - Action: makecache, - Name: "makecache", - Usage: "Generate ethash verification cache (for testing)", - ArgsUsage: " ", - Description: ` -The makecache command generates an ethash cache in . - -This command exists to support the system testing project. -Regular users do not need to execute it. -`, - } - makedagCommand = &cli.Command{ - Action: makedag, - Name: "makedag", - Usage: "Generate ethash mining DAG (for testing)", - ArgsUsage: " ", - Description: ` -The makedag command generates an ethash DAG in . - -This command exists to support the system testing project. -Regular users do not need to execute it. -`, - } versionCommand = &cli.Command{ Action: printVersion, Name: "version", @@ -96,36 +69,6 @@ and displays information about any security vulnerabilities that affect the curr } ) -// makecache generates an ethash verification cache into the provided folder. -func makecache(ctx *cli.Context) error { - args := ctx.Args().Slice() - if len(args) != 2 { - utils.Fatalf(`Usage: geth makecache `) - } - block, err := strconv.ParseUint(args[0], 0, 64) - if err != nil { - utils.Fatalf("Invalid block number: %v", err) - } - ethash.MakeCache(block, args[1]) - - return nil -} - -// makedag generates an ethash mining DAG into the provided folder. -func makedag(ctx *cli.Context) error { - args := ctx.Args().Slice() - if len(args) != 2 { - utils.Fatalf(`Usage: geth makedag `) - } - block, err := strconv.ParseUint(args[0], 0, 64) - if err != nil { - utils.Fatalf("Invalid block number: %v", err) - } - ethash.MakeDataset(block, args[1]) - - return nil -} - func printVersion(ctx *cli.Context) error { git, _ := version.VCS() diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ba9916d93b..300d39b94a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -39,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/txpool" @@ -325,54 +324,6 @@ var ( Usage: "Enables serving light clients before syncing", Category: flags.LightCategory, } - - // Ethash settings - EthashCacheDirFlag = &flags.DirectoryFlag{ - Name: "ethash.cachedir", - Usage: "Directory to store the ethash verification caches (default = inside the datadir)", - Category: flags.EthashCategory, - } - EthashCachesInMemoryFlag = &cli.IntFlag{ - Name: "ethash.cachesinmem", - Usage: "Number of recent ethash caches to keep in memory (16MB each)", - Value: ethconfig.Defaults.Ethash.CachesInMem, - Category: flags.EthashCategory, - } - EthashCachesOnDiskFlag = &cli.IntFlag{ - Name: "ethash.cachesondisk", - Usage: "Number of recent ethash caches to keep on disk (16MB each)", - Value: ethconfig.Defaults.Ethash.CachesOnDisk, - Category: flags.EthashCategory, - } - EthashCachesLockMmapFlag = &cli.BoolFlag{ - Name: "ethash.cacheslockmmap", - Usage: "Lock memory maps of recent ethash caches", - Category: flags.EthashCategory, - } - EthashDatasetDirFlag = &flags.DirectoryFlag{ - Name: "ethash.dagdir", - Usage: "Directory to store the ethash mining DAGs", - Value: flags.DirectoryString(ethconfig.Defaults.Ethash.DatasetDir), - Category: flags.EthashCategory, - } - EthashDatasetsInMemoryFlag = &cli.IntFlag{ - Name: "ethash.dagsinmem", - Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)", - Value: ethconfig.Defaults.Ethash.DatasetsInMem, - Category: flags.EthashCategory, - } - EthashDatasetsOnDiskFlag = &cli.IntFlag{ - Name: "ethash.dagsondisk", - Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)", - Value: ethconfig.Defaults.Ethash.DatasetsOnDisk, - Category: flags.EthashCategory, - } - EthashDatasetsLockMmapFlag = &cli.BoolFlag{ - Name: "ethash.dagslockmmap", - Usage: "Lock memory maps for recent ethash mining DAGs", - Category: flags.EthashCategory, - } - // Transaction pool settings TxPoolLocalsFlag = &cli.StringFlag{ Name: "txpool.locals", @@ -510,22 +461,6 @@ var ( Usage: "Enable mining", Category: flags.MinerCategory, } - MinerThreadsFlag = &cli.IntFlag{ - Name: "miner.threads", - Usage: "Number of CPU threads to use for mining", - Value: 0, - Category: flags.MinerCategory, - } - MinerNotifyFlag = &cli.StringFlag{ - Name: "miner.notify", - Usage: "Comma separated HTTP URL list to notify of new work packages", - Category: flags.MinerCategory, - } - MinerNotifyFullFlag = &cli.BoolFlag{ - Name: "miner.notify.full", - Usage: "Notify with pending block headers instead of work packages", - Category: flags.MinerCategory, - } MinerGasLimitFlag = &cli.Uint64Flag{ Name: "miner.gaslimit", Usage: "Target gas ceiling for mined blocks", @@ -554,11 +489,6 @@ var ( Value: ethconfig.Defaults.Miner.Recommit, Category: flags.MinerCategory, } - MinerNoVerifyFlag = &cli.BoolFlag{ - Name: "miner.noverify", - Usage: "Disable remote sealing verification", - Category: flags.MinerCategory, - } MinerNewPayloadTimeout = &cli.DurationFlag{ Name: "miner.newpayload-timeout", Usage: "Specify the maximum time allowance for creating a new payload", @@ -648,11 +578,6 @@ var ( Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)", Category: flags.MetricsCategory, } - FakePoWFlag = &cli.BoolFlag{ - Name: "fakepow", - Usage: "Disables proof-of-work verification", - Category: flags.LoggingCategory, - } NoCompactionFlag = &cli.BoolFlag{ Name: "nocompaction", Usage: "Disables db compaction after import", @@ -1604,38 +1529,7 @@ func setTxPool(ctx *cli.Context, cfg *txpool.Config) { } } -func setEthash(ctx *cli.Context, cfg *ethconfig.Config) { - if ctx.IsSet(EthashCacheDirFlag.Name) { - cfg.Ethash.CacheDir = ctx.String(EthashCacheDirFlag.Name) - } - if ctx.IsSet(EthashDatasetDirFlag.Name) { - cfg.Ethash.DatasetDir = ctx.String(EthashDatasetDirFlag.Name) - } - if ctx.IsSet(EthashCachesInMemoryFlag.Name) { - cfg.Ethash.CachesInMem = ctx.Int(EthashCachesInMemoryFlag.Name) - } - if ctx.IsSet(EthashCachesOnDiskFlag.Name) { - cfg.Ethash.CachesOnDisk = ctx.Int(EthashCachesOnDiskFlag.Name) - } - if ctx.IsSet(EthashCachesLockMmapFlag.Name) { - cfg.Ethash.CachesLockMmap = ctx.Bool(EthashCachesLockMmapFlag.Name) - } - if ctx.IsSet(EthashDatasetsInMemoryFlag.Name) { - cfg.Ethash.DatasetsInMem = ctx.Int(EthashDatasetsInMemoryFlag.Name) - } - if ctx.IsSet(EthashDatasetsOnDiskFlag.Name) { - cfg.Ethash.DatasetsOnDisk = ctx.Int(EthashDatasetsOnDiskFlag.Name) - } - if ctx.IsSet(EthashDatasetsLockMmapFlag.Name) { - cfg.Ethash.DatasetsLockMmap = ctx.Bool(EthashDatasetsLockMmapFlag.Name) - } -} - func setMiner(ctx *cli.Context, cfg *miner.Config) { - if ctx.IsSet(MinerNotifyFlag.Name) { - cfg.Notify = strings.Split(ctx.String(MinerNotifyFlag.Name), ",") - } - cfg.NotifyFull = ctx.Bool(MinerNotifyFullFlag.Name) if ctx.IsSet(MinerExtraDataFlag.Name) { cfg.ExtraData = []byte(ctx.String(MinerExtraDataFlag.Name)) } @@ -1648,9 +1542,6 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) { if ctx.IsSet(MinerRecommitIntervalFlag.Name) { cfg.Recommit = ctx.Duration(MinerRecommitIntervalFlag.Name) } - if ctx.IsSet(MinerNoVerifyFlag.Name) { - cfg.Noverify = ctx.Bool(MinerNoVerifyFlag.Name) - } if ctx.IsSet(MinerNewPayloadTimeout.Name) { cfg.NewPayloadTimeout = ctx.Duration(MinerNewPayloadTimeout.Name) } @@ -1741,7 +1632,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { setEtherbase(ctx, cfg) setGPO(ctx, &cfg.GPO, ctx.String(SyncModeFlag.Name) == "light") setTxPool(ctx, &cfg.TxPool) - setEthash(ctx, cfg) setMiner(ctx, &cfg.Miner) setRequiredBlocks(ctx, cfg) setLes(ctx, cfg) @@ -2226,15 +2116,14 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh gspec = MakeGenesis(ctx) chainDb = MakeChainDatabase(ctx, stack, readonly) ) - cliqueConfig, err := core.LoadCliqueConfig(chainDb, gspec) + config, err := core.LoadChainConfig(chainDb, gspec) if err != nil { Fatalf("%v", err) } - ethashConfig := ethconfig.Defaults.Ethash - if ctx.Bool(FakePoWFlag.Name) { - ethashConfig.PowMode = ethash.ModeFake + engine, err := ethconfig.CreateConsensusEngine(config, chainDb) + if err != nil { + Fatalf("%v", err) } - engine := ethconfig.CreateConsensusEngine(stack, ðashConfig, cliqueConfig, nil, false, chainDb) if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 1129ac06c8..284477b277 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -78,13 +78,13 @@ func (beacon *Beacon) Author(header *types.Header) (common.Address, error) { // VerifyHeader checks whether a header conforms to the consensus rules of the // stock Ethereum consensus engine. -func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error { +func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error { reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1) if err != nil { return err } if !reached { - return beacon.ethone.VerifyHeader(chain, header, seal) + return beacon.ethone.VerifyHeader(chain, header) } // Short circuit if the parent is not known parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) @@ -149,13 +149,13 @@ func (beacon *Beacon) splitHeaders(chain consensus.ChainHeaderReader, headers [] // concurrently. The method returns a quit channel to abort the operations and // a results channel to retrieve the async verifications. // VerifyHeaders expect the headers to be ordered and continuous. -func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { +func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) (chan<- struct{}, <-chan error) { preHeaders, postHeaders, err := beacon.splitHeaders(chain, headers) if err != nil { return make(chan struct{}), errOut(len(headers), err) } if len(postHeaders) == 0 { - return beacon.ethone.VerifyHeaders(chain, headers, seals) + return beacon.ethone.VerifyHeaders(chain, headers) } if len(preHeaders) == 0 { return beacon.verifyHeaders(chain, headers, nil) @@ -171,7 +171,7 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ old, new, out = 0, len(preHeaders), 0 errors = make([]error, len(headers)) done = make([]bool, len(headers)) - oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders, seals[:len(preHeaders)]) + oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders) newDone, newResult = beacon.verifyHeaders(chain, postHeaders, preHeaders[len(preHeaders)-1]) ) // Collect the results diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 2345a5ca03..535cbeb262 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -214,14 +214,14 @@ func (c *Clique) Author(header *types.Header) (common.Address, error) { } // VerifyHeader checks whether a header conforms to the consensus rules. -func (c *Clique) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error { +func (c *Clique) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error { return c.verifyHeader(chain, header, nil) } // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The // method returns a quit channel to abort the operations and a results channel to // retrieve the async verifications (the order is that of the input slice). -func (c *Clique) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { +func (c *Clique) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) (chan<- struct{}, <-chan error) { abort := make(chan struct{}) results := make(chan error, len(headers)) diff --git a/consensus/consensus.go b/consensus/consensus.go index a9fd8dd1cf..3a2c2d2229 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -66,15 +66,14 @@ type Engine interface { Author(header *types.Header) (common.Address, error) // VerifyHeader checks whether a header conforms to the consensus rules of a - // given engine. Verifying the seal may be done optionally here, or explicitly - // via the VerifySeal method. - VerifyHeader(chain ChainHeaderReader, header *types.Header, seal bool) error + // given engine. + VerifyHeader(chain ChainHeaderReader, header *types.Header) error // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers // concurrently. The method returns a quit channel to abort the operations and // a results channel to retrieve the async verifications (the order is that of // the input slice). - VerifyHeaders(chain ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) + VerifyHeaders(chain ChainHeaderReader, headers []*types.Header) (chan<- struct{}, <-chan error) // VerifyUncles verifies that the given block's uncles conform to the consensus // rules of a given engine. diff --git a/consensus/ethash/algorithm.go b/consensus/ethash/algorithm.go deleted file mode 100644 index a2a6081f55..0000000000 --- a/consensus/ethash/algorithm.go +++ /dev/null @@ -1,1152 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ethash - -import ( - "encoding/binary" - "hash" - "math/big" - "reflect" - "runtime" - "sync" - "sync/atomic" - "time" - "unsafe" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/bitutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "golang.org/x/crypto/sha3" -) - -const ( - datasetInitBytes = 1 << 30 // Bytes in dataset at genesis - datasetGrowthBytes = 1 << 23 // Dataset growth per epoch - cacheInitBytes = 1 << 24 // Bytes in cache at genesis - cacheGrowthBytes = 1 << 17 // Cache growth per epoch - epochLength = 30000 // Blocks per epoch - mixBytes = 128 // Width of mix - hashBytes = 64 // Hash length in bytes - hashWords = 16 // Number of 32 bit ints in a hash - datasetParents = 256 // Number of parents of each dataset element - cacheRounds = 3 // Number of rounds in cache production - loopAccesses = 64 // Number of accesses in hashimoto loop -) - -// cacheSize returns the size of the ethash verification cache that belongs to a certain -// block number. -func cacheSize(block uint64) uint64 { - epoch := int(block / epochLength) - if epoch < maxEpoch { - return cacheSizes[epoch] - } - return calcCacheSize(epoch) -} - -// calcCacheSize calculates the cache size for epoch. The cache size grows linearly, -// however, we always take the highest prime below the linearly growing threshold in order -// to reduce the risk of accidental regularities leading to cyclic behavior. -func calcCacheSize(epoch int) uint64 { - size := cacheInitBytes + cacheGrowthBytes*uint64(epoch) - hashBytes - for !new(big.Int).SetUint64(size / hashBytes).ProbablyPrime(1) { // Always accurate for n < 2^64 - size -= 2 * hashBytes - } - return size -} - -// datasetSize returns the size of the ethash mining dataset that belongs to a certain -// block number. -func datasetSize(block uint64) uint64 { - epoch := int(block / epochLength) - if epoch < maxEpoch { - return datasetSizes[epoch] - } - return calcDatasetSize(epoch) -} - -// calcDatasetSize calculates the dataset size for epoch. The dataset size grows linearly, -// however, we always take the highest prime below the linearly growing threshold in order -// to reduce the risk of accidental regularities leading to cyclic behavior. -func calcDatasetSize(epoch int) uint64 { - size := datasetInitBytes + datasetGrowthBytes*uint64(epoch) - mixBytes - for !new(big.Int).SetUint64(size / mixBytes).ProbablyPrime(1) { // Always accurate for n < 2^64 - size -= 2 * mixBytes - } - return size -} - -// hasher is a repetitive hasher allowing the same hash data structures to be -// reused between hash runs instead of requiring new ones to be created. -type hasher func(dest []byte, data []byte) - -// makeHasher creates a repetitive hasher, allowing the same hash data structures to -// be reused between hash runs instead of requiring new ones to be created. The returned -// function is not thread safe! -func makeHasher(h hash.Hash) hasher { - // sha3.state supports Read to get the sum, use it to avoid the overhead of Sum. - // Read alters the state but we reset the hash before every operation. - type readerHash interface { - hash.Hash - Read([]byte) (int, error) - } - rh, ok := h.(readerHash) - if !ok { - panic("can't find Read method on hash") - } - outputLen := rh.Size() - return func(dest []byte, data []byte) { - rh.Reset() - rh.Write(data) - rh.Read(dest[:outputLen]) - } -} - -// seedHash is the seed to use for generating a verification cache and the mining -// dataset. -func seedHash(block uint64) []byte { - seed := make([]byte, 32) - if block < epochLength { - return seed - } - keccak256 := makeHasher(sha3.NewLegacyKeccak256()) - for i := 0; i < int(block/epochLength); i++ { - keccak256(seed, seed) - } - return seed -} - -// generateCache creates a verification cache of a given size for an input seed. -// The cache production process involves first sequentially filling up 32 MB of -// memory, then performing two passes of Sergio Demian Lerner's RandMemoHash -// algorithm from Strict Memory Hard Hashing Functions (2014). The output is a -// set of 524288 64-byte values. -// This method places the result into dest in machine byte order. -func generateCache(dest []uint32, epoch uint64, seed []byte) { - // Print some debug logs to allow analysis on low end devices - logger := log.New("epoch", epoch) - - start := time.Now() - defer func() { - elapsed := time.Since(start) - - logFn := logger.Debug - if elapsed > 3*time.Second { - logFn = logger.Info - } - logFn("Generated ethash verification cache", "elapsed", common.PrettyDuration(elapsed)) - }() - // Convert our destination slice to a byte buffer - var cache []byte - cacheHdr := (*reflect.SliceHeader)(unsafe.Pointer(&cache)) - dstHdr := (*reflect.SliceHeader)(unsafe.Pointer(&dest)) - cacheHdr.Data = dstHdr.Data - cacheHdr.Len = dstHdr.Len * 4 - cacheHdr.Cap = dstHdr.Cap * 4 - - // Calculate the number of theoretical rows (we'll store in one buffer nonetheless) - size := uint64(len(cache)) - rows := int(size) / hashBytes - - // Start a monitoring goroutine to report progress on low end devices - var progress atomic.Uint32 - - done := make(chan struct{}) - defer close(done) - - go func() { - for { - select { - case <-done: - return - case <-time.After(3 * time.Second): - logger.Info("Generating ethash verification cache", "percentage", progress.Load()*100/uint32(rows)/(cacheRounds+1), "elapsed", common.PrettyDuration(time.Since(start))) - } - } - }() - // Create a hasher to reuse between invocations - keccak512 := makeHasher(sha3.NewLegacyKeccak512()) - - // Sequentially produce the initial dataset - keccak512(cache, seed) - for offset := uint64(hashBytes); offset < size; offset += hashBytes { - keccak512(cache[offset:], cache[offset-hashBytes:offset]) - progress.Add(1) - } - // Use a low-round version of randmemohash - temp := make([]byte, hashBytes) - - for i := 0; i < cacheRounds; i++ { - for j := 0; j < rows; j++ { - var ( - srcOff = ((j - 1 + rows) % rows) * hashBytes - dstOff = j * hashBytes - xorOff = (binary.LittleEndian.Uint32(cache[dstOff:]) % uint32(rows)) * hashBytes - ) - bitutil.XORBytes(temp, cache[srcOff:srcOff+hashBytes], cache[xorOff:xorOff+hashBytes]) - keccak512(cache[dstOff:], temp) - - progress.Add(1) - } - } - // Swap the byte order on big endian systems and return - if !isLittleEndian() { - swap(cache) - } -} - -// swap changes the byte order of the buffer assuming a uint32 representation. -func swap(buffer []byte) { - for i := 0; i < len(buffer); i += 4 { - binary.BigEndian.PutUint32(buffer[i:], binary.LittleEndian.Uint32(buffer[i:])) - } -} - -// fnv is an algorithm inspired by the FNV hash, which in some cases is used as -// a non-associative substitute for XOR. Note that we multiply the prime with -// the full 32-bit input, in contrast with the FNV-1 spec which multiplies the -// prime with one byte (octet) in turn. -func fnv(a, b uint32) uint32 { - return a*0x01000193 ^ b -} - -// fnvHash mixes in data into mix using the ethash fnv method. -func fnvHash(mix []uint32, data []uint32) { - for i := 0; i < len(mix); i++ { - mix[i] = mix[i]*0x01000193 ^ data[i] - } -} - -// generateDatasetItem combines data from 256 pseudorandomly selected cache nodes, -// and hashes that to compute a single dataset node. -func generateDatasetItem(cache []uint32, index uint32, keccak512 hasher) []byte { - // Calculate the number of theoretical rows (we use one buffer nonetheless) - rows := uint32(len(cache) / hashWords) - - // Initialize the mix - mix := make([]byte, hashBytes) - - binary.LittleEndian.PutUint32(mix, cache[(index%rows)*hashWords]^index) - for i := 1; i < hashWords; i++ { - binary.LittleEndian.PutUint32(mix[i*4:], cache[(index%rows)*hashWords+uint32(i)]) - } - keccak512(mix, mix) - - // Convert the mix to uint32s to avoid constant bit shifting - intMix := make([]uint32, hashWords) - for i := 0; i < len(intMix); i++ { - intMix[i] = binary.LittleEndian.Uint32(mix[i*4:]) - } - // fnv it with a lot of random cache nodes based on index - for i := uint32(0); i < datasetParents; i++ { - parent := fnv(index^i, intMix[i%16]) % rows - fnvHash(intMix, cache[parent*hashWords:]) - } - // Flatten the uint32 mix into a binary one and return - for i, val := range intMix { - binary.LittleEndian.PutUint32(mix[i*4:], val) - } - keccak512(mix, mix) - return mix -} - -// generateDataset generates the entire ethash dataset for mining. -// This method places the result into dest in machine byte order. -func generateDataset(dest []uint32, epoch uint64, cache []uint32) { - // Print some debug logs to allow analysis on low end devices - logger := log.New("epoch", epoch) - - start := time.Now() - defer func() { - elapsed := time.Since(start) - - logFn := logger.Debug - if elapsed > 3*time.Second { - logFn = logger.Info - } - logFn("Generated ethash verification cache", "elapsed", common.PrettyDuration(elapsed)) - }() - - // Figure out whether the bytes need to be swapped for the machine - swapped := !isLittleEndian() - - // Convert our destination slice to a byte buffer - var dataset []byte - datasetHdr := (*reflect.SliceHeader)(unsafe.Pointer(&dataset)) - destHdr := (*reflect.SliceHeader)(unsafe.Pointer(&dest)) - datasetHdr.Data = destHdr.Data - datasetHdr.Len = destHdr.Len * 4 - datasetHdr.Cap = destHdr.Cap * 4 - - // Generate the dataset on many goroutines since it takes a while - threads := runtime.NumCPU() - size := uint64(len(dataset)) - - var pend sync.WaitGroup - pend.Add(threads) - - var progress atomic.Uint64 - for i := 0; i < threads; i++ { - go func(id int) { - defer pend.Done() - - // Create a hasher to reuse between invocations - keccak512 := makeHasher(sha3.NewLegacyKeccak512()) - - // Calculate the data segment this thread should generate - batch := (size + hashBytes*uint64(threads) - 1) / (hashBytes * uint64(threads)) - first := uint64(id) * batch - limit := first + batch - if limit > size/hashBytes { - limit = size / hashBytes - } - // Calculate the dataset segment - percent := size / hashBytes / 100 - for index := first; index < limit; index++ { - item := generateDatasetItem(cache, uint32(index), keccak512) - if swapped { - swap(item) - } - copy(dataset[index*hashBytes:], item) - - if status := progress.Add(1); status%percent == 0 { - logger.Info("Generating DAG in progress", "percentage", (status*100)/(size/hashBytes), "elapsed", common.PrettyDuration(time.Since(start))) - } - } - }(i) - } - // Wait for all the generators to finish and return - pend.Wait() -} - -// hashimoto aggregates data from the full dataset in order to produce our final -// value for a particular header hash and nonce. -func hashimoto(hash []byte, nonce uint64, size uint64, lookup func(index uint32) []uint32) ([]byte, []byte) { - // Calculate the number of theoretical rows (we use one buffer nonetheless) - rows := uint32(size / mixBytes) - - // Combine header+nonce into a 40 byte seed - seed := make([]byte, 40) - copy(seed, hash) - binary.LittleEndian.PutUint64(seed[32:], nonce) - - seed = crypto.Keccak512(seed) - seedHead := binary.LittleEndian.Uint32(seed) - - // Start the mix with replicated seed - mix := make([]uint32, mixBytes/4) - for i := 0; i < len(mix); i++ { - mix[i] = binary.LittleEndian.Uint32(seed[i%16*4:]) - } - // Mix in random dataset nodes - temp := make([]uint32, len(mix)) - - for i := 0; i < loopAccesses; i++ { - parent := fnv(uint32(i)^seedHead, mix[i%len(mix)]) % rows - for j := uint32(0); j < mixBytes/hashBytes; j++ { - copy(temp[j*hashWords:], lookup(2*parent+j)) - } - fnvHash(mix, temp) - } - // Compress mix - for i := 0; i < len(mix); i += 4 { - mix[i/4] = fnv(fnv(fnv(mix[i], mix[i+1]), mix[i+2]), mix[i+3]) - } - mix = mix[:len(mix)/4] - - digest := make([]byte, common.HashLength) - for i, val := range mix { - binary.LittleEndian.PutUint32(digest[i*4:], val) - } - return digest, crypto.Keccak256(append(seed, digest...)) -} - -// hashimotoLight aggregates data from the full dataset (using only a small -// in-memory cache) in order to produce our final value for a particular header -// hash and nonce. -func hashimotoLight(size uint64, cache []uint32, hash []byte, nonce uint64) ([]byte, []byte) { - keccak512 := makeHasher(sha3.NewLegacyKeccak512()) - - lookup := func(index uint32) []uint32 { - rawData := generateDatasetItem(cache, index, keccak512) - - data := make([]uint32, len(rawData)/4) - for i := 0; i < len(data); i++ { - data[i] = binary.LittleEndian.Uint32(rawData[i*4:]) - } - return data - } - return hashimoto(hash, nonce, size, lookup) -} - -// hashimotoFull aggregates data from the full dataset (using the full in-memory -// dataset) in order to produce our final value for a particular header hash and -// nonce. -func hashimotoFull(dataset []uint32, hash []byte, nonce uint64) ([]byte, []byte) { - lookup := func(index uint32) []uint32 { - offset := index * hashWords - return dataset[offset : offset+hashWords] - } - return hashimoto(hash, nonce, uint64(len(dataset))*4, lookup) -} - -const maxEpoch = 2048 - -// datasetSizes is a lookup table for the ethash dataset size for the first 2048 -// epochs (i.e. 61440000 blocks). -var datasetSizes = [maxEpoch]uint64{ - 1073739904, 1082130304, 1090514816, 1098906752, 1107293056, - 1115684224, 1124070016, 1132461952, 1140849536, 1149232768, - 1157627776, 1166013824, 1174404736, 1182786944, 1191180416, - 1199568512, 1207958912, 1216345216, 1224732032, 1233124736, - 1241513344, 1249902464, 1258290304, 1266673792, 1275067264, - 1283453312, 1291844992, 1300234112, 1308619904, 1317010048, - 1325397376, 1333787776, 1342176128, 1350561664, 1358954368, - 1367339392, 1375731584, 1384118144, 1392507008, 1400897408, - 1409284736, 1417673344, 1426062464, 1434451072, 1442839168, - 1451229056, 1459615616, 1468006016, 1476394112, 1484782976, - 1493171584, 1501559168, 1509948032, 1518337664, 1526726528, - 1535114624, 1543503488, 1551892096, 1560278656, 1568669056, - 1577056384, 1585446272, 1593831296, 1602219392, 1610610304, - 1619000192, 1627386752, 1635773824, 1644164224, 1652555648, - 1660943488, 1669332608, 1677721216, 1686109312, 1694497664, - 1702886272, 1711274624, 1719661184, 1728047744, 1736434816, - 1744829056, 1753218944, 1761606272, 1769995904, 1778382464, - 1786772864, 1795157888, 1803550592, 1811937664, 1820327552, - 1828711552, 1837102976, 1845488768, 1853879936, 1862269312, - 1870656896, 1879048064, 1887431552, 1895825024, 1904212096, - 1912601216, 1920988544, 1929379456, 1937765504, 1946156672, - 1954543232, 1962932096, 1971321728, 1979707264, 1988093056, - 1996487552, 2004874624, 2013262208, 2021653888, 2030039936, - 2038430848, 2046819968, 2055208576, 2063596672, 2071981952, - 2080373632, 2088762752, 2097149056, 2105539712, 2113928576, - 2122315136, 2130700672, 2139092608, 2147483264, 2155872128, - 2164257664, 2172642176, 2181035392, 2189426048, 2197814912, - 2206203008, 2214587264, 2222979712, 2231367808, 2239758208, - 2248145024, 2256527744, 2264922752, 2273312128, 2281701248, - 2290086272, 2298476672, 2306867072, 2315251072, 2323639168, - 2332032128, 2340420224, 2348808064, 2357196416, 2365580416, - 2373966976, 2382363008, 2390748544, 2399139968, 2407530368, - 2415918976, 2424307328, 2432695424, 2441084288, 2449472384, - 2457861248, 2466247808, 2474637184, 2483026816, 2491414144, - 2499803776, 2508191872, 2516582272, 2524970368, 2533359232, - 2541743488, 2550134144, 2558525056, 2566913408, 2575301504, - 2583686528, 2592073856, 2600467328, 2608856192, 2617240448, - 2625631616, 2634022016, 2642407552, 2650796416, 2659188352, - 2667574912, 2675965312, 2684352896, 2692738688, 2701130624, - 2709518464, 2717907328, 2726293376, 2734685056, 2743073152, - 2751462016, 2759851648, 2768232832, 2776625536, 2785017728, - 2793401984, 2801794432, 2810182016, 2818571648, 2826959488, - 2835349376, 2843734144, 2852121472, 2860514432, 2868900992, - 2877286784, 2885676928, 2894069632, 2902451584, 2910843008, - 2919234688, 2927622784, 2936011648, 2944400768, 2952789376, - 2961177728, 2969565568, 2977951616, 2986338944, 2994731392, - 3003120256, 3011508352, 3019895936, 3028287104, 3036675968, - 3045063808, 3053452928, 3061837696, 3070228352, 3078615424, - 3087003776, 3095394944, 3103782272, 3112173184, 3120562048, - 3128944768, 3137339264, 3145725056, 3154109312, 3162505088, - 3170893184, 3179280256, 3187669376, 3196056704, 3204445568, - 3212836736, 3221224064, 3229612928, 3238002304, 3246391168, - 3254778496, 3263165824, 3271556224, 3279944576, 3288332416, - 3296719232, 3305110912, 3313500032, 3321887104, 3330273152, - 3338658944, 3347053184, 3355440512, 3363827072, 3372220288, - 3380608384, 3388997504, 3397384576, 3405774208, 3414163072, - 3422551936, 3430937984, 3439328384, 3447714176, 3456104576, - 3464493952, 3472883584, 3481268864, 3489655168, 3498048896, - 3506434432, 3514826368, 3523213952, 3531603584, 3539987072, - 3548380288, 3556763264, 3565157248, 3573545344, 3581934464, - 3590324096, 3598712704, 3607098752, 3615488384, 3623877248, - 3632265856, 3640646528, 3649043584, 3657430144, 3665821568, - 3674207872, 3682597504, 3690984832, 3699367808, 3707764352, - 3716152448, 3724541056, 3732925568, 3741318016, 3749706368, - 3758091136, 3766481536, 3774872704, 3783260032, 3791650432, - 3800036224, 3808427648, 3816815488, 3825204608, 3833592704, - 3841981568, 3850370432, 3858755968, 3867147904, 3875536256, - 3883920512, 3892313728, 3900702592, 3909087872, 3917478784, - 3925868416, 3934256512, 3942645376, 3951032192, 3959422336, - 3967809152, 3976200064, 3984588416, 3992974976, 4001363584, - 4009751168, 4018141312, 4026530432, 4034911616, 4043308928, - 4051695488, 4060084352, 4068472448, 4076862848, 4085249408, - 4093640576, 4102028416, 4110413696, 4118805632, 4127194496, - 4135583104, 4143971968, 4152360832, 4160746112, 4169135744, - 4177525888, 4185912704, 4194303616, 4202691968, 4211076736, - 4219463552, 4227855488, 4236246656, 4244633728, 4253022848, - 4261412224, 4269799808, 4278184832, 4286578048, 4294962304, - 4303349632, 4311743104, 4320130432, 4328521088, 4336909184, - 4345295488, 4353687424, 4362073472, 4370458496, 4378852736, - 4387238528, 4395630208, 4404019072, 4412407424, 4420790656, - 4429182848, 4437571456, 4445962112, 4454344064, 4462738048, - 4471119232, 4479516544, 4487904128, 4496289664, 4504682368, - 4513068416, 4521459584, 4529846144, 4538232704, 4546619776, - 4555010176, 4563402112, 4571790208, 4580174464, 4588567936, - 4596957056, 4605344896, 4613734016, 4622119808, 4630511488, - 4638898816, 4647287936, 4655675264, 4664065664, 4672451968, - 4680842624, 4689231488, 4697620352, 4706007424, 4714397056, - 4722786176, 4731173248, 4739562368, 4747951744, 4756340608, - 4764727936, 4773114496, 4781504384, 4789894784, 4798283648, - 4806667648, 4815059584, 4823449472, 4831835776, 4840226176, - 4848612224, 4857003392, 4865391488, 4873780096, 4882169728, - 4890557312, 4898946944, 4907333248, 4915722368, 4924110976, - 4932499328, 4940889728, 4949276032, 4957666432, 4966054784, - 4974438016, 4982831488, 4991221376, 4999607168, 5007998848, - 5016386432, 5024763776, 5033164672, 5041544576, 5049941888, - 5058329728, 5066717056, 5075107456, 5083494272, 5091883904, - 5100273536, 5108662144, 5117048192, 5125436032, 5133827456, - 5142215296, 5150605184, 5158993024, 5167382144, 5175769472, - 5184157568, 5192543872, 5200936064, 5209324928, 5217711232, - 5226102656, 5234490496, 5242877312, 5251263872, 5259654016, - 5268040832, 5276434304, 5284819328, 5293209728, 5301598592, - 5309986688, 5318374784, 5326764416, 5335151488, 5343542144, - 5351929472, 5360319872, 5368706944, 5377096576, 5385484928, - 5393871232, 5402263424, 5410650496, 5419040384, 5427426944, - 5435816576, 5444205952, 5452594816, 5460981376, 5469367936, - 5477760896, 5486148736, 5494536832, 5502925952, 5511315328, - 5519703424, 5528089984, 5536481152, 5544869504, 5553256064, - 5561645696, 5570032768, 5578423936, 5586811264, 5595193216, - 5603585408, 5611972736, 5620366208, 5628750464, 5637143936, - 5645528192, 5653921408, 5662310272, 5670694784, 5679082624, - 5687474048, 5695864448, 5704251008, 5712641408, 5721030272, - 5729416832, 5737806208, 5746194304, 5754583936, 5762969984, - 5771358592, 5779748224, 5788137856, 5796527488, 5804911232, - 5813300608, 5821692544, 5830082176, 5838468992, 5846855552, - 5855247488, 5863636096, 5872024448, 5880411008, 5888799872, - 5897186432, 5905576832, 5913966976, 5922352768, 5930744704, - 5939132288, 5947522432, 5955911296, 5964299392, 5972688256, - 5981074304, 5989465472, 5997851008, 6006241408, 6014627968, - 6023015552, 6031408256, 6039796096, 6048185216, 6056574848, - 6064963456, 6073351808, 6081736064, 6090128768, 6098517632, - 6106906496, 6115289216, 6123680896, 6132070016, 6140459648, - 6148849024, 6157237376, 6165624704, 6174009728, 6182403712, - 6190792064, 6199176064, 6207569792, 6215952256, 6224345216, - 6232732544, 6241124224, 6249510272, 6257899136, 6266287744, - 6274676864, 6283065728, 6291454336, 6299843456, 6308232064, - 6316620928, 6325006208, 6333395584, 6341784704, 6350174848, - 6358562176, 6366951296, 6375337856, 6383729536, 6392119168, - 6400504192, 6408895616, 6417283456, 6425673344, 6434059136, - 6442444672, 6450837376, 6459223424, 6467613056, 6476004224, - 6484393088, 6492781952, 6501170048, 6509555072, 6517947008, - 6526336384, 6534725504, 6543112832, 6551500672, 6559888768, - 6568278656, 6576662912, 6585055616, 6593443456, 6601834112, - 6610219648, 6618610304, 6626999168, 6635385472, 6643777408, - 6652164224, 6660552832, 6668941952, 6677330048, 6685719424, - 6694107776, 6702493568, 6710882176, 6719274112, 6727662976, - 6736052096, 6744437632, 6752825984, 6761213824, 6769604224, - 6777993856, 6786383488, 6794770816, 6803158144, 6811549312, - 6819937664, 6828326528, 6836706176, 6845101696, 6853491328, - 6861880448, 6870269312, 6878655104, 6887046272, 6895433344, - 6903822208, 6912212864, 6920596864, 6928988288, 6937377152, - 6945764992, 6954149248, 6962544256, 6970928768, 6979317376, - 6987709312, 6996093824, 7004487296, 7012875392, 7021258624, - 7029652352, 7038038912, 7046427776, 7054818944, 7063207808, - 7071595136, 7079980928, 7088372608, 7096759424, 7105149824, - 7113536896, 7121928064, 7130315392, 7138699648, 7147092352, - 7155479168, 7163865728, 7172249984, 7180648064, 7189036672, - 7197424768, 7205810816, 7214196608, 7222589824, 7230975104, - 7239367552, 7247755904, 7256145536, 7264533376, 7272921472, - 7281308032, 7289694848, 7298088832, 7306471808, 7314864512, - 7323253888, 7331643008, 7340029568, 7348419712, 7356808832, - 7365196672, 7373585792, 7381973888, 7390362752, 7398750592, - 7407138944, 7415528576, 7423915648, 7432302208, 7440690304, - 7449080192, 7457472128, 7465860992, 7474249088, 7482635648, - 7491023744, 7499412608, 7507803008, 7516192384, 7524579968, - 7532967296, 7541358464, 7549745792, 7558134656, 7566524032, - 7574912896, 7583300992, 7591690112, 7600075136, 7608466816, - 7616854912, 7625244544, 7633629824, 7642020992, 7650410368, - 7658794112, 7667187328, 7675574912, 7683961984, 7692349568, - 7700739712, 7709130368, 7717519232, 7725905536, 7734295424, - 7742683264, 7751069056, 7759457408, 7767849088, 7776238208, - 7784626816, 7793014912, 7801405312, 7809792128, 7818179968, - 7826571136, 7834957184, 7843347328, 7851732352, 7860124544, - 7868512384, 7876902016, 7885287808, 7893679744, 7902067072, - 7910455936, 7918844288, 7927230848, 7935622784, 7944009344, - 7952400256, 7960786048, 7969176704, 7977565312, 7985953408, - 7994339968, 8002730368, 8011119488, 8019508096, 8027896192, - 8036285056, 8044674688, 8053062272, 8061448832, 8069838464, - 8078227328, 8086616704, 8095006592, 8103393664, 8111783552, - 8120171392, 8128560256, 8136949376, 8145336704, 8153726848, - 8162114944, 8170503296, 8178891904, 8187280768, 8195669632, - 8204058496, 8212444544, 8220834176, 8229222272, 8237612672, - 8246000768, 8254389376, 8262775168, 8271167104, 8279553664, - 8287944064, 8296333184, 8304715136, 8313108352, 8321497984, - 8329885568, 8338274432, 8346663296, 8355052928, 8363441536, - 8371828352, 8380217984, 8388606592, 8396996224, 8405384576, - 8413772672, 8422161536, 8430549376, 8438939008, 8447326592, - 8455715456, 8464104832, 8472492928, 8480882048, 8489270656, - 8497659776, 8506045312, 8514434944, 8522823808, 8531208832, - 8539602304, 8547990656, 8556378752, 8564768384, 8573154176, - 8581542784, 8589933952, 8598322816, 8606705024, 8615099264, - 8623487872, 8631876992, 8640264064, 8648653952, 8657040256, - 8665430656, 8673820544, 8682209152, 8690592128, 8698977152, - 8707374464, 8715763328, 8724151424, 8732540032, 8740928384, - 8749315712, 8757704576, 8766089344, 8774480768, 8782871936, - 8791260032, 8799645824, 8808034432, 8816426368, 8824812928, - 8833199488, 8841591424, 8849976448, 8858366336, 8866757248, - 8875147136, 8883532928, 8891923328, 8900306816, 8908700288, - 8917088384, 8925478784, 8933867392, 8942250368, 8950644608, - 8959032704, 8967420544, 8975809664, 8984197504, 8992584064, - 9000976256, 9009362048, 9017752448, 9026141312, 9034530688, - 9042917504, 9051307904, 9059694208, 9068084864, 9076471424, - 9084861824, 9093250688, 9101638528, 9110027648, 9118416512, - 9126803584, 9135188096, 9143581312, 9151969664, 9160356224, - 9168747136, 9177134464, 9185525632, 9193910144, 9202302848, - 9210690688, 9219079552, 9227465344, 9235854464, 9244244864, - 9252633472, 9261021824, 9269411456, 9277799296, 9286188928, - 9294574208, 9302965888, 9311351936, 9319740032, 9328131968, - 9336516736, 9344907392, 9353296768, 9361685888, 9370074752, - 9378463616, 9386849408, 9395239808, 9403629184, 9412016512, - 9420405376, 9428795008, 9437181568, 9445570688, 9453960832, - 9462346624, 9470738048, 9479121536, 9487515008, 9495903616, - 9504289664, 9512678528, 9521067904, 9529456256, 9537843584, - 9546233728, 9554621312, 9563011456, 9571398784, 9579788672, - 9588178304, 9596567168, 9604954496, 9613343104, 9621732992, - 9630121856, 9638508416, 9646898816, 9655283584, 9663675776, - 9672061312, 9680449664, 9688840064, 9697230464, 9705617536, - 9714003584, 9722393984, 9730772608, 9739172224, 9747561088, - 9755945344, 9764338816, 9772726144, 9781116544, 9789503872, - 9797892992, 9806282624, 9814670464, 9823056512, 9831439232, - 9839833984, 9848224384, 9856613504, 9865000576, 9873391232, - 9881772416, 9890162816, 9898556288, 9906940544, 9915333248, - 9923721088, 9932108672, 9940496512, 9948888448, 9957276544, - 9965666176, 9974048384, 9982441088, 9990830464, 9999219584, - 10007602816, 10015996544, 10024385152, 10032774016, 10041163648, - 10049548928, 10057940096, 10066329472, 10074717824, 10083105152, - 10091495296, 10099878784, 10108272256, 10116660608, 10125049216, - 10133437312, 10141825664, 10150213504, 10158601088, 10166991232, - 10175378816, 10183766144, 10192157312, 10200545408, 10208935552, - 10217322112, 10225712768, 10234099328, 10242489472, 10250876032, - 10259264896, 10267656064, 10276042624, 10284429184, 10292820352, - 10301209472, 10309598848, 10317987712, 10326375296, 10334763392, - 10343153536, 10351541632, 10359930752, 10368318592, 10376707456, - 10385096576, 10393484672, 10401867136, 10410262144, 10418647424, - 10427039104, 10435425664, 10443810176, 10452203648, 10460589952, - 10468982144, 10477369472, 10485759104, 10494147712, 10502533504, - 10510923392, 10519313536, 10527702656, 10536091264, 10544478592, - 10552867712, 10561255808, 10569642368, 10578032768, 10586423168, - 10594805632, 10603200128, 10611588992, 10619976064, 10628361344, - 10636754048, 10645143424, 10653531776, 10661920384, 10670307968, - 10678696832, 10687086464, 10695475072, 10703863168, 10712246144, - 10720639616, 10729026688, 10737414784, 10745806208, 10754190976, - 10762581376, 10770971264, 10779356288, 10787747456, 10796135552, - 10804525184, 10812915584, 10821301888, 10829692288, 10838078336, - 10846469248, 10854858368, 10863247232, 10871631488, 10880023424, - 10888412032, 10896799616, 10905188992, 10913574016, 10921964672, - 10930352768, 10938742912, 10947132544, 10955518592, 10963909504, - 10972298368, 10980687488, 10989074816, 10997462912, 11005851776, - 11014241152, 11022627712, 11031017344, 11039403904, 11047793024, - 11056184704, 11064570752, 11072960896, 11081343872, 11089737856, - 11098128256, 11106514816, 11114904448, 11123293568, 11131680128, - 11140065152, 11148458368, 11156845696, 11165236864, 11173624192, - 11182013824, 11190402688, 11198790784, 11207179136, 11215568768, - 11223957376, 11232345728, 11240734592, 11249122688, 11257511296, - 11265899648, 11274285952, 11282675584, 11291065472, 11299452544, - 11307842432, 11316231296, 11324616832, 11333009024, 11341395584, - 11349782656, 11358172288, 11366560384, 11374950016, 11383339648, - 11391721856, 11400117376, 11408504192, 11416893568, 11425283456, - 11433671552, 11442061184, 11450444672, 11458837888, 11467226752, - 11475611776, 11484003968, 11492392064, 11500780672, 11509169024, - 11517550976, 11525944448, 11534335616, 11542724224, 11551111808, - 11559500672, 11567890304, 11576277376, 11584667008, 11593056128, - 11601443456, 11609830016, 11618221952, 11626607488, 11634995072, - 11643387776, 11651775104, 11660161664, 11668552576, 11676940928, - 11685330304, 11693718656, 11702106496, 11710496128, 11718882688, - 11727273088, 11735660416, 11744050048, 11752437376, 11760824704, - 11769216128, 11777604736, 11785991296, 11794381952, 11802770048, - 11811157888, 11819548544, 11827932544, 11836324736, 11844713344, - 11853100928, 11861486464, 11869879936, 11878268032, 11886656896, - 11895044992, 11903433088, 11911822976, 11920210816, 11928600448, - 11936987264, 11945375872, 11953761152, 11962151296, 11970543488, - 11978928512, 11987320448, 11995708288, 12004095104, 12012486272, - 12020875136, 12029255552, 12037652096, 12046039168, 12054429568, - 12062813824, 12071206528, 12079594624, 12087983744, 12096371072, - 12104759936, 12113147264, 12121534592, 12129924992, 12138314624, - 12146703232, 12155091584, 12163481216, 12171864704, 12180255872, - 12188643968, 12197034112, 12205424512, 12213811328, 12222199424, - 12230590336, 12238977664, 12247365248, 12255755392, 12264143488, - 12272531584, 12280920448, 12289309568, 12297694592, 12306086528, - 12314475392, 12322865024, 12331253632, 12339640448, 12348029312, - 12356418944, 12364805248, 12373196672, 12381580928, 12389969024, - 12398357632, 12406750592, 12415138432, 12423527552, 12431916416, - 12440304512, 12448692352, 12457081216, 12465467776, 12473859968, - 12482245504, 12490636672, 12499025536, 12507411584, 12515801728, - 12524190592, 12532577152, 12540966272, 12549354368, 12557743232, - 12566129536, 12574523264, 12582911872, 12591299456, 12599688064, - 12608074624, 12616463488, 12624845696, 12633239936, 12641631616, - 12650019968, 12658407296, 12666795136, 12675183232, 12683574656, - 12691960192, 12700350592, 12708740224, 12717128576, 12725515904, - 12733906816, 12742295168, 12750680192, 12759071872, 12767460736, - 12775848832, 12784236928, 12792626816, 12801014656, 12809404288, - 12817789312, 12826181504, 12834568832, 12842954624, 12851345792, - 12859732352, 12868122496, 12876512128, 12884901248, 12893289088, - 12901672832, 12910067584, 12918455168, 12926842496, 12935232896, - 12943620736, 12952009856, 12960396928, 12968786816, 12977176192, - 12985563776, 12993951104, 13002341504, 13010730368, 13019115392, - 13027506304, 13035895168, 13044272512, 13052673152, 13061062528, - 13069446272, 13077838976, 13086227072, 13094613632, 13103000192, - 13111393664, 13119782528, 13128157568, 13136559232, 13144945024, - 13153329536, 13161724288, 13170111872, 13178502784, 13186884736, - 13195279744, 13203667072, 13212057472, 13220445824, 13228832128, - 13237221248, 13245610624, 13254000512, 13262388352, 13270777472, - 13279166336, 13287553408, 13295943296, 13304331904, 13312719488, - 13321108096, 13329494656, 13337885824, 13346274944, 13354663808, - 13363051136, 13371439232, 13379825024, 13388210816, 13396605056, - 13404995456, 13413380224, 13421771392, 13430159744, 13438546048, - 13446937216, 13455326848, 13463708288, 13472103808, 13480492672, - 13488875648, 13497269888, 13505657728, 13514045312, 13522435712, - 13530824576, 13539210112, 13547599232, 13555989376, 13564379008, - 13572766336, 13581154432, 13589544832, 13597932928, 13606320512, - 13614710656, 13623097472, 13631477632, 13639874944, 13648264064, - 13656652928, 13665041792, 13673430656, 13681818496, 13690207616, - 13698595712, 13706982272, 13715373184, 13723762048, 13732150144, - 13740536704, 13748926592, 13757316224, 13765700992, 13774090112, - 13782477952, 13790869376, 13799259008, 13807647872, 13816036736, - 13824425344, 13832814208, 13841202304, 13849591424, 13857978752, - 13866368896, 13874754688, 13883145344, 13891533184, 13899919232, - 13908311168, 13916692096, 13925085056, 13933473152, 13941866368, - 13950253696, 13958643584, 13967032192, 13975417216, 13983807616, - 13992197504, 14000582272, 14008973696, 14017363072, 14025752192, - 14034137984, 14042528384, 14050918016, 14059301504, 14067691648, - 14076083584, 14084470144, 14092852352, 14101249664, 14109635968, - 14118024832, 14126407552, 14134804352, 14143188608, 14151577984, - 14159968384, 14168357248, 14176741504, 14185127296, 14193521024, - 14201911424, 14210301824, 14218685056, 14227067264, 14235467392, - 14243855488, 14252243072, 14260630144, 14269021568, 14277409408, - 14285799296, 14294187904, 14302571392, 14310961792, 14319353728, - 14327738752, 14336130944, 14344518784, 14352906368, 14361296512, - 14369685376, 14378071424, 14386462592, 14394848128, 14403230848, - 14411627392, 14420013952, 14428402304, 14436793472, 14445181568, - 14453569664, 14461959808, 14470347904, 14478737024, 14487122816, - 14495511424, 14503901824, 14512291712, 14520677504, 14529064832, - 14537456768, 14545845632, 14554234496, 14562618496, 14571011456, - 14579398784, 14587789184, 14596172672, 14604564608, 14612953984, - 14621341312, 14629724288, 14638120832, 14646503296, 14654897536, - 14663284864, 14671675264, 14680061056, 14688447616, 14696835968, - 14705228416, 14713616768, 14722003328, 14730392192, 14738784128, - 14747172736, 14755561088, 14763947648, 14772336512, 14780725376, - 14789110144, 14797499776, 14805892736, 14814276992, 14822670208, - 14831056256, 14839444352, 14847836032, 14856222848, 14864612992, - 14872997504, 14881388672, 14889775744, 14898165376, 14906553472, - 14914944896, 14923329664, 14931721856, 14940109696, 14948497024, - 14956887424, 14965276544, 14973663616, 14982053248, 14990439808, - 14998830976, 15007216768, 15015605888, 15023995264, 15032385152, - 15040768384, 15049154944, 15057549184, 15065939072, 15074328448, - 15082715008, 15091104128, 15099493504, 15107879296, 15116269184, - 15124659584, 15133042304, 15141431936, 15149824384, 15158214272, - 15166602368, 15174991232, 15183378304, 15191760512, 15200154496, - 15208542592, 15216931712, 15225323392, 15233708416, 15242098048, - 15250489216, 15258875264, 15267265408, 15275654528, 15284043136, - 15292431488, 15300819584, 15309208192, 15317596544, 15325986176, - 15334374784, 15342763648, 15351151744, 15359540608, 15367929728, - 15376318336, 15384706432, 15393092992, 15401481856, 15409869952, - 15418258816, 15426649984, 15435037568, 15443425664, 15451815296, - 15460203392, 15468589184, 15476979328, 15485369216, 15493755776, - 15502146944, 15510534272, 15518924416, 15527311232, 15535699072, - 15544089472, 15552478336, 15560866688, 15569254528, 15577642624, - 15586031488, 15594419072, 15602809472, 15611199104, 15619586432, - 15627975296, 15636364928, 15644753792, 15653141888, 15661529216, - 15669918848, 15678305152, 15686696576, 15695083136, 15703474048, - 15711861632, 15720251264, 15728636288, 15737027456, 15745417088, - 15753804928, 15762194048, 15770582656, 15778971008, 15787358336, - 15795747712, 15804132224, 15812523392, 15820909696, 15829300096, - 15837691264, 15846071936, 15854466944, 15862855808, 15871244672, - 15879634816, 15888020608, 15896409728, 15904799104, 15913185152, - 15921577088, 15929966464, 15938354816, 15946743424, 15955129472, - 15963519872, 15971907968, 15980296064, 15988684928, 15997073024, - 16005460864, 16013851264, 16022241152, 16030629248, 16039012736, - 16047406976, 16055794816, 16064181376, 16072571264, 16080957824, - 16089346688, 16097737856, 16106125184, 16114514816, 16122904192, - 16131292544, 16139678848, 16148066944, 16156453504, 16164839552, - 16173236096, 16181623424, 16190012032, 16198401152, 16206790528, - 16215177344, 16223567744, 16231956352, 16240344704, 16248731008, - 16257117824, 16265504384, 16273898624, 16282281856, 16290668672, - 16299064192, 16307449216, 16315842176, 16324230016, 16332613504, - 16341006464, 16349394304, 16357783168, 16366172288, 16374561664, - 16382951296, 16391337856, 16399726208, 16408116352, 16416505472, - 16424892032, 16433282176, 16441668224, 16450058624, 16458448768, - 16466836864, 16475224448, 16483613056, 16492001408, 16500391808, - 16508779648, 16517166976, 16525555328, 16533944192, 16542330752, - 16550719616, 16559110528, 16567497088, 16575888512, 16584274816, - 16592665472, 16601051008, 16609442944, 16617832064, 16626218624, - 16634607488, 16642996096, 16651385728, 16659773824, 16668163712, - 16676552576, 16684938112, 16693328768, 16701718144, 16710095488, - 16718492288, 16726883968, 16735272832, 16743661184, 16752049792, - 16760436608, 16768827008, 16777214336, 16785599104, 16793992832, - 16802381696, 16810768768, 16819151744, 16827542656, 16835934848, - 16844323712, 16852711552, 16861101952, 16869489536, 16877876864, - 16886265728, 16894653056, 16903044736, 16911431296, 16919821696, - 16928207488, 16936592768, 16944987776, 16953375616, 16961763968, - 16970152832, 16978540928, 16986929536, 16995319168, 17003704448, - 17012096896, 17020481152, 17028870784, 17037262208, 17045649536, - 17054039936, 17062426496, 17070814336, 17079205504, 17087592064, - 17095978112, 17104369024, 17112759424, 17121147776, 17129536384, - 17137926016, 17146314368, 17154700928, 17163089792, 17171480192, - 17179864192, 17188256896, 17196644992, 17205033856, 17213423488, - 17221811072, 17230198912, 17238588032, 17246976896, 17255360384, - 17263754624, 17272143232, 17280530048, 17288918912, 17297309312, - 17305696384, 17314085504, 17322475136, 17330863744, 17339252096, - 17347640192, 17356026496, 17364413824, 17372796544, 17381190016, - 17389583488, 17397972608, 17406360704, 17414748544, 17423135872, - 17431527296, 17439915904, 17448303232, 17456691584, 17465081728, - 17473468288, 17481857408, 17490247552, 17498635904, 17507022464, - 17515409024, 17523801728, 17532189824, 17540577664, 17548966016, - 17557353344, 17565741184, 17574131584, 17582519168, 17590907008, - 17599296128, 17607687808, 17616076672, 17624455808, 17632852352, - 17641238656, 17649630848, 17658018944, 17666403968, 17674794112, - 17683178368, 17691573376, 17699962496, 17708350592, 17716739968, - 17725126528, 17733517184, 17741898112, 17750293888, 17758673024, - 17767070336, 17775458432, 17783848832, 17792236928, 17800625536, - 17809012352, 17817402752, 17825785984, 17834178944, 17842563968, - 17850955648, 17859344512, 17867732864, 17876119424, 17884511872, - 17892900224, 17901287296, 17909677696, 17918058112, 17926451072, - 17934843776, 17943230848, 17951609216, 17960008576, 17968397696, - 17976784256, 17985175424, 17993564032, 18001952128, 18010339712, - 18018728576, 18027116672, 18035503232, 18043894144, 18052283264, - 18060672128, 18069056384, 18077449856, 18085837184, 18094225792, - 18102613376, 18111004544, 18119388544, 18127781248, 18136170368, - 18144558976, 18152947328, 18161336192, 18169724288, 18178108544, - 18186498944, 18194886784, 18203275648, 18211666048, 18220048768, - 18228444544, 18236833408, 18245220736} - -// cacheSizes is a lookup table for the ethash verification cache size for the -// first 2048 epochs (i.e. 61440000 blocks). -var cacheSizes = [maxEpoch]uint64{ - 16776896, 16907456, 17039296, 17170112, 17301056, 17432512, 17563072, - 17693888, 17824192, 17955904, 18087488, 18218176, 18349504, 18481088, - 18611392, 18742336, 18874304, 19004224, 19135936, 19267264, 19398208, - 19529408, 19660096, 19791424, 19922752, 20053952, 20184896, 20315968, - 20446912, 20576576, 20709184, 20840384, 20971072, 21102272, 21233216, - 21364544, 21494848, 21626816, 21757376, 21887552, 22019392, 22151104, - 22281536, 22412224, 22543936, 22675264, 22806464, 22935872, 23068096, - 23198272, 23330752, 23459008, 23592512, 23723968, 23854912, 23986112, - 24116672, 24247616, 24378688, 24509504, 24640832, 24772544, 24903488, - 25034432, 25165376, 25296704, 25427392, 25558592, 25690048, 25820096, - 25951936, 26081728, 26214208, 26345024, 26476096, 26606656, 26737472, - 26869184, 26998208, 27131584, 27262528, 27393728, 27523904, 27655744, - 27786688, 27917888, 28049344, 28179904, 28311488, 28441792, 28573504, - 28700864, 28835648, 28966208, 29096768, 29228608, 29359808, 29490752, - 29621824, 29752256, 29882816, 30014912, 30144448, 30273728, 30406976, - 30538432, 30670784, 30799936, 30932672, 31063744, 31195072, 31325248, - 31456192, 31588288, 31719232, 31850432, 31981504, 32110784, 32243392, - 32372672, 32505664, 32636608, 32767808, 32897344, 33029824, 33160768, - 33289664, 33423296, 33554368, 33683648, 33816512, 33947456, 34076992, - 34208704, 34340032, 34471744, 34600256, 34734016, 34864576, 34993984, - 35127104, 35258176, 35386688, 35518528, 35650624, 35782336, 35910976, - 36044608, 36175808, 36305728, 36436672, 36568384, 36699968, 36830656, - 36961984, 37093312, 37223488, 37355072, 37486528, 37617472, 37747904, - 37879232, 38009792, 38141888, 38272448, 38403392, 38535104, 38660672, - 38795584, 38925632, 39059264, 39190336, 39320768, 39452096, 39581632, - 39713984, 39844928, 39974848, 40107968, 40238144, 40367168, 40500032, - 40631744, 40762816, 40894144, 41023552, 41155904, 41286208, 41418304, - 41547712, 41680448, 41811904, 41942848, 42073792, 42204992, 42334912, - 42467008, 42597824, 42729152, 42860096, 42991552, 43122368, 43253696, - 43382848, 43515712, 43646912, 43777088, 43907648, 44039104, 44170432, - 44302144, 44433344, 44564288, 44694976, 44825152, 44956864, 45088448, - 45219008, 45350464, 45481024, 45612608, 45744064, 45874496, 46006208, - 46136768, 46267712, 46399424, 46529344, 46660672, 46791488, 46923328, - 47053504, 47185856, 47316928, 47447872, 47579072, 47710144, 47839936, - 47971648, 48103232, 48234176, 48365248, 48496192, 48627136, 48757312, - 48889664, 49020736, 49149248, 49283008, 49413824, 49545152, 49675712, - 49807168, 49938368, 50069056, 50200256, 50331584, 50462656, 50593472, - 50724032, 50853952, 50986048, 51117632, 51248576, 51379904, 51510848, - 51641792, 51773248, 51903296, 52035136, 52164032, 52297664, 52427968, - 52557376, 52690112, 52821952, 52952896, 53081536, 53213504, 53344576, - 53475776, 53608384, 53738816, 53870528, 54000832, 54131776, 54263744, - 54394688, 54525248, 54655936, 54787904, 54918592, 55049152, 55181248, - 55312064, 55442752, 55574336, 55705024, 55836224, 55967168, 56097856, - 56228672, 56358592, 56490176, 56621888, 56753728, 56884928, 57015488, - 57146816, 57278272, 57409216, 57540416, 57671104, 57802432, 57933632, - 58064576, 58195264, 58326976, 58457408, 58588864, 58720192, 58849984, - 58981696, 59113024, 59243456, 59375552, 59506624, 59637568, 59768512, - 59897792, 60030016, 60161984, 60293056, 60423872, 60554432, 60683968, - 60817216, 60948032, 61079488, 61209664, 61341376, 61471936, 61602752, - 61733696, 61865792, 61996736, 62127808, 62259136, 62389568, 62520512, - 62651584, 62781632, 62910784, 63045056, 63176128, 63307072, 63438656, - 63569216, 63700928, 63831616, 63960896, 64093888, 64225088, 64355392, - 64486976, 64617664, 64748608, 64879424, 65009216, 65142464, 65273792, - 65402816, 65535424, 65666752, 65797696, 65927744, 66060224, 66191296, - 66321344, 66453056, 66584384, 66715328, 66846656, 66977728, 67108672, - 67239104, 67370432, 67501888, 67631296, 67763776, 67895104, 68026304, - 68157248, 68287936, 68419264, 68548288, 68681408, 68811968, 68942912, - 69074624, 69205568, 69337024, 69467584, 69599168, 69729472, 69861184, - 69989824, 70122944, 70253888, 70385344, 70515904, 70647232, 70778816, - 70907968, 71040832, 71171648, 71303104, 71432512, 71564992, 71695168, - 71826368, 71958464, 72089536, 72219712, 72350144, 72482624, 72613568, - 72744512, 72875584, 73006144, 73138112, 73268672, 73400128, 73530944, - 73662272, 73793344, 73924544, 74055104, 74185792, 74316992, 74448832, - 74579392, 74710976, 74841664, 74972864, 75102784, 75233344, 75364544, - 75497024, 75627584, 75759296, 75890624, 76021696, 76152256, 76283072, - 76414144, 76545856, 76676672, 76806976, 76937792, 77070016, 77200832, - 77331392, 77462464, 77593664, 77725376, 77856448, 77987776, 78118336, - 78249664, 78380992, 78511424, 78642496, 78773056, 78905152, 79033664, - 79166656, 79297472, 79429568, 79560512, 79690816, 79822784, 79953472, - 80084672, 80214208, 80346944, 80477632, 80608576, 80740288, 80870848, - 81002048, 81133504, 81264448, 81395648, 81525952, 81657536, 81786304, - 81919808, 82050112, 82181312, 82311616, 82443968, 82573376, 82705984, - 82835776, 82967744, 83096768, 83230528, 83359552, 83491264, 83622464, - 83753536, 83886016, 84015296, 84147776, 84277184, 84409792, 84540608, - 84672064, 84803008, 84934336, 85065152, 85193792, 85326784, 85458496, - 85589312, 85721024, 85851968, 85982656, 86112448, 86244416, 86370112, - 86506688, 86637632, 86769344, 86900672, 87031744, 87162304, 87293632, - 87424576, 87555392, 87687104, 87816896, 87947968, 88079168, 88211264, - 88341824, 88473152, 88603712, 88735424, 88862912, 88996672, 89128384, - 89259712, 89390272, 89521984, 89652544, 89783872, 89914816, 90045376, - 90177088, 90307904, 90438848, 90569152, 90700096, 90832832, 90963776, - 91093696, 91223744, 91356992, 91486784, 91618496, 91749824, 91880384, - 92012224, 92143552, 92273344, 92405696, 92536768, 92666432, 92798912, - 92926016, 93060544, 93192128, 93322816, 93453632, 93583936, 93715136, - 93845056, 93977792, 94109504, 94240448, 94371776, 94501184, 94632896, - 94764224, 94895552, 95023424, 95158208, 95287744, 95420224, 95550016, - 95681216, 95811904, 95943872, 96075328, 96203584, 96337856, 96468544, - 96599744, 96731072, 96860992, 96992576, 97124288, 97254848, 97385536, - 97517248, 97647808, 97779392, 97910464, 98041408, 98172608, 98303168, - 98434496, 98565568, 98696768, 98827328, 98958784, 99089728, 99220928, - 99352384, 99482816, 99614272, 99745472, 99876416, 100007104, - 100138048, 100267072, 100401088, 100529984, 100662592, 100791872, - 100925248, 101056064, 101187392, 101317952, 101449408, 101580608, - 101711296, 101841728, 101973824, 102104896, 102235712, 102366016, - 102498112, 102628672, 102760384, 102890432, 103021888, 103153472, - 103284032, 103415744, 103545152, 103677248, 103808576, 103939648, - 104070976, 104201792, 104332736, 104462528, 104594752, 104725952, - 104854592, 104988608, 105118912, 105247808, 105381184, 105511232, - 105643072, 105774784, 105903296, 106037056, 106167872, 106298944, - 106429504, 106561472, 106691392, 106822592, 106954304, 107085376, - 107216576, 107346368, 107478464, 107609792, 107739712, 107872192, - 108003136, 108131392, 108265408, 108396224, 108527168, 108657344, - 108789568, 108920384, 109049792, 109182272, 109312576, 109444928, - 109572928, 109706944, 109837888, 109969088, 110099648, 110230976, - 110362432, 110492992, 110624704, 110755264, 110886208, 111017408, - 111148864, 111279296, 111410752, 111541952, 111673024, 111803456, - 111933632, 112066496, 112196416, 112328512, 112457792, 112590784, - 112715968, 112852672, 112983616, 113114944, 113244224, 113376448, - 113505472, 113639104, 113770304, 113901376, 114031552, 114163264, - 114294592, 114425536, 114556864, 114687424, 114818624, 114948544, - 115080512, 115212224, 115343296, 115473472, 115605184, 115736128, - 115867072, 115997248, 116128576, 116260288, 116391488, 116522944, - 116652992, 116784704, 116915648, 117046208, 117178304, 117308608, - 117440192, 117569728, 117701824, 117833024, 117964096, 118094656, - 118225984, 118357312, 118489024, 118617536, 118749632, 118882112, - 119012416, 119144384, 119275328, 119406016, 119537344, 119668672, - 119798464, 119928896, 120061376, 120192832, 120321728, 120454336, - 120584512, 120716608, 120848192, 120979136, 121109056, 121241408, - 121372352, 121502912, 121634752, 121764416, 121895744, 122027072, - 122157632, 122289088, 122421184, 122550592, 122682944, 122813888, - 122945344, 123075776, 123207488, 123338048, 123468736, 123600704, - 123731264, 123861952, 123993664, 124124608, 124256192, 124386368, - 124518208, 124649024, 124778048, 124911296, 125041088, 125173696, - 125303744, 125432896, 125566912, 125696576, 125829056, 125958592, - 126090304, 126221248, 126352832, 126483776, 126615232, 126746432, - 126876608, 127008704, 127139392, 127270336, 127401152, 127532224, - 127663552, 127794752, 127925696, 128055232, 128188096, 128319424, - 128449856, 128581312, 128712256, 128843584, 128973632, 129103808, - 129236288, 129365696, 129498944, 129629888, 129760832, 129892288, - 130023104, 130154048, 130283968, 130416448, 130547008, 130678336, - 130807616, 130939456, 131071552, 131202112, 131331776, 131464384, - 131594048, 131727296, 131858368, 131987392, 132120256, 132250816, - 132382528, 132513728, 132644672, 132774976, 132905792, 133038016, - 133168832, 133299392, 133429312, 133562048, 133692992, 133823296, - 133954624, 134086336, 134217152, 134348608, 134479808, 134607296, - 134741056, 134872384, 135002944, 135134144, 135265472, 135396544, - 135527872, 135659072, 135787712, 135921472, 136052416, 136182848, - 136313792, 136444864, 136576448, 136707904, 136837952, 136970048, - 137099584, 137232064, 137363392, 137494208, 137625536, 137755712, - 137887424, 138018368, 138149824, 138280256, 138411584, 138539584, - 138672832, 138804928, 138936128, 139066688, 139196864, 139328704, - 139460032, 139590208, 139721024, 139852864, 139984576, 140115776, - 140245696, 140376512, 140508352, 140640064, 140769856, 140902336, - 141032768, 141162688, 141294016, 141426496, 141556544, 141687488, - 141819584, 141949888, 142080448, 142212544, 142342336, 142474432, - 142606144, 142736192, 142868288, 142997824, 143129408, 143258944, - 143392448, 143523136, 143653696, 143785024, 143916992, 144045632, - 144177856, 144309184, 144440768, 144570688, 144701888, 144832448, - 144965056, 145096384, 145227584, 145358656, 145489856, 145620928, - 145751488, 145883072, 146011456, 146144704, 146275264, 146407232, - 146538176, 146668736, 146800448, 146931392, 147062336, 147193664, - 147324224, 147455936, 147586624, 147717056, 147848768, 147979456, - 148110784, 148242368, 148373312, 148503232, 148635584, 148766144, - 148897088, 149028416, 149159488, 149290688, 149420224, 149551552, - 149683136, 149814976, 149943616, 150076352, 150208064, 150338624, - 150470464, 150600256, 150732224, 150862784, 150993088, 151125952, - 151254976, 151388096, 151519168, 151649728, 151778752, 151911104, - 152042944, 152174144, 152304704, 152435648, 152567488, 152698816, - 152828992, 152960576, 153091648, 153222976, 153353792, 153484096, - 153616192, 153747008, 153878336, 154008256, 154139968, 154270912, - 154402624, 154533824, 154663616, 154795712, 154926272, 155057984, - 155188928, 155319872, 155450816, 155580608, 155712064, 155843392, - 155971136, 156106688, 156237376, 156367424, 156499264, 156630976, - 156761536, 156892352, 157024064, 157155008, 157284416, 157415872, - 157545536, 157677248, 157810496, 157938112, 158071744, 158203328, - 158334656, 158464832, 158596288, 158727616, 158858048, 158988992, - 159121216, 159252416, 159381568, 159513152, 159645632, 159776192, - 159906496, 160038464, 160169536, 160300352, 160430656, 160563008, - 160693952, 160822208, 160956352, 161086784, 161217344, 161349184, - 161480512, 161611456, 161742272, 161873216, 162002752, 162135872, - 162266432, 162397888, 162529216, 162660032, 162790976, 162922048, - 163052096, 163184576, 163314752, 163446592, 163577408, 163707968, - 163839296, 163969984, 164100928, 164233024, 164364224, 164494912, - 164625856, 164756672, 164887616, 165019072, 165150016, 165280064, - 165412672, 165543104, 165674944, 165805888, 165936832, 166067648, - 166198336, 166330048, 166461248, 166591552, 166722496, 166854208, - 166985408, 167116736, 167246656, 167378368, 167508416, 167641024, - 167771584, 167903168, 168034112, 168164032, 168295744, 168427456, - 168557632, 168688448, 168819136, 168951616, 169082176, 169213504, - 169344832, 169475648, 169605952, 169738048, 169866304, 169999552, - 170131264, 170262464, 170393536, 170524352, 170655424, 170782016, - 170917696, 171048896, 171179072, 171310784, 171439936, 171573184, - 171702976, 171835072, 171966272, 172097216, 172228288, 172359232, - 172489664, 172621376, 172747712, 172883264, 173014208, 173144512, - 173275072, 173407424, 173539136, 173669696, 173800768, 173931712, - 174063424, 174193472, 174325696, 174455744, 174586816, 174718912, - 174849728, 174977728, 175109696, 175242688, 175374272, 175504832, - 175636288, 175765696, 175898432, 176028992, 176159936, 176291264, - 176422592, 176552512, 176684864, 176815424, 176946496, 177076544, - 177209152, 177340096, 177470528, 177600704, 177731648, 177864256, - 177994816, 178126528, 178257472, 178387648, 178518464, 178650176, - 178781888, 178912064, 179044288, 179174848, 179305024, 179436736, - 179568448, 179698496, 179830208, 179960512, 180092608, 180223808, - 180354752, 180485696, 180617152, 180748096, 180877504, 181009984, - 181139264, 181272512, 181402688, 181532608, 181663168, 181795136, - 181926592, 182057536, 182190016, 182320192, 182451904, 182582336, - 182713792, 182843072, 182976064, 183107264, 183237056, 183368384, - 183494848, 183631424, 183762752, 183893824, 184024768, 184154816, - 184286656, 184417984, 184548928, 184680128, 184810816, 184941248, - 185072704, 185203904, 185335616, 185465408, 185596352, 185727296, - 185859904, 185989696, 186121664, 186252992, 186383552, 186514112, - 186645952, 186777152, 186907328, 187037504, 187170112, 187301824, - 187429184, 187562048, 187693504, 187825472, 187957184, 188087104, - 188218304, 188349376, 188481344, 188609728, 188743616, 188874304, - 189005248, 189136448, 189265088, 189396544, 189528128, 189660992, - 189791936, 189923264, 190054208, 190182848, 190315072, 190447424, - 190577984, 190709312, 190840768, 190971328, 191102656, 191233472, - 191364032, 191495872, 191626816, 191758016, 191888192, 192020288, - 192148928, 192282176, 192413504, 192542528, 192674752, 192805952, - 192937792, 193068608, 193198912, 193330496, 193462208, 193592384, - 193723456, 193854272, 193985984, 194116672, 194247232, 194379712, - 194508352, 194641856, 194772544, 194900672, 195035072, 195166016, - 195296704, 195428032, 195558592, 195690304, 195818176, 195952576, - 196083392, 196214336, 196345792, 196476736, 196607552, 196739008, - 196869952, 197000768, 197130688, 197262784, 197394368, 197523904, - 197656384, 197787584, 197916608, 198049472, 198180544, 198310208, - 198442432, 198573632, 198705088, 198834368, 198967232, 199097792, - 199228352, 199360192, 199491392, 199621696, 199751744, 199883968, - 200014016, 200146624, 200276672, 200408128, 200540096, 200671168, - 200801984, 200933312, 201062464, 201194944, 201326144, 201457472, - 201588544, 201719744, 201850816, 201981632, 202111552, 202244032, - 202374464, 202505152, 202636352, 202767808, 202898368, 203030336, - 203159872, 203292608, 203423296, 203553472, 203685824, 203816896, - 203947712, 204078272, 204208192, 204341056, 204472256, 204603328, - 204733888, 204864448, 204996544, 205125568, 205258304, 205388864, - 205517632, 205650112, 205782208, 205913536, 206044736, 206176192, - 206307008, 206434496, 206569024, 206700224, 206831168, 206961856, - 207093056, 207223616, 207355328, 207486784, 207616832, 207749056, - 207879104, 208010048, 208141888, 208273216, 208404032, 208534336, - 208666048, 208796864, 208927424, 209059264, 209189824, 209321792, - 209451584, 209582656, 209715136, 209845568, 209976896, 210106432, - 210239296, 210370112, 210501568, 210630976, 210763712, 210894272, - 211024832, 211156672, 211287616, 211418176, 211549376, 211679296, - 211812032, 211942592, 212074432, 212204864, 212334016, 212467648, - 212597824, 212727616, 212860352, 212991424, 213120832, 213253952, - 213385024, 213515584, 213645632, 213777728, 213909184, 214040128, - 214170688, 214302656, 214433728, 214564544, 214695232, 214826048, - 214956992, 215089088, 215219776, 215350592, 215482304, 215613248, - 215743552, 215874752, 216005312, 216137024, 216267328, 216399296, - 216530752, 216661696, 216790592, 216923968, 217054528, 217183168, - 217316672, 217448128, 217579072, 217709504, 217838912, 217972672, - 218102848, 218233024, 218364736, 218496832, 218627776, 218759104, - 218888896, 219021248, 219151936, 219281728, 219413056, 219545024, - 219675968, 219807296, 219938624, 220069312, 220200128, 220331456, - 220461632, 220592704, 220725184, 220855744, 220987072, 221117888, - 221249216, 221378368, 221510336, 221642048, 221772736, 221904832, - 222031808, 222166976, 222297536, 222428992, 222559936, 222690368, - 222820672, 222953152, 223083968, 223213376, 223345984, 223476928, - 223608512, 223738688, 223869376, 224001472, 224132672, 224262848, - 224394944, 224524864, 224657344, 224788288, 224919488, 225050432, - 225181504, 225312704, 225443776, 225574592, 225704768, 225834176, - 225966784, 226097216, 226229824, 226360384, 226491712, 226623424, - 226754368, 226885312, 227015104, 227147456, 227278528, 227409472, - 227539904, 227669696, 227802944, 227932352, 228065216, 228196288, - 228326464, 228457792, 228588736, 228720064, 228850112, 228981056, - 229113152, 229243328, 229375936, 229505344, 229636928, 229769152, - 229894976, 230030272, 230162368, 230292416, 230424512, 230553152, - 230684864, 230816704, 230948416, 231079616, 231210944, 231342016, - 231472448, 231603776, 231733952, 231866176, 231996736, 232127296, - 232259392, 232388672, 232521664, 232652608, 232782272, 232914496, - 233043904, 233175616, 233306816, 233438528, 233569984, 233699776, - 233830592, 233962688, 234092224, 234221888, 234353984, 234485312, - 234618304, 234749888, 234880832, 235011776, 235142464, 235274048, - 235403456, 235535936, 235667392, 235797568, 235928768, 236057152, - 236190272, 236322752, 236453312, 236583616, 236715712, 236846528, - 236976448, 237108544, 237239104, 237371072, 237501632, 237630784, - 237764416, 237895232, 238026688, 238157632, 238286912, 238419392, - 238548032, 238681024, 238812608, 238941632, 239075008, 239206336, - 239335232, 239466944, 239599168, 239730496, 239861312, 239992384, - 240122816, 240254656, 240385856, 240516928, 240647872, 240779072, - 240909632, 241040704, 241171904, 241302848, 241433408, 241565248, - 241696192, 241825984, 241958848, 242088256, 242220224, 242352064, - 242481856, 242611648, 242744896, 242876224, 243005632, 243138496, - 243268672, 243400384, 243531712, 243662656, 243793856, 243924544, - 244054592, 244187072, 244316608, 244448704, 244580032, 244710976, - 244841536, 244972864, 245104448, 245233984, 245365312, 245497792, - 245628736, 245759936, 245889856, 246021056, 246152512, 246284224, - 246415168, 246545344, 246675904, 246808384, 246939584, 247070144, - 247199552, 247331648, 247463872, 247593536, 247726016, 247857088, - 247987648, 248116928, 248249536, 248380736, 248512064, 248643008, - 248773312, 248901056, 249036608, 249167552, 249298624, 249429184, - 249560512, 249692096, 249822784, 249954112, 250085312, 250215488, - 250345792, 250478528, 250608704, 250739264, 250870976, 251002816, - 251133632, 251263552, 251395136, 251523904, 251657792, 251789248, - 251919424, 252051392, 252182464, 252313408, 252444224, 252575552, - 252706624, 252836032, 252968512, 253099712, 253227584, 253361728, - 253493056, 253623488, 253754432, 253885504, 254017216, 254148032, - 254279488, 254410432, 254541376, 254672576, 254803264, 254933824, - 255065792, 255196736, 255326528, 255458752, 255589952, 255721408, - 255851072, 255983296, 256114624, 256244416, 256374208, 256507712, - 256636096, 256768832, 256900544, 257031616, 257162176, 257294272, - 257424448, 257555776, 257686976, 257818432, 257949632, 258079552, - 258211136, 258342464, 258473408, 258603712, 258734656, 258867008, - 258996544, 259127744, 259260224, 259391296, 259522112, 259651904, - 259784384, 259915328, 260045888, 260175424, 260308544, 260438336, - 260570944, 260700992, 260832448, 260963776, 261092672, 261226304, - 261356864, 261487936, 261619648, 261750592, 261879872, 262011968, - 262143424, 262274752, 262404416, 262537024, 262667968, 262799296, - 262928704, 263061184, 263191744, 263322944, 263454656, 263585216, - 263716672, 263847872, 263978944, 264108608, 264241088, 264371648, - 264501184, 264632768, 264764096, 264895936, 265024576, 265158464, - 265287488, 265418432, 265550528, 265681216, 265813312, 265943488, - 266075968, 266206144, 266337728, 266468032, 266600384, 266731072, - 266862272, 266993344, 267124288, 267255616, 267386432, 267516992, - 267648704, 267777728, 267910592, 268040512, 268172096, 268302784, - 268435264, 268566208, 268696256, 268828096, 268959296, 269090368, - 269221312, 269352256, 269482688, 269614784, 269745856, 269876416, - 270007616, 270139328, 270270272, 270401216, 270531904, 270663616, - 270791744, 270924736, 271056832, 271186112, 271317184, 271449536, - 271580992, 271711936, 271843136, 271973056, 272105408, 272236352, - 272367296, 272498368, 272629568, 272759488, 272891456, 273022784, - 273153856, 273284672, 273415616, 273547072, 273677632, 273808448, - 273937088, 274071488, 274200896, 274332992, 274463296, 274595392, - 274726208, 274857536, 274988992, 275118656, 275250496, 275382208, - 275513024, 275643968, 275775296, 275906368, 276037184, 276167872, - 276297664, 276429376, 276560576, 276692672, 276822976, 276955072, - 277085632, 277216832, 277347008, 277478848, 277609664, 277740992, - 277868608, 278002624, 278134336, 278265536, 278395328, 278526784, - 278657728, 278789824, 278921152, 279052096, 279182912, 279313088, - 279443776, 279576256, 279706048, 279838528, 279969728, 280099648, - 280230976, 280361408, 280493632, 280622528, 280755392, 280887104, - 281018176, 281147968, 281278912, 281411392, 281542592, 281673152, - 281803712, 281935552, 282066496, 282197312, 282329024, 282458816, - 282590272, 282720832, 282853184, 282983744, 283115072, 283246144, - 283377344, 283508416, 283639744, 283770304, 283901504, 284032576, - 284163136, 284294848, 284426176, 284556992, 284687296, 284819264, - 284950208, 285081536} diff --git a/consensus/ethash/algorithm_test.go b/consensus/ethash/algorithm_test.go deleted file mode 100644 index 3ecd730681..0000000000 --- a/consensus/ethash/algorithm_test.go +++ /dev/null @@ -1,815 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ethash - -import ( - "bytes" - "encoding/binary" - "math/big" - "os" - "reflect" - "sync" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" -) - -// prepare converts an ethash cache or dataset from a byte stream into the internal -// int representation. All ethash methods work with ints to avoid constant byte to -// int conversions as well as to handle both little and big endian systems. -func prepare(dest []uint32, src []byte) { - for i := 0; i < len(dest); i++ { - dest[i] = binary.LittleEndian.Uint32(src[i*4:]) - } -} - -// Tests whether the dataset size calculator works correctly by cross checking the -// hard coded lookup table with the value generated by it. -func TestSizeCalculations(t *testing.T) { - // Verify all the cache and dataset sizes from the lookup table. - for epoch, want := range cacheSizes { - if size := calcCacheSize(epoch); size != want { - t.Errorf("cache %d: cache size mismatch: have %d, want %d", epoch, size, want) - } - } - for epoch, want := range datasetSizes { - if size := calcDatasetSize(epoch); size != want { - t.Errorf("dataset %d: dataset size mismatch: have %d, want %d", epoch, size, want) - } - } -} - -// Tests that verification caches can be correctly generated. -func TestCacheGeneration(t *testing.T) { - tests := []struct { - size uint64 - epoch uint64 - cache []byte - }{ - { - size: 1024, - epoch: 0, - cache: hexutil.MustDecode("0x" + - "7ce2991c951f7bf4c4c1bb119887ee07871eb5339d7b97b8588e85c742de90e5bafd5bbe6ce93a134fb6be9ad3e30db99d9528a2ea7846833f52e9ca119b6b54" + - "8979480c46e19972bd0738779c932c1b43e665a2fd3122fc3ddb2691f353ceb0ed3e38b8f51fd55b6940290743563c9f8fa8822e611924657501a12aafab8a8d" + - "88fb5fbae3a99d14792406672e783a06940a42799b1c38bc28715db6d37cb11f9f6b24e386dc52dd8c286bd8c36fa813dffe4448a9f56ebcbeea866b42f68d22" + - "6c32aae4d695a23cab28fd74af53b0c2efcc180ceaaccc0b2e280103d097a03c1d1b0f0f26ce5f32a90238f9bc49f645db001ef9cd3d13d44743f841fad11a37" + - "fa290c62c16042f703578921f30b9951465aae2af4a5dad43a7341d7b4a62750954965a47a1c3af638dc3495c4d62a9bab843168c9fc0114e79cffd1b2827b01" + - "75d30ba054658f214e946cf24c43b40d3383fbb0493408e5c5392434ca21bbcf43200dfb876c713d201813934fa485f48767c5915745cf0986b1dc0f33e57748" + - "bf483ee2aff4248dfe461ec0504a13628401020fc22638584a8f2f5206a13b2f233898c78359b21c8226024d0a7a93df5eb6c282bdbf005a4aab497e096f2847" + - "76c71cee57932a8fb89f6d6b8743b60a4ea374899a94a2e0f218d5c55818cefb1790c8529a76dba31ebb0f4592d709b49587d2317970d39c086f18dd244291d9" + - "eedb16705e53e3350591bd4ff4566a3595ac0f0ce24b5e112a3d033bc51b6fea0a92296dea7f5e20bf6ee6bc347d868fda193c395b9bb147e55e5a9f67cfe741" + - "7eea7d699b155bd13804204df7ea91fa9249e4474dddf35188f77019c67d201e4c10d7079c5ad492a71afff9a23ca7e900ba7d1bdeaf3270514d8eb35eab8a0a" + - "718bb7273aeb37768fa589ed8ab01fbf4027f4ebdbbae128d21e485f061c20183a9bc2e31edbda0727442e9d58eb0fe198440fe199e02e77c0f7b99973f1f74c" + - "c9089a51ab96c94a84d66e6aa48b2d0a4543adb5a789039a2aa7b335ca85c91026c7d3c894da53ae364188c3fd92f78e01d080399884a47385aa792e38150cda" + - "a8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995c" + - "778401b94a2e66e6993ad67ad3ecdc2acb17779f1ea8606827ec92b11c728f8c3b6d3f04a3e6ed05ff81dd76d5dc5695a50377bc135aaf1671cf68b750315493" + - "6c64510164d53312bf3c41740c7a237b05faf4a191bd8a95dafa068dbcf370255c725900ce5c934f36feadcfe55b687c440574c1f06f39d207a8553d39156a24" + - "845f64fd8324bb85312979dead74f764c9677aab89801ad4f927f1c00f12e28f22422bb44200d1969d9ab377dd6b099dc6dbc3222e9321b2c1e84f8e2f07731c"), - }, - { - size: 1024, - epoch: 1, - cache: hexutil.MustDecode("0x" + - "1f56855d59cc5a085720899b4377a0198f1abe948d85fe5820dc0e346b7c0931b9cde8e541d751de3b2b3275d0aabfae316209d5879297d8bd99f8a033c9d4df" + - "35add1029f4e6404a022d504fb8023e42989aba985a65933b0109c7218854356f9284983c9e7de97de591828ae348b63d1fc78d8db58157344d4e06530ffd422" + - "5c7f6080d451ff94961ec2dd9e28e6d81b49102451676dbdcb6ef1094c1e8b29e7e808d47b2ba5aeb52dabf00d5f0ee08c116289cbf56d8132e5ca557c3d6220" + - "5ba3a48539acabfd4ca3c89e3aaa668e24ffeaeb9eb0136a9fc5a8a676b6d5ad76175eeda0a1fa44b5ff5591079e4b7f581569b6c82416adcb82d7e92980df67" + - "2248c4024013e7be52cf91a82491627d9e6d80eda2770ab82badc5e120cd33a4c84495f718b57396a8f397e797087fad81fa50f0e2f5da71e40816a85de35a96" + - "3cd351364905c45b3116ff25851d43a2ca1d2aa5cdb408440dabef8c57778fc18608bf431d0c7ffd37649a21a7bb9d90def39c821669dbaf165c0262434dfb08" + - "5d057a12de4a7a59fd2dfc931c29c20371abf748b69b618a9bd485b3fb3166cad4d3d27edf0197aabeceb28b96670bdf020f26d1bb9b564aaf82d866bdffd6d4" + - "1aea89e20b15a5d1264ab01d1556bfc2a266081609d60928216bd9646038f07de9fedcc9f2b86ab1b07d7bd88ba1df08b3d89b2ac789001b48a723f217debcb7" + - "090303a3ef50c1d5d99a75c640ec2b401ab149e06511753d8c49cafdde2929ae61e09cc0f0319d262869d21ead9e0cf5ff2de3dbedfb994f32432d2e4aa44c82" + - "7c42781d1477fe03ea0772998e776d63363c6c3edd2d52c89b4d2c9d89cdd90fa33b2b41c8e3f78ef06fe90bcf5cc5756d33a032f16b744141aaa8852bb4cb3a" + - "40792b93489c6d6e56c235ec4aa36c263e9b766a4daaff34b2ea709f9f811aef498a65bfbc1deffd36fcc4d1a123345fac7bf57a1fb50394843cd28976a6c7ff" + - "fe70f7b8d8f384aa06e2c9964c92a8788cef397fffdd35181b42a35d5d98cd7244bbd09e802888d7efc0311ae58e0961e3656205df4bdc553f317df4b6ede4ca" + - "846294a32aec830ab1aa5aac4e78b821c35c70fd752fec353e373bf9be656e775a0111bcbeffdfebd3bd5251d27b9f6971aa561a2bd27a99d61b2ce3965c3726" + - "1e114353e6a31b09340f4078b8a8c6ce6ff4213067a8f21020f78aff4f8b472b701ef730aacb8ce7806ea31b14abe8f8efdd6357ca299d339abc4e43ba324ad1" + - "efe6eb1a5a6e137daa6ec9f6be30931ca368a944cfcf2a0a29f9a9664188f0466e6f078c347f9fe26a9a89d2029462b19245f24ace47aecace6ef85a4e96b31b" + - "5f470eb0165c6375eb8f245d50a25d521d1e569e3b2dccce626752bb26eae624a24511e831a81fab6898a791579f462574ca4851e6588116493dbccc3072e0c5"), - }, - } - for i, tt := range tests { - cache := make([]uint32, tt.size/4) - generateCache(cache, tt.epoch, seedHash(tt.epoch*epochLength+1)) - - want := make([]uint32, tt.size/4) - prepare(want, tt.cache) - - if !reflect.DeepEqual(cache, want) { - t.Errorf("cache %d: content mismatch: have %x, want %x", i, cache, want) - } - } -} - -func TestDatasetGeneration(t *testing.T) { - tests := []struct { - epoch uint64 - cacheSize uint64 - datasetSize uint64 - dataset []byte - }{ - { - epoch: 0, - cacheSize: 1024, - datasetSize: 32 * 1024, - dataset: hexutil.MustDecode("0x" + - "4bc09fbd530a041dd2ec296110a29e8f130f179c59d223f51ecce3126e8b0c74326abc2f32ccd9d7f976bd0944e3ccf8479db39343cbbffa467046ca97e2da63" + - "da5f9d9688c7c33ab7b8aace570e422fa48b24659b72fc534669209d66389ca15b099c5604601e7581488e3bd6925cec0f12d465f8004d4fa84793f8e1e46a1b" + - "31b7298991c6142f4f0b6e6b296728ae5fa63ccb667b61fbb1b078003d18d97b906af157debed5e6c55d5a61cae90c85f9e97d565314a2f9fd9e0c08430547d0" + - "7cfcee3271f921b95c32a11596219abaa30abc62c2c72c6725078c436c677320594df6bcb92134c1b114fffec982a1f68f13a9f812f074b9fb9c78f2cd4c1c90" + - "7ebf1e447f7a422b06303921e3d54f430584d849eaa4b7d652e92a5d659bdfc462adcdd7991e8c66a19da4ddb5390463d073941491859397f135ebbbdbdf5801" + - "cafb873c383893390141ae385515504d74a33608273310c312ba468046d2e20c271a38cc0e3920b39705050e752f34f244fc23ddd17ff18677756a87671d4145" + - "3aebf97e4890da1d645f41eb20da92a8537c787ce419580073c46aa3bb154952993142ec5b4fb6e8f108fd15fc618cd5c27b45a37ee6dcd52a4ce656c0f58604" + - "717ec55f5e592355f1f20e8316f8fd77243734a8b0f50ad93c1d95b5b0482afb22cd0667d935bd6053d7198b54974e10d100df7ca3ec2e0bb5ccce5807b266e0" + - "8429d5fec2ae6ae1cc7c5efc27f19c89d4b4a6c5c0b9397886dac635ba37446ff528b582457a4fe7f803f1a47903574f8982d4a679b627396a4e97aaa12fa179" + - "0d31ba52e9010bc3c26ace81f702f86649fe9eeda9ec03b74a8a5cf540d82e22af33ab893564397dfc4edd8b1677350df5b82ab61d24db95f58fd2d78afb49c7" + - "2d2b1fefa8ff6606b8623829cc752ea37d663b945f3f1d48ad07b1416af252f81b55acd8f164da4faa9d9453721b3b795041ce7df7c77edc13865dbe04fee331" + - "47daebe18c183c4a6594a6df3a4d2dc5e3811d805102c9c49286e3d12b38927fa49a7b0cdcb1d799f57118953e31c560aae213a1799d59a78ae68f0590347061" + - "fc2668caf08f860452f6b7d3ebc1efecc2e1227d33296b1f1850360dee7236e85274eaede4d18a58b4261ce1f6a7d283dcf64e6d021813f82a566354445327e5" + - "6217279b2393fe5aa0f9eb149d4866e1105106bcc221810ceaf053f2ec733d8a22f409c1baf955e50184005c5d55de907de97f5f713b62ae10937e1a7af6267b" + - "d2a239e8589017197c343b81540bc26bc52bffd5336fb1da1202a511c7175014d2f500b9d9ce78e4b9f2b158d0fb27af352b6f78c129cad642fe909612c9d658" + - "17a8d7f9195ee97201675a918e3cf520fdc19f92b7e6a3db806d4f3799361334082cc58a22ddb4e4f5760bd1667c177b26be325166c6bbed669a158fc87acd43" + - "a2462e12578d72db6606f9e24ae659ff411ac9b31d696b8354fd08a591622967a14f8468eaaae3907b7818154ba2d6e4581589354d178bb6ae1c03651c44bbf0" + - "e7fa52cb0da09508b5a444aed05a54f416841247a4fe36bd5529029e3adf78b105e22468ed775f4d0954504dd55f2c9b9e6b3a086370b2c0b6fec7efd6914e07" + - "26627edb7a04869a874e31f448271077a7de3031cf81bdbc39848efee6075e0d65fa3a32640e9f0395cf7ec12139992aff0a54e0a7dfe5048b3cc03246b56f7d" + - "3093538a7b87538d8792a665bc589373621b2f3cf47d2c1f8f580fe34d79c6b2a66323ce89808ce0e5cf77700f5a4446c4be01a310e8f7c7ebefe756b0044886" + - "a0477c88ee8ea8c71503748a4cf9eb40ad5c1c8accf7c63c0f43a94ed2b8a5999df3ab9b11b80de73310e036ca88668e640015fcf9cd18eed05517d54896f43e" + - "25e7931b44872c4e4183500e0e8c5103292bca1c0d6b0b00c9acce25d31204bb3e4f255c03a0a0916664e9c831b28b364078109a74411a11afb1e610c7d1c9d4" + - "ba5e10d0ee0da409654d9e7308395e17caeb9caebccb0192679866e6f2ecb5f10044333bb70d61712adb6d74cdec6918ed9a71d9925da576a1e6f4e906a5cd5f" + - "0e94a25e48a4141e4e2770144b63e2449b0f84c82879f34d78440cc430196ba85a213fdac1bcf279a46d7592fa29a876bb7a2efb7081365522a3f06fdceaedd3" + - "cc0335cef9ea570733fe8799bb1b918aa7732b4d175929d80c7844a78e19f2dc6a6febf648f49b40320b0f7d784e7f84e45408d70b046bd01cbd8fdaf606fcd3" + - "02f4e5a48ab8d13e93a246adfcc94f3109e02a7a969986e75b6ced6bf2d11a55ab77488e131b65a06398fa8e384dc90d875584c9b17cdcf2da5dd72a461cd07c" + - "4a955c5fe48509b3284476c42247e086de7d63839b7358cf4ebd9edf9ac8b6fd0c096166405de19c51e8785009d30feb67cdb8ff9ba55459dfdffba8c022e26c" + - "0ebd399e4b76ccb4d5491a862c2c4d8cdf1461a96c9b98150e170efacec980edc00a2c7f6d7c6bea3075627e1eb386a7f1ede1059da81a4ac5cf35aa173c88c5" + - "1818dc0fbc688b68b82ddc225b6c87588e0c680e303e737c82a13e34be58df8b0cb336aeacc698c79e7682ebb69e6cd6bdc5d11790c96afcfa9290f39515142f" + - "5f90b938216a1d14bc049ce3f0ac135722208b989d2557d3520c2186479f179e50fe5b125b8d6638a65047729c6249b9b2c6381c9103c97d1b389cc9cdb31c21" + - "8a2eecbf4b9ad1dcfa57446cde88f96563a544c49d6f5303a84a1b7cf074fca78e67e72c9ffa0c542fb646418c6434b16b771088140725cf2dc723c1a975c4ca" + - "8a80e633721274907353f51e95952c2b403b45750b42ad10961f60473eb54616f61f7b038c5b7eca475d6a2b844994a9eeddce4f7bb49782e50ef78bc13b85d1" + - "9e956f47c60823f3d1981413cb78d309f63a844694861b11b5238961c71f61d82daef6795734f0961e92b9167c57f48e91693e9656fcc6e88f9ce2d373da26bf" + - "45b3dff50211fec72387005a7e04828e4ae7ddd10fc2332acf5f1b0f67adcd863752573c2d24488857bfc58c41af45be7641f5cfff611f184612fc0d695866f4" + - "2b396b1d9881f442c4a995f4b500f02d4ab4b53ad6e01776ab0e244583f01301203a1515f3dbb73906014e36c7143bf882b005f0228ca0562623893c8a24b7c6" + - "4c2c561912010c121b5c3a1e35e75c0b094731e9c0d6acf5a2b1e5b179355525a175640579705f898feb98bffa25633bc126613fa27d2ceb214812902ada23f4" + - "367a78655d0d2276095c9e83dfa79153730103963499c367c5621fecfd0888253df82b3d5716703ef92594cf269310b9e6c892c488edb3bba1d0b216e92f622a" + - "7f8f7f00d2926d81a4c7ca6cef40d240576a8d5541ccf561c8e0e699925d20347ba7493ed6e182cfe3b633e70b3ce3a0d90813574f6fe329c495d3cd46fd5d7e" + - "bdde58d7eafcb134a9a5d3e5d66136e8c9b5d9ecac195dcc44158941c9fe2d87db52a7ddcedc9f82ec160901cc36a9c877af80ceae0563dfa75cabde5d7a7c94" + - "9f24bc190f7c2045368356474ff6eee284e7125d1c5f9a036fbde24cecfd3a30481ce077f20cbcb31924368296abf66ce4834102cf7cb949d1b4c6faa6d006ef" + - "21379cead5d5a39324d41555c46e0b42a1e871143e47f8e6b3d794e75d7a43c282732766d856e04e666ea346657b157404b0fc8534a2dee8243d40a5e37609e6" + - "18bc1d52b91a7623aaf8214a97e4c8c5d860b31c3792b129354a121a7a7e42b50dfbe3ab6590769401eb280545547a43c3a1455355d5d5fdedccb472abfe75b8" + - "f5e7d62b0b31553d8d55de0c3c71e6f5a2abba6fe81e9a42ec1968f235bc4296c1ac5df7430917453384450ab56dafa7c7af764cefa3b0bc861c52ae27692365" + - "9d7d9ed7609958884147acca867909a75bb6a2c364debefaf98c7ff70c7f4acb5cdb81100fd79a48c5139f8bbdc6553b509f1eb0f5d5d31886a602cd669b3f9f" + - "59195a1fa2bcff1170003ba1b2e5e9ad7f2bfcd0573d0f2be9d8fc1773c3a63a2b9292cdbf9b4515c0b1d51772e5ee95303ff493d85314c989e269df4ec3a916" + - "40988a11c6a4ad96f7d0541a150edf444c2b1672aa6d37564453b835c2d39864c05c4366492fc9164bf73795410e7aae8206430403357fec6389142b4976b218" + - "d70622b4098e322f73020a0d045f07668d1e512c6eeed6e2befbfc3a6ac64054396df96fd41f7aeefa0ab1f66bb52ee1a1df066f365fc43ff0800b0398b621f9" + - "a415895268505a81517c44a56dc94e76580fd107dba034bab9f4f4b8a9f881ff34c60c406c47b6d4a998894401006aa88f328393f9cd55a2b4d24db5abbcb05e" + - "20d392f3feab3ca12dac475eb3690f2bf9c699d7d90900d9a840068c8cdda2ca7a27bebd685a26eb01a768259a65ab4d7efc1811c87a5a1f4e5038f6b3dc74a6" + - "b46d9ac58d31bfc22dac23645aeef819329c9419326f22e1c24c53457baf62ae9b92ab5f999d4ef0ccfb5a21b7598340eb2d399ec81588b6a674c5a1e45aa238" + - "c55cae8e1af0f5d64ea378b8afeab263a3a2e5c71cdda4cdb824ae55df2b0260aadf386275ef57781d46f6da3d0b300ea68c14a620c25b5df738c54aef04d63b" + - "7dee06cd225e9ed00e78abcddca5a133d8b5e0d9b287e6436014c5da729442239bddb7ecd3fe34e6f6e530134a03ef45de4ae4fe3bf507f16cdfb9bab1fc90e8" + - "dc565e4a7ead95352c5a894661e5d82c6d0fc47843d5cab12c4013db76c90734cbff34c73d0d873ac9b27b417665f4948469865f33179624860604a9aba2ceb1" + - "68e74b6af3d1ad0bfcac4180ea844339a034b6b2c3e2f61f0c7afbaa76c1ebe93727df1d3db27d59a5cf51b2baaf637b6eb8a20302ef9af0b25dbe3a5e74331c" + - "6b0c8a0cf2a2ad72d2e19797983e09468ea95270dc229f2fa084dd2aa96e722016504f6d82508572d9c30711c3ef41ae3ae2f36cc6f5dddbcb0b40d9499b24c5" + - "4cd36d2927a6b9d57e335e4fca7f0f16887711a8c1ffa0b48bda46c506ca444b7c23e2c8dd086c2a87283d5fc0d58e9a384106837318dc84ffe65b52d4cb9141" + - "2672adfe139c3327350fe3cf355a08c0ca43598a253833e114243c5253077d65643323f5d69b3c7902d91bab7a0928754e7d80afab8d48539fcbe0d9ab83b4db" + - "43a6594c4071df2ef35acd1f53006a570f09104f1776b26a303e2aec93a00d2fd8c952d1ca0e54504cd9b469be7c1e71557ec31467ecc773ee817b17c4418712" + - "163ae86646b20b80c85860e828c48e88f1309c9ff018e6a95f4c1178de6a4f9f5860039511845da7d8727b5d824ba2502d0a3d76ce74372db77c2050c728dd65" + - "b3a15da4f1e1e41c3c2acfebc5618e5e923d503c43a3421d2628ac037c5ce13c74c4ee14d47af02323872f6bf2e8bf09d017ea6e8ec4d3f9fc4fb203ac4e1663" + - "756b11629224c676713a42b1f43dfd6362876be1c4865928688765589e26c8dd8bc04ca18d76ced7f786cdb0fa5028ae53991d5b7b45f93bbd50aeb97300f04e" + - "69c6736f270907f6a7ad76dde0a365183a961bc8385511e0f22ce0cb8f3c42c5d3928621841e30285fb625294865409267dbb0cf91730ba2fb1088fb79789a54" + - "a856311bdca5b0ac0e95fbc79b11c561dc03ea82db182808031e86ec327097143ee761bb62dae8a9f4101fabcac1fc87b3c2080820582dc8a7a8287364550013" + - "08053c781b3eb279c89e817fe97103b6930fef2dbf7728def389403a4283f63ec04ae953784b749f0ea6f08749781cd17fadfd15bb197afd2f4e0a8aade2b1ad" + - "5100cbdce49ed59658993c00e06bf57c0026b97beadc30cd25f586ff03ab40fcd731535c9a1ccb2c99dc7f8815feab767e1237cb069981f28d8fe26bdec24218" + - "488e6086c0ab0efc5d4211fa0726b3a11387df9bb62b863a7b154ca390a268f5e49f50dec45d24bece2a06575cc07a24bfff017d7445024739efb050ace5f345" + - "98dacda843d4ef5bfb2c931dc16ee3dd8b61a6f01d9a7de8bbb6d89ca8695f8ef8bd1cc6e0455848fac7691e6789218790270aef40fba114557fd88ff74fe8fc" + - "476d9b9665d7e45582540710ce92c8dcad1ad8c05642a23a0d58c02db37ae1a0e70fbc5f71b1300fe398c74cbad37fd57379f58dd3e2d3de6860a17acf3c9321" + - "02eb4f9d596497bd849c5bfaf59a83113ef389b6896aa4d4665504a22486299993a9987b2bbdb47d59b3f6ce5d2c9f9ba33b5f0760388ca7f8d8af07c1cd28f5" + - "67a417a59ebde4bb9867d4e7b7b79dd8665602c029e9a16a7718efde3d034f13f7f0b9af1702c335893526cb87afc2100e874b25c37fd666bf34bf6a653c7cf5" + - "44e1fe0286a6723c7d33461dea380b392dad68f79a78fe1b785d7833ca0d1cd68cff472991a625e3099f3ad2cdc99bd37eae35353cecf424098389dbaf1885fd" + - "7db54909a92ee879609eb2e9ef4de1f4338f0df53dbde486ede944ae69869fac701d4f1f48c83757b470ea28c9de2ae5f1ef5d1c91118d16ca0d80b1baf3d314" + - "056949df27a09eff70c9ac50b54feff67a165ce5e22ba2222defedc7c39e02356c3553e97524c1506441527da4f5de121142ccd494f83114b3ca2dc37e15c752" + - "e2faed7d50254124d68f67e26f4f50c9f0edf6e58b916ca830c4e33801dc11039b18292b87b08f4f2edbaaacddcdab78ff3a0004f86034080f2ca4394b14aed4" + - "31e38e3605e6b257bd772954d2f4b846a17df7ed6e5dafa33964d9e56a07a19898fb4dfe8b2ddbd11fa0013e6ebc0e429a5166a43d1ec45557cd1fc1bddbec4b" + - "2e9ca26395394c96395ff8f557bd0f7f805c09f0c18534585b7c7fc1d07f145372983ad77fa804fbb7765934e72beae0929a87cc6bf7f6c242ff5db2d4d5541c" + - "8c366d22e24e1da5379836fc0eb484683285f99f178b98ca170464bdff60ee04584c12c65408102ac6dc7d10bf58a7d770bf1b3c636a48f934f6f4bbdbcc75d3" + - "fc551de3ebaf77006707f6120b3804f2bef9b4bd59f5996610c09ba3953994d1b78a9f3bc3bafeb52266f10755ea842e5b4370c937c09afd34a092ff9b98b4d3" + - "518bc2480d4b132455b7f03774ad76b83b254742117921c31cebeab5f39c145f7f373a5603d17dd95217ba1af37a0aa95b2992efcd02d0bb4ad08ebafb31440f" + - "1ccfce45882b547ee4bf6ec7ecae11ed79fc63b03636c8a14ec4e0f6877eb658d839be2eac0f10a8948e74203f46078ce66aad2764ff05590e2ac7a8dd8b3036" + - "901fcb7ff3369ee989a28e34b9b62e1e607d14da3049ded1a4ee50257195eaaef995bed79ec85111abb522aba1fb306869a1ab381e82943f35345bb5502bb90a" + - "e2a0af77526a84754ee4d600ba7f8ac98705ee687bab949a081849889d7b83a21a3dd34af84dc2b9458230ef0ff44c6398d3c6e48e5c09c399ac4d4c7b285549" + - "e0bcab7fd96de42f072f1cb633e3e250745321049d0d7ecdef4636e70e94c8414e76ecaedd6ee0792e97de11e7dc1e1e1801ad68f9147278e268d7ad76c5bbb7" + - "98386fdc13ca8c77569d96e0debba8ea3b751352136c8f1c8d611a69f1baa9aa4b9d0a476ebd5dd21339ef7f97f09aa86b69a7b114cebe17a6b0e58bf52803d6" + - "fd47d9eac3a988b51e9bca95c546d49367a3126bf8ee44fbd0e77611473a1d3d2de0ce4ea54f9bb7f9dd0d0c065f613a623fad43a445eba294fd00037492914f" + - "b74d10d0b97a0cf9bd3151c3cade89521f36b6fe1aca7f352e79a77d063da5337a7c88d90e9e566bcd97732baa4459305967c2f65adf1a4a4c7991cbc99df3b7" + - "14335a107a97a4ab104bc94fecd1d003fe6d2f22e717853c449881c4ccaa7e7a1e44961a14a47a0d0aa1b1493dd02760ff4d31fbddf5941f93c8e5925d1886e2" + - "8761baef8610fa6be016c8f4fe65bb0f335152d5e94893e274f2ab90118e4c07957d252963755b4b638ffc0a734fbe6e32c2e304b10a46a4eed330d101c4f0ae" + - "011e7f94b89bc0eb9d358a6548b3f0c47ccc3c2d986d381437c49041629c6cbf61bdf0825efe17e4abef128003681450ceeff0e28842895d8e338c247abf81cb" + - "7260fd45042c1f6c630a4b195579721392e577fbfdb9f5b003a8b9a6bc15ae754f6255131a0be600c7b07e2cee1ffe32aad4687f9a429998ed9059a99fd879ea" + - "c4dcb55f4551bbb70c187cf1b162e2ca4a929edd6ec9260877df652622ae073fc63c0d8522d3882ba888ac50a67a68fb6530193f93165093a1d8132e87d8887e" + - "ff2fdab0fbae6ab9506dae61fada4023133d166bcf1956aedc3237c77d1c81dcc84ae957d89367b0fc950c78e58f2cb9c4fd93e16b94421fdecd46c3ff55592e" + - "4374a7f7d8ede9923115770cb416071e8f102d4ad78b891464ffd14f589c238c8e13a4e2a81744d179e7d3ae36cffee75ceb99633face85d077d0c15b3970930" + - "075dc08b420e0a545200895207c5a746a18ce9ab64a50d3dcf44da857fb65e4efc29b2b4d532dc6a03b699dcfd77030a4945e6431273e25f06ad8f913c2a9eb7" + - "59d8d3049868d337e451726d95c4cf8baf381096fc9b62679175dc8f14e52f8b99f212cab6544414c62f17c8323256cce95356dcd351e34c7a1576b17c1406d7" + - "5b8bcca8099a1993df1541ded61b876ae83396b191b719c4b1cbe50d73fc13da352d827ba09aa7fdfef3e4e0273c31ef4fd38b93cf64199c3969a7c09dd5e0f3" + - "ff93a5a7db9c2c1ec25e3060bcb5481c6802e1eca78f31862842ea08e8f92b8e52856c4c9fedd0bf20e386cfdf926425f7756ff41fd3567c5bf334e96e3f492f" + - "74bd0519d8d98efa0b427ba681b8b1be8fab041ff084dc5f8c4d5d48f481115d7e407ad8a6034f481c2be86f8451980c3aa83a3fff245d90d13801a54527e97b" + - "e392b25867882d43e3819f4a8aa380db63954ec23d2f0c11a7aa5bc7a3aedc43ecd3b024280ed8843399e28deb954bfc11a3197fb14a9c9a895859e390e9586e" + - "2ad21da39bb9ba79a62222d228a0fc96a24e801f00afc3f98d2168a8a253f24deffe461f6313de9b433e1d2e307239c0e3fd5d9fe4c8352c2c6797b1737e93fc" + - "14d411bc69bbc9d78cf91734052b8aa1dab348e4c243b8e6d623865c135f807de8d5fd88f3921327affa37066dd538351bc4ec52eece88856de0a424a87d062a" + - "f68cf24db37dbaa8e8e96a812fbf32ccafdf1b9d27f11bea23df02143bd09061a881c010819a315a5b6ee44b3c60979b3f7b41f488b2429d49377d6542fb0e22" + - "d09a0ef5b81aa7c8134c0aecdc7a4f9228559d0bb826d30fd77fe0f834212647ce61e22fef0a1c10eb4177de81c31c12054a15f81b605619f3045646110673d0" + - "b2d79d80577fa43284266fd2ed54f9a3b9df3509f79559c5bc51a58521bfeb2f95d8851527b7ea47b92a694f6ea2b67dc2d4f506d11d2db32c2929cdf5c8816b" + - "7f0c310cceb7ede08d5965ed2c7be6c0a317251c7d31cc4a15f6d7976a8a1e6a2f386fe0071d43a50bd0ce5e864a8e449fe9600c6e4a84866879c490de9f9d46" + - "3f22708abf34d3e180dbb6005484a6afad373838cdac335f05c034e3090b2fbaaa53fa2db1f96bbe141d570f17363ff98672500e16994b79be74634755b09e66" + - "f1b37e338c946bf85e06c97e31dbddf257d58fd10468278648d86f38710c2ca0b6ea7cac4ea0e2c49b96bf1998bde1b3d38aa853736308e12b4a0d467fdb8a73" + - "0d810ce45518614bd5845f58a9835a5cfbe745f45ef59ce9a677d10d8c9f6294f1a0565301efb3c6610afda35167150bd326c77057e530c213da63af3e6a600a" + - "d87b16ec5cbf76a13764f71b3e7e0c867086ebd9fad02e1d747030064e071a13da4758cd0fa20872b3dc350f4cbfcde1b68a97aca41e32207b40beddec412c0e" + - "c75d87c6671ed94bda5170aa2866509161c28d550190675f60139a7b460469f3d4829b3c65f5d185936582629160522fcfdcc53fd0dcc8fc46de11d52bfcc5e6" + - "3407ecbbb682cc1693d6543756fa4e068e92ae1a94924a1ff6891361e5f262b7d3c3a3bc2866f54e6d03ebd5479afa3f424077d51668cc60e23b35fb0222ae22" + - "5223ba8a8c416b68c8853022d150c951f06f8f85c2078d3035b8ac3ae984ffcfb024431acaae8bfbeb981870f9ad6bbb88d7d5ff34ba21a44cbffd0aeaa435ba" + - "7d40d22602e807ac9a69db514ab13248133142cf03fac999a2b185f34d83fdb495ef042d4a5e92f2624193c88858d91c0812b18fd67046cf50635e6ab1ea9ade" + - "7b1fe783dc5147f14f9194cfa92c03a0456f4171f9e5c156fee1c607a1e9e06535f2dac49b92ddf5fdacbf88a062bd7ca5439bae645100121e598deee6043baa" + - "85cc0d727f08d37a766a55a9ca21ffb6594fb73f9aad15be4a64bafddb6c85d00f7bb5705d9e56b410dd80df8b087b6d67c7ca84eff2ad699f901415fab21343" + - "6351a9bdf83b440e29f3950c7e4c49963ab109686d78fce629e9207db2e17eb5f02f01db6441002d72c06c6c6bbcdc0a7443589ba29909a5a78864ad51e1dfda" + - "14782d869e4989ac3c5ef0aa1eabe540e9e7cd4e8eabe25b07f300a134a92718186f085d5c10a711ed0e574bf7550f6bccfc3c094d6e59619bde9fd892af8ef2" + - "50e1cc3afdcd9c84ccb97344542843028b00064b0c3d18ac0f0703fe6f9683d40813abbb883e164c5797bc1555338566cf8cdd358e9fcb0e93f08f7ae06a5121" + - "c67a231106ad8fd42f0798d7185c2de78b8b76c10e82272a405212ce3b904f90236eeea02054953b967cb614e8f8ac49b977152a52df981c86fa4a92f7f70eb6" + - "cd4eb65986564039b0d77f8bafedb4fcbf9c34b8fe9c5fa87b0785c118a8624498fb0184a0dbbfb16777579e1964330c12e494449f6aa5cf69ec4a32054be553" + - "6027e0d27c7044abd4c0b8e43db703209037efcfd08944647a90a1ab0c71011753354990cac5a472fae44dc370aac8131ebdf31456a8484e7fdefd268cbf5cb5" + - "85ac615039d3655b1348fc0b3b078ac41cbcaf6aaedcc1153bb8d55c307f45405ad6a959abb37bf8891c8dec79a9d7ccd9b791cb60361d4a28f33ec0dfd13fa8" + - "e0b9b29e14bf36f5047e51a39c2efcefcc156bd08e46c5c1000a3cdc2bb20713e19d6f492c40e51eb93628cf85d07041ae5353e7decc824cbb1db8ab3a7a7fca" + - "ff04c2af423bcfb1864ddc864624b827ddcff2a2f8fdb7a3d86d76e72b4f850ec1262d8fc89e7b12e4cc618afe6a2bdf205075c2008f93b7281d80180199409c" + - "de850d1f14ca0ff960f69772385cf0f0a0f47cafd5489ea4fd8b68ec7aa539b942379139756c95bb90818842cd43511edbb7577ae469f46728b13a61e6eede06" + - "3a4cdfab5ed590feb807d55d76e518d1d74bfa6704f7c8ccc672824b4d5ef5fa5b3ab8fdf2b6c1753404ba35b76aaa931a4e0e5ca7e440524166b23e9a8be9e8" + - "635381f6c9086802d428fece81395dada6b3b866e905ec00ccc4fb9b8415dd15e443f84b7220e3b28700ce3d88f9c6df2afea39e0ead537a50ee11f0c247ee86" + - "d4b3074e8761de4de611c409c6d4c369c2c11742a7763f6550edfaae49afeec33353a14d2ae60687dbeefd2fe29689da6ae79d7b06042dfd25a68bde9182fba4" + - "1ac53706a8b96535057fc2f99ac84a9cfc6549920c3e2cab44e48a08e77207b6a95b2f6179d6dfd6c2d9e3c91106a7a687e40bb2a1c5ccf566c0e31a0fdbd0a4" + - "f270f9812208f939efd9698a8b28ce9c5633f18ace7ab0a7550d9e7e26cf62eef49200331e19a64bed648b5d18ceb389bafbcb3f280ba78e4cf03b053f2a5f08" + - "3c852452837138004073cf6726143179386279f1a8f15d44876c19bf6c2e2992ce6056191bb1a386f0e1f6f249495cff126991c6560e3f613e56525c0c49b5cc" + - "2ea4e736d83480f2b45d7dc840b849887f54a2aa072e72e3fd0db34e5cddb02221fdf2a40fb6ec271ba3a09de8dc73c24328c5d9a33ae0adc9874902f25d5bef" + - "4d85914557e2983c93fba16cdd4bd929e878b5d51b142b6e9aa0ce84871b7b03ee6cc13251e17547c2d20a7d4e948760e207e29de58a7ccb71b87f99d79837db" + - "d0f293ad3d33ffe91435598e8a4584b7b7ef5b1a895a2827b4976f81d335e4aa6feda3539690899619a4cb34fdcbbecf1b8b38cec2ec7c07ce84ec3044f49656" + - "28fdba8971585afb509526640d36425777b6ddf5b2a49d795fdcf71e57fd35f29fff37890541b6e152f14fb6ea4c70a1b9f159d02ed895a68dcc276f5d5ae83e" + - "47c021392ee22a398c8c73b3446d61562b3ec596036959aa645a65e5d24f733e142ec0e184b72a2adcbe3913932b2c9503c856a7e989d24f306e01e99268188d" + - "f858694e297803effeb8e28bf8fb63ed6787acc2c61f509e19099607512d40928a08e649474a43728b63523175fad12ad088aade0c1e20815c7c12773bc959e8" + - "640ee23eef2b1653ae8918615b45158a01be5a5f39a75a7c6cd8f1f6b463516539771ad251d5c2d40c5049877765512c44e58bd3b9ac3a0ac281771097880fe2" + - "c9516dcd6f1373e1e8a52fc485d104004dcc839fe3d120f1432b213388dd37980ce8238c87a70d5abe95d78d696d2436eb23a8f620ce74335d5e47f6524b11c3" + - "e22288644b539e3ab664dd5fd6bafb02897aab35adaef204f82d9318b22f45b787f5bacd74b01d23537973060868a47f2e3a45c1d8805a1d657f2332af8170e2" + - "9435d7540e70e92a8c8794bf22d3e11d54ff2d48cbc7a1ac3cecfc48f80fe521f6852f97aafa0605f3e7084b15e61a74869512c9c2d84180686ea07b562cf35b" + - "5a0ca529481ddbdba9c60729f821dc7a5a8b5c7eaef1ea7927d455a702aab538e7441933c4fff2d27de5659d6fa41f0ee72bb13a829839267f3a7b51a81a85b0" + - "d737194d94e1bf8173248cb057cee19eb5e2cdda38c529298f3c4d3b95400198063c5b27e9262f9c66425c65568a09035bed9cd55c1f2ec4becb6b9c59445398" + - "ad5b7c85142e713b6dd32493dcb817c8bcdbd728e325c25c5a14d764b63f960d1e48a0bc7f4d2bf51060f83b1d1f2591c6a9b79182e686b887a2c1461442e2f9" + - "16e8582e298f87ca95a8052df33af20ebded7bb1c528920233d1aca3b3789494d97084890fa3db0ea7eb561b0087c4a90000db41ea072613f91ebba82790f33c" + - "fd52cdd92d2ef1246911ef1dd82ad083881b72a08a40ee55884380dd136a7c0724cded69c6abf1f156b14ecd7284abcbf66522264145ee78ab0ef0d2a74eb390" + - "10946d5efefb7175164e96621d3f158de8b57956b8b1155c35b32007e47d915cb61dabd556a370537737574741fcf9a8a23f7155bf1f0e3d3c0d2088d1191d9c" + - "9c974139303f3dda55a70ab4810fddca3561114969d370f4e6bad60a53815eab1c4613854d04ba8b049dd7ab1a935c728299d1502ff9aa3fbb356f87f2a52b6e" + - "947dc79b5fd211ed31dee722d3fd857f43aad973fbfacb7cbfe1b2553bdc76142ccae5b4021a4647b8d8087925dd3191a57198792b6f918de87a92705ce57905" + - "f2dcfb67a20f8c77e700933432d60a4536d0959415f15f3eb8a788f1b19c497d3b68194e27ee736231835469d8bf0ce1717ecf533ab77dd97b35881d8eda959f" + - "54a7935b1bc11d7f2e472757734afaf0463da3fad9804eb948e8d6444e8394b33f1c187618c7c02371ee6d378ebb7a20b6049a5504daa71999d15944ee82650a" + - "2388f374f3ec3afd4ca58ef3f2588997d194a2741252cf6562e00cd6b5c5fe4066454d2b3150317694052b4dafb40c2f04c850e4062cd8f0af2da75280046850" + - "77990788b27fa457ae9d0b622d18fc070f1d2661ecab529b5cb82f30a29610dc6a9e93ca9a2617ab0109957a45c1204e5eedb8860c6f4d57122060f39a4194fc" + - "a285f1e9e7a75cc3511b8cb4865719c2260a630845051876e7795bba59573b6ce5faf7e5708eda7be25dd49c8cace4c04c541074d703e6601e043f6c63a0a371" + - "1a381f0ff83d136f4aa29de266169ce5b3105cbfeffba370fa306a93830e3c0519a495b8b9f4b72078e2c45421b4b0667f903676a1339c70ddd1a90dbd21853b" + - "2826ac3fa5add5073c634d4c5e87db0efe18638ee93c460257e52aacb8600ff36739818056110b2e974a1959e3784903aa97b0fcd9264f7d8f6bb5d8b7d9f03c" + - "4b643955bf7966250936d4e7d651712db5e695a6a36b5e6f56c651ff737042b5bb73638e21ca6ce9a3e63fbb1906675d97001d7ee240d277d62df18acb169677" + - "963d231c5276bdf5767ec35fbedb062e61c23d759aefd287b2dd62a0d6f0518d90b3c1756fde50afd33cab395ddf3cd538b9ad8862a199141331c63110c9ddaf" + - "fa3d6c63a1fb1b45529eace826cc29a1df5df327bb782e573c41864c18e6d31401d19719326e5c35bb50de7fdc67177a6a6015b4264fecba2360ab72ae8b060a" + - "6c66c5a05782a15fe3c1833b47e3495d29f2cfa579fcb08f02fd064e9ef2ef5564ac6a43cfbcae7d79e9f87ebc2176611823c6624db11892f8c47f8c96a49539" + - "1c18f821ecdefb343eae3fd98dae1ef96fa3527788543c0d06d9793579cc62d91dc4d25312901c6368ba81c8536c6287230e8f97d25f6c77366609580cf26a27" + - "88502a9aada84a794d3674ae11cd1742cf245e9d9502dbb5b340c2a6c79e3607f6b47666e1ea991ccfbdf6cc41ede46d043bc4d3e5e6882414dc65d62f9f47b9" + - "fb7b828a89afd6361ae458c2cdc82f459c54977072702ee5a4c22955b8019d8b8d91f558897c4b661f8e5412ccdc10c40521303c0ffd353a0c04cebca5622a71" + - "192b144d0f9c5c0706a130df887526b7b6e0f358ad9f7d0fd4d87c5fdb29a7453388c0d009da0d4c47a5d6cf8363892ac42b6ce3388771f698802b4dbfd66aa3" + - "5fa6a6f8b42dd8446324501c807b6e72cdd35cfe08956a52f86bb4709fe2980f62152dba3571f18fcc4c1cf7a25384c4b5174e93e5afc9b9f12db2bd505ddade" + - "d670d0d71b9548f9a07ef98521961cd96e8f363cf3222336bc4baa284b5305aab47dace615c1b3f3fb1ee23ad9ca3f58b086d9169ee5b2d3c2831e1db4f905da" + - "11e1fe79e3d48c01bd9879ed68391e4d24d6db8d6774cb8747e7ea368aba3bbf355386408af4a59b23fce74a5e673a1044db66ed8529a65462269480736cdaa5" + - "0784fbd77e1c41197335b4c517af8a67eef5b7165c5fd6022cceed0396089c3985c36595497db0a0fcae478e4e4d68c57b93f466aae86dd4244633beaa8116a0" + - "de25d2a54353b7ee85fee58ad4780a2957d69816585a64f65e75f332614aa6786d1a1432f6acde385d3d6e870bc968c60c81401726a958f0caae336c83a9523a" + - "c174faed43ec67473dcd151506e334a6aaf1731dd3aaa831f934be83beaefafa11810e7eb140f4fe80cfba574e6106c1bfe9f0b20173a4ec2663ce0580df6daa" + - "7966a3a8906677ab680025782c61b95cec6a73b5deb16599e6521f9c6c4cae0d9286566388d5181d6ba11c51a25c62b510d9b1793f3ce9f73ff0c9226c8aae69" + - "5d014287df074a244014720ee38e3968557db00aa63dab71854b8573c42c65116e3d88bf040d53ef3165a5827c717179e2939e310be5eaf6fb75447ba98ce925" + - "98e83a32a90eea848500a30eaaaceb307d37b1201b83a744468a1a52632ce5525c1fce5f702421e42e7cc4c61caed539dc09001cd31a8a2b48a783c36c56a3a2" + - "d50de42c63981c86642cc92bcceeec8a66b4afad3c1be1df4bcb8beedd442c281080c94692bf453196ed1a66a074d56a8e7f60238ce18358373efc173e70c691" + - "f832e1139bc04e6258d77cf7529af7ce5eca28ca5cda818625c0bb5beca96d99fc9b6689a7771434aa96e23c55a41cff7b7b718df58260b3bc91762034debf49" + - "7d8ca8d5764c52bc9665bf86db5407ee1b786d90f8d7772597eceb98f0121e3996e771d951568a162f6b71042998db8208ece5b8b0c68107b8e2079765b0d8c3" + - "2747597072756208b0d84415a5334a88d916bda390e26ccf3046b860e7ccbe22c48cd3d3f51bb65a98ace74d52613f782db726babd02780b8d620655bf9d551c" + - "ae9ef3056e3d24f5e7c3105c4857492fedd244ac2b8c30a874c1446630b042d819bc6b6d2d96829de903db22af706e93c5ae876d72c633600222443d1765bc62" + - "a8a20c458ae55bce8cbbef753cccc5e7d929408d6a3709467373651f0163128aba4142ecc56ef11ff1fabf5eaf6e955b4252d1350e9002300a1236ab2fa0ed34" + - "c9cc7dc1d4f09bd31296cec1493e725b57cc496fdac4e8d26197376bda7f74c0965c4352bc9d5c731df04f9908899cce6ec3afe15210d115992b2d95308dd032" + - "13c557ac527424c7db02475a2fc78b88d022d212c3d02d5ee490e2436e6e572e8a1330465b9052f8a3de01aab76662d18fa3d076fb77103fe432d549bc861fcf" + - "f63f3401cda31673ee48826b68b387802fea4471deb1fc928586f1b1614c16311c9820b563ab0112c28af5c1af5121818540c4b7d7f549b33906c1b86c6674ad" + - "799acee7342e4a79d9295493b2430fd08f373338795764621bca444868f3f42b0e40abd4b8e148cad2861fb4980b83bb58d40eeecd8d8cb1ef1ece17b0ab72e5" + - "06c6e650a3a43081f545acbac51ed7e121df51edb75120cce30ef7dbf41fad331120e537fb35be45d93de4fac0cadc7e5f644e2b767a285facd5f12845559785" + - "57f4afc276e21d77f6162062430dc8918435f035f435ea419ae9f1ddb6afd46b243f8bd6a3a33e7970e7e76fab9ba6afa72a4806189462f9d0f231a23e3ee1cc" + - "51cd10cb9043a27deecaca866751f971254fbe3084c243ef5f516bb652988b770896ae5abfa12db2eb2abe404cf694e9f60d47e734e260ae668b750e11b26001" + - "0d2bee5ca555a44523742fb069e484f7a69c12d4bad026c03ed7af10ebc9cf2f54d143fbe4de83448df80668217a11f5a1187f35ff306e6c685cfc2417c14aa7" + - "aeba1fb7dab05c913fbcbb8e677dd0f89324048862220ab6f5340c38b70804f625f5a526d6675a49fdc22ea6ceed477097fc723a7b6eaffd65c48dbee13df566" + - "f8f3449d91abb367cf37a8460fc8072c4ac75f88be8b9c840ef438cbf12a2e7d55799f641316e3381f72265425f3e90fbeaa9919533d8f9262da27f1f933d4f9" + - "a83e07aeb968016fed89e7b16babf0b6af3800a27c9c3d330b6bf8be447d31bedcc526b1bb53ecb10c3ea098bfa7d014d93274bec70b6e82bd5c443e860835f0" + - "ae82b7be7c78cd996e0990e3cac8c1c431481c8159ae1dbc40c03f4ac543e5758f347e12715822d86c881030de83a76ba1c49e4d4836bab7b5287122ccf523d2" + - "33935d802d2bca303cf57b36a5ff17e7c611f1cf99699881ae464da2911d77580587a7228db8325f204adb14413a13fe318e995d60e35c88bb47b99ba9ee8daa" + - "3e40ce5818876a3911107a159125dcf768ba04074e5771334e0de430c439070422508577e474e9532f7dfbc489d0c87d37103920415b6c116a422ac15e0736a8" + - "1e1e317adc87005f868815950882fc7497794c5eaf76f9def434d198304ff495bd2f9f4026aea330450741fb969700b953ab265aabf1fe146d861ba2aedc53d4" + - "f929abec2dee710aed8fa605fbb9bba914eaff01fdc113836d34d855383e4a311b4ec6ef6e80dfe32bc8035d84ddc4e2c305c112b93560112c1f3dff800d6043" + - "7eab01991f924075b4dea4db01c377ee1ca374d383ff1fbb463bf7078f6cc7509a0ecf536871abe7c95bf89f29c71f72f1a2002854113cb0d6d2192c00123010" + - "8dc9477808a218f84afb81f0274718c024393d5be66edaac7406e520b0c8e2c02ab98ee7b290db261f2122ea68bd79f2cc6dc64936af5064cce2b4d1b7078703" + - "951b6b81b9b60b99da4c2d12bbb50351a5b7713541db0958740910ff69e748c71bc7470a3c05489febefd384e06d267371935f652736bbcaacb20c34bd50144c" + - "71923b5a521ac4b1ba694d024ba51b4bef3ffcff74d5dc63810b2c0f529073e13ec3232d8647ad124b21ff73402d371c0db39d46cf4d2d4cf7ad43fd8dd365f6" + - "9b6b7bcdf664df0e62ba58f3ca0c62ad6fdcc9b091fb4926cb47b5ff8de7d3b12bd8709a46e5c3d5f0d22934c7a0574ee70b87af97d0fa46f7d9673915fed1d5" + - "a6c57197524ec9978d1bdf65633721ea2ccc25626dcb5e7f5e090b00e413c10a6d20b45fb8e98c22928de6dda184e856c86792c7cd09d38e4333a76882d363f1" + - "7f4d773ba104b2d04fd81027da087258fb175bfa8005c035a4719bac5b9630ae57889fb3b52a0fd47ec4060137b0f95fa5d5684172d07ca91e91eaf20dbfdea8" + - "a3e23937f33d8774f30c7e8e5d4b2d5371e5ea5e8d290970904c4c1ff33baf675ed79599653808f652ec4fd0088877f7dd7973023ccc8377d1ada2b80c07d077" + - "d7208686354f511925a3514c9e93c13525353b3d9528ab678e3e783c290ead88c2c3d6230bd4cb3bf79fce6dc3e95bfebda41e5d994e61ab083d73408ff6b627" + - "6996a263d2920170fff6869c2311441837a2fc190bee104328591b402defa38b421b972b01d020bd20b1b6a6ae884b23eb829fdf032a81d4f199a87ef125d4cc" + - "8662e24deb93700980e6ebc6882bcbaaa0283492e81f81e76bbe2ce18df4fb665436310658918ee217b5da262f1a1adbd59eb3c555cfebb12280058c75b5b33f" + - "8aa8c2d7cebf12ce46c5f49ecec5a865a9f0b65476793884f0021f8731b1bd288f55dfa1665776b2aee1007bcaa6d92a76a2ba9925bcfa68db7cc727b2a07ebc" + - "e24c0314c96ee4d6164c699e585461388dd73476a1e0519d92f51b64eb2842a7b17bb55d512d52da802df63206ee926f6a6a8c32de7b30e7cd3f23e37e0fd82a" + - "556323736ecd9de77494a2f8702463f40fb837c2a99270b9050b0cbbc2c305a32380ff5fa94bf9c101c667f36293c12ff9aaf6e0a810b75230caf915135cbe6e" + - "63ffb2a0e8632d32f72a65aa965fc556e10ddf6d5e40be919066eebda09d581a32156e1675300f52c8b355e88696fc2a67dd8e350a6e902e082af28a9809ba11" + - "ae0a5fd9c6627fb808d757147e5d59cffd9c45874478ab226e72909ccba6592a54391d072c7eb0221f1ff7be9924b9d037e4f8c31e94fdc814a8c4cc7ad4c9f6" + - "eacd5af66dd76bb6222b2fd3ea50a828fc3a91ef8b084214bfdcca56348517be18ca472166dd7f18c8e444e3641486e7dada626ced8710fc73a2b09b6e9395b0" + - "31ee2c48c9183851357d230204c911b345457de602824273193b795fc21e90a0c1cdaaba36787424b23ce73e2116947f143f9641d39a4c07c2e40e02f3bd7c68" + - "6899fd57e3eb23c6f5615c9dbc279fca0d4218bc79d928e70018533a85b4646bdc78015149b4d41d77ec7b46900e7fd5250116ce978f825569bd887bf3fd0365" + - "e1259a7514116fdcdd6da3ffdf432bbe8e59b9bca9222c5dca1eaa61caf29b8461ddced6f312838fe490f742db696fadddd19bab8de6bedaade878be07aca4ac" + - "76d69b81a6890e66dccd702720c3bd5601c6abdab95fbe4ccde6e35385b75e1977d5085ace928adfa382ea2890889017b9c4c81d9ba4629771f84cced6280db7" + - "a6cd83ff9375ffb0a75a6bebba9a209f048788ba39127c1036e4bd0aad9be40754fd75295611e455909a818a3541af32eae98df7222353a4405da0e7be9f1cf1" + - "bcb823fdea7976a810e8a3c7bf93fd947f961a344a93aa1ba99bf2df48ec82769d8c08e7b14191050d5706a9467c9122f34e27f060dd4d6e936c414c4e551b9e" + - "5d6b5b58347ed0012a8a323f41b43bf5e960b2806de59da85b998affdb490fbc965d569114223db3ca65df69a617f6808bea23017327ddaf32990070aaf5f444" + - "a9db44a57b5c92bc27bc71c5f8a2b6929edfed8e182bf5942564ef045c75448450eb1a4e4e09a1875e8a4a74f229879ccb7a2f2cd0359abd91a782c2ec1f68bb" + - "40ce0a63bcc014b198adc222fc957eec0483f5b93f0db91b7ab3b3e3c59841dae057eec97abb55fc42b2de124946e66ed2a7fe8cd047cb79051b55f82594ab45" + - "711c92364f932a5fd274fe184c85583ac7cfaf258c57e296f9c18fd181308565315e27272cbad3b21cb4490ca0e5f675365caac42f299e22d8a74ca51a9d0883" + - "bb376804e234502db66067e7a434d38c3dc075346e888e4558b1745d00458df99db02f0e4c37702fb0989387f74d002a924790a6b7351ee0f41684bef079be26" + - "ee9d70b560c006cff4b08b9578afb5019c21ab9418ae4ecaa7a1cfed2d880a06a03c2c7711b601a2cb3d9193e1577b4f1d0e614c0be1f69205fa6524fee80bf1" + - "e1f1906b50e75fea2d19b8a83071a460145e1730581e5e9538888d2e797ee3cbd3b31399ecb4d6244ee44362493802b142ea397c2e7a3c1bc86f0ea0546a38ce" + - "574e1df0c27ad8a28dca70f659ae6a1369d8b3aee7d0dd24ea370cc2bc1b1a4dc9f63911b63e60fe4ed8552bbca10e01c82d11b0ddf748d234b4aa3b31683c09" + - "86358fad680dd2178902beadc4646b3eceff572631ff9e6b64d8a622ad9f0308cc46b7d422ce792fe5573e9b9480e1ae9fedf31edaaac3b08c5a2c6c27d6b033" + - "6b92a3da7b838bb0a2916ebb6ee72bf33a7fa70630491f49c67031ce4b9dec2315088d0a5cbf7473fd121e0ef5f4e92d43114014c9f8c6e671086a446eb1f66f" + - "70f0cb0c668998ed96ee0ad2687946681fe40dc46cbd170e0cabb6f6216be61221f171fb2f4273f58c10d5c4eccafd1df62fdc8ac2c5c8f6d5eb637b71fa89e3" + - "f8347343f89667a4450c5c6e3791034d2dc3a593185b55bb95d8f8f2984ef981e4b692c1383ace4cb2c4adb80d5d582857b5d0e3ccb12845a59587b47232ad20" + - "926efa78e05a57b136e284401c516296b6b194d541ec165d11ef94f166cb52f45145d745ff3deaf643b5c45573ed0e69a22f0e0c9c5367f6d1398105516729b6" + - "3f2edf1b01ad9633edf80efbba6555d4253fd99b45a36f16ba98ea0bb0d80533aed806544a084a398a692f698c78b9bcfc9b4d3328dd869dbf7085893b8dafe1" + - "59e0517c2f6a3ddfd4a8c670072b30c96b90f81fcc08523e4fd75919752bfa52a1db7c374debbd83ca8e311b98b0d8275bedad215847fa8984cb50e108f69550" + - "f6517d719dbb5dade1d3c283357e14b6d9e85d61e33813546517e1262a7cbac814d79cf6b7e21b0fbbee9b6314f02b2d4e6995d2231670884c78cfd86a2acbcf" + - "0a178ba64de2f13f022e22b9b968ceefaff374aff02b703811f3dc541a69a21d6e1c5d1aca48889b125ff1274e65413f61e42bb0194b60b65a3454c696033cc8" + - "e3cc3613a52850296a0154bde0e2a81b7a6489bfce505dbe1bc44e0e1052f678297bb19cbdf7970bfa5268af8a54eee004063f9894118ddce7fae8bbba53a428" + - "678cec8a2bf6cca2b1a5f4a2e95562437e4eae41167f39d2a150f7c46c1eb6da35587f7234d870b16ed91c7db548ddc99967381b4bb4f3a2b0a5ebcbc7ab1b06" + - "7d5418768eaf7d526ca116e239ceb3ab393c45f3b32b713c11fa8e5ae8d7611e6008fa08d1305d5655315a72c85a04dc853da3e8ea9d46674194e15226f126c1" + - "a233c26dd7d3cc04ae572320d0c351911b6fcdbc0b8450523e96022f4b964d4e479b6cb1c40a6d27699b57ed2952ef7fb3172c69ba7beb8c8633a01070ac4344" + - "d4c401acf8ca7fcafeaa59e1d4c2ff251bb67dbe10a862103df1b416fd2097fe412b3da9d4095b48ea094fc3bbf2ca41e4452af3a179580e3bc11a7d97ba050c" + - "ae1d6b8075da267b3ae2231a1fcfce0c976402f34963c007d4f85d9ca95646990d1bb09691ceea3b34211dc58409e052d0acf8c2296a7e8fb52d7c673506d89b" + - "847c369daec7909da8657e8976f59f2ef4c8a049b46fdf30d6d223ea4175e4d60e469bcea0eb3bdcaa4d6024f2b43cf6de9bb40efa9172381291079dd82ac5b2" + - "39f2051a7f1aabcb8d50333e8c160de19ce1c76ced8056a0724ac630dd45ec4e315437391158a633c179a3d1f364b475454fd29c1e539077b9d5f7227786a5d9" + - "d8ec78e5615c25e517e9fcaf07611b85dff2c131a1b11a901a431a601854e5cb627cf7b8b0c5e66ad6cf60b7ffd6c6441f9ecd58f414013279e9de533d8d797b" + - "936cfdbfcc78342b7ab586457541df5f3b7d1873612df200896e2929f44c6fe10d24f7e6dbe52b6c42c0a40c947c1cbda2a41437079eebcdc29716d80957c159" + - "627e7366cc16df92cdedfa9f52edc848335f1c7152652fe24661a469fd503393229063c7ab20d8d895139a2f580dceac9f6dd4c4ac652b1d60c2b8a1b0b2923a" + - "86c31742807549e6d523b3c88d31e8534b9e05a6c63f6c8fb8a1eb4dad733d92e7071e410f0087ca3074f4a2df511ae89cefe9ed09a8df603d61f23754e43cc2" + - "e42bcdcbe58b0587aba9a62f32c7507116fdc8a9db3d65d6c0097c8f473eb7f3bcd11ab81d5b636b0812b7982201a63d0b8d40f2c38f65ffd953668eaa5751b3" + - "dab7f038aa7adbcd1f1102267c9d55d43649f9b4f65f1851546c5a9ef2c7ef56e84b16f12641e9d5ddaa78ec778b5f113b2e06bad5821e1a5203b006a774e36f" + - "56c9336d92c8cd8bddcf014b6d58c394e2a93554af6361fc1bbd13c359fed98bb5adfa4dd1266e2744e126e1bc029ab28fd68b648a2ab26ac23252171b298641" + - "2621f2a8697a00ab3fdc1b3b04921390ee16d213601ab249a51830661051d34eb777f690fc2d8dfb8e0898567e388830bac8b0bc896f43003feadf34256a927e" + - "b4d9293e32ca135351a19d1246cda30551c87de1e148ff5ea576b67e19e1a0389b88a5548b3b1a8cbee19eecc7de5c2333264c711d50d688a1c57eebc28dd6f3" + - "3dc0e4cb857973c3d0f28683a6f3c09db9f54b8fabeca9e4f9b86d794ca55d6611858f0d48736adc10dd6763ed7199bad81369ab1f3de30f521d43382bcccb7b" + - "be0178f716d5c3cb87488cebd7d9e2bbe671dfcf2512f1b815075777ea92a867f35e09ff0110e61db24423d0598eb6fd078dde0dc2b5d7f5e0bb6fee207da109" + - "2e656b5c982866d5fe01e6db79809646559a6f2b9088e977789aac74435dc625b54296b25788bfbbda9bbb25247d428f5141b03172fa11f12339b91ca96c92e7" + - "ea5a128c8046087dc7a7eba63e3bdb200565d8a103e7b3c292b088eb06aa27b43688c8516bbffcf123499574f00908ff43d66b79106cebaf16725f1dee600a29" + - "7b3a3da878940867f9549e65c73ea798ca923b012fb8a7ef3e2ded1d2c4e85635219f627dc4feb90f884ae6436e7b44f9159f9889d8e194828e079cd2ee60a7a" + - "6fbb6b8fc1f7355d7322709fabddd76e4283ddda3018b7882ad79b32bac133da415453eecd5bb1f0deb4f3b987a71a2f2e60194cde63a42b91b39bfe51b4aa8c" + - "20952b601df11d170c65a7fe935915890849a367936e97bd242edf305eaf2f4f4fb9e5ee1464c51a899ba5cc69cf56731502c1b75d0d565b1dce15440b0de0f5" + - "58bd4f810bf058af99c158a2be0dd02a01bb5317f55675f4d42c6766fc61271954b6988c33a84518bcedbac8de305946d060d19c4691c026953ebd680a4c9012" + - "0e8bd54675d6c33cc86e65f5cd3c34cb1e6fd47784a64f39e95a1945b5c21df2b3288f963863b33366908b05c2bd499dd25c1b8e97329d7e435899afeaed174d" + - "2a2471b6e8d6ad7a0b1b6a8b19fbd976362283e5abffcbd2cd310245092749b23e0d114e727622953487f373c833281a74a1b97742ca99e49cac14d9102e3680" + - "404509889ace009c47d075ba9891e7f67b89aca3e213150f3c715cbab1869135601612d7dffda3cc104b6508f56eb8b7e7f379b21e1ce290ce5fb96f53e3a7eb" + - "c7f7bddcbdfc266f23b775602d8d12527d30446cb4144df7fe3c2756e232a8ffca625d7b6ea2c8c0a92e6425ba67ab75160623c39f01fd96856b582e257a6930" + - "224c6da90a6eac4249214c3b85aef52835d904a8a5e224d59eae0c80a33b3141ffb31a7d8e62833fa4c850fa6be135558fff5434777df45feed00316c475759f" + - "ac6e014e9d3cf23e7322281ed75623ed69a81d6f05ee7de193f6b44ede4a94ced27aef5ab9056144593a836da80f5297875e7bd84d8ca6df95de8650b00b3528" + - "123132f26aabf755d00450648e44f3beafa4dc746775958c6dd88bee825c29112a3af582bb2ebe628d70364fe9ad01b8a9961d5b71018690440151486114af1a" + - "d85679bcd3eca510c6d6887e70e0d04b04fc2db5ab1eb21fff925b66f08f4fcbf31be3d743154056ba137727b63576e72f1756029c86bbcf9452fc6cfd89f3b5" + - "9f243d84c410253ba7c9284191a0ed87b2513901a93606f1aeb736c90dfe40c0a343d45e9a992ea894b22ee5d49e0f7d55d9bddaa6c74bde8ca5839db67b77a9" + - "ef740f9a47241f05e5dc1b9c95c459cc9db560b1db090daa3f4c6de46f695a158baaf357a1fc63ebc0d9db8144137ec4bd69c5af89cdf9cfa66e06bff6339d62" + - "2c372fbe5a855d14fa7ff3726512f966e4da0556b29ca6d7517803f897d0e1911f9b46a291002a8320091aa7016cb7ac993e35c8b0f5aed3c94ff0b5dadd8b77" + - "056d06d1bed59aaf7bca8516c3bba6b33e12df2e5ca4aa40664b3bf48c4dc2c57cfd74c765fe9f794f55b5df6ac6dd2b3592bbc71354c8dd9ae41b0a05e1c7c0" + - "d3bd1a0ac6b671c48c01d4a0fec7a01ad11040f213461759f9e029c835ca1d22f9a661b69d72bc46e34b1be7ed85a21830fb87baa74d7ab145ac1647f5f2df68" + - "671100d4d9e41082d3c81f3b5a6e603bb33fd56c1dbcbdce5e213c651da45d9d1dd7532d9a955202338387af6315137dc458fed62920a0e721aa7ff1660981c0" + - "e4c3de0a4863f6f660a7c1b9745ea26036a25cfa37e1337ded405ebb0401d7041a7938800a97a032fcababcc06391a77a580b1a61de014db9d7e280ffa6b2381" + - "ab6969ae5cfcca00a47ac2fa05be02aae7beb806d2afcc11dc0642d2a12ecde2d2926efd9fe790e1bee19f9114d22ca42f438ef656a1311e4931ab7fac93ed17" + - "3f68ea0abed18cc2c8905bb2d599780690eabe4996e38872a3190fee361df9fecd5906f664106de4835f8fbb657366327871a2d38cbb671df04e0d14fe97e260" + - "c42eb07bd1d70514913c7a64a51e405cc92e06845e5a78981fef9822fc79e9937ce0513138f6bbf247f5c457da708cf84e30d083b4ba48d2d43d70e7c31e9482" + - "4472617910a3de4369217b4daf892c2c3250d1de0457e88b3bcb5c4568f9b26aa675c551a9a730fe9ea8145ce7f8e23ec825be9be3b9edd588c391295fe31ac5" + - "bfc97d2e438ca9bf6551728b3be6d6c6ac064baca763e0eaa24f754f4bbc84a4377de45fb6a8f37150865df18749df1af4ea911b62f616dd4dd4b25b27c7b6fd" + - "99d8c00ce8a53fde3ced091891e8daf43cade10086be046ee5607003de24101db49b1a4fb0ac270d05bab12583e263e903e94dab8bba7c785e40499ab01ff92b" + - "b82c2e5342dce84881adedf77cab593f541e4c963f4f9ffc80a16bd4eb7f20ef4bf3f57abc7cbd86332d8be80f0794fc82767d13c71d8ee20468ee35c13308b0" + - "dc29ebe8c6a81e02ee9a21807ff57e4d932edcaf59ae9e76f7cdad46b32f94a74982f0887d7083c90ff54058e873b10cec67fba1b717deba5356e170dec1a40d" + - "36c57674ad8d43c5c98022b553fe060251b994271585f702de3e71fb1c8e36293dd44a4b99a1baf33f6205e9fbc9acdfe8cfdf007224f93a7104e7803454fdc0" + - "9fc5a20be59f600ee734847257a5ad62c599a7fa836d1174a6291e61c1be4b310bd4d7b7cb9be976dbdfdd2b99340a9863c8c0e5009165d7097317e6c3a29cfc" + - "dc84b19bc68f38694998f626567b80ce6699124b12bae4bb9e661c2484f5109517318341287e142a849d61d0d7b11d4996547e7325f28842dcaed26367f7a888" + - "e58c24c857da2f48a9fb91c78cf351a23e82ae443223580a9fe15a6a778f6c13be66888219e3e15971170712b6c356520cc15e4e75167993b66e6f125799cd40" + - "86c72588a85f68361f1c2f09e87f9a4de95ef9a3b92c3313664a706cb72916b96a9cb50771f6917ddcf696ce8d7f2525745fb6edc30bf3fdaad66ca5b013300a" + - "7ec7cd274327b1b9cd931c068d8fa9fd6336d59f6ac79b84a24b34c47e408b3bcb8ead49428c123922e54bfcaec7e39c4d6ef79e5645a35f715d151e679ef5c6" + - "6f86cd013fdaab978ee4e52eea5e2753e693271344a1f215e1c690de06f29c856c469ccb484d445bacb16694f4def1537cdb32260705e8a50fd65e98a24967a2" + - "456af6cf90643638999389a35de6e192068fd2e2ec29aced58611560c792ea5c7fa37583ebd5452a8d94cbf1898937dd8aa6656047e6e03f84dfd0bded514a6c" + - "b47ca71c2cf1e76f606c04374663712fd96925eecf0ac1c38392390c8cb095f39e1814252ded78b55ebeb9915dc5e2ec14fe99e3a075bd389ac601681f154286" + - "885289e568a8646d94abc806b4637492e3a407cde582d42764eef0d56ab14b00e9aa1f64d8fdd533d4314145c8255c44d0c746af6da844d285eb044d57e8cafb" + - "ab6c3b962e0177f11a839f4a5c0d2c2e8d5f76375ac115e0a89f460ea1be238f974a68e0693d15790117106c1a65ab5f7aa08e738aa888d5b56be39d2078837d" + - "fb2357d86f5be85a9af41aed611b231495564493e46acc90c6a3e67d5b055320290aef508aa6a1896f19cb5633edc0fec023216726e50960a44d81e0614ce748" + - "6ccfdaf620eaac0517e8cdeb1095d55f3a60d61dd27d967eb26128b84c9ea8418779e074cee8961c5dac811ce5ee8134d3910a47de7a1344293f5c64ae8f1b38" + - "9d6c457dc74e7005c339394f5f24630f5e40cf270640d1e4c27cb6a74fb440f3203026acfcd31f39cd4844ede7e785290878fac8770f930e96c3edf61748dc6f" + - "b7476832cf77ddfbe8eb8e12fd002038630301439ef8a7659bb10593a92cb84018e1ec78856f403e1eb9d6343aa0bbd77a63d776f1d12838f27f3cf6296ab0b3" + - "b4436f0ec545a5a1e92a5351fb273b3ed56a40e5a5d25e0057f4077bfeba2e2d8cb17a553b157609b20bfb5cd2699af9936f50d823bb59a950a24b8fd15ed705" + - "b1628663f0eb5b5c2b18f000ab039bc425ebafb2010e1a2264c38fa2bbd0f77e38eac8acd670565490fd60cac7fd28d988c8dc0658505dd98425f22c94647d44" + - "5d0236b97ea58b3c71feee90be0055ce1fabda5ebfced9d9bf5efaeac8408c4b6bcdb39851cfe038d88ada5211de2f0f69e9e3c62453106c366cf0c40971c0e8" + - "e8f2a790aa66999a0cb4cdb57a8c2d812e9e4a66df2f001a57e291864339257ec26c9bc2dc6cb2eb5c3301c167e1ed0387f9ce9f76c6759ebe5c68e8be378c42" + - "e0350b344acbc8b40c95cee9e82bb43cef5e91a32a6be8a727d5fbe089321ede3abee4da6b9f41775d7e9abc36f6a5d26ab88ba32978b5ea0ad63f0ce8a772be" + - "5aa51143bcd00d78bdcbd69beb652139ad658dc7ad242b2057eacee092aab4940d6ff993a8c7d8fbe93c08c93c45d5f3a01058f3c75c94be9da1a19a97754734" + - "b713e1ad6b7cd472619ec1abd4cf42f50b0648661c2b8dbe8976037c094c7176090ba94618e1918db44f5d2c367a0c7f911132d9a8b2398b9417542c7ad99b53" + - "a7ca48253bab8382a1a24d35b9b9818bda513f4b52fc576a71fa63e72aa8042ee1fc806c6fd3fc16e07ed2caf9f82bd3bb6b393b2708c051c24c2e05aaf72531" + - "d865888db06f719314d6094b2c4f0718c151c88958d2d6c8a6f49464f81cc46709dde026f4e05325ea4ca2dddf9a79bf98bff3aa5eb412434f0b7457b4ed47ab" + - "85a212e0c7720c78c961d56141bff0f964622d4d3984c1017de6f5846c72fae0c771a819ba6c111bd739fcf16f4b85f8101e7c3f0daefe753ec130a6f34c7697" + - "4dc531f83715ecae28bf2e55111778ae42aef17fa95340584cfae3d4599af9dbd10211baf3aafa8ac8a07edf8243daffd6a6486b1e3be4b60711194261e2b646" + - "e2667554cc0bb2fc07054b653231cede43154c9002890ca20b0ac81c4788847c6ecf7c174e528f36f8cfc53f3366fa9ce07b1843939cf6d318ed11f7ba6eb791" + - "ce25e75cbe37d2ee3d45bea487d969de041011959c0fed4e6c86802a7485fad70059ece14a29b03d4df41677acf71419ee63f1101060ca5e4ca0ab2edd71fe77" + - "46c6bd9f36bdbbf0a9956eaaf974f7bef982cd34881abd686fe77b536c85d042d77dadd00c5cb0130737e5318a025e6ae6af96ca28cbd41094d86a85765ff891" + - "af825793910c406470cc61be5d9282911d2faf82abfb309598fce0101ca64abe3920701a958c20ac35927733466a23de809afa2bdf331f68c3ab0cfa08b0c549" + - "a20e9b50dbe85d22d215d0e5fef854ba271a4c0f95e6abca19018bdd4a042721887418136b4a60cf291bf06ec47a5a4d2f9b29f988733c6bf6f65da5a95f8939" + - "fe0f2bab0bdce98569a81f861014e532f6a995542db02b6bdf3169191d300fb0429c1cae1d2dd4d29e0b61751576e04b558d38d3afcce8326c2871e969c1492a" + - "8391c0becec29edcf7f038a8093471763db9f13b97114acf7a979f5ba3bf6f990317890ee0705850fb97bfacf306a0ad621b2c3b633af01fc5aa059c0e22ed17" + - "23584dde6cf140bd1d0087ca9090ca9f07d3b93c60938af8df976555455bafbd8cc986ba32fc3f15b5962dbb2d37b6ae55a7de0c0c6f2366be0278e26bf9a725" + - "f61f2bcb545d66f79261783f7f03395f2a5d27e56af62a01ffcf778c3c686e244bd9b7e5029d1d40dd2250705c6825bf78e83730212640cb5ba54191b61fce33" + - "ce6df7721b15662162b631d99e6431efd24ec35639c2b97f10374fa5b9e2ca4231f523195206fb9695ec7721c98d74f29533cf714866adae8edbe8ed2d0969c4" + - "9ed36200c4b8b75131e6d1efa913106bb0759aa8255bd6a9dc2b00407358f4523486575b111676730094f46d0a7b95427df74f053c6611b4c465efa5310f760c" + - "5ff081e841e5f90c2de35855d45a7f35ce73d7c7f9f61fbfa953398e042c3946aaa4b7a2094d95410b8a5ef76c8b57d49f77311192b3f4578f37bda1a426de7c" + - "7cc54b5400bd16bb30cd8d1b7b42ff31c5e3759e3c9a7668174c02bc5a08f1bcc7e3ba145fa5f5c41e48877b41b0ef8fffd0f75c6547047c2e7b7c7e1aef2cda" + - "c4a778adbf71257618b4eb3c6dbd8211f829c1d6373415b969cc48f33d586d2678e7c1b441364a9fe2bb426a33b2a132741fac547766d196df3505fdb17977de" + - "7853cdcd8d9932eb9452620aa4921b4416f65055d77573b132a40795bf142815b655e670bf2c4464adb5d826a1744c8049d7a6cfbc8a4634e66eb32f0cb6fa17" + - "ffa8925131c3a253101733406a2a3a0dc61ec3ca1448623b6295791d4e2d65d303f78038e15d0ef75d823759bcb4b277b51410c37d5efbbb2e3a9e0cd78a8475" + - "05d44bb1fed7f72b1bf1a96ad0148e816d34c66b1b5faf172b8141ba007bf2e5dbbfee4b09ef66656ea3cde54f086040d14116aa7f3584ab6773f6091a2fbcee" + - "f59d6ea115f88ef9fcb358c87c35caf7c1a6022e141a3c688beef17da5a619e733d854218b30d5edc39b933b19dedd6750acabc52234934b08f930b608a18008" + - "838cb0fb73d4c78af0c468d9fa4fc5852135ae91ae00a99a6c603371d09b031ee37f87586cdc83897d8fd8ee2e07b9d0478a812d3f7eddca08860386e3ad9521" + - "98d5fc04fd0aba4b3da6ab8bdd9eca8e0399a2012d6158ed75ced5f432a223449b4e3db3fd4b19c494a69e9f2670833f8a88f7b2873319e9495f03fc69b6d098" + - "6006e3ffd8cdb9c1b98f72345848deea1b98ff6ef766f4398e642e5f2b217c1a87a608c1dc701bbb79d75a4433ca1d600061836888a220ee262124d145d371f6" + - "576f04cf71701133787a97aaa615ca98138c2be1046604d885e2f274b0de8743af50ad5dfc4c3a09164448e102be577eecf77ffaec1724f91f00f908ff6af41e" + - "57056dfa8f5dbcade85a66c10e524bae55922b4084407fb36ca8d6b7322f76a8139be9455a34440c719d0db8a36385efa48841170c8d35046407b586f5bbd169" + - "7cbaf6819b663fb17d0f0ae89691a099a8ccf47fa61fb6dbb22b3298e5cf2465e4b93c49da70fa76924fdf29389194cc5c61cb4b3084d0851bc3018270d1a24c" + - "b4b04e8af927d9fec9ea1c9ce18d4dbe61f7aac0ffd4e7c2e9729b49ed9874b883ec644864c6d9ad0422c4d89f87df1dfb2c96314b6a3e19afd21783f365445f" + - "bef10562a26b48df42dc344ddd63fcc03220dbde98f1109cade221027c40f0f996f4beb29513c3979ba374c4c6a2c2dc6276ca6be66eecf1dcb245d6efe78aea" + - "e49ece37f87894bef3c0cb1b993d974685564e2476c12c8d8f63a1aaf142fe34a6840be340b64f96d441f4537dff434ddce630101ed9f78e807881f6b7590697" + - "bc97e60accd7a135d8915781f4fc22e437145154dad0a39e5e306c117b11deb10462ba74d58e81de7674ef0bcb20b38511991447f63ad906b11abd4ba88df3c9" + - "e6931f87fece49f48543fed0439c88ad78f82aabb32dea03d030bdd76efef6b737daac2de2db1cce10e2ec74565b0a609606cbb6aa259ba88715229b8176c874" + - "db3fc4f6db9f167e7b2d55b33a261f9eecb69a0d36ecf9ec4f8f9cee5b74bcdc5d77b02ada89f56259edeec0d9ea866ccf454b9abd29d5d21041179912a5c302" + - "1862d850c3ff483e09479957df5bde03a29504b4a43e1fd40af2b8a2653a37cae89c8d917aecdec3959fecd32b7fd313a61e134abc15ad008aa993aba9629a5f" + - "0af0ec713f742bee096e171729e70530b60f910ef83746a61580f0cc6d67723792c0e0e94775d5b1edf37864a50678d197bb34a97e84d7f764c0bfe05f4b2d0c" + - "dc431d1f4410500dbe2758eb05bb6b19b154707c255a97cedc6aec1841f1817f6bcba0b9a9c1d3aebf747bec4423c71309fb8b4ada90dd9f7adbcffebbc905de" + - "74ce531403df33457c4d0b970fea5df4f85732e3c33c5b8242b041141a8c51a62f0bb14dbe07b14d3f5ce646d76e87b258e9b62128f9c0c0a8014f2c5b3d3dbd" + - "a3a77be6222419cd3fbbd3b842c46c099f142bcd36442961e8205ec5d7fd159befdbff12693953307026f1e06fd57b6447dd3cb52df466f0352cc46f27d1fc56" + - "56e06f68ca2847d291421bc9e0af6bbcfb7b3ce07600827809506ba3f96f40ca22766f8cba32d4461488f6596082a52c11e9ac908922075a7b443c41e55b719d" + - "9cac9fb587cf02432e1accf3cb7a16de0d5bc3a1c0aeff5a1795680b4551316e3d7b5a9bc63a09c6f75b0f00eb69fb6ef5130c1ec40c7a7d5d6ccce364b74f63" + - "a836a4a711027e592d6a70e10e573cc6d730a0def4a7a2d4dfcf3b0aba37fa2060ae6935710191c023a0b8e123a67ee811ed43b5127a1c4cf82d52ad6c40fd66" + - "1160f77dc320bbed349c8b6d08b2a7a6234a8dc88e4744b51d2d7c56e02f1c3bea9e6c2c3d5522ca02ec7e0b8160555eaf28797ed30b5c931a73562791f5f0a1" + - "b7ce83824bae17de449cff41312bd441f34df62904f4a0265d6fb9b8a352895ac6f0025d6b2074570970b4e679c559d03ef40794708eae36567008d9c33f7fc3" + - "5f8df7e901c27f408cc7fcc52631f1178695ea660d07df541e5a32721d145a32e8d32f06301b5073149e8798371fdb1a2daa5e1d02c24da07682a2cbacf5af55" + - "64810e479e5966dc6bfe14b4472c42cb154e19f7b8659d42de5ac926224cc6b0d8f3fa797058fd6e21ea85146838c4612760d84e24341825b6931a6417327394" + - "0154125254d4e11ac80e475a178605e851e1be39695cdc0781da241f232cedb32a04b1cc7352882fb635162ec3f5fc5004cfa7d03780753c14173ae7b12a71cd" + - "b40d4835023a00a4803bdfb6916956ade9f687af567e6f29981120d306084ad061ca1585f0e9497fdb27f9d54cbac8fecff176145114ebfc17e3f346b246ab91" + - "094dac0e684a708b45dcea16378fc29683dd033310068339b13d995dce77a50f9ee9cb4cf564566b05ce352a21159ad21e720e05ce6069a5ef4e9fe8ffd28516" + - "8356a0b80c4d1da547776f486a117f6f7ff6557edae7d68834cd71973517cfe4af045ad0fecdead68edc8017000958b69410247a51bd9bd3152dd57389f25223" + - "d5e88c0d343ab3aeb89b763eeb7ee48b3966fee147a4614e436c9a1a398487c80a001700666251b3dd6a2e5dc96814d21e6498e75811ba4c51160cbecb7d5510" + - "62697171a25a6abbc41fd806c3dfc83daaa10d7ce47f5a29ef0d85dda5a61429c637520e6a4048624cbb25f53977254cf803848ad81f25eda07690fe7a0466e4" + - "d18a2fd145dda1c94a994bc4ba5ce1aa1b50c38151febee757afceeaa91c7b35e57b90ff7b62efa929dcb962d32dde5a0bc3159524728621a3d7487eb7c3edd8" + - "6df3f8a18e590039bfc84a22b23b11468c90dcdc8506187233d8a6b3dc9785ddf6f341709fefccde91a7a0925a8446b1896aabd6a6826ef88b756a9711cb3b78" + - "1ab1f4df4d0515070e41fd5b0c5483270307e60eaaaf0b3a48f6bb96eef6141075445285675bb12f2ce38b42c91c1e063400d7bba9b322a0783e7d2f5d3f8874" + - "52ceb65bdedaa032336d969d2e0e3007d2ac07bcf054b9d0330f2e26c486c054bfa709fdabe283ed9a4ae67cee24f40f2a5c4e70160e6ceead208ca400959922" + - "70bc35be104c9ad94cdbe288b1c599db1758331340c9e927bc9d688e4186d5badd463bd3ba116bdc22a39c604778cd95503ce4ce642041e89bcdeb86fb19ab25" + - "e1f94ed2a2f857b228ed4a582ad411d7273a0d5189bf7a2b87a135753e03383033b989ea532041ab9ed397ecb3ce61e01923b3729068f6828ffd12e2ab1d28db" + - "6ed7423d458decb00476657a0580b4af3aa5615bf07df55beaa2bec71447aeb39791477dd09349bf573e29e9c4fd454b4bbf1e19591bf38dc47c83bf39babdc8" + - "737d69ce4b586cd10ed406426b88e686c11072f04c680e8b6275166e2dbe91f701642b1b4ed92d23d6fe14f39ff7f5a09401f3a398eb4bb742f6cf10aa35e767" + - "7e6e92aec791e94f8122e8c9cc9d0bc979e3eac6562ab614ff20330b00d9cdbd08e9deaeaf5cd67b49164f550c5f5c2d7523fe5ad71a2bd03fe2a97329980cb3" + - "049ecf6d677d815e56f7cc27407cf73528549ea98265ef90277c14763d5acb3572f5a482432cd8288972af580fdd3418889bfa6a373c4813c4c45e933ea4ec72" + - "cdd068089c2a30897dd57031445834de9f23faf506ad930d843b1cabad2c0aa8965d1b5e57032c969f9f55fe2a3049f4e63d5b5c6f5f760da5ba44e3bb9307e9" + - "ea39973d05a74a49e15bb71eaecf62373153ca316fdd40b1c64ce2896c95a7b5df970c2bec85edbd5ed84fa7949c08d5ec4d987052fffe357d444e2408a22295" + - "6ac1fb272f5023740b381e00dae9f09751a33bc6ad673c4221ce3f932164deb99f1da3eb3581caf475e385bcc56d47a7a1615a9543403750f0121d5482c4ea5c" + - "94fa3428178f6a4deea08d754ba2abb3d1aa48c3e06f06ffcdf4571579d398cd991e60599e9633fae6a0c07e10e538aebb7d33aa127c830f14b083728f6ad7eb" + - "c9a60a0ba222f47780eaa82a21393a49defee97aa8c3aa2fa53a2af86059a7587074128c2fee7060f398ae70b156d53aba0bf1af4bff10a966ce7e6382cec4b6" + - "054a8f6b9ef0e8729ee182f86c862f9b7d5ea36ef7e15bed10ed41b25738c380e58cf42795e3202749074fe5cb6e8fcb49a116f54d84734a834609a3443b8b42" + - "97c05ced428f5756ba59bfc1535bc7e16d370d81b72b1f3f78ba75c820b22e485dc042e4f38e93cc2918a491750c92998f03aee571cbe9abce4d00fdf9801f9e" + - "8e0fa276822e1e5349945f1d337e656b431c48c1a2e9d4142ea14e9427881bf201ad8cd8effaa6fe6a7e07c8112299db1b327a0cc34c9fbd35596f4ee25caeee" + - "221afad93ce7df64aa6ac766cf4fe1660446dcbafdfb86b4e0fea78c29c3e84ce42da4a503178bd250a6dbc4fc65e397062229001da05d5be118dea7ca5ce67f" + - "b4ee07a8b01e408aebef2c913434921df686a242b7d015a559f9efdc54ad62d7f31ceb72463041843d7fb60f948fed03ff143fe24ab81bd4ef6bdabb856ef1b7" + - "174cc987436322271bf48423114e05758a08cdbf300931fc7e950830b7ee920f7033541f1db9b0d2b91cad80d06c049b05fd0a76d6dc211bef2a08d53b1d16d4" + - "2232fb263941daac4e004542517807341bde98e9990a97739ef86d66c7a51324f1f6911cce4c3db37ebacb6e58eb02d8f7d6ea31338b56a99649c4e730a01bca" + - "deb6fc87cabe00addf1bf76b83927de26bc2bb3f0cd5945d863b0c31cfe8fd4b60462000a911755cbecdb6a98139041d52df498aa99aa3876836ce5b5bb426e7" + - "c22b5977902e0b3425fdbdb8f44e8758b207b469c3e5363f552c89fbf778e95e8b7ff6566ab591fb68a8bde38d8169c708a321b669c08d9ecf1a06c5321bb1cc" + - "9c8a585b6381645edfbd1ea4a2ad7e7eb8be6c431958add393c0a257aeb283644c6fe97580aef613f1b9d83e5b009f7a4d059025c11e0a0a67801be511dc097e" + - "4e7c065684effcafab83e0e716e2d0862e83b295f82089ed3ba4f6897c8d8eb2b358231f95eef840e1fe22e9065de2b3dfb3633e2968135756cd9c109e8acbb3" + - "172bbb6680c2e4fd69e179916a7849315c9f4dc86991d75cc6358617454694b3fcf2471ec7fca6ea2d99f704b9aa37a25a3b3183c5e32e3711346ba2336d6001" + - "489afb9cbd8822dbe4f0323ebf7cfa9367b6548213d473c0f07b1bb6d16e1c66fd2bfa1ca623e03149fc81eb6f71c12e7b4b76ca588548bb4872469687f334f9" + - "7e114a16a0a58ec70ed74ef69dd96666a85aa52d1ca812235796d90b9af4296247f4c1ab632effeaaef6acbb637f1aa9379195b3b668ca541bc6eb595bbc430b" + - "28adc5d1a26fd4cc2239516ac9ca9c0c028110926a2f88881a5886554c31539f4c8260e16364f4ac27710d2becdadf573f4a2b7b55d76ef059432c91c6f5beb1" + - "56686a620bdb4aea50df564cc0c5ccd8a93c454e06b8969a0f59d63ae5a29105149c08a5de65e87b0dc445dc5d86db8788ba77b83e22125c69621140d7f17906" + - "4ec0157a877cc51ce3c0d565bdf6c884f69b0ca631d6863770f6db30eff847e33c8b30d5714668a38a09f454ee44ff2b7f97207f10efcba74325378f6f272ef9" + - "9f09c501c12bd0a4155f559a604204b36751ce8d4c0af35a8b445a9290c305d5d3ea21f944e31df9a711ee90bd16a37850e2a87c3bd3fdecdc6e2f261a5d6d0d" + - "580990fcab9228cbb39f8c79608d821ce27c10b0ee0b5a96474759f67970cbe03cec9fe594765bc935abccf867b9717a4087465c8604eae89497c8ffae7e46f7" + - "ade2848916b54aa796809cb98a4364b7b44c17944dbc408909a92d4cbb24a514b72fe8de7d1cbba0a101973fa9b29d97dcf1f4ed8a05d5e0cb38849dc6e2d041" + - "16892ce649e0a553a727bfbb1d5794a059d6a411e43876e561d83bd22c054680cc8fa928f5f4be2d849f02ddf9c6d11ba35810b81553e1938ab013663f6ef35b" + - "08f06260932d7acf99f57967eec57a61f03d880c3225e53102a672f5842da21aaaee02444d372ab8ed7096235a4926e3288912d9c736c2c4dc49918abdfdd6d6" + - "d0df5be0133abd61b02a6f008909c5350f9077598ab2e612603431bddd3826e314feb280585b37eb89e597f7f0bdb738a9a93d9af224659d50c8f7479b240487" + - "76c2a960eb18923fa2d3b31b3d20ef538759cf22f5b415d19bdae689f2bab651d79ff99f77a721bc1b2233da12c12be0c9881ad82fc97a6343b3af8207dda8b6" + - "5c600644d741b8a16750964e341e060260c4de26f991f3a1f6a606d1153565f1c9cfee58eef327edc0e9cfaa206ce930b191f521be2344949bc75d583a413a96" + - "ee4edac424cbf9bdad2883c96a1306b96ee059d8044e3b7af4e7138697f142774ed6409a86a3c6c456600d4e405e6117ec759f4b22d7e5a185b0f9c67ad987bc" + - "58d2e8c929d4a487e5b77201d7c1416878e8d63258b2f58727cb631494cf1d68b99c28493b99b0409ccc1f9c218a2b95c45ff36563f0045ae5c3098f641ea6a9" + - "b48a3e1489831b2d176a1e0cb2afe6bd8cc5e797de01391e47e798c1aa945d33d5e7dd607aa73c9efe93f0646adcd7e211303ac7deea4d02c80370e8e867e2ad" + - "9942bfd5a66143560a1f59e5be1f3aeecd7eab689a4a481aec78045ae0604f69d9eea550152f6e2bc692529357b509d60e5a497bd94e63dc698cdfa2a3a55976" + - "0b2d072a2fe9c1fd41f31518aae0edaab532591476a9c5a61cd76937575cef71ff5dd66e158e7820b4b6bff4067cc26ee9aa66f41b80f078645b920512b5efd8" + - "88b3644601a72e3f665b9c8f0ee246593667379b8fa043718f2d75c21d2a11640c328971c32d5743c11ada6c95cfabf1c6b66e0b09342afc899e1f272ec48a7f" + - "ba5a51943763bf969cbac879363e14dad1952517d8f4b463511adccf25e655bced7cd9666d01dd4f2a0a21729ac4f44970c9c478a995d1c3b358a244110f1db9" + - "fe6335685701e0c2660ae69d33a93a75e44f5374b979a5af140200db43ff612be2728548192ebfd0a3860a9e135b910fe3fb249926d334167622bf4123bdf0d5" + - "38e9ff2a3bb67a44f8407328e3c94b47d92e0401aa1db85459967699804df245a7808f972683afded9cad8fbce15c1be38fd10c62c7abc302eb0537d5cc573ec" + - "245513a87c1a8d386f7ef0c4a91ec3c602b14a14ae395da13284df3391b929c7379e181c5d3d4597e3c955ef6e3dc2fc55890df04785bdd4e3fa35ac775f44ef" + - "9d7813cc036d6bcc316e869eeddf7b30e4b837e9285eb20397b4d7e0d12080c502c750268bcd6ffc323cb094afbe8304ae840d37be833878697f2cf931faf06d" + - "28dc6c7e1b5df69327127b47eddd0237f1bb5942ee5903d8cbfe1b11484199e90fe7c8e7f2f725deb2293630bd8c8a377d539736e2ccc2b90c08b97abd8c5ce4" + - "ea91a6219ab06c61c31eb48a35587b3c1719f387bd8c2063c5a79d041ca8a9ffac2e3c728f74efdb74ee0730f84cb3a8aefff7c8a1b570127cfc93eb6d3327f5" + - "ba7f886dee8be0548f710d6bfb18cbe5910bf61aed2c95028006f419241d968933aa00bb0760a41d2693465827a00837a84cadaf8a8e804d175adc5915c6cb6e" + - "fefb2cf70db063f2f3812da17586436c176aa0a815dfc7983eb88bfb1b6d1db7ab119cd3058c0db4d1910034f70f6eedfee8b742ea45af9780f415be2f851061" + - "313a218ad48e992b75afaa07c33ca47ee0155fe72e13d7e5736e512c5e5a45d351f7c7902d8b0fa31b34569a9aea31b018d63d572a9898c389d07caa427f114d" + - "251263d56cf5d6663159c2b32683b266fb909ba9d4caadaeda6700c03b25307cdea597a3287fd76082dbf33f073482872fdb494b892112c594d7f265d2799b5e" + - "5ec46a30fbf1557fa344a664a7af457a4e8ce2c014a270215d3f95d47a42d8f86a61d6d6b363d04a99a0d8f06c5b15cd803d951aea0ca185a807ca4c677db789" + - "fca64f0c5ba95b8c64f930eda658f9f773a9e1c8669589a7d98ade8dbc2c2c4cbbaf6ea2bbc6e762d4098f4db0d3f055958ae9da15ae57ee0b60fb9513dacf5a" + - "d65e34613570186acecf9e165bfa470aabcd35f22620497fbcabf220c53cff84eec12cf9965297b364f0e9122895c175d213fc2a9c9cbf27ebe1cf96fdacaf1c" + - "1c79ede66cfaa5057d33e09b31b43869812e5a0ce730663c18c4333141ae9565e437d99ade6b2cbe005214e8b3392c55bf4d7b38ef16e7f84b4ba3c85e1dfd1a" + - "ca8da1a5c75fd190e7752926533327880aed1461c7e9de2443ba0a2d094f4a14d5fffd3b102ea78acd34d162e82ab78fbb82bfbc8a9708ab532aa861643c39cd" + - "2bc89f2be53c583f9930fb2da14f1c5d5f218384b1740a76bd8b7ddd2c9888c8d7e7e78cc7a3304fa41995c7c1c3316894296caeeb9711f0e6bf16abc380bd41" + - "10448be3cb03cc3246ee7b9559c858307001033c84ecf89690526544c05c146f206d4a21e710597bb57759d232154a1f9d88eb3f3440374bad1e901da7a154b8" + - "39a6d1b1b6b2ab0be872ff036a9f9f769a169fbf91bada732d8f28c453b9be49011b211155fa5c588b43018775f99e3b92b322a4c41282326b79fd26541ccafc" + - "c0e2f09797e3217fb0e5785b72e654dbcde8ba14b2d56faa2218748c6789c158bb635d43c9a64690b004ab70f457e9fd959b2d90875966968c7ac44b103283e7" + - "50b60deeb1f89444aee25fbdb7fa3a96d70c3dce38246f111e466cdfa3b807c54ed584f5b1a64456e923dcf37f45b36cea3d602ba3a55a4fd883ebb6dc198650" + - "b522461614656897b9b7d408d48b12e594af06c91f715b32a4ed65a379f0ab461acb9b8b20d1f1b12e9f7fea422c0c7d545eff4152e06002cbd120fd74b483d3" + - "a0ee30cfd851c98e9aa8fb19b60528de4a75b412bed656933ae8ab600aeaef5befdcca4d35fa472ed38ffb91a9017c19c5d500426f262ba379034c45cf5d1627" + - "48da223207721b4bc4504b79309f3d622c53dfe3c83ff8866dd7614a2e90a85c077b2e18bf1cb6008f0d785d6a0ffd5f15a83a343036f3fdd25314bfe47b5a12" + - "58a7c89475f39a58a671d0a17f6fd100a8928181b94d8d53149316d5addf14bd398b538e2593273f02cf296fd73ff92d02230de939dae94e03d44ce93dd4dfa1" + - "b9219fd369c854ec409d7bf94b316e5e9c16e1ba525a783e24bd3fc0ecc949be245c402efae8ea77aaca74c78703506cfd5a5a614793e04c76652b4f344f79fd" + - "f2da1e34f650fc1094116ead723813d204ffe375d20707fd94d90f21c009194201c88d22afaee83a8a6be7518dc915331b863664e033d397c64e1516c0fd9324" + - "11614a1bdf2feb86e0d0ae21e784a55086c596c7eedd44d3afd7295455450f507f1c1a33c9ba94d50931ec054d8740510ea23990c266f30678a74fdd485b482b" + - "cbfb4070e3f10b66c65a4210794a3137adabe887ffb9bcf2a30c625138f840b2666610e76e5a0abc183088a94930c025836653eddbc440621bbf94761c74e108" + - "3672c6a914a753fd452e8e7a02c54b21d7bab4b705b4509b9b5b27e2e5144289eece950c3634b410b5e3cf8c5a5f74d98b55d17d45d7014390cf696a7e693777" + - "4c028517062a69276910cf5f139078e8ef6e77aa8b35aa55fd4f53e48ae6b4875d1732b286ffe8bf852b73af7b964fdf1aa4c4f16d9f14485a2b1a704c2615ac" + - "8ac74eaaacec7e8e4e506e1b418d377e4d5a271dfab47b3d3c11a809beda596fdf37935dfe06c147dfe7d5be696ffb2a0cff907d1eb2a88477c261d5a7aba06c" + - "d70dc52d00b9a9d851e849f86e1cba91b4c40d1ae3d4f21a2763369dde34d084adfc09d2a6cb5f09114cd8d6fa26d15f1ec428adc245064e5b8e80f21b0b3ff2" + - "6690398d3080f5355fc082bc4bf3a38576c7da00efbc80839dc9a06fab2b998a152553c36fab42e03e3e4b54456ed954e53bd63902d89e2617a263e70146d1eb" + - "71557baf43aeb0a681f600a784778c895afce26fe17e3ac33990c54cd96fcb2432de79d4f95ab2fb96effdd37f4e4247ae5b4c1fa461ca3269d45a90af090333" + - "fc3ab5152bd5aed4445eab93466701382ba76fc8745abd911bdb45a494e1c62647670380c04377bcdb5e631318dfa79850469a988094acd48a4110bbc7289617" + - "ce436294ff242302d154ad75437ae2f551df5b84f884c87497de0bb2ef7bd41a8c758e4b158084c78ef047389d88974faafa00ce7396e849509d39c403fdcca6" + - "8f47e1d0fc294e5510a07af24c165e1a4b4ba9498e7b333c4e8624c552801079775fc684b6e98b72ff133164a2052c2aadcef168d9cdeab8a935c98f08e23b95" + - "859277381a2ce23ea61fbe9ec1439a489523161ed370b0069aa6a5c7981e4a80c04e304ff2fd85f80b51e3de3484b53084f376cc72a390aaefc49baddf4d2545" + - "93dcb5a49326c9c15c3d1c0e0709c9879d68bee07b956d018a995bf1e7f8fa03ef2079d01e0bec601519704cced98854c94f1f0ae837653f14c0221e12f2cbdb" + - "1564066062bc1d4dcf7ed8b2c980b90e8101842d5844375cb370f402d858dffd9eb52572f8420d4d246462230ca0dbd567250e4f065730a6aecbd804b1acf949" + - "30e2890a39fdd4c1eb693f7e345504dbad5ac207f1a649968c3a7b416bd972b6a6bfde04375337a93b0ac08f6fae62c0fa7df8ae9deeee421f7ac62d8cf5ecf3" + - "b5ff39877ee4abaeb9db03d8a8f13f7925e54267a2651c55ecf580d5cbb24bf504fb01291e3e97ad1696ed995608fceda79f2441ca67bfe3c31f4f4bf0fffcd6" + - "55408744524412cd4d3cbdbdd216694aa7477e88b25f7efeb34abf491a50695ff686829a8fea9e999877bcb37291b8dbeeddfd44465a2c28a215aa532590c487" + - "d4747b6ece4e1aeaef725cb305d11b965a9647bef36a5c2fb45cc334d35ff4e308cd8813b6de3953b35a4ef6a3ae07794f8b54ef6365a573135320612bd1acfe" + - "6cac5524c0e98b6f2a33a790b94f5134f0cba075a6fa93c191f4176ca62ea2e365557d6b3363a17b9ee52f3c347c82cd19f8432d16a934ae9c5d4d4505e7d20e" + - "1ae31bb64ccb084f7a59744b27d58c2388d449ff4b63604878ae858240348ecfcb51761678265bd60d5dd7d51e25e91668fdf80f6b726b29ef6c3f0f229d8af4" + - "b2cdadc3ca7fbadab49b28819b9c9b92b49cbe9a281e5891f4eae7616013777605a0623dd7a650baf9a9dad66ca9aae3c76ef1e27db32bd9514a2776eb0c8d05" + - "65eec06fc4c8a69c417efa336842e248e5a51e3b5f3ba3227e3f78f1bd12d81595e03a01f4259c772fd481ab5f3d7a945e1c95fe0dc3c4742eeb7e15c9426ec3" + - "ed4c90ee07d56acc78fecfd7c5ce1e04e7db1a970091f15c90f0aae2865d135395d27787aaf68c6a179064d82691e0b6c795f61875f317dc6d2e8feea55a28f2" + - "461d74e14e350351720b6f536adfe3addd4111f08e3a84da2656fd4bc83989b329b383da9f01cf2392aa0b19577884d1281f2e6c106df451c078a472b36057d3" + - "065dfc4bbb47ce4e5dce4acf6da095bdd10322f3ae12bcdd1f805e73b303f1fc7a7e16cf3ffd822bd8b25fbc93be065019e394113182713f1ad299ae6537f6bf" + - "57116e8dc9ec775519b797ab4107c2ac5129ba85188852c3bc5f116044bbd8985b6dc8b8da4659589bf9d2351c4c3adaed87fe2ea20ef6bf62224c7af86fe8b4" + - "973e558f39465dff43bf23cf1f78957514e4e82a3009d40d97bf8d8442a11deabde806e2fa84c1ba75273da75ce8dad3b2a34786b2958ac4bfd248ebe604a173" + - "83c727b11dd922b1f72476af700b663fbd7033d0ac74b463d40a92d26c938b69f96fb4a9cb7a9ca2bd9496251270c0c5fcae6b3c2eda5377b897891648a97125" + - "8ac71fed8dce8e02c30961a299cb7f3145845dbe8f4dfaaaf4baf0ca3fb730abdd258e98215f072a943d5aee8d8bc4c86023524f7b69186d99ad88ccdfc0b4bd" + - "7db422bbad7eaa0824ce24b5c186e172c8c584f1cc5c126c901a69ebee8dbd230a653a3643b7875672d22fd86079daf8d834ba33664f5ad0b6eec767b4f58b45" + - "e67b776b90e0a5e130aa5365003eb7fd78b757b1cf9133f6a1d51064b293cb42c8c41b15b7e95e2a39fa5dae19c6e20031d2bfa4632c37779163fdecc6b45624" + - "4d6bfd01a8877f6fe7739591917a86e7dd795ad85cc3f256cff5961e8b62e92a0754a51f2c6d59819446eec8bdd08b87cf9f4fb5373e809d52240d2dd691cd50" + - "37fc79d35b61d63851917cfdba164868a3f79e2061bd4610c1f5216ed77df00baa75f949ad37142db4fd282a5c7d2e2636ca590f92fc4781d4f51efa69f53947" + - "d4fca1dc7dd2429837b6d7e5c9528effdecf6f731f676587785e5c4096bdb6f1f44e72f5f77d9025813e848881506f65bfb0f2b2d3ae6f9e00731929b5ac083d" + - "b1c9c324703e63fef6319e1d8150aa0ff7d9a2049961df9158f3e1f2e540a91feb742625d2a859a452186d2ccaa3ec2ba086ee0868a4dc24ae6818fc02f9c1df" + - "dc326cc31c46feefda97265238592f638968627ec24903b97513ab05ed58ce5b516decda0e2fbf01a70e6cb2e53c3e7b8855f80cd7e007b78da727ef0893e099" + - "592ba684d62ae2d1f06ad148fa7f34cfc724d804149cda21aee7eac064ad20d29132b260c2c2867fa6a2e747739fc30df2f002c2a99da6c7e64ee51e806af7d9" + - "768aec456b93a05002666cb61b2229c99f2cdef9afc9cea1c4ee3a85dd189823399781ee33cde2abedff09c47960c035e075a29156005d75845a11fa06abcc50" + - "5f7f849a0caaf683f334e9e7bbbef90fe6cf94cbf87767219440d31713daef6ad1e4a1cc720ce59fee4cf7731e46bbba9ec1648908ea345030aa8f10ade10ffa" + - "3d2acfd480b0b11eadc4fb2b740596b204e911456cb2f35ad9993ab7dd6a48b35ba0c207625384bb3c2ff24437810bd13c7ee96cd6f97f19ffd537ad182a3657" + - "b0e83d42fd6e2ebac6cbf5ea1bde97465b7cec6954ff5b5be049e59a49ea25ed6667dbace765401bde12031e5cfabf2df7afb728d2a0b2a38b24d79bf23a313c" + - "40fe5adef97487641c6088dd8712c0c352708e474b02c08fd2d71b6d44f16d82f291ccd61c43a339408379a8de54cfdbbae5e421e084112fbc17fb5561e084d1" + - "4149bf4bb06fd161878d8574f856867cff974d5898e161923d55bdac8699c9df6a220bcb6c800d3ae7f107b8c4acab206d780aafaf6c2e2379de8c900700d9c9" + - "c87d464772514c5aa3e5f5bfc00fb54f2b74702838b4731c5ac8a070b50783e81dd97fa8d55c739d026b607a2a78aba1bb79b1a7a3c22c78368672ac020061e6" + - "d9683d57d6989c6c6f08b8d5d74720f5cb25505fbe81d2bf53a68e972a54784705b20f83fd1ab5afff30764ef89dba4465b56f48b325ab3810bf8dcbf4faa61f" + - "676e2043ac8540df9e3af4c0f51d816e89c09bf67253be45fc5f75f64be97f6c7dc0c6392af6fa8e75aab58eda976b36773cd37d315771400a2cb846fdef3d8a" + - "a15bce5dfda0379e526f87cf67767a2ab93d41c85b4ed016ed0a89d2f94737433a3ebade813def29eaa18a1fb925fca7d08d1020f64caebc562cb4ad2fb241e2" + - "94923b2f2df5e6c4953c4b73be0f5568defe57ce49d16e2a205323e46cbb5a3e77fff1557671503bd7b5de5320f1fb951fbe26400cfa854af2d12fab0215310c" + - "f070add34dc4565d1757d7e10a03e3bb73a607ed7e10861b1274ddee76183cf7e56c1de7162c805c2dba0e0331d36f3a4e2019a2e0705ee2747ed1e52bc3a6fb" + - "3b061f784348204cdf8d643ff6c271fa72b56900edcc2f77201f3bd4fc296ad6534a7029ea66761bb9a3589a1f6ef566504c70297b98fbb603214fed2e4b7ca1" + - "06e3f0e993118897fa641fb9722d4667fa98d07a6837e5ab2144e5ec1548a7dbca28c559f2a9a99d54b8e55f56d0e59bcef1ac45e2046835b60579da0d2261e7" + - "30dab9009d138421c6458d146e870358b0b3fa20257e50b58f167c6b47edf7053513d58f33547d06ce52458baaa4dcf15f77b103565c66a81f183c827801b455" + - "b61b6287a46a37a96884075a7eada9ba7f0ddcc14654bf87a26d2e27a978b415257773796923a220e06b25af16fb5aaded9b2d081a4c64106df460ddce9c3b2a" + - "c8553e1521e501ad29a4b7f7681c9b60576a127087a5237c4c2bacf9b163dd590e63f2bc80e7f1e613773f87d034313064710404739d63363d204be7b14800c4" + - "d8c1b6a2a21da70223be51d281fee302ef806454f9d7d28244ba537c1d9f8f1bcc5d47038d986a8f95ca48437ffe94fd44a90bb03014a259112a97508adb3db4" + - "34f72a5268c1af6bc6d5801e579aab2228ca33600ebbf1a1959081c3a4ca99e444f97409f5e0ca4779241c9aacad1f4ee7fb4369bd6ae076378e4f63000b9a5c" + - "849ba6e72e47e2454a44659149338ac0767cd25d8693c0d143e354bd600f1c1d3a44eeb024923ea659060665d5cd9a4ca1ca86162819556535fd59b9fde90caa" + - "29920efe99479fe7e4b4e5371e13ccb43a1419cf023433239d840900d31bab37fabc3fd20e31bb7dbcb3ae8df66f67e2844944bcf544b658364f9e3d0b6d84b4" + - "63ad4eb621644fd7d774b501407a1178814b15149345d551b474347188067db2ab4d7f4d1abd3027133039e855e129f3f5649550da8c04fe2db57cb89bf1bf4f" + - "72eb35ccfe31afb92f6136d4c2a1c115b07b721b2da43151f11c356256230408979c5d95243714429e2c9500e7b043b20dac8a9763e5b487d1cbdb34ac379b9c" + - "6409454c79385b6e562459c4fdaad1b7f9297c1473e9b90fffe6d1c5390e241a187a4cefa2eb0cb0c11f4ca6c5b961c18ceb57892295290dbc991692556bffa3" + - "b8c405cf285e6bcb8a90246ad0ac15122f4cf73adc129d23aa2240733404beb6d74bf698e5589288a522573c774ce9f514b5d5c086382ea1dd4e89ff5facbf23" + - "d36bc3d203941e17747ede4b82820351f4df278ddb787ce8f6f1cc468ef953399efb072ce706e253f1bab76444bb70be6443cd0db633e958dc57bd223e00418e" + - "915a7c2e4d94c0623f9788276480cdfe798387d35e2ea2d304d066aec7627794cdd4200a44208d6c87f242c76e2d4a3f966b6fb96eaa63d892c1a177bef249b4" + - "fdd1a4c06c791f677dd9919f739ccf318bd77835330b0219786249c9c9736161dac771a838724f2dd70afba46a6782fd27601cf8a7126ae95a66e526131a68d7" + - "7a809e513533ed8021eecdbc5851dfcf95e10f1bbe47b5c7f079275a1837836245266b66d89fab25ac4bd6c1225560bea3259b67bf50a58ee056754d574da79e" + - "f9a1a0df3a5defed0f74fe74ce0bf65a04086f17e94a8451828c723c97932f26f9349f1a2c7866c617a528602721de4f3cc8916bcfc66cdc106bafa26ea87a13" + - "94dfa37e396365fb7f92df007b46a50ff04c7f85bfa679230ebedf18c2fb876fc7098dd1c4328adf85de71c31d94687a308053bfcdc158cfa7772170fbed63f5" + - "37dda41f65196dfacdd1186b5de0f3369d841ce6502192292d05a19ce7464f5bcab3015c721cac13ddca561b92dc1ee25d3068dc1945a1b4e2bd1e6604c42e4c" + - "3c04b490f6365828957990007394557854a903e19feb06906e41cbc8766bf37bd7dece90f4cdc987709b1129e84bfdc502543b5bfa887bf78553a5ec10ad68c5" + - "d10eff75f7aa495e7d934a55577fdc0aead31aee4522db0259d7d4ea8438a7996d80a787465a2980457193d1c4bf1a0a1e01741d72e5fc4dfe58475c1c01026b" + - "5a3bc973b902280753e9c3226db9cc778e2506c56ee86ae85b4d54dbf05394107329b2d1ee56522cb1ce562fb1aa4e592199d9c29f64cc3ab1d757531e209eec" + - "aa138d8388169b5e28c45f5aba267eeaa57f69869f0b6855d82b0eafcde63895251f41e8e676a0ab12ef3f569bb7de91b79fa46ad9637da01ca004f4d30259c1" + - "f5b00761f6ca9c17721a6718390624a10a11f7f52d7afb71ee5f8338828910e48f94a1347761abac87897b2dd0e23f1d325aec5031ef58f2972e8b402e05f8c1" + - "ae7053a90380a1ae0d4d06645548c23e13afa31aac8ff83b10f8341418af4114632f6406d6e33076391696c9161d63c8bcfd1c625fc737f68198046212d1638a" + - "d2d2d42ff7029c1fcc682a046edc4d4f24862d82c600180b1e8f57ff6a3865dfe9274f9886d00efa523a1b3b3757c4489200fec3dc5583854c955492336253dd" + - "767f2a60ce3d224afcff9cdc19e9b28830d33affda6af99942a8fe39562055f3e884fd6c1ebc1908ac159061f35e9b0da80434ce9673d9c6b87265170077c670" + - "743e37474d7605cd01c44af600f16d9ffaf24acf87fbe5ccf39bac41047a810d210051c87f06147a0bb8f1427a406700483679638f1af23f1dafb7aa0c468669" + - "71c3a82f535c26cf6cb335e8e915fda393799d3dbe0e04b907ed3612d12ac95783a6876cd986d2a13b82192532e02c250eaa42f891d2481655fa4494c723fe00" + - "87d224444245eb5b0eade5f741b025db1992a8ad0dce51b0c1af4a18a9e244f9f755891adf0f19179c7baa6c32bffc91e0b03c4ed3aaee1978b6a1f03b87ac6a" + - "fc3b9e7030bb212b17de198edfccde29d04224798c1204e47ea235f048724fac62d637d1ba0ee3922048fcf79c746b6c0c036d882e3491fd72bad6e009c6403e" + - "55876f4d31330caa02aedd0b0c121c3c41e736853a08071f0dd4ddc7412db0bbe274a9ac2932552bb37c40e72c2ef1d7cca8236942e480d709d3ea9d5ae0a1b7", - ), - }, - } - for i, tt := range tests { - cache := make([]uint32, tt.cacheSize/4) - generateCache(cache, tt.epoch, seedHash(tt.epoch*epochLength+1)) - - dataset := make([]uint32, tt.datasetSize/4) - generateDataset(dataset, tt.epoch, cache) - - want := make([]uint32, tt.datasetSize/4) - prepare(want, tt.dataset) - - if !reflect.DeepEqual(dataset, want) { - t.Errorf("dataset %d: content mismatch: have %x, want %x", i, dataset, want) - } - } -} - -// Tests whether the hashimoto lookup works for both light as well as the full -// datasets. -func TestHashimoto(t *testing.T) { - // Create the verification cache and mining dataset - cache := make([]uint32, 1024/4) - generateCache(cache, 0, make([]byte, 32)) - - dataset := make([]uint32, 32*1024/4) - generateDataset(dataset, 0, cache) - - // Create a block to verify - hash := hexutil.MustDecode("0xc9149cc0386e689d789a1c2f3d5d169a61a6218ed30e74414dc736e442ef3d1f") - nonce := uint64(0) - - wantDigest := hexutil.MustDecode("0xe4073cffaef931d37117cefd9afd27ea0f1cad6a981dd2605c4a1ac97c519800") - wantResult := hexutil.MustDecode("0xd3539235ee2e6f8db665c0a72169f55b7f6c605712330b778ec3944f0eb5a557") - - digest, result := hashimotoLight(32*1024, cache, hash, nonce) - if !bytes.Equal(digest, wantDigest) { - t.Errorf("light hashimoto digest mismatch: have %x, want %x", digest, wantDigest) - } - if !bytes.Equal(result, wantResult) { - t.Errorf("light hashimoto result mismatch: have %x, want %x", result, wantResult) - } - digest, result = hashimotoFull(dataset, hash, nonce) - if !bytes.Equal(digest, wantDigest) { - t.Errorf("full hashimoto digest mismatch: have %x, want %x", digest, wantDigest) - } - if !bytes.Equal(result, wantResult) { - t.Errorf("full hashimoto result mismatch: have %x, want %x", result, wantResult) - } -} - -// Tests that caches generated on disk may be done concurrently. -func TestConcurrentDiskCacheGeneration(t *testing.T) { - // Create a temp folder to generate the caches into - // TODO: t.TempDir fails to remove the directory on Windows - // \AppData\Local\Temp\1\TestConcurrentDiskCacheGeneration2382060137\001\cache-R23-1dca8a85e74aa763: Access is denied. - cachedir, err := os.MkdirTemp("", "") - if err != nil { - t.Fatalf("Failed to create temporary cache dir: %v", err) - } - defer os.RemoveAll(cachedir) - - // Define a heavy enough block, one from mainnet should do - block := types.NewBlockWithHeader(&types.Header{ - Number: big.NewInt(3311058), - ParentHash: common.HexToHash("0xd783efa4d392943503f28438ad5830b2d5964696ffc285f338585e9fe0a37a05"), - UncleHash: types.EmptyUncleHash, - Coinbase: common.HexToAddress("0xc0ea08a2d404d3172d2add29a45be56da40e2949"), - Root: common.HexToHash("0x77d14e10470b5850332524f8cd6f69ad21f070ce92dca33ab2858300242ef2f1"), - TxHash: types.EmptyTxsHash, - ReceiptHash: types.EmptyReceiptsHash, - Difficulty: big.NewInt(167925187834220), - GasLimit: 4015682, - GasUsed: 0, - Time: 1488928920, - Extra: []byte("www.bw.com"), - MixDigest: common.HexToHash("0x3e140b0784516af5e5ec6730f2fb20cca22f32be399b9e4ad77d32541f798cd0"), - Nonce: types.EncodeNonce(0xf400cd0006070c49), - }) - // Simulate multiple processes sharing the same datadir - var pend sync.WaitGroup - - for i := 0; i < 3; i++ { - pend.Add(1) - go func(idx int) { - defer pend.Done() - - config := Config{ - CacheDir: cachedir, - CachesOnDisk: 1, - } - ethash := New(config, nil, false) - defer ethash.Close() - if err := ethash.verifySeal(nil, block.Header(), false); err != nil { - t.Errorf("proc %d: block verification failed: %v", idx, err) - } - }(i) - } - pend.Wait() -} - -// Benchmarks the cache generation performance. -func BenchmarkCacheGeneration(b *testing.B) { - for i := 0; i < b.N; i++ { - cache := make([]uint32, cacheSize(1)/4) - generateCache(cache, 0, make([]byte, 32)) - } -} - -// Benchmarks the dataset (small) generation performance. -func BenchmarkSmallDatasetGeneration(b *testing.B) { - cache := make([]uint32, 65536/4) - generateCache(cache, 0, make([]byte, 32)) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - dataset := make([]uint32, 32*65536/4) - generateDataset(dataset, 0, cache) - } -} - -// Benchmarks the light verification performance. -func BenchmarkHashimotoLight(b *testing.B) { - cache := make([]uint32, cacheSize(1)/4) - generateCache(cache, 0, make([]byte, 32)) - - hash := hexutil.MustDecode("0xc9149cc0386e689d789a1c2f3d5d169a61a6218ed30e74414dc736e442ef3d1f") - - b.ResetTimer() - for i := 0; i < b.N; i++ { - hashimotoLight(datasetSize(1), cache, hash, 0) - } -} - -// Benchmarks the full (small) verification performance. -func BenchmarkHashimotoFullSmall(b *testing.B) { - cache := make([]uint32, 65536/4) - generateCache(cache, 0, make([]byte, 32)) - - dataset := make([]uint32, 32*65536/4) - generateDataset(dataset, 0, cache) - - hash := hexutil.MustDecode("0xc9149cc0386e689d789a1c2f3d5d169a61a6218ed30e74414dc736e442ef3d1f") - - b.ResetTimer() - for i := 0; i < b.N; i++ { - hashimotoFull(dataset, hash, 0) - } -} - -func benchmarkHashimotoFullMmap(b *testing.B, name string, lock bool) { - b.Run(name, func(b *testing.B) { - tmpdir := b.TempDir() - - d := &dataset{epoch: 0} - d.generate(tmpdir, 1, lock, false) - var hash [common.HashLength]byte - b.ResetTimer() - for i := 0; i < b.N; i++ { - binary.PutVarint(hash[:], int64(i)) - hashimotoFull(d.dataset, hash[:], 0) - } - }) -} - -// Benchmarks the full verification performance for mmap -func BenchmarkHashimotoFullMmap(b *testing.B) { - benchmarkHashimotoFullMmap(b, "WithLock", true) - benchmarkHashimotoFullMmap(b, "WithoutLock", false) -} diff --git a/consensus/ethash/api.go b/consensus/ethash/api.go deleted file mode 100644 index da3b0751be..0000000000 --- a/consensus/ethash/api.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ethash - -import ( - "errors" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" -) - -var errEthashStopped = errors.New("ethash stopped") - -// API exposes ethash related methods for the RPC interface. -type API struct { - ethash *Ethash -} - -// GetWork returns a work package for external miner. -// -// The work package consists of 3 strings: -// -// result[0] - 32 bytes hex encoded current block header pow-hash -// result[1] - 32 bytes hex encoded seed hash used for DAG -// result[2] - 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty -// result[3] - hex encoded block number -func (api *API) GetWork() ([4]string, error) { - if api.ethash.remote == nil { - return [4]string{}, errors.New("not supported") - } - - var ( - workCh = make(chan [4]string, 1) - errc = make(chan error, 1) - ) - select { - case api.ethash.remote.fetchWorkCh <- &sealWork{errc: errc, res: workCh}: - case <-api.ethash.remote.exitCh: - return [4]string{}, errEthashStopped - } - select { - case work := <-workCh: - return work, nil - case err := <-errc: - return [4]string{}, err - } -} - -// SubmitWork can be used by external miner to submit their POW solution. -// It returns an indication if the work was accepted. -// Note either an invalid solution, a stale work a non-existent work will return false. -func (api *API) SubmitWork(nonce types.BlockNonce, hash, digest common.Hash) bool { - if api.ethash.remote == nil { - return false - } - - var errc = make(chan error, 1) - select { - case api.ethash.remote.submitWorkCh <- &mineResult{ - nonce: nonce, - mixDigest: digest, - hash: hash, - errc: errc, - }: - case <-api.ethash.remote.exitCh: - return false - } - err := <-errc - return err == nil -} - -// SubmitHashrate can be used for remote miners to submit their hash rate. -// This enables the node to report the combined hash rate of all miners -// which submit work through this node. -// -// It accepts the miner hash rate and an identifier which must be unique -// between nodes. -func (api *API) SubmitHashrate(rate hexutil.Uint64, id common.Hash) bool { - if api.ethash.remote == nil { - return false - } - - var done = make(chan struct{}, 1) - select { - case api.ethash.remote.submitRateCh <- &hashrate{done: done, rate: uint64(rate), id: id}: - case <-api.ethash.remote.exitCh: - return false - } - - // Block until hash rate submitted successfully. - <-done - return true -} - -// GetHashrate returns the current hashrate for local CPU miner and remote miner. -func (api *API) GetHashrate() uint64 { - return uint64(api.ethash.Hashrate()) -} diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index e3e0f28b3e..b912fb513a 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -17,11 +17,9 @@ package ethash import ( - "bytes" "errors" "fmt" "math/big" - "runtime" "time" mapset "github.com/deckarep/golang-set/v2" @@ -84,14 +82,11 @@ var ( // codebase, inherently breaking if the engine is swapped out. Please put common // error types into the consensus package. var ( - errOlderBlockTime = errors.New("timestamp older than parent") - errTooManyUncles = errors.New("too many uncles") - errDuplicateUncle = errors.New("duplicate uncle") - errUncleIsAncestor = errors.New("uncle is ancestor") - errDanglingUncle = errors.New("uncle's parent is not ancestor") - errInvalidDifficulty = errors.New("non-positive difficulty") - errInvalidMixDigest = errors.New("invalid mix digest") - errInvalidPoW = errors.New("invalid proof-of-work") + errOlderBlockTime = errors.New("timestamp older than parent") + errTooManyUncles = errors.New("too many uncles") + errDuplicateUncle = errors.New("duplicate uncle") + errUncleIsAncestor = errors.New("uncle is ancestor") + errDanglingUncle = errors.New("uncle's parent is not ancestor") ) // Author implements consensus.Engine, returning the header's coinbase as the @@ -102,11 +97,7 @@ func (ethash *Ethash) Author(header *types.Header) (common.Address, error) { // VerifyHeader checks whether a header conforms to the consensus rules of the // stock Ethereum ethash engine. -func (ethash *Ethash) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error { - // If we're running a full engine faking, accept any input as valid - if ethash.config.PowMode == ModeFullFake { - return nil - } +func (ethash *Ethash) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error { // Short circuit if the header is known, or its parent not number := header.Number.Uint64() if chain.GetHeader(header.Hash(), number) != nil { @@ -117,93 +108,54 @@ func (ethash *Ethash) VerifyHeader(chain consensus.ChainHeaderReader, header *ty return consensus.ErrUnknownAncestor } // Sanity checks passed, do a proper verification - return ethash.verifyHeader(chain, header, parent, false, seal, time.Now().Unix()) + return ethash.verifyHeader(chain, header, parent, false, time.Now().Unix()) } // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers // concurrently. The method returns a quit channel to abort the operations and // a results channel to retrieve the async verifications. -func (ethash *Ethash) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { +func (ethash *Ethash) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) (chan<- struct{}, <-chan error) { // If we're running a full engine faking, accept any input as valid - if ethash.config.PowMode == ModeFullFake || len(headers) == 0 { + if ethash.fakeFull || len(headers) == 0 { abort, results := make(chan struct{}), make(chan error, len(headers)) for i := 0; i < len(headers); i++ { results <- nil } return abort, results } + abort := make(chan struct{}) + results := make(chan error, len(headers)) + unixNow := time.Now().Unix() - // Spawn as many workers as allowed threads - workers := runtime.GOMAXPROCS(0) - if len(headers) < workers { - workers = len(headers) - } - - // Create a task channel and spawn the verifiers - var ( - inputs = make(chan int) - done = make(chan int, workers) - errors = make([]error, len(headers)) - abort = make(chan struct{}) - unixNow = time.Now().Unix() - ) - for i := 0; i < workers; i++ { - go func() { - for index := range inputs { - errors[index] = ethash.verifyHeaderWorker(chain, headers, seals, index, unixNow) - done <- index - } - }() - } - - errorsOut := make(chan error, len(headers)) go func() { - defer close(inputs) - var ( - in, out = 0, 0 - checked = make([]bool, len(headers)) - inputs = inputs - ) - for { + for i, header := range headers { + var parent *types.Header + if i == 0 { + parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) + } else if headers[i-1].Hash() == headers[i].ParentHash { + parent = headers[i-1] + } + var err error + if parent == nil { + err = consensus.ErrUnknownAncestor + } else { + err = ethash.verifyHeader(chain, header, parent, false, unixNow) + } select { - case inputs <- in: - if in++; in == len(headers) { - // Reached end of headers. Stop sending to workers. - inputs = nil - } - case index := <-done: - for checked[index] = true; checked[out]; out++ { - errorsOut <- errors[out] - if out == len(headers)-1 { - return - } - } case <-abort: return + case results <- err: } } }() - return abort, errorsOut -} - -func (ethash *Ethash) verifyHeaderWorker(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool, index int, unixNow int64) error { - var parent *types.Header - if index == 0 { - parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) - } else if headers[index-1].Hash() == headers[index].ParentHash { - parent = headers[index-1] - } - if parent == nil { - return consensus.ErrUnknownAncestor - } - return ethash.verifyHeader(chain, headers[index], parent, false, seals[index], unixNow) + return abort, results } // VerifyUncles verifies that the given block's uncles conform to the consensus // rules of the stock Ethereum ethash engine. func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { // If we're running a full engine faking, accept any input as valid - if ethash.config.PowMode == ModeFullFake { + if ethash.fakeFull { return nil } // Verify that there are at most 2 uncles included in this block @@ -255,7 +207,7 @@ func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Blo if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == block.ParentHash() { return errDanglingUncle } - if err := ethash.verifyHeader(chain, uncle, ancestors[uncle.ParentHash], true, true, time.Now().Unix()); err != nil { + if err := ethash.verifyHeader(chain, uncle, ancestors[uncle.ParentHash], true, time.Now().Unix()); err != nil { return err } } @@ -265,7 +217,7 @@ func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Blo // verifyHeader checks whether a header conforms to the consensus rules of the // stock Ethereum ethash engine. // See YP section 4.3.4. "Block Header Validity" -func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header, uncle bool, seal bool, unixNow int64) error { +func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header, uncle bool, unixNow int64) error { // Ensure that the header's extra-data section is of a reasonable size if uint64(len(header.Extra)) > params.MaximumExtraDataSize { return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize) @@ -316,11 +268,12 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa if chain.Config().IsCancun(header.Time) { return fmt.Errorf("ethash does not support cancun fork") } - // Verify the engine specific seal securing the block - if seal { - if err := ethash.verifySeal(chain, header, false); err != nil { - return err - } + // Add some fake checks for tests + if ethash.fakeDelay != nil { + time.Sleep(*ethash.fakeDelay) + } + if ethash.fakeFail != nil && *ethash.fakeFail == header.Number.Uint64() { + return errors.New("invalid tester pow") } // If all checks passed, validate any special fields for hard forks if err := misc.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil { @@ -521,72 +474,6 @@ var FrontierDifficultyCalculator = calcDifficultyFrontier var HomesteadDifficultyCalculator = calcDifficultyHomestead var DynamicDifficultyCalculator = makeDifficultyCalculator -// verifySeal checks whether a block satisfies the PoW difficulty requirements, -// either using the usual ethash cache for it, or alternatively using a full DAG -// to make remote mining fast. -func (ethash *Ethash) verifySeal(chain consensus.ChainHeaderReader, header *types.Header, fulldag bool) error { - // If we're running a fake PoW, accept any seal as valid - if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake { - time.Sleep(ethash.fakeDelay) - if ethash.fakeFail == header.Number.Uint64() { - return errInvalidPoW - } - return nil - } - // If we're running a shared PoW, delegate verification to it - if ethash.shared != nil { - return ethash.shared.verifySeal(chain, header, fulldag) - } - // Ensure that we have a valid difficulty for the block - if header.Difficulty.Sign() <= 0 { - return errInvalidDifficulty - } - // Recompute the digest and PoW values - number := header.Number.Uint64() - - var ( - digest []byte - result []byte - ) - // If fast-but-heavy PoW verification was requested, use an ethash dataset - if fulldag { - dataset := ethash.dataset(number, true) - if dataset.generated() { - digest, result = hashimotoFull(dataset.dataset, ethash.SealHash(header).Bytes(), header.Nonce.Uint64()) - - // Datasets are unmapped in a finalizer. Ensure that the dataset stays alive - // until after the call to hashimotoFull so it's not unmapped while being used. - runtime.KeepAlive(dataset) - } else { - // Dataset not yet generated, don't hang, use a cache instead - fulldag = false - } - } - // If slow-but-light PoW verification was requested (or DAG not yet ready), use an ethash cache - if !fulldag { - cache := ethash.cache(number) - - size := datasetSize(number) - if ethash.config.PowMode == ModeTest { - size = 32 * 1024 - } - digest, result = hashimotoLight(size, cache.cache, ethash.SealHash(header).Bytes(), header.Nonce.Uint64()) - - // Caches are unmapped in a finalizer. Ensure that the cache stays alive - // until after the call to hashimotoLight so it's not unmapped while being used. - runtime.KeepAlive(cache) - } - // Verify the calculated values against the ones provided in the header - if !bytes.Equal(header.MixDigest[:], digest) { - return errInvalidMixDigest - } - target := new(big.Int).Div(two256, header.Difficulty) - if new(big.Int).SetBytes(result).Cmp(target) > 0 { - return errInvalidPoW - } - return nil -} - // Prepare implements consensus.Engine, initializing the difficulty field of a // header to conform to the ethash protocol. The changes are done inline. func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index 462f109564..f37ec26056 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -18,503 +18,26 @@ package ethash import ( - "errors" - "fmt" - "math" - "math/big" - "math/rand" - "os" - "path/filepath" - "reflect" - "runtime" - "strconv" - "sync" - "sync/atomic" "time" - "unsafe" - "github.com/edsrzf/mmap-go" - lrupkg "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" ) -var ErrInvalidDumpMagic = errors.New("invalid dump magic") - -var ( - // two256 is a big integer representing 2^256 - two256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) - - // sharedEthash is a full instance that can be shared between multiple users. - sharedEthash *Ethash - - // algorithmRevision is the data structure version used for file naming. - algorithmRevision = 23 - - // dumpMagic is a dataset dump header to sanity check a data dump. - dumpMagic = []uint32{0xbaddcafe, 0xfee1dead} -) - -func init() { - sharedConfig := Config{ - PowMode: ModeNormal, - CachesInMem: 3, - DatasetsInMem: 1, - } - sharedEthash = New(sharedConfig, nil, false) -} - -// isLittleEndian returns whether the local system is running in little or big -// endian byte order. -func isLittleEndian() bool { - n := uint32(0x01020304) - return *(*byte)(unsafe.Pointer(&n)) == 0x04 -} - -// memoryMap tries to memory map a file of uint32s for read only access. -func memoryMap(path string, lock bool) (*os.File, mmap.MMap, []uint32, error) { - file, err := os.OpenFile(path, os.O_RDONLY, 0644) - if err != nil { - return nil, nil, nil, err - } - mem, buffer, err := memoryMapFile(file, false) - if err != nil { - file.Close() - return nil, nil, nil, err - } - for i, magic := range dumpMagic { - if buffer[i] != magic { - mem.Unmap() - file.Close() - return nil, nil, nil, ErrInvalidDumpMagic - } - } - if lock { - if err := mem.Lock(); err != nil { - mem.Unmap() - file.Close() - return nil, nil, nil, err - } - } - return file, mem, buffer[len(dumpMagic):], err -} - -// memoryMapFile tries to memory map an already opened file descriptor. -func memoryMapFile(file *os.File, write bool) (mmap.MMap, []uint32, error) { - // Try to memory map the file - flag := mmap.RDONLY - if write { - flag = mmap.RDWR - } - mem, err := mmap.Map(file, flag, 0) - if err != nil { - return nil, nil, err - } - // The file is now memory-mapped. Create a []uint32 view of the file. - var view []uint32 - header := (*reflect.SliceHeader)(unsafe.Pointer(&view)) - header.Data = (*reflect.SliceHeader)(unsafe.Pointer(&mem)).Data - header.Cap = len(mem) / 4 - header.Len = header.Cap - return mem, view, nil -} - -// memoryMapAndGenerate tries to memory map a temporary file of uint32s for write -// access, fill it with the data from a generator and then move it into the final -// path requested. -func memoryMapAndGenerate(path string, size uint64, lock bool, generator func(buffer []uint32)) (*os.File, mmap.MMap, []uint32, error) { - // Ensure the data folder exists - if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { - return nil, nil, nil, err - } - // Create a huge temporary empty file to fill with data - temp := path + "." + strconv.Itoa(rand.Int()) - - dump, err := os.Create(temp) - if err != nil { - return nil, nil, nil, err - } - if err = ensureSize(dump, int64(len(dumpMagic))*4+int64(size)); err != nil { - dump.Close() - os.Remove(temp) - return nil, nil, nil, err - } - // Memory map the file for writing and fill it with the generator - mem, buffer, err := memoryMapFile(dump, true) - if err != nil { - dump.Close() - os.Remove(temp) - return nil, nil, nil, err - } - copy(buffer, dumpMagic) - - data := buffer[len(dumpMagic):] - generator(data) - - if err := mem.Unmap(); err != nil { - return nil, nil, nil, err - } - if err := dump.Close(); err != nil { - return nil, nil, nil, err - } - if err := os.Rename(temp, path); err != nil { - return nil, nil, nil, err - } - return memoryMap(path, lock) -} - -type cacheOrDataset interface { - *cache | *dataset -} - -// lru tracks caches or datasets by their last use time, keeping at most N of them. -type lru[T cacheOrDataset] struct { - what string - new func(epoch uint64) T - mu sync.Mutex - // Items are kept in a LRU cache, but there is a special case: - // We always keep an item for (highest seen epoch) + 1 as the 'future item'. - cache lrupkg.BasicLRU[uint64, T] - future uint64 - futureItem T -} - -// newlru create a new least-recently-used cache for either the verification caches -// or the mining datasets. -func newlru[T cacheOrDataset](maxItems int, new func(epoch uint64) T) *lru[T] { - var what string - switch any(T(nil)).(type) { - case *cache: - what = "cache" - case *dataset: - what = "dataset" - default: - panic("unknown type") - } - return &lru[T]{ - what: what, - new: new, - cache: lrupkg.NewBasicLRU[uint64, T](maxItems), - } -} - -// get retrieves or creates an item for the given epoch. The first return value is always -// non-nil. The second return value is non-nil if lru thinks that an item will be useful in -// the near future. -func (lru *lru[T]) get(epoch uint64) (item, future T) { - lru.mu.Lock() - defer lru.mu.Unlock() - - // Get or create the item for the requested epoch. - item, ok := lru.cache.Get(epoch) - if !ok { - if lru.future > 0 && lru.future == epoch { - item = lru.futureItem - } else { - log.Trace("Requiring new ethash "+lru.what, "epoch", epoch) - item = lru.new(epoch) - } - lru.cache.Add(epoch, item) - } - // Update the 'future item' if epoch is larger than previously seen. - if epoch < maxEpoch-1 && lru.future < epoch+1 { - log.Trace("Requiring new future ethash "+lru.what, "epoch", epoch+1) - future = lru.new(epoch + 1) - lru.future = epoch + 1 - lru.futureItem = future - } - return item, future -} - -// cache wraps an ethash cache with some metadata to allow easier concurrent use. -type cache struct { - epoch uint64 // Epoch for which this cache is relevant - dump *os.File // File descriptor of the memory mapped cache - mmap mmap.MMap // Memory map itself to unmap before releasing - cache []uint32 // The actual cache data content (may be memory mapped) - once sync.Once // Ensures the cache is generated only once -} - -// newCache creates a new ethash verification cache. -func newCache(epoch uint64) *cache { - return &cache{epoch: epoch} -} - -// generate ensures that the cache content is generated before use. -func (c *cache) generate(dir string, limit int, lock bool, test bool) { - c.once.Do(func() { - size := cacheSize(c.epoch*epochLength + 1) - seed := seedHash(c.epoch*epochLength + 1) - if test { - size = 1024 - } - // If we don't store anything on disk, generate and return. - if dir == "" { - c.cache = make([]uint32, size/4) - generateCache(c.cache, c.epoch, seed) - return - } - // Disk storage is needed, this will get fancy - var endian string - if !isLittleEndian() { - endian = ".be" - } - path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x%s", algorithmRevision, seed[:8], endian)) - logger := log.New("epoch", c.epoch) - - // We're about to mmap the file, ensure that the mapping is cleaned up when the - // cache becomes unused. - runtime.SetFinalizer(c, (*cache).finalizer) - - // Try to load the file from disk and memory map it - var err error - c.dump, c.mmap, c.cache, err = memoryMap(path, lock) - if err == nil { - logger.Debug("Loaded old ethash cache from disk") - return - } - logger.Debug("Failed to load old ethash cache", "err", err) - - // No previous cache available, create a new cache file to fill - c.dump, c.mmap, c.cache, err = memoryMapAndGenerate(path, size, lock, func(buffer []uint32) { generateCache(buffer, c.epoch, seed) }) - if err != nil { - logger.Error("Failed to generate mapped ethash cache", "err", err) - - c.cache = make([]uint32, size/4) - generateCache(c.cache, c.epoch, seed) - } - // Iterate over all previous instances and delete old ones - for ep := int(c.epoch) - limit; ep >= 0; ep-- { - seed := seedHash(uint64(ep)*epochLength + 1) - path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x%s*", algorithmRevision, seed[:8], endian)) - files, _ := filepath.Glob(path) // find also the temp files that are generated. - for _, file := range files { - os.Remove(file) - } - } - }) -} - -// finalizer unmaps the memory and closes the file. -func (c *cache) finalizer() { - if c.mmap != nil { - c.mmap.Unmap() - c.dump.Close() - c.mmap, c.dump = nil, nil - } -} - -// dataset wraps an ethash dataset with some metadata to allow easier concurrent use. -type dataset struct { - epoch uint64 // Epoch for which this cache is relevant - dump *os.File // File descriptor of the memory mapped cache - mmap mmap.MMap // Memory map itself to unmap before releasing - dataset []uint32 // The actual cache data content - once sync.Once // Ensures the cache is generated only once - done atomic.Bool // Atomic flag to determine generation status -} - -// newDataset creates a new ethash mining dataset and returns it as a plain Go -// interface to be usable in an LRU cache. -func newDataset(epoch uint64) *dataset { - return &dataset{epoch: epoch} -} - -// generate ensures that the dataset content is generated before use. -func (d *dataset) generate(dir string, limit int, lock bool, test bool) { - d.once.Do(func() { - // Mark the dataset generated after we're done. This is needed for remote - defer d.done.Store(true) - - csize := cacheSize(d.epoch*epochLength + 1) - dsize := datasetSize(d.epoch*epochLength + 1) - seed := seedHash(d.epoch*epochLength + 1) - if test { - csize = 1024 - dsize = 32 * 1024 - } - // If we don't store anything on disk, generate and return - if dir == "" { - cache := make([]uint32, csize/4) - generateCache(cache, d.epoch, seed) - - d.dataset = make([]uint32, dsize/4) - generateDataset(d.dataset, d.epoch, cache) - - return - } - // Disk storage is needed, this will get fancy - var endian string - if !isLittleEndian() { - endian = ".be" - } - path := filepath.Join(dir, fmt.Sprintf("full-R%d-%x%s", algorithmRevision, seed[:8], endian)) - logger := log.New("epoch", d.epoch) - - // We're about to mmap the file, ensure that the mapping is cleaned up when the - // cache becomes unused. - runtime.SetFinalizer(d, (*dataset).finalizer) - - // Try to load the file from disk and memory map it - var err error - d.dump, d.mmap, d.dataset, err = memoryMap(path, lock) - if err == nil { - logger.Debug("Loaded old ethash dataset from disk") - return - } - logger.Debug("Failed to load old ethash dataset", "err", err) - - // No previous dataset available, create a new dataset file to fill - cache := make([]uint32, csize/4) - generateCache(cache, d.epoch, seed) - - d.dump, d.mmap, d.dataset, err = memoryMapAndGenerate(path, dsize, lock, func(buffer []uint32) { generateDataset(buffer, d.epoch, cache) }) - if err != nil { - logger.Error("Failed to generate mapped ethash dataset", "err", err) - - d.dataset = make([]uint32, dsize/4) - generateDataset(d.dataset, d.epoch, cache) - } - // Iterate over all previous instances and delete old ones - for ep := int(d.epoch) - limit; ep >= 0; ep-- { - seed := seedHash(uint64(ep)*epochLength + 1) - path := filepath.Join(dir, fmt.Sprintf("full-R%d-%x%s", algorithmRevision, seed[:8], endian)) - os.Remove(path) - } - }) -} - -// generated returns whether this particular dataset finished generating already -// or not (it may not have been started at all). This is useful for remote miners -// to default to verification caches instead of blocking on DAG generations. -func (d *dataset) generated() bool { - return d.done.Load() -} - -// finalizer closes any file handlers and memory maps open. -func (d *dataset) finalizer() { - if d.mmap != nil { - d.mmap.Unmap() - d.dump.Close() - d.mmap, d.dump = nil, nil - } -} - -// MakeCache generates a new ethash cache and optionally stores it to disk. -func MakeCache(block uint64, dir string) { - c := cache{epoch: block / epochLength} - c.generate(dir, math.MaxInt32, false, false) -} - -// MakeDataset generates a new ethash dataset and optionally stores it to disk. -func MakeDataset(block uint64, dir string) { - d := dataset{epoch: block / epochLength} - d.generate(dir, math.MaxInt32, false, false) -} - -// Mode defines the type and amount of PoW verification an ethash engine makes. -type Mode uint - -const ( - ModeNormal Mode = iota - ModeShared - ModeTest - ModeFake - ModeFullFake -) - -// Config are the configuration parameters of the ethash. -type Config struct { - CacheDir string - CachesInMem int - CachesOnDisk int - CachesLockMmap bool - DatasetDir string - DatasetsInMem int - DatasetsOnDisk int - DatasetsLockMmap bool - PowMode Mode - - // When set, notifications sent by the remote sealer will - // be block header JSON objects instead of work package arrays. - NotifyFull bool - - Log log.Logger `toml:"-"` -} - // Ethash is a consensus engine based on proof-of-work implementing the ethash // algorithm. type Ethash struct { - config Config - - caches *lru[*cache] // In memory caches to avoid regenerating too often - datasets *lru[*dataset] // In memory datasets to avoid regenerating too often - - // Mining related fields - rand *rand.Rand // Properly seeded random source for nonces - threads int // Number of threads to mine on if mining - update chan struct{} // Notification channel to update mining parameters - hashrate metrics.Meter // Meter tracking the average hashrate - remote *remoteSealer - - // The fields below are hooks for testing - shared *Ethash // Shared PoW verifier to avoid cache regeneration - fakeFail uint64 // Block number which fails PoW check even in fake mode - fakeDelay time.Duration // Time delay to sleep for before returning from verify - - lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields - closeOnce sync.Once // Ensures exit channel will not be closed twice. -} - -// New creates a full sized ethash PoW scheme and starts a background thread for -// remote mining, also optionally notifying a batch of remote services of new work -// packages. -func New(config Config, notify []string, noverify bool) *Ethash { - if config.Log == nil { - config.Log = log.Root() - } - if config.CachesInMem <= 0 { - config.Log.Warn("One ethash cache must always be in memory", "requested", config.CachesInMem) - config.CachesInMem = 1 - } - if config.CacheDir != "" && config.CachesOnDisk > 0 { - config.Log.Info("Disk storage enabled for ethash caches", "dir", config.CacheDir, "count", config.CachesOnDisk) - } - if config.DatasetDir != "" && config.DatasetsOnDisk > 0 { - config.Log.Info("Disk storage enabled for ethash DAGs", "dir", config.DatasetDir, "count", config.DatasetsOnDisk) - } - ethash := &Ethash{ - config: config, - caches: newlru(config.CachesInMem, newCache), - datasets: newlru(config.DatasetsInMem, newDataset), - update: make(chan struct{}), - hashrate: metrics.NewMeterForced(), - } - if config.PowMode == ModeShared { - ethash.shared = sharedEthash - } - ethash.remote = startRemoteSealer(ethash, notify, noverify) - return ethash + fakeFail *uint64 // Block number which fails PoW check even in fake mode + fakeDelay *time.Duration // Time delay to sleep for before returning from verify + fakeFull bool // Accepts everything as valid } -// NewTester creates a small sized ethash PoW scheme useful only for testing -// purposes. -func NewTester(notify []string, noverify bool) *Ethash { - return New(Config{PowMode: ModeTest}, notify, noverify) -} - -// NewFaker creates a ethash consensus engine with a fake PoW scheme that accepts +// NewFaker creates an ethash consensus engine with a fake PoW scheme that accepts // all blocks' seal as valid, though they still have to conform to the Ethereum // consensus rules. func NewFaker() *Ethash { - return &Ethash{ - config: Config{ - PowMode: ModeFake, - Log: log.Root(), - }, - } + return new(Ethash) } // NewFakeFailer creates a ethash consensus engine with a fake PoW scheme that @@ -522,11 +45,7 @@ func NewFaker() *Ethash { // still have to conform to the Ethereum consensus rules. func NewFakeFailer(fail uint64) *Ethash { return &Ethash{ - config: Config{ - PowMode: ModeFake, - Log: log.Root(), - }, - fakeFail: fail, + fakeFail: &fail, } } @@ -535,11 +54,7 @@ func NewFakeFailer(fail uint64) *Ethash { // they still have to conform to the Ethereum consensus rules. func NewFakeDelayer(delay time.Duration) *Ethash { return &Ethash{ - config: Config{ - PowMode: ModeFake, - Log: log.Root(), - }, - fakeDelay: delay, + fakeDelay: &delay, } } @@ -547,154 +62,24 @@ func NewFakeDelayer(delay time.Duration) *Ethash { // accepts all blocks as valid, without checking any consensus rules whatsoever. func NewFullFaker() *Ethash { return &Ethash{ - config: Config{ - PowMode: ModeFullFake, - Log: log.Root(), - }, + fakeFull: true, } } -// NewShared creates a full sized ethash PoW shared between all requesters running -// in the same process. -func NewShared() *Ethash { - return &Ethash{shared: sharedEthash} -} - // Close closes the exit channel to notify all backend threads exiting. func (ethash *Ethash) Close() error { - return ethash.StopRemoteSealer() -} - -// StopRemoteSealer stops the remote sealer -func (ethash *Ethash) StopRemoteSealer() error { - ethash.closeOnce.Do(func() { - // Short circuit if the exit channel is not allocated. - if ethash.remote == nil { - return - } - close(ethash.remote.requestExit) - <-ethash.remote.exitCh - }) return nil } -// cache tries to retrieve a verification cache for the specified block number -// by first checking against a list of in-memory caches, then against caches -// stored on disk, and finally generating one if none can be found. -func (ethash *Ethash) cache(block uint64) *cache { - epoch := block / epochLength - current, future := ethash.caches.get(epoch) - - // Wait for generation finish. - current.generate(ethash.config.CacheDir, ethash.config.CachesOnDisk, ethash.config.CachesLockMmap, ethash.config.PowMode == ModeTest) - - // If we need a new future cache, now's a good time to regenerate it. - if future != nil { - go future.generate(ethash.config.CacheDir, ethash.config.CachesOnDisk, ethash.config.CachesLockMmap, ethash.config.PowMode == ModeTest) - } - return current -} - -// dataset tries to retrieve a mining dataset for the specified block number -// by first checking against a list of in-memory datasets, then against DAGs -// stored on disk, and finally generating one if none can be found. -// -// If async is specified, not only the future but the current DAG is also -// generates on a background thread. -func (ethash *Ethash) dataset(block uint64, async bool) *dataset { - // Retrieve the requested ethash dataset - epoch := block / epochLength - current, future := ethash.datasets.get(epoch) - - // If async is specified, generate everything in a background thread - if async && !current.generated() { - go func() { - current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.DatasetsLockMmap, ethash.config.PowMode == ModeTest) - if future != nil { - future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.DatasetsLockMmap, ethash.config.PowMode == ModeTest) - } - }() - } else { - // Either blocking generation was requested, or already done - current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.DatasetsLockMmap, ethash.config.PowMode == ModeTest) - if future != nil { - go future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.DatasetsLockMmap, ethash.config.PowMode == ModeTest) - } - } - return current -} - -// Threads returns the number of mining threads currently enabled. This doesn't -// necessarily mean that mining is running! -func (ethash *Ethash) Threads() int { - ethash.lock.Lock() - defer ethash.lock.Unlock() - - return ethash.threads -} - -// SetThreads updates the number of mining threads currently enabled. Calling -// this method does not start mining, only sets the thread count. If zero is -// specified, the miner will use all cores of the machine. Setting a thread -// count below zero is allowed and will cause the miner to idle, without any -// work being done. -func (ethash *Ethash) SetThreads(threads int) { - ethash.lock.Lock() - defer ethash.lock.Unlock() - - // If we're running a shared PoW, set the thread count on that instead - if ethash.shared != nil { - ethash.shared.SetThreads(threads) - return - } - // Update the threads and ping any running seal to pull in any changes - ethash.threads = threads - select { - case ethash.update <- struct{}{}: - default: - } -} - -// Hashrate implements PoW, returning the measured rate of the search invocations -// per second over the last minute. -// Note the returned hashrate includes local hashrate, but also includes the total -// hashrate of all remote miner. -func (ethash *Ethash) Hashrate() float64 { - // Short circuit if we are run the ethash in normal/test mode. - if ethash.config.PowMode != ModeNormal && ethash.config.PowMode != ModeTest { - return ethash.hashrate.Rate1() - } - var res = make(chan uint64, 1) - - select { - case ethash.remote.fetchRateCh <- res: - case <-ethash.remote.exitCh: - // Return local hashrate only if ethash is stopped. - return ethash.hashrate.Rate1() - } - - // Gather total submitted hash rate of remote sealers. - return ethash.hashrate.Rate1() + float64(<-res) -} - -// APIs implements consensus.Engine, returning the user facing RPC APIs. +// APIs implements consensus.Engine, returning no APIs as ethash is an empty +// shell in the post-merge world. func (ethash *Ethash) APIs(chain consensus.ChainHeaderReader) []rpc.API { - // In order to ensure backward compatibility, we exposes ethash RPC APIs - // to both eth and ethash namespaces. - return []rpc.API{ - { - Namespace: "eth", - Service: &API{ethash}, - }, - { - Namespace: "ethash", - Service: &API{ethash}, - }, - } + return []rpc.API{} } -// SeedHash is the seed to use for generating a verification cache and the mining -// dataset. -func SeedHash(block uint64) []byte { - return seedHash(block) +// Seal generates a new sealing request for the given input block and pushes +// the result into the given channel. For the ethash engine, this method will +// just panic as sealing is not supported anymore. +func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { + panic("ethash (pow) sealing not supported any more") } diff --git a/consensus/ethash/ethash_test.go b/consensus/ethash/ethash_test.go deleted file mode 100644 index eb6bad9622..0000000000 --- a/consensus/ethash/ethash_test.go +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ethash - -import ( - "math/big" - "math/rand" - "os" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" -) - -// Tests that ethash works correctly in test mode. -func TestTestMode(t *testing.T) { - header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} - - ethash := NewTester(nil, false) - defer ethash.Close() - - results := make(chan *types.Block) - err := ethash.Seal(nil, types.NewBlockWithHeader(header), results, nil) - if err != nil { - t.Fatalf("failed to seal block: %v", err) - } - select { - case block := <-results: - header.Nonce = types.EncodeNonce(block.Nonce()) - header.MixDigest = block.MixDigest() - if err := ethash.verifySeal(nil, header, false); err != nil { - t.Fatalf("unexpected verification error: %v", err) - } - case <-time.NewTimer(4 * time.Second).C: - t.Error("sealing result timeout") - } -} - -// This test checks that cache lru logic doesn't crash under load. -// It reproduces https://github.com/ethereum/go-ethereum/issues/14943 -func TestCacheFileEvict(t *testing.T) { - // TODO: t.TempDir fails to remove the directory on Windows - // \AppData\Local\Temp\1\TestCacheFileEvict2179435125\001\cache-R23-0000000000000000: Access is denied. - tmpdir, err := os.MkdirTemp("", "ethash-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - - config := Config{ - CachesInMem: 3, - CachesOnDisk: 10, - CacheDir: tmpdir, - PowMode: ModeTest, - } - e := New(config, nil, false) - defer e.Close() - - workers := 8 - epochs := 100 - var wg sync.WaitGroup - wg.Add(workers) - for i := 0; i < workers; i++ { - go verifyTest(&wg, e, i, epochs) - } - wg.Wait() -} - -func verifyTest(wg *sync.WaitGroup, e *Ethash, workerIndex, epochs int) { - defer wg.Done() - - const wiggle = 4 * epochLength - r := rand.New(rand.NewSource(int64(workerIndex))) - for epoch := 0; epoch < epochs; epoch++ { - block := int64(epoch)*epochLength - wiggle/2 + r.Int63n(wiggle) - if block < 0 { - block = 0 - } - header := &types.Header{Number: big.NewInt(block), Difficulty: big.NewInt(100)} - e.verifySeal(nil, header, false) - } -} - -func TestRemoteSealer(t *testing.T) { - ethash := NewTester(nil, false) - defer ethash.Close() - - api := &API{ethash} - if _, err := api.GetWork(); err != errNoMiningWork { - t.Error("expect to return an error indicate there is no mining work") - } - header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} - block := types.NewBlockWithHeader(header) - sealhash := ethash.SealHash(header) - - // Push new work. - results := make(chan *types.Block) - ethash.Seal(nil, block, results, nil) - - var ( - work [4]string - err error - ) - if work, err = api.GetWork(); err != nil || work[0] != sealhash.Hex() { - t.Error("expect to return a mining work has same hash") - } - - if res := api.SubmitWork(types.BlockNonce{}, sealhash, common.Hash{}); res { - t.Error("expect to return false when submit a fake solution") - } - // Push new block with same block number to replace the original one. - header = &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(1000)} - block = types.NewBlockWithHeader(header) - sealhash = ethash.SealHash(header) - ethash.Seal(nil, block, results, nil) - - if work, err = api.GetWork(); err != nil || work[0] != sealhash.Hex() { - t.Error("expect to return the latest pushed work") - } -} - -func TestHashrate(t *testing.T) { - var ( - hashrate = []hexutil.Uint64{100, 200, 300} - expect uint64 - ids = []common.Hash{common.HexToHash("a"), common.HexToHash("b"), common.HexToHash("c")} - ) - ethash := NewTester(nil, false) - defer ethash.Close() - - if tot := ethash.Hashrate(); tot != 0 { - t.Error("expect the result should be zero") - } - - api := &API{ethash} - for i := 0; i < len(hashrate); i += 1 { - if res := api.SubmitHashrate(hashrate[i], ids[i]); !res { - t.Error("remote miner submit hashrate failed") - } - expect += uint64(hashrate[i]) - } - if tot := ethash.Hashrate(); tot != float64(expect) { - t.Error("expect total hashrate should be same") - } -} - -func TestClosedRemoteSealer(t *testing.T) { - ethash := NewTester(nil, false) - time.Sleep(1 * time.Second) // ensure exit channel is listening - ethash.Close() - - api := &API{ethash} - if _, err := api.GetWork(); err != errEthashStopped { - t.Error("expect to return an error to indicate ethash is stopped") - } - - if res := api.SubmitHashrate(hexutil.Uint64(100), common.HexToHash("a")); res { - t.Error("expect to return false when submit hashrate to a stopped ethash") - } -} diff --git a/consensus/ethash/mmap_help_linux.go b/consensus/ethash/mmap_help_linux.go deleted file mode 100644 index b40a1dd25c..0000000000 --- a/consensus/ethash/mmap_help_linux.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2021 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 . - -//go:build linux -// +build linux - -package ethash - -import ( - "os" - - "golang.org/x/sys/unix" -) - -// ensureSize expands the file to the given size. This is to prevent runtime -// errors later on, if the underlying file expands beyond the disk capacity, -// even though it ostensibly is already expanded, but due to being sparse -// does not actually occupy the full declared size on disk. -func ensureSize(f *os.File, size int64) error { - // Docs: https://www.man7.org/linux/man-pages/man2/fallocate.2.html - return unix.Fallocate(int(f.Fd()), 0, 0, size) -} diff --git a/consensus/ethash/mmap_help_other.go b/consensus/ethash/mmap_help_other.go deleted file mode 100644 index 8ad514ce42..0000000000 --- a/consensus/ethash/mmap_help_other.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2021 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 . - -//go:build !linux -// +build !linux - -package ethash - -import ( - "os" -) - -// ensureSize expands the file to the given size. This is to prevent runtime -// errors later on, if the underlying file expands beyond the disk capacity, -// even though it ostensibly is already expanded, but due to being sparse -// does not actually occupy the full declared size on disk. -func ensureSize(f *os.File, size int64) error { - // On systems which do not support fallocate, we merely truncate it. - // More robust alternatives would be to - // - Use posix_fallocate, or - // - explicitly fill the file with zeroes. - return f.Truncate(size) -} diff --git a/consensus/ethash/sealer.go b/consensus/ethash/sealer.go deleted file mode 100644 index 340ad440f3..0000000000 --- a/consensus/ethash/sealer.go +++ /dev/null @@ -1,451 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ethash - -import ( - "bytes" - "context" - crand "crypto/rand" - "encoding/json" - "errors" - "math" - "math/big" - "math/rand" - "net/http" - "runtime" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/core/types" -) - -const ( - // staleThreshold is the maximum depth of the acceptable stale but valid ethash solution. - staleThreshold = 7 -) - -var ( - errNoMiningWork = errors.New("no mining work available yet") - errInvalidSealResult = errors.New("invalid or stale proof-of-work solution") -) - -// Seal implements consensus.Engine, attempting to find a nonce that satisfies -// the block's difficulty requirements. -func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { - // If we're running a fake PoW, simply return a 0 nonce immediately - if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake { - header := block.Header() - header.Nonce, header.MixDigest = types.BlockNonce{}, common.Hash{} - select { - case results <- block.WithSeal(header): - default: - ethash.config.Log.Warn("Sealing result is not read by miner", "mode", "fake", "sealhash", ethash.SealHash(block.Header())) - } - return nil - } - // If we're running a shared PoW, delegate sealing to it - if ethash.shared != nil { - return ethash.shared.Seal(chain, block, results, stop) - } - // Create a runner and the multiple search threads it directs - abort := make(chan struct{}) - - ethash.lock.Lock() - threads := ethash.threads - if ethash.rand == nil { - seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) - if err != nil { - ethash.lock.Unlock() - return err - } - ethash.rand = rand.New(rand.NewSource(seed.Int64())) - } - ethash.lock.Unlock() - if threads == 0 { - threads = runtime.NumCPU() - } - if threads < 0 { - threads = 0 // Allows disabling local mining without extra logic around local/remote - } - // Push new work to remote sealer - if ethash.remote != nil { - ethash.remote.workCh <- &sealTask{block: block, results: results} - } - var ( - pend sync.WaitGroup - locals = make(chan *types.Block) - ) - for i := 0; i < threads; i++ { - pend.Add(1) - go func(id int, nonce uint64) { - defer pend.Done() - ethash.mine(block, id, nonce, abort, locals) - }(i, uint64(ethash.rand.Int63())) - } - // Wait until sealing is terminated or a nonce is found - go func() { - var result *types.Block - select { - case <-stop: - // Outside abort, stop all miner threads - close(abort) - case result = <-locals: - // One of the threads found a block, abort all others - select { - case results <- result: - default: - ethash.config.Log.Warn("Sealing result is not read by miner", "mode", "local", "sealhash", ethash.SealHash(block.Header())) - } - close(abort) - case <-ethash.update: - // Thread count was changed on user request, restart - close(abort) - if err := ethash.Seal(chain, block, results, stop); err != nil { - ethash.config.Log.Error("Failed to restart sealing after update", "err", err) - } - } - // Wait for all miners to terminate and return the block - pend.Wait() - }() - return nil -} - -// mine is the actual proof-of-work miner that searches for a nonce starting from -// seed that results in correct final block difficulty. -func (ethash *Ethash) mine(block *types.Block, id int, seed uint64, abort chan struct{}, found chan *types.Block) { - // Extract some data from the header - var ( - header = block.Header() - hash = ethash.SealHash(header).Bytes() - target = new(big.Int).Div(two256, header.Difficulty) - number = header.Number.Uint64() - dataset = ethash.dataset(number, false) - ) - // Start generating random nonces until we abort or find a good one - var ( - attempts = int64(0) - nonce = seed - powBuffer = new(big.Int) - ) - logger := ethash.config.Log.New("miner", id) - logger.Trace("Started ethash search for new nonces", "seed", seed) -search: - for { - select { - case <-abort: - // Mining terminated, update stats and abort - logger.Trace("Ethash nonce search aborted", "attempts", nonce-seed) - ethash.hashrate.Mark(attempts) - break search - - default: - // We don't have to update hash rate on every nonce, so update after after 2^X nonces - attempts++ - if (attempts % (1 << 15)) == 0 { - ethash.hashrate.Mark(attempts) - attempts = 0 - } - // Compute the PoW value of this nonce - digest, result := hashimotoFull(dataset.dataset, hash, nonce) - if powBuffer.SetBytes(result).Cmp(target) <= 0 { - // Correct nonce found, create a new header with it - header = types.CopyHeader(header) - header.Nonce = types.EncodeNonce(nonce) - header.MixDigest = common.BytesToHash(digest) - - // Seal and return a block (if still needed) - select { - case found <- block.WithSeal(header): - logger.Trace("Ethash nonce found and reported", "attempts", nonce-seed, "nonce", nonce) - case <-abort: - logger.Trace("Ethash nonce found but discarded", "attempts", nonce-seed, "nonce", nonce) - } - break search - } - nonce++ - } - } - // Datasets are unmapped in a finalizer. Ensure that the dataset stays live - // during sealing so it's not unmapped while being read. - runtime.KeepAlive(dataset) -} - -// This is the timeout for HTTP requests to notify external miners. -const remoteSealerTimeout = 1 * time.Second - -type remoteSealer struct { - works map[common.Hash]*types.Block - rates map[common.Hash]hashrate - currentBlock *types.Block - currentWork [4]string - notifyCtx context.Context - cancelNotify context.CancelFunc // cancels all notification requests - reqWG sync.WaitGroup // tracks notification request goroutines - - ethash *Ethash - noverify bool - notifyURLs []string - results chan<- *types.Block - workCh chan *sealTask // Notification channel to push new work and relative result channel to remote sealer - fetchWorkCh chan *sealWork // Channel used for remote sealer to fetch mining work - submitWorkCh chan *mineResult // Channel used for remote sealer to submit their mining result - fetchRateCh chan chan uint64 // Channel used to gather submitted hash rate for local or remote sealer. - submitRateCh chan *hashrate // Channel used for remote sealer to submit their mining hashrate - requestExit chan struct{} - exitCh chan struct{} -} - -// sealTask wraps a seal block with relative result channel for remote sealer thread. -type sealTask struct { - block *types.Block - results chan<- *types.Block -} - -// mineResult wraps the pow solution parameters for the specified block. -type mineResult struct { - nonce types.BlockNonce - mixDigest common.Hash - hash common.Hash - - errc chan error -} - -// hashrate wraps the hash rate submitted by the remote sealer. -type hashrate struct { - id common.Hash - ping time.Time - rate uint64 - - done chan struct{} -} - -// sealWork wraps a seal work package for remote sealer. -type sealWork struct { - errc chan error - res chan [4]string -} - -func startRemoteSealer(ethash *Ethash, urls []string, noverify bool) *remoteSealer { - ctx, cancel := context.WithCancel(context.Background()) - s := &remoteSealer{ - ethash: ethash, - noverify: noverify, - notifyURLs: urls, - notifyCtx: ctx, - cancelNotify: cancel, - works: make(map[common.Hash]*types.Block), - rates: make(map[common.Hash]hashrate), - workCh: make(chan *sealTask), - fetchWorkCh: make(chan *sealWork), - submitWorkCh: make(chan *mineResult), - fetchRateCh: make(chan chan uint64), - submitRateCh: make(chan *hashrate), - requestExit: make(chan struct{}), - exitCh: make(chan struct{}), - } - go s.loop() - return s -} - -func (s *remoteSealer) loop() { - defer func() { - s.ethash.config.Log.Trace("Ethash remote sealer is exiting") - s.cancelNotify() - s.reqWG.Wait() - close(s.exitCh) - }() - - ticker := time.NewTicker(5 * time.Second) - defer ticker.Stop() - - for { - select { - case work := <-s.workCh: - // Update current work with new received block. - // Note same work can be past twice, happens when changing CPU threads. - s.results = work.results - s.makeWork(work.block) - s.notifyWork() - - case work := <-s.fetchWorkCh: - // Return current mining work to remote miner. - if s.currentBlock == nil { - work.errc <- errNoMiningWork - } else { - work.res <- s.currentWork - } - - case result := <-s.submitWorkCh: - // Verify submitted PoW solution based on maintained mining blocks. - if s.submitWork(result.nonce, result.mixDigest, result.hash) { - result.errc <- nil - } else { - result.errc <- errInvalidSealResult - } - - case result := <-s.submitRateCh: - // Trace remote sealer's hash rate by submitted value. - s.rates[result.id] = hashrate{rate: result.rate, ping: time.Now()} - close(result.done) - - case req := <-s.fetchRateCh: - // Gather all hash rate submitted by remote sealer. - var total uint64 - for _, rate := range s.rates { - // this could overflow - total += rate.rate - } - req <- total - - case <-ticker.C: - // Clear stale submitted hash rate. - for id, rate := range s.rates { - if time.Since(rate.ping) > 10*time.Second { - delete(s.rates, id) - } - } - // Clear stale pending blocks - if s.currentBlock != nil { - for hash, block := range s.works { - if block.NumberU64()+staleThreshold <= s.currentBlock.NumberU64() { - delete(s.works, hash) - } - } - } - - case <-s.requestExit: - return - } - } -} - -// makeWork creates a work package for external miner. -// -// The work package consists of 3 strings: -// -// result[0], 32 bytes hex encoded current block header pow-hash -// result[1], 32 bytes hex encoded seed hash used for DAG -// result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty -// result[3], hex encoded block number -func (s *remoteSealer) makeWork(block *types.Block) { - hash := s.ethash.SealHash(block.Header()) - s.currentWork[0] = hash.Hex() - s.currentWork[1] = common.BytesToHash(SeedHash(block.NumberU64())).Hex() - s.currentWork[2] = common.BytesToHash(new(big.Int).Div(two256, block.Difficulty()).Bytes()).Hex() - s.currentWork[3] = hexutil.EncodeBig(block.Number()) - - // Trace the seal work fetched by remote sealer. - s.currentBlock = block - s.works[hash] = block -} - -// notifyWork notifies all the specified mining endpoints of the availability of -// new work to be processed. -func (s *remoteSealer) notifyWork() { - work := s.currentWork - - // Encode the JSON payload of the notification. When NotifyFull is set, - // this is the complete block header, otherwise it is a JSON array. - var blob []byte - if s.ethash.config.NotifyFull { - blob, _ = json.Marshal(s.currentBlock.Header()) - } else { - blob, _ = json.Marshal(work) - } - - s.reqWG.Add(len(s.notifyURLs)) - for _, url := range s.notifyURLs { - go s.sendNotification(s.notifyCtx, url, blob, work) - } -} - -func (s *remoteSealer) sendNotification(ctx context.Context, url string, json []byte, work [4]string) { - defer s.reqWG.Done() - - req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(json)) - if err != nil { - s.ethash.config.Log.Warn("Can't create remote miner notification", "err", err) - return - } - ctx, cancel := context.WithTimeout(ctx, remoteSealerTimeout) - defer cancel() - req = req.WithContext(ctx) - req.Header.Set("Content-Type", "application/json") - - resp, err := http.DefaultClient.Do(req) - if err != nil { - s.ethash.config.Log.Warn("Failed to notify remote miner", "err", err) - } else { - s.ethash.config.Log.Trace("Notified remote miner", "miner", url, "hash", work[0], "target", work[2]) - resp.Body.Close() - } -} - -// submitWork verifies the submitted pow solution, returning -// whether the solution was accepted or not (not can be both a bad pow as well as -// any other error, like no pending work or stale mining result). -func (s *remoteSealer) submitWork(nonce types.BlockNonce, mixDigest common.Hash, sealhash common.Hash) bool { - if s.currentBlock == nil { - s.ethash.config.Log.Error("Pending work without block", "sealhash", sealhash) - return false - } - // Make sure the work submitted is present - block := s.works[sealhash] - if block == nil { - s.ethash.config.Log.Warn("Work submitted but none pending", "sealhash", sealhash, "curnumber", s.currentBlock.NumberU64()) - return false - } - // Verify the correctness of submitted result. - header := block.Header() - header.Nonce = nonce - header.MixDigest = mixDigest - - start := time.Now() - if !s.noverify { - if err := s.ethash.verifySeal(nil, header, true); err != nil { - s.ethash.config.Log.Warn("Invalid proof-of-work submitted", "sealhash", sealhash, "elapsed", common.PrettyDuration(time.Since(start)), "err", err) - return false - } - } - // Make sure the result channel is assigned. - if s.results == nil { - s.ethash.config.Log.Warn("Ethash result channel is empty, submitted mining result is rejected") - return false - } - s.ethash.config.Log.Trace("Verified correct proof-of-work", "sealhash", sealhash, "elapsed", common.PrettyDuration(time.Since(start))) - - // Solutions seems to be valid, return to the miner and notify acceptance. - solution := block.WithSeal(header) - - // The submitted solution is within the scope of acceptance. - if solution.NumberU64()+staleThreshold > s.currentBlock.NumberU64() { - select { - case s.results <- solution: - s.ethash.config.Log.Debug("Work submitted is acceptable", "number", solution.NumberU64(), "sealhash", sealhash, "hash", solution.Hash()) - return true - default: - s.ethash.config.Log.Warn("Sealing result is not read by miner", "mode", "remote", "sealhash", sealhash) - return false - } - } - // The submitted block is too old to accept, drop it. - s.ethash.config.Log.Warn("Work submitted is too old", "number", solution.NumberU64(), "sealhash", sealhash, "hash", solution.Hash()) - return false -} diff --git a/consensus/ethash/sealer_test.go b/consensus/ethash/sealer_test.go deleted file mode 100644 index e338f75290..0000000000 --- a/consensus/ethash/sealer_test.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ethash - -import ( - "encoding/json" - "io" - "math/big" - "net/http" - "net/http/httptest" - "strconv" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/internal/testlog" - "github.com/ethereum/go-ethereum/log" -) - -// Tests whether remote HTTP servers are correctly notified of new work. -func TestRemoteNotify(t *testing.T) { - // Start a simple web server to capture notifications. - sink := make(chan [3]string) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - blob, err := io.ReadAll(req.Body) - if err != nil { - t.Errorf("failed to read miner notification: %v", err) - } - var work [3]string - if err := json.Unmarshal(blob, &work); err != nil { - t.Errorf("failed to unmarshal miner notification: %v", err) - } - sink <- work - })) - defer server.Close() - - // Create the custom ethash engine. - ethash := NewTester([]string{server.URL}, false) - defer ethash.Close() - - // Stream a work task and ensure the notification bubbles out. - header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} - block := types.NewBlockWithHeader(header) - - ethash.Seal(nil, block, nil, nil) - select { - case work := <-sink: - if want := ethash.SealHash(header).Hex(); work[0] != want { - t.Errorf("work packet hash mismatch: have %s, want %s", work[0], want) - } - if want := common.BytesToHash(SeedHash(header.Number.Uint64())).Hex(); work[1] != want { - t.Errorf("work packet seed mismatch: have %s, want %s", work[1], want) - } - target := new(big.Int).Div(new(big.Int).Lsh(big.NewInt(1), 256), header.Difficulty) - if want := common.BytesToHash(target.Bytes()).Hex(); work[2] != want { - t.Errorf("work packet target mismatch: have %s, want %s", work[2], want) - } - case <-time.After(3 * time.Second): - t.Fatalf("notification timed out") - } -} - -// Tests whether remote HTTP servers are correctly notified of new work. (Full pending block body / --miner.notify.full) -func TestRemoteNotifyFull(t *testing.T) { - // Start a simple web server to capture notifications. - sink := make(chan map[string]interface{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - blob, err := io.ReadAll(req.Body) - if err != nil { - t.Errorf("failed to read miner notification: %v", err) - } - var work map[string]interface{} - if err := json.Unmarshal(blob, &work); err != nil { - t.Errorf("failed to unmarshal miner notification: %v", err) - } - sink <- work - })) - defer server.Close() - - // Create the custom ethash engine. - config := Config{ - PowMode: ModeTest, - NotifyFull: true, - Log: testlog.Logger(t, log.LvlWarn), - } - ethash := New(config, []string{server.URL}, false) - defer ethash.Close() - - // Stream a work task and ensure the notification bubbles out. - header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} - block := types.NewBlockWithHeader(header) - - ethash.Seal(nil, block, nil, nil) - select { - case work := <-sink: - if want := "0x" + strconv.FormatUint(header.Number.Uint64(), 16); work["number"] != want { - t.Errorf("pending block number mismatch: have %v, want %v", work["number"], want) - } - if want := "0x" + header.Difficulty.Text(16); work["difficulty"] != want { - t.Errorf("pending block difficulty mismatch: have %s, want %s", work["difficulty"], want) - } - case <-time.After(3 * time.Second): - t.Fatalf("notification timed out") - } -} - -// Tests that pushing work packages fast to the miner doesn't cause any data race -// issues in the notifications. -func TestRemoteMultiNotify(t *testing.T) { - // Start a simple web server to capture notifications. - sink := make(chan [3]string, 64) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - blob, err := io.ReadAll(req.Body) - if err != nil { - t.Errorf("failed to read miner notification: %v", err) - } - var work [3]string - if err := json.Unmarshal(blob, &work); err != nil { - t.Errorf("failed to unmarshal miner notification: %v", err) - } - sink <- work - })) - defer server.Close() - - // Create the custom ethash engine. - ethash := NewTester([]string{server.URL}, false) - ethash.config.Log = testlog.Logger(t, log.LvlWarn) - defer ethash.Close() - - // Provide a results reader. - // Otherwise the unread results will be logged asynchronously - // and this can happen after the test is finished, causing a panic. - results := make(chan *types.Block, cap(sink)) - - // Stream a lot of work task and ensure all the notifications bubble out. - for i := 0; i < cap(sink); i++ { - header := &types.Header{Number: big.NewInt(int64(i)), Difficulty: big.NewInt(100)} - block := types.NewBlockWithHeader(header) - ethash.Seal(nil, block, results, nil) - } - - for i := 0; i < cap(sink); i++ { - select { - case <-sink: - <-results - case <-time.After(10 * time.Second): - t.Fatalf("notification %d timed out", i) - } - } -} - -// Tests that pushing work packages fast to the miner doesn't cause any data race -// issues in the notifications. Full pending block body / --miner.notify.full) -func TestRemoteMultiNotifyFull(t *testing.T) { - // Start a simple web server to capture notifications. - sink := make(chan map[string]interface{}, 64) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - blob, err := io.ReadAll(req.Body) - if err != nil { - t.Errorf("failed to read miner notification: %v", err) - } - var work map[string]interface{} - if err := json.Unmarshal(blob, &work); err != nil { - t.Errorf("failed to unmarshal miner notification: %v", err) - } - sink <- work - })) - defer server.Close() - - // Create the custom ethash engine. - config := Config{ - PowMode: ModeTest, - NotifyFull: true, - Log: testlog.Logger(t, log.LvlWarn), - } - ethash := New(config, []string{server.URL}, false) - defer ethash.Close() - - // Provide a results reader. - // Otherwise the unread results will be logged asynchronously - // and this can happen after the test is finished, causing a panic. - results := make(chan *types.Block, cap(sink)) - - // Stream a lot of work task and ensure all the notifications bubble out. - for i := 0; i < cap(sink); i++ { - header := &types.Header{Number: big.NewInt(int64(i)), Difficulty: big.NewInt(100)} - block := types.NewBlockWithHeader(header) - ethash.Seal(nil, block, results, nil) - } - - for i := 0; i < cap(sink); i++ { - select { - case <-sink: - <-results - case <-time.After(10 * time.Second): - t.Fatalf("notification %d timed out", i) - } - } -} - -// Tests whether stale solutions are correctly processed. -func TestStaleSubmission(t *testing.T) { - ethash := NewTester(nil, true) - defer ethash.Close() - api := &API{ethash} - - fakeNonce, fakeDigest := types.BlockNonce{0x01, 0x02, 0x03}, common.HexToHash("deadbeef") - - testcases := []struct { - headers []*types.Header - submitIndex int - submitRes bool - }{ - // Case1: submit solution for the latest mining package - { - []*types.Header{ - {ParentHash: common.BytesToHash([]byte{0xa}), Number: big.NewInt(1), Difficulty: big.NewInt(100000000)}, - }, - 0, - true, - }, - // Case2: submit solution for the previous package but have same parent. - { - []*types.Header{ - {ParentHash: common.BytesToHash([]byte{0xb}), Number: big.NewInt(2), Difficulty: big.NewInt(100000000)}, - {ParentHash: common.BytesToHash([]byte{0xb}), Number: big.NewInt(2), Difficulty: big.NewInt(100000001)}, - }, - 0, - true, - }, - // Case3: submit stale but acceptable solution - { - []*types.Header{ - {ParentHash: common.BytesToHash([]byte{0xc}), Number: big.NewInt(3), Difficulty: big.NewInt(100000000)}, - {ParentHash: common.BytesToHash([]byte{0xd}), Number: big.NewInt(9), Difficulty: big.NewInt(100000000)}, - }, - 0, - true, - }, - // Case4: submit very old solution - { - []*types.Header{ - {ParentHash: common.BytesToHash([]byte{0xe}), Number: big.NewInt(10), Difficulty: big.NewInt(100000000)}, - {ParentHash: common.BytesToHash([]byte{0xf}), Number: big.NewInt(17), Difficulty: big.NewInt(100000000)}, - }, - 0, - false, - }, - } - results := make(chan *types.Block, 16) - - for id, c := range testcases { - for _, h := range c.headers { - ethash.Seal(nil, types.NewBlockWithHeader(h), results, nil) - } - if res := api.SubmitWork(fakeNonce, ethash.SealHash(c.headers[c.submitIndex]), fakeDigest); res != c.submitRes { - t.Errorf("case %d submit result mismatch, want %t, get %t", id+1, c.submitRes, res) - } - if !c.submitRes { - continue - } - select { - case res := <-results: - if res.Header().Nonce != fakeNonce { - t.Errorf("case %d block nonce mismatch, want %x, get %x", id+1, fakeNonce, res.Header().Nonce) - } - if res.Header().MixDigest != fakeDigest { - t.Errorf("case %d block digest mismatch, want %x, get %x", id+1, fakeDigest, res.Header().MixDigest) - } - if res.Header().Difficulty.Uint64() != c.headers[c.submitIndex].Difficulty.Uint64() { - t.Errorf("case %d block difficulty mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Difficulty, res.Header().Difficulty) - } - if res.Header().Number.Uint64() != c.headers[c.submitIndex].Number.Uint64() { - t.Errorf("case %d block number mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Number.Uint64(), res.Header().Number.Uint64()) - } - if res.Header().ParentHash != c.headers[c.submitIndex].ParentHash { - t.Errorf("case %d block parent hash mismatch, want %s, get %s", id+1, c.headers[c.submitIndex].ParentHash.Hex(), res.Header().ParentHash.Hex()) - } - case <-time.NewTimer(time.Second).C: - t.Errorf("case %d fetch ethash result timeout", id+1) - } - } -} diff --git a/console/console_test.go b/console/console_test.go index 35341fcba0..cc61f021ce 100644 --- a/console/console_test.go +++ b/console/console_test.go @@ -26,7 +26,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/console/prompt" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/eth" @@ -99,9 +98,6 @@ func newTester(t *testing.T, confOverride func(*ethconfig.Config)) *tester { Miner: miner.Config{ Etherbase: common.HexToAddress(testAddress), }, - Ethash: ethash.Config{ - PowMode: ethash.ModeTest, - }, } if confOverride != nil { confOverride(ethConf) diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 3e951d56a2..d189545166 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -55,10 +55,10 @@ func TestHeaderVerification(t *testing.T) { if valid { engine := ethash.NewFaker() - _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}, []bool{true}) + _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}) } else { engine := ethash.NewFakeFailer(headers[i].Number.Uint64()) - _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}, []bool{true}) + _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}) } // Wait for the verification result select { @@ -164,7 +164,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { // Verify the blocks before the merging for i := 0; i < len(preBlocks); i++ { - _, results := engine.VerifyHeaders(chain, []*types.Header{preHeaders[i]}, []bool{true}) + _, results := engine.VerifyHeaders(chain, []*types.Header{preHeaders[i]}) // Wait for the verification result select { case result := <-results: @@ -189,7 +189,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { // Verify the blocks after the merging for i := 0; i < len(postBlocks); i++ { - _, results := engine.VerifyHeaders(chain, []*types.Header{postHeaders[i]}, []bool{true}) + _, results := engine.VerifyHeaders(chain, []*types.Header{postHeaders[i]}) // Wait for the verification result select { case result := <-results: @@ -209,19 +209,14 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { } // Verify the blocks with pre-merge blocks and post-merge blocks - var ( - headers []*types.Header - seals []bool - ) + var headers []*types.Header for _, block := range preBlocks { headers = append(headers, block.Header()) - seals = append(seals, true) } for _, block := range postBlocks { headers = append(headers, block.Header()) - seals = append(seals, true) } - _, results := engine.VerifyHeaders(chain, headers, seals) + _, results := engine.VerifyHeaders(chain, headers) for i := 0; i < len(headers); i++ { select { case result := <-results: @@ -252,11 +247,8 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) { _, blocks, _ = GenerateChainWithGenesis(gspec, ethash.NewFaker(), 8, nil) ) headers := make([]*types.Header, len(blocks)) - seals := make([]bool, len(blocks)) - for i, block := range blocks { headers[i] = block.Header() - seals[i] = true } // Set the number of threads to verify on old := runtime.GOMAXPROCS(threads) @@ -269,11 +261,11 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) { if valid { chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - _, results = chain.engine.VerifyHeaders(chain, headers, seals) + _, results = chain.engine.VerifyHeaders(chain, headers) chain.Stop() } else { chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil) - _, results = chain.engine.VerifyHeaders(chain, headers, seals) + _, results = chain.engine.VerifyHeaders(chain, headers) chain.Stop() } // Wait for all the verification results @@ -322,11 +314,8 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) { _, blocks, _ = GenerateChainWithGenesis(gspec, ethash.NewFaker(), 1024, nil) ) headers := make([]*types.Header, len(blocks)) - seals := make([]bool, len(blocks)) - for i, block := range blocks { headers[i] = block.Header() - seals[i] = true } // Set the number of threads to verify on old := runtime.GOMAXPROCS(threads) @@ -336,7 +325,7 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) { chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil) defer chain.Stop() - abort, results := chain.engine.VerifyHeaders(chain, headers, seals) + abort, results := chain.engine.VerifyHeaders(chain, headers) close(abort) // Deplete the results channel diff --git a/core/blockchain.go b/core/blockchain.go index 2e3a45b905..de64ab7c39 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -365,7 +365,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis // The first thing the node will do is reconstruct the verification data for // the head block (ethash cache or clique voting snapshot). Might as well do // it in advance. - bc.engine.VerifyHeader(bc, bc.CurrentHeader(), true) + bc.engine.VerifyHeader(bc, bc.CurrentHeader()) // Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain for hash := range BadHashes { @@ -1522,7 +1522,7 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) { return 0, errChainStopped } defer bc.chainmu.Unlock() - return bc.insertChain(chain, true, true) + return bc.insertChain(chain, true) } // insertChain is the internal implementation of InsertChain, which assumes that @@ -1533,7 +1533,7 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) { // racey behaviour. If a sidechain import is in progress, and the historic state // is imported, but then new canon-head is added before the actual sidechain // completes, then the historic state could be pruned again -func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) (int, error) { +func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) { // If the chain is terminating, don't even bother starting up. if bc.insertStopped() { return 0, nil @@ -1554,13 +1554,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) }() // Start the parallel header verifier headers := make([]*types.Header, len(chain)) - seals := make([]bool, len(chain)) - for i, block := range chain { headers[i] = block.Header() - seals[i] = verifySeals } - abort, results := bc.engine.VerifyHeaders(bc, headers, seals) + abort, results := bc.engine.VerifyHeaders(bc, headers) defer close(abort) // Peek the error for the first block to decide the directing import logic @@ -1981,7 +1978,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i // memory here. if len(blocks) >= 2048 || memory > 64*1024*1024 { log.Info("Importing heavy sidechain segment", "blocks", len(blocks), "start", blocks[0].NumberU64(), "end", block.NumberU64()) - if _, err := bc.insertChain(blocks, false, true); err != nil { + if _, err := bc.insertChain(blocks, true); err != nil { return 0, err } blocks, memory = blocks[:0], 0 @@ -1995,7 +1992,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i } if len(blocks) > 0 { log.Info("Importing sidechain segment", "start", blocks[0].NumberU64(), "end", blocks[len(blocks)-1].NumberU64()) - return bc.insertChain(blocks, false, true) + return bc.insertChain(blocks, true) } return 0, nil } @@ -2038,7 +2035,7 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error) } else { b = bc.GetBlock(hashes[i], numbers[i]) } - if _, err := bc.insertChain(types.Blocks{b}, false, false); err != nil { + if _, err := bc.insertChain(types.Blocks{b}, false); err != nil { return b.ParentHash(), err } } @@ -2242,7 +2239,7 @@ func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block) error { } defer bc.chainmu.Unlock() - _, err := bc.insertChain(types.Blocks{block}, true, false) + _, err := bc.insertChain(types.Blocks{block}, false) return err } @@ -2462,17 +2459,12 @@ Receipts: %v // InsertHeaderChain attempts to insert the given header chain in to the local // chain, possibly creating a reorg. If an error is returned, it will return the // index number of the failing header as well an error describing what went wrong. -// -// The verify parameter can be used to fine tune whether nonce verification -// should be done or not. The reason behind the optional check is because some -// of the header retrieval mechanisms already need to verify nonces, as well as -// because nonces can be verified sparsely, not needing to check each. -func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) { +func (bc *BlockChain) InsertHeaderChain(chain []*types.Header) (int, error) { if len(chain) == 0 { return 0, nil } start := time.Now() - if i, err := bc.hc.ValidateHeaderChain(chain, checkFreq); err != nil { + if i, err := bc.hc.ValidateHeaderChain(chain); err != nil { return i, err } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 77c3b00c1b..92a65ab9eb 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -74,7 +74,7 @@ func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *G } // Header-only chain requested genDb, headers := makeHeaderChainWithGenesis(genesis, n, engine, canonicalSeed) - _, err := blockchain.InsertHeaderChain(headers, 1) + _, err := blockchain.InsertHeaderChain(headers) return genDb, genesis, blockchain, err } @@ -115,7 +115,7 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara } } else { headerChainB = makeHeaderChain(blockchain2.chainConfig, blockchain2.CurrentHeader(), n, ethash.NewFaker(), genDb, forkSeed) - if _, err := blockchain2.InsertHeaderChain(headerChainB, 1); err != nil { + if _, err := blockchain2.InsertHeaderChain(headerChainB); err != nil { t.Fatalf("failed to insert forking chain: %v", err) } } @@ -148,7 +148,7 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { for _, block := range chain { // Try and process the block - err := blockchain.engine.VerifyHeader(blockchain, block.Header(), true) + err := blockchain.engine.VerifyHeader(blockchain, block.Header()) if err == nil { err = blockchain.validator.ValidateBody(block) } @@ -187,7 +187,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error { for _, header := range chain { // Try and validate the header - if err := blockchain.engine.VerifyHeader(blockchain, header, false); err != nil { + if err := blockchain.engine.VerifyHeader(blockchain, header); err != nil { return err } // Manually insert the header into the database, but don't reorganise (allows subsequent testing) @@ -252,7 +252,7 @@ func testInsertAfterMerge(t *testing.T, blockchain *BlockChain, i, n int, full b } } else { headerChainB := makeHeaderChain(blockchain2.chainConfig, blockchain2.CurrentHeader(), n, ethash.NewFaker(), genDb, forkSeed) - if _, err := blockchain2.InsertHeaderChain(headerChainB, 1); err != nil { + if _, err := blockchain2.InsertHeaderChain(headerChainB); err != nil { t.Fatalf("failed to insert forking chain: %v", err) } if blockchain2.CurrentHeader().Number.Uint64() != headerChainB[len(headerChainB)-1].Number.Uint64() { @@ -549,10 +549,10 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool) { for i, block := range diffBlocks { diffHeaders[i] = block.Header() } - if _, err := blockchain.InsertHeaderChain(easyHeaders, 1); err != nil { + if _, err := blockchain.InsertHeaderChain(easyHeaders); err != nil { t.Fatalf("failed to insert easy chain: %v", err) } - if _, err := blockchain.InsertHeaderChain(diffHeaders, 1); err != nil { + if _, err := blockchain.InsertHeaderChain(diffHeaders); err != nil { t.Fatalf("failed to insert difficult chain: %v", err) } } @@ -613,7 +613,7 @@ func testBadHashes(t *testing.T, full bool) { BadHashes[headers[2].Hash()] = true defer func() { delete(BadHashes, headers[2].Hash()) }() - _, err = blockchain.InsertHeaderChain(headers, 1) + _, err = blockchain.InsertHeaderChain(headers) } if !errors.Is(err, ErrBannedHash) { t.Errorf("error mismatch: have: %v, want: %v", err, ErrBannedHash) @@ -645,7 +645,7 @@ func testReorgBadHashes(t *testing.T, full bool) { BadHashes[blocks[3].Header().Hash()] = true defer func() { delete(BadHashes, blocks[3].Header().Hash()) }() } else { - if _, err = blockchain.InsertHeaderChain(headers, 1); err != nil { + if _, err = blockchain.InsertHeaderChain(headers); err != nil { t.Errorf("failed to import headers: %v", err) } if blockchain.CurrentHeader().Hash() != headers[3].Hash() { @@ -711,7 +711,7 @@ func testInsertNonceError(t *testing.T, full bool) { blockchain.engine = ethash.NewFakeFailer(failNum) blockchain.hc.engine = blockchain.engine - failRes, err = blockchain.InsertHeaderChain(headers, 1) + failRes, err = blockchain.InsertHeaderChain(headers) } // Check that the returned error indicates the failure if failRes != failAt { @@ -785,7 +785,7 @@ func TestFastVsFullChains(t *testing.T) { for i, block := range blocks { headers[i] = block.Header() } - if n, err := fast.InsertHeaderChain(headers, 1); err != nil { + if n, err := fast.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } if n, err := fast.InsertReceiptChain(blocks, receipts, 0); err != nil { @@ -800,7 +800,7 @@ func TestFastVsFullChains(t *testing.T) { ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() - if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { + if n, err := ancient.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(len(blocks)/2)); err != nil { @@ -931,7 +931,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { for i, block := range blocks { headers[i] = block.Header() } - if n, err := fast.InsertHeaderChain(headers, 1); err != nil { + if n, err := fast.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } if n, err := fast.InsertReceiptChain(blocks, receipts, 0); err != nil { @@ -947,7 +947,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() - if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { + if n, err := ancient.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(3*len(blocks)/4)); err != nil { @@ -964,7 +964,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { lightDb := makeDb() defer lightDb.Close() light, _ := NewBlockChain(lightDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - if n, err := light.InsertHeaderChain(headers, 1); err != nil { + if n, err := light.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } defer light.Stop() @@ -1781,7 +1781,7 @@ func TestBlockchainRecovery(t *testing.T) { for i, block := range blocks { headers[i] = block.Header() } - if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { + if n, err := ancient.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(3*len(blocks)/4)); err != nil { @@ -1850,7 +1850,7 @@ func TestInsertReceiptChainRollback(t *testing.T) { for i, block := range canonblocks { canonHeaders[i] = block.Header() } - if _, err = ancientChain.InsertHeaderChain(canonHeaders, 1); err != nil { + if _, err = ancientChain.InsertHeaderChain(canonHeaders); err != nil { t.Fatal("can't import canon headers:", err) } @@ -2128,7 +2128,7 @@ func testInsertKnownChainData(t *testing.T, typ string) { for _, block := range blocks { headers = append(headers, block.Header()) } - _, err := chain.InsertHeaderChain(headers, 1) + _, err := chain.InsertHeaderChain(headers) return err } asserter = func(t *testing.T, block *types.Block) { @@ -2142,7 +2142,7 @@ func testInsertKnownChainData(t *testing.T, typ string) { for _, block := range blocks { headers = append(headers, block.Header()) } - _, err := chain.InsertHeaderChain(headers, 1) + _, err := chain.InsertHeaderChain(headers) if err != nil { return err } @@ -2299,7 +2299,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i for _, block := range blocks { headers = append(headers, block.Header()) } - i, err := chain.InsertHeaderChain(headers, 1) + i, err := chain.InsertHeaderChain(headers) if err != nil { return fmt.Errorf("index %d, number %d: %w", i, headers[i].Number, err) } @@ -2316,7 +2316,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i for _, block := range blocks { headers = append(headers, block.Header()) } - i, err := chain.InsertHeaderChain(headers, 1) + i, err := chain.InsertHeaderChain(headers) if err != nil { return fmt.Errorf("index %d: %w", i, err) } @@ -2492,7 +2492,7 @@ func TestReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T) { for i, block := range canonblocks { canonHeaders[i] = block.Header() } - if n, err := chain.InsertHeaderChain(canonHeaders, 0); err != nil { + if n, err := chain.InsertHeaderChain(canonHeaders); err != nil { t.Fatalf("header %d: failed to insert into chain: %v", n, err) } canonNum := chain.CurrentHeader().Number.Uint64() @@ -2501,7 +2501,7 @@ func TestReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T) { for i, block := range sideblocks { sideHeaders[i] = block.Header() } - if n, err := chain.InsertHeaderChain(sideHeaders, 0); err != nil { + if n, err := chain.InsertHeaderChain(sideHeaders); err != nil { t.Fatalf("header %d: failed to insert into chain: %v", n, err) } head := chain.CurrentHeader() @@ -2692,7 +2692,7 @@ func TestSkipStaleTxIndicesInSnapSync(t *testing.T) { for i, block := range blocks { headers[i] = block.Header() } - if n, err := chain.InsertHeaderChain(headers, 0); err != nil { + if n, err := chain.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } // The indices before ancient-N(32) should be ignored. After that all blocks should be indexed. diff --git a/core/genesis.go b/core/genesis.go index e1682ebebb..1a9ee24dff 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -379,11 +379,9 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen return newcfg, stored, nil } -// LoadCliqueConfig loads the stored clique config if the chain config -// is already present in database, otherwise, return the config in the -// provided genesis specification. Note the returned clique config can -// be nil if we are not in the clique network. -func LoadCliqueConfig(db ethdb.Database, genesis *Genesis) (*params.CliqueConfig, error) { +// LoadChainConfig loads the stored chain config if it is already present in +// database, otherwise, return the config in the provided genesis specification. +func LoadChainConfig(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, error) { // Load the stored chain config from the database. It can be nil // in case the database is empty. Notably, we only care about the // chain config corresponds to the canonical chain. @@ -391,10 +389,10 @@ func LoadCliqueConfig(db ethdb.Database, genesis *Genesis) (*params.CliqueConfig if stored != (common.Hash{}) { storedcfg := rawdb.ReadChainConfig(db, stored) if storedcfg != nil { - return storedcfg.Clique, nil + return storedcfg, nil } } - // Load the clique config from the provided genesis specification. + // Load the config from the provided genesis specification if genesis != nil { // Reject invalid genesis spec without valid chain config if genesis.Config == nil { @@ -407,12 +405,11 @@ func LoadCliqueConfig(db ethdb.Database, genesis *Genesis) (*params.CliqueConfig if stored != (common.Hash{}) && genesis.ToBlock().Hash() != stored { return nil, &GenesisMismatchError{stored, genesis.ToBlock().Hash()} } - return genesis.Config.Clique, nil + return genesis.Config, nil } // There is no stored chain config and no new config provided, - // In this case the default chain config(mainnet) will be used, - // namely ethash is the specified consensus engine, return nil. - return nil, nil + // In this case the default chain config(mainnet) will be used + return params.MainnetChainConfig, nil } func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { diff --git a/core/headerchain.go b/core/headerchain.go index aed3c720c6..519a32ab80 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -300,7 +300,7 @@ func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *F return result, nil } -func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int) (int, error) { +func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header) (int, error) { // Do a sanity check that the provided chain is actually ordered and linked for i := 1; i < len(chain); i++ { if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 { @@ -322,23 +322,8 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int) return i, ErrBannedHash } } - - // Generate the list of seal verification requests, and start the parallel verifier - seals := make([]bool, len(chain)) - if checkFreq != 0 { - // In case of checkFreq == 0 all seals are left false. - for i := 0; i <= len(seals)/checkFreq; i++ { - index := i*checkFreq + hc.rand.Intn(checkFreq) - if index >= len(seals) { - index = len(seals) - 1 - } - seals[index] = true - } - // Last should always be verified to avoid junk. - seals[len(seals)-1] = true - } - - abort, results := hc.engine.VerifyHeaders(hc, chain, seals) + // Start the parallel verifier + abort, results := hc.engine.VerifyHeaders(hc, chain) defer close(abort) // Iterate over the headers and ensure they all check out diff --git a/eth/api.go b/eth/api.go index 66df927ac6..5fdd0117dd 100644 --- a/eth/api.go +++ b/eth/api.go @@ -24,7 +24,6 @@ import ( "io" "math/big" "os" - "runtime" "strings" "time" @@ -86,11 +85,8 @@ func NewMinerAPI(e *Ethereum) *MinerAPI { // usable by this process. If mining is already running, this method adjust the // number of threads allowed to use and updates the minimum price required by the // transaction pool. -func (api *MinerAPI) Start(threads *int) error { - if threads == nil { - return api.e.StartMining(runtime.NumCPU()) - } - return api.e.StartMining(*threads) +func (api *MinerAPI) Start() error { + return api.e.StartMining() } // Stop terminates the miner, both at the consensus engine level as well as at diff --git a/eth/api_backend.go b/eth/api_backend.go index 959568d294..9ea288a949 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -397,8 +397,8 @@ func (b *EthAPIBackend) Miner() *miner.Miner { return b.eth.Miner() } -func (b *EthAPIBackend) StartMining(threads int) error { - return b.eth.StartMining(threads) +func (b *EthAPIBackend) StartMining() error { + return b.eth.StartMining() } func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) { diff --git a/eth/backend.go b/eth/backend.go index 21c0deaa2d..4caab9bad6 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -134,14 +134,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { log.Error("Failed to recover state", "error", err) } // Transfer mining-related config to the ethash config. - ethashConfig := config.Ethash - ethashConfig.NotifyFull = config.Miner.NotifyFull - cliqueConfig, err := core.LoadCliqueConfig(chainDb, config.Genesis) + chainConfig, err := core.LoadChainConfig(chainDb, config.Genesis) + if err != nil { + return nil, err + } + engine, err := ethconfig.CreateConsensusEngine(chainConfig, chainDb) if err != nil { return nil, err } - engine := ethconfig.CreateConsensusEngine(stack, ðashConfig, cliqueConfig, config.Miner.Notify, config.Miner.Noverify, chainDb) - eth := &Ethereum{ config: config, merger: consensus.NewMerger(chainDb), @@ -392,18 +392,7 @@ func (s *Ethereum) SetEtherbase(etherbase common.Address) { // StartMining starts the miner with the given number of CPU threads. If mining // is already running, this method adjust the number of threads allowed to use // and updates the minimum price required by the transaction pool. -func (s *Ethereum) StartMining(threads int) error { - // Update the thread count within the consensus engine - type threaded interface { - SetThreads(threads int) - } - if th, ok := s.engine.(threaded); ok { - log.Info("Updated mining threads", "threads", threads) - if threads == 0 { - threads = -1 // Disable the miner from within - } - th.SetThreads(threads) - } +func (s *Ethereum) StartMining() error { // If the miner was not running, initialize it if !s.IsMining() { // Propagate the initial price point to the transaction pool diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index f381222002..5bab7ba186 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -440,7 +440,7 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) t.Fatal("can't create node:", err) } - ethcfg := ðconfig.Config{Genesis: genesis, Ethash: ethash.Config{PowMode: ethash.ModeFake}, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256} + ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256} ethservice, err := eth.New(n, ethcfg) if err != nil { t.Fatal("can't create eth service:", err) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 1e2022ba7b..e56321e58f 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -53,11 +53,9 @@ var ( reorgProtThreshold = 48 // Threshold number of recent blocks to disable mini reorg protection reorgProtHeaderDelay = 2 // Number of headers to delay delivering to cover mini reorgs - fsHeaderCheckFrequency = 100 // Verification frequency of the downloaded headers during snap sync - fsHeaderSafetyNet = 2048 // Number of headers to discard in case a chain violation is detected - fsHeaderForceVerify = 24 // Number of headers to verify before and after the pivot to accept it - fsHeaderContCheck = 3 * time.Second // Time interval to check for header continuations during state download - fsMinFullBlocks = 64 // Number of blocks to retrieve fully even in snap sync + fsHeaderSafetyNet = 2048 // Number of headers to discard in case a chain violation is detected + fsHeaderContCheck = 3 * time.Second // Time interval to check for header continuations during state download + fsMinFullBlocks = 64 // Number of blocks to retrieve fully even in snap sync ) var ( @@ -175,7 +173,7 @@ type LightChain interface { GetTd(common.Hash, uint64) *big.Int // InsertHeaderChain inserts a batch of headers into the local chain. - InsertHeaderChain([]*types.Header, int) (int, error) + InsertHeaderChain([]*types.Header) (int, error) // SetHead rewinds the local chain to a new head. SetHead(uint64) error @@ -1381,19 +1379,6 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode // In case of header only syncing, validate the chunk immediately if mode == SnapSync || mode == LightSync { - // If we're importing pure headers, verify based on their recentness - var pivot uint64 - - d.pivotLock.RLock() - if d.pivotHeader != nil { - pivot = d.pivotHeader.Number.Uint64() - } - d.pivotLock.RUnlock() - - frequency := fsHeaderCheckFrequency - if chunkHeaders[len(chunkHeaders)-1].Number.Uint64()+uint64(fsHeaderForceVerify) > pivot { - frequency = 1 - } // Although the received headers might be all valid, a legacy // PoW/PoA sync must not accept post-merge headers. Make sure // that any transition is rejected at this point. @@ -1426,11 +1411,11 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode } } if len(chunkHeaders) > 0 { - if n, err := d.lightchain.InsertHeaderChain(chunkHeaders, frequency); err != nil { + if n, err := d.lightchain.InsertHeaderChain(chunkHeaders); err != nil { rollbackErr = err // If some headers were inserted, track them as uncertain - if (mode == SnapSync || frequency > 1) && n > 0 && rollback == 0 { + if mode == SnapSync && n > 0 && rollback == 0 { rollback = chunkHeaders[0].Number.Uint64() } log.Warn("Invalid header encountered", "number", chunkHeaders[n].Number, "hash", chunkHashes[n], "parent", chunkHeaders[n].ParentHash, "err", err) diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 3279d9a1b2..a98d9ee4aa 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -18,10 +18,7 @@ package ethconfig import ( - "os" - "os/user" - "path/filepath" - "runtime" + "errors" "time" "github.com/ethereum/go-ethereum/common" @@ -34,9 +31,7 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/miner" - "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" ) @@ -62,16 +57,7 @@ var LightClientGPO = gasprice.Config{ // Defaults contains default settings for use on the Ethereum main net. var Defaults = Config{ - SyncMode: downloader.SnapSync, - Ethash: ethash.Config{ - CacheDir: "ethash", - CachesInMem: 2, - CachesOnDisk: 3, - CachesLockMmap: false, - DatasetsInMem: 1, - DatasetsOnDisk: 2, - DatasetsLockMmap: false, - }, + SyncMode: downloader.SnapSync, NetworkId: 1, TxLookupLimit: 2350000, LightPeers: 100, @@ -92,27 +78,6 @@ var Defaults = Config{ RPCTxFeeCap: 1, // 1 ether } -func init() { - home := os.Getenv("HOME") - if home == "" { - if user, err := user.Current(); err == nil { - home = user.HomeDir - } - } - if runtime.GOOS == "darwin" { - Defaults.Ethash.DatasetDir = filepath.Join(home, "Library", "Ethash") - } else if runtime.GOOS == "windows" { - localappdata := os.Getenv("LOCALAPPDATA") - if localappdata != "" { - Defaults.Ethash.DatasetDir = filepath.Join(localappdata, "Ethash") - } else { - Defaults.Ethash.DatasetDir = filepath.Join(home, "AppData", "Local", "Ethash") - } - } else { - Defaults.Ethash.DatasetDir = filepath.Join(home, ".ethash") - } -} - //go:generate go run github.com/fjl/gencodec -type Config -formats toml -out gen_config.go // Config contains configuration options for of the ETH and LES protocols. @@ -173,9 +138,6 @@ type Config struct { // Mining options Miner miner.Config - // Ethash options - Ethash ethash.Config - // Transaction pool options TxPool txpool.Config @@ -202,34 +164,19 @@ type Config struct { OverrideCancun *uint64 `toml:",omitempty"` } -// CreateConsensusEngine creates a consensus engine for the given chain configuration. -func CreateConsensusEngine(stack *node.Node, ethashConfig *ethash.Config, cliqueConfig *params.CliqueConfig, notify []string, noverify bool, db ethdb.Database) consensus.Engine { +// CreateConsensusEngine creates a consensus engine for the given chain config. +// Clique is allowed for now to live standalone, but ethash is forbidden and can +// only exist on already merged networks. +func CreateConsensusEngine(config *params.ChainConfig, db ethdb.Database) (consensus.Engine, error) { // If proof-of-authority is requested, set it up - var engine consensus.Engine - if cliqueConfig != nil { - engine = clique.New(cliqueConfig, db) - } else { - switch ethashConfig.PowMode { - case ethash.ModeFake: - log.Warn("Ethash used in fake mode") - case ethash.ModeTest: - log.Warn("Ethash used in test mode") - case ethash.ModeShared: - log.Warn("Ethash used in shared mode") - } - engine = ethash.New(ethash.Config{ - PowMode: ethashConfig.PowMode, - CacheDir: stack.ResolvePath(ethashConfig.CacheDir), - CachesInMem: ethashConfig.CachesInMem, - CachesOnDisk: ethashConfig.CachesOnDisk, - CachesLockMmap: ethashConfig.CachesLockMmap, - DatasetDir: ethashConfig.DatasetDir, - DatasetsInMem: ethashConfig.DatasetsInMem, - DatasetsOnDisk: ethashConfig.DatasetsOnDisk, - DatasetsLockMmap: ethashConfig.DatasetsLockMmap, - NotifyFull: ethashConfig.NotifyFull, - }, notify, noverify) - engine.(*ethash.Ethash).SetThreads(-1) // Disable CPU mining + if config.Clique != nil { + return beacon.New(clique.New(config.Clique, db)), nil + } + // If defaulting to proof-of-work, enforce an already merged network since + // we cannot run PoW algorithms and more, so we cannot even follow a chain + // not coordinated by a beacon node. + if !config.TerminalTotalDifficultyPassed { + return nil, errors.New("ethash is only supported as a historical component of already merged networks") } - return beacon.New(engine) + return beacon.New(ethash.NewFaker()), nil } diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 7d7fd32666..0e2f037740 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -6,7 +6,6 @@ import ( "time" "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/txpool" "github.com/ethereum/go-ethereum/eth/downloader" @@ -48,7 +47,6 @@ func (c Config) MarshalTOML() (interface{}, error) { Preimages bool FilterLogCacheSize int Miner miner.Config - Ethash ethash.Config TxPool txpool.Config GPO gasprice.Config EnablePreimageRecording bool @@ -90,7 +88,6 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.Preimages = c.Preimages enc.FilterLogCacheSize = c.FilterLogCacheSize enc.Miner = c.Miner - enc.Ethash = c.Ethash enc.TxPool = c.TxPool enc.GPO = c.GPO enc.EnablePreimageRecording = c.EnablePreimageRecording @@ -136,7 +133,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { Preimages *bool FilterLogCacheSize *int Miner *miner.Config - Ethash *ethash.Config TxPool *txpool.Config GPO *gasprice.Config EnablePreimageRecording *bool @@ -243,9 +239,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.Miner != nil { c.Miner = *dec.Miner } - if dec.Ethash != nil { - c.Ethash = *dec.Ethash - } if dec.TxPool != nil { c.TxPool = *dec.TxPool } diff --git a/eth/handler.go b/eth/handler.go index d4c538e6fe..f0b043166e 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -207,7 +207,7 @@ func newHandler(config *handlerConfig) (*handler, error) { return errors.New("unexpected post-merge header") } } - return h.chain.Engine().VerifyHeader(h.chain, header, true) + return h.chain.Engine().VerifyHeader(h.chain, header) } heighter := func() uint64 { return h.chain.CurrentBlock().Number.Uint64() diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 8bd8b0614c..cd619862c7 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -221,7 +221,6 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { } // Create Ethereum Service config := ðconfig.Config{Genesis: genesis} - config.Ethash.PowMode = ethash.ModeFake ethservice, err := eth.New(n, config) if err != nil { t.Fatalf("can't create new ethereum service: %v", err) diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index 87456fd64c..296d328484 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -56,7 +56,6 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { } // Create Ethereum Service config := ðconfig.Config{Genesis: genesis} - config.Ethash.PowMode = ethash.ModeFake ethservice, err := eth.New(n, config) if err != nil { t.Fatalf("can't create new ethereum service: %v", err) diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 00ad4f0211..0efee51a66 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -376,10 +376,7 @@ func createNode(t *testing.T) *node.Node { func newGQLService(t *testing.T, stack *node.Node, gspec *core.Genesis, genBlocks int, genfunc func(i int, gen *core.BlockGen)) (*handler, []*types.Block) { ethConf := ðconfig.Config{ - Genesis: gspec, - Ethash: ethash.Config{ - PowMode: ethash.ModeFake, - }, + Genesis: gspec, NetworkId: 1337, TrieCleanCache: 5, TrieCleanCacheJournal: "triecache", diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index dbd27bcae4..9a0aed7b18 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -34,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" @@ -2055,15 +2054,6 @@ func (api *DebugAPI) PrintBlock(ctx context.Context, number uint64) (string, err return spew.Sdump(block), nil } -// SeedHash retrieves the seed hash of a block. -func (api *DebugAPI) SeedHash(ctx context.Context, number uint64) (string, error) { - block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) - if block == nil { - return "", fmt.Errorf("block #%d not found", number) - } - return fmt.Sprintf("%#x", ethash.SeedHash(number)), nil -} - // ChaindbProperty returns leveldb properties of the key-value database. func (api *DebugAPI) ChaindbProperty(property string) (string, error) { if property == "" { diff --git a/les/api_test.go b/les/api_test.go index db680da0bf..ac895362a0 100644 --- a/les/api_test.go +++ b/les/api_test.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/eth" ethdownloader "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" @@ -495,7 +494,6 @@ func testSim(t *testing.T, serverCount, clientCount int, serverDir, clientDir [] func newLesClientService(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { config := ethconfig.Defaults config.SyncMode = (ethdownloader.SyncMode)(downloader.LightSync) - config.Ethash.PowMode = ethash.ModeFake return New(stack, &config) } diff --git a/les/catalyst/api_test.go b/les/catalyst/api_test.go index 54757f61da..2405499d32 100644 --- a/les/catalyst/api_test.go +++ b/les/catalyst/api_test.go @@ -223,7 +223,6 @@ func startLesService(t *testing.T, genesis *core.Genesis, headers []*types.Heade } ethcfg := ðconfig.Config{ Genesis: genesis, - Ethash: ethash.Config{PowMode: ethash.ModeFake}, SyncMode: downloader.LightSync, TrieDirtyCache: 256, TrieCleanCache: 256, @@ -236,7 +235,7 @@ func startLesService(t *testing.T, genesis *core.Genesis, headers []*types.Heade if err := n.Start(); err != nil { t.Fatal("can't start node:", err) } - if _, err := lesService.BlockChain().InsertHeaderChain(headers, 0); err != nil { + if _, err := lesService.BlockChain().InsertHeaderChain(headers); err != nil { n.Close() t.Fatal("can't import test headers:", err) } diff --git a/les/client.go b/les/client.go index 8eb46c2e63..9561ba777e 100644 --- a/les/client.go +++ b/les/client.go @@ -101,6 +101,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { return nil, genesisErr } + engine, err := ethconfig.CreateConsensusEngine(chainConfig, chainDb) + if err != nil { + return nil, err + } log.Info("") log.Info(strings.Repeat("-", 153)) for _, line := range strings.Split(chainConfig.Description(), "\n") { @@ -126,7 +130,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { reqDist: newRequestDistributor(peers, &mclock.System{}), accountManager: stack.AccountManager(), merger: merger, - engine: ethconfig.CreateConsensusEngine(stack, &config.Ethash, chainConfig.Clique, nil, false, chainDb), + engine: engine, bloomRequests: make(chan chan *bloombits.Retrieval), bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), p2pServer: stack.Server(), @@ -185,11 +189,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) leth.handler = newClientHandler(config.UltraLightServers, config.UltraLightFraction, leth) - if leth.handler.ulc != nil { - log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.handler.ulc.keys), "minTrustedFraction", leth.handler.ulc.fraction) - leth.blockchain.DisableCheckFreq() - } - leth.netRPCService = ethapi.NewNetAPI(leth.p2pServer, leth.config.NetworkId) // Register the backend on the node diff --git a/les/downloader/downloader.go b/les/downloader/downloader.go index a6ebf1d2a5..5ffcbfa423 100644 --- a/les/downloader/downloader.go +++ b/les/downloader/downloader.go @@ -58,11 +58,9 @@ var ( reorgProtThreshold = 48 // Threshold number of recent blocks to disable mini reorg protection reorgProtHeaderDelay = 2 // Number of headers to delay delivering to cover mini reorgs - fsHeaderCheckFrequency = 100 // Verification frequency of the downloaded headers during fast sync - fsHeaderSafetyNet = 2048 // Number of headers to discard in case a chain violation is detected - fsHeaderForceVerify = 24 // Number of headers to verify before and after the pivot to accept it - fsHeaderContCheck = 3 * time.Second // Time interval to check for header continuations during state download - fsMinFullBlocks = 64 // Number of blocks to retrieve fully even in fast sync + fsHeaderSafetyNet = 2048 // Number of headers to discard in case a chain violation is detected + fsHeaderContCheck = 3 * time.Second // Time interval to check for header continuations during state download + fsMinFullBlocks = 64 // Number of blocks to retrieve fully even in fast sync ) var ( @@ -166,7 +164,7 @@ type LightChain interface { GetTd(common.Hash, uint64) *big.Int // InsertHeaderChain inserts a batch of headers into the local chain. - InsertHeaderChain([]*types.Header, int) (int, error) + InsertHeaderChain([]*types.Header) (int, error) // SetHead rewinds the local chain to a new head. SetHead(uint64) error @@ -1604,24 +1602,11 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error { // In case of header only syncing, validate the chunk immediately if mode == FastSync || mode == LightSync { - // If we're importing pure headers, verify based on their recentness - var pivot uint64 - - d.pivotLock.RLock() - if d.pivotHeader != nil { - pivot = d.pivotHeader.Number.Uint64() - } - d.pivotLock.RUnlock() - - frequency := fsHeaderCheckFrequency - if chunk[len(chunk)-1].Number.Uint64()+uint64(fsHeaderForceVerify) > pivot { - frequency = 1 - } - if n, err := d.lightchain.InsertHeaderChain(chunk, frequency); err != nil { + if n, err := d.lightchain.InsertHeaderChain(chunk); err != nil { rollbackErr = err // If some headers were inserted, track them as uncertain - if (mode == FastSync || frequency > 1) && n > 0 && rollback == 0 { + if mode == FastSync && n > 0 && rollback == 0 { rollback = chunk[0].Number.Uint64() } log.Warn("Invalid header encountered", "number", chunk[n].Number, "hash", chunk[n].Hash(), "parent", chunk[n].ParentHash, "err", err) diff --git a/les/downloader/downloader_test.go b/les/downloader/downloader_test.go index 1704d3e743..ae0d5ccda3 100644 --- a/les/downloader/downloader_test.go +++ b/les/downloader/downloader_test.go @@ -254,7 +254,7 @@ func (dl *downloadTester) getTd(hash common.Hash) *big.Int { } // InsertHeaderChain injects a new batch of headers into the simulated chain. -func (dl *downloadTester) InsertHeaderChain(headers []*types.Header, checkFreq int) (i int, err error) { +func (dl *downloadTester) InsertHeaderChain(headers []*types.Header) (i int, err error) { dl.lock.Lock() defer dl.lock.Unlock() // Do a quick check, as the blockchain.InsertHeaderChain doesn't insert anything in case of errors diff --git a/les/fetcher.go b/les/fetcher.go index c7a55b193d..df81ca4d9b 100644 --- a/les/fetcher.go +++ b/les/fetcher.go @@ -161,18 +161,11 @@ func newLightFetcher(chain *light.LightChain, engine consensus.Engine, peers *se // Construct the fetcher by offering all necessary APIs validator := func(header *types.Header) error { // Disable seal verification explicitly if we are running in ulc mode. - return engine.VerifyHeader(chain, header, ulc == nil) + return engine.VerifyHeader(chain, header) } heighter := func() uint64 { return chain.CurrentHeader().Number.Uint64() } dropper := func(id string) { peers.unregister(id) } - inserter := func(headers []*types.Header) (int, error) { - // Disable PoW checking explicitly if we are running in ulc mode. - checkFreq := 1 - if ulc != nil { - checkFreq = 0 - } - return chain.InsertHeaderChain(headers, checkFreq) - } + inserter := func(headers []*types.Header) (int, error) { return chain.InsertHeaderChain(headers) } f := &lightFetcher{ ulc: ulc, peerset: peers, diff --git a/light/lightchain.go b/light/lightchain.go index e2d236fb83..617658b85b 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -70,9 +70,8 @@ type LightChain struct { wg sync.WaitGroup // Atomic boolean switches: - stopped atomic.Bool // whether LightChain is stopped or running - procInterrupt atomic.Bool // interrupts chain insert - disableCheckFreq atomic.Bool // disables header verification + stopped atomic.Bool // whether LightChain is stopped or running + procInterrupt atomic.Bool // interrupts chain insert } // NewLightChain returns a fully initialised light chain using information @@ -345,7 +344,7 @@ func (lc *LightChain) Rollback(chain []common.Hash) { func (lc *LightChain) InsertHeader(header *types.Header) error { // Verify the header first before obtaining the lock headers := []*types.Header{header} - if _, err := lc.hc.ValidateHeaderChain(headers, 100); err != nil { + if _, err := lc.hc.ValidateHeaderChain(headers); err != nil { return err } // Make sure only one thread manipulates the chain at once @@ -381,23 +380,15 @@ func (lc *LightChain) SetCanonical(header *types.Header) error { // InsertHeaderChain attempts to insert the given header chain in to the local // chain, possibly creating a reorg. If an error is returned, it will return the // index number of the failing header as well an error describing what went wrong. -// -// The verify parameter can be used to fine tune whether nonce verification -// should be done or not. The reason behind the optional check is because some -// of the header retrieval mechanisms already need to verify nonces, as well as -// because nonces can be verified sparsely, not needing to check each. -// + // In the case of a light chain, InsertHeaderChain also creates and posts light // chain events when necessary. -func (lc *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) { +func (lc *LightChain) InsertHeaderChain(chain []*types.Header) (int, error) { if len(chain) == 0 { return 0, nil } - if lc.disableCheckFreq.Load() { - checkFreq = 0 - } start := time.Now() - if i, err := lc.hc.ValidateHeaderChain(chain, checkFreq); err != nil { + if i, err := lc.hc.ValidateHeaderChain(chain); err != nil { return i, err } @@ -538,13 +529,3 @@ func (lc *LightChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscript func (lc *LightChain) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { return lc.scope.Track(new(event.Feed).Subscribe(ch)) } - -// DisableCheckFreq disables header validation. This is used for ultralight mode. -func (lc *LightChain) DisableCheckFreq() { - lc.disableCheckFreq.Store(true) -} - -// EnableCheckFreq enables header validation. -func (lc *LightChain) EnableCheckFreq() { - lc.disableCheckFreq.Store(false) -} diff --git a/light/lightchain_test.go b/light/lightchain_test.go index 905d522552..e3d756f801 100644 --- a/light/lightchain_test.go +++ b/light/lightchain_test.go @@ -64,7 +64,7 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) { } // Header-only chain requested headers := makeHeaderChain(genesis.Header(), n, db, canonicalSeed) - _, err := blockchain.InsertHeaderChain(headers, 1) + _, err := blockchain.InsertHeaderChain(headers) return db, blockchain, err } @@ -99,7 +99,7 @@ func testFork(t *testing.T, LightChain *LightChain, i, n int, comparator func(td } // Extend the newly created chain headerChainB := makeHeaderChain(LightChain2.CurrentHeader(), n, db, forkSeed) - if _, err := LightChain2.InsertHeaderChain(headerChainB, 1); err != nil { + if _, err := LightChain2.InsertHeaderChain(headerChainB); err != nil { t.Fatalf("failed to insert forking chain: %v", err) } // Sanity check that the forked chain can be imported into the original @@ -120,7 +120,7 @@ func testFork(t *testing.T, LightChain *LightChain, i, n int, comparator func(td func testHeaderChainImport(chain []*types.Header, lightchain *LightChain) error { for _, header := range chain { // Try and validate the header - if err := lightchain.engine.VerifyHeader(lightchain.hc, header, true); err != nil { + if err := lightchain.engine.VerifyHeader(lightchain.hc, header); err != nil { return err } // Manually insert the header into the database, but don't reorganize (allows subsequent testing) @@ -300,8 +300,8 @@ func testReorg(t *testing.T, first, second []int, td int64) { bc := newTestLightChain() // Insert an easy and a difficult chain afterwards - bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1) - bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1) + bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11)) + bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22)) // Check that the chain is valid number and link wise prev := bc.CurrentHeader() for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) { @@ -324,7 +324,7 @@ func TestBadHeaderHashes(t *testing.T) { var err error headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10) core.BadHashes[headers[2].Hash()] = true - if _, err = bc.InsertHeaderChain(headers, 1); !errors.Is(err, core.ErrBannedHash) { + if _, err = bc.InsertHeaderChain(headers); !errors.Is(err, core.ErrBannedHash) { t.Errorf("error mismatch: have: %v, want %v", err, core.ErrBannedHash) } } @@ -337,7 +337,7 @@ func TestReorgBadHeaderHashes(t *testing.T) { // Create a chain, import and ban afterwards headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10) - if _, err := bc.InsertHeaderChain(headers, 1); err != nil { + if _, err := bc.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to import headers: %v", err) } if bc.CurrentHeader().Hash() != headers[3].Hash() { diff --git a/light/odr_test.go b/light/odr_test.go index 5c15ae5afe..0df1fbf2f5 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -292,7 +292,7 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { for i, block := range gchain { headers[i] = block.Header() } - if _, err := lightchain.InsertHeaderChain(headers, 1); err != nil { + if _, err := lightchain.InsertHeaderChain(headers); err != nil { t.Fatal(err) } diff --git a/light/txpool_test.go b/light/txpool_test.go index 02f982d9af..1181e3889e 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -122,7 +122,7 @@ func TestTxPool(t *testing.T) { } } - if _, err := lightchain.InsertHeaderChain([]*types.Header{block.Header()}, 1); err != nil { + if _, err := lightchain.InsertHeaderChain([]*types.Header{block.Header()}); err != nil { panic(err) } diff --git a/miner/miner.go b/miner/miner.go index c969aec735..b1d1f7c4cb 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -45,15 +45,12 @@ type Backend interface { // Config is the configuration parameters of mining. type Config struct { - Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards - Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages (only useful in ethash). - NotifyFull bool `toml:",omitempty"` // Notify with pending block headers instead of work packages - ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner - GasFloor uint64 // Target gas floor for mined blocks. - GasCeil uint64 // Target gas ceiling for mined blocks. - GasPrice *big.Int // Minimum gas price for mining a transaction - Recommit time.Duration // The time interval for miner to re-create mining work. - Noverify bool // Disable remote mining solution verification(only useful in ethash). + Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards + ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner + GasFloor uint64 // Target gas floor for mined blocks. + GasCeil uint64 // Target gas ceiling for mined blocks. + GasPrice *big.Int // Minimum gas price for mining a transaction + Recommit time.Duration // The time interval for miner to re-create mining work. NewPayloadTimeout time.Duration // The maximum time allowance for creating a new payload } diff --git a/miner/stress/1559/main.go b/miner/stress/1559/main.go deleted file mode 100644 index 2e8b78d85e..0000000000 --- a/miner/stress/1559/main.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2021 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 . - -// This file contains a miner stress test for eip 1559. -package main - -import ( - "crypto/ecdsa" - crand "crypto/rand" - "math/big" - "math/rand" - "os" - "os/signal" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/fdlimit" - "github.com/ethereum/go-ethereum/consensus/ethash" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/txpool" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/miner" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/params" -) - -var ( - londonBlock = big.NewInt(30) // Predefined london fork block for activating eip 1559. -) - -func main() { - log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - fdlimit.Raise(2048) - - // Generate a batch of accounts to seal and fund with - faucets := make([]*ecdsa.PrivateKey, 128) - for i := 0; i < len(faucets); i++ { - faucets[i], _ = crypto.GenerateKey() - } - // Pre-generate the ethash mining DAG so we don't race - ethash.MakeDataset(1, ethconfig.Defaults.Ethash.DatasetDir) - - // Create an Ethash network - genesis := makeGenesis(faucets) - - // Handle interrupts. - interruptCh := make(chan os.Signal, 5) - signal.Notify(interruptCh, os.Interrupt) - - var ( - stacks []*node.Node - nodes []*eth.Ethereum - enodes []*enode.Node - ) - for i := 0; i < 4; i++ { - // Start the node and wait until it's up - stack, ethBackend, err := makeMiner(genesis) - if err != nil { - panic(err) - } - defer stack.Close() - - for stack.Server().NodeInfo().Ports.Listener == 0 { - time.Sleep(250 * time.Millisecond) - } - // Connect the node to all the previous ones - for _, n := range enodes { - stack.Server().AddPeer(n) - } - // Start tracking the node and its enode - nodes = append(nodes, ethBackend) - enodes = append(enodes, stack.Server().Self()) - } - - // Iterate over all the nodes and start mining - time.Sleep(3 * time.Second) - for _, node := range nodes { - if err := node.StartMining(1); err != nil { - panic(err) - } - } - time.Sleep(3 * time.Second) - - // Start injecting transactions from the faucets like crazy - var ( - nonces = make([]uint64, len(faucets)) - - // The signer activates the 1559 features even before the fork, - // so the new 1559 txs can be created with this signer. - signer = types.LatestSignerForChainID(genesis.Config.ChainID) - ) - for { - // Stop when interrupted. - select { - case <-interruptCh: - for _, node := range stacks { - node.Close() - } - return - default: - } - - // Pick a random mining node - index := rand.Intn(len(faucets)) - backend := nodes[index%len(nodes)] - - headHeader := backend.BlockChain().CurrentHeader() - baseFee := headHeader.BaseFee - - // Create a self transaction and inject into the pool. The legacy - // and 1559 transactions can all be created by random even if the - // fork is not happened. - tx := makeTransaction(nonces[index], faucets[index], signer, baseFee) - if err := backend.TxPool().AddLocal(tx); err != nil { - continue - } - nonces[index]++ - - // Wait if we're too saturated - if pend, _ := backend.TxPool().Stats(); pend > 4192 { - time.Sleep(100 * time.Millisecond) - } - - // Wait if the basefee is raised too fast - if baseFee != nil && baseFee.Cmp(new(big.Int).Mul(big.NewInt(100), big.NewInt(params.GWei))) > 0 { - time.Sleep(500 * time.Millisecond) - } - } -} - -func makeTransaction(nonce uint64, privKey *ecdsa.PrivateKey, signer types.Signer, baseFee *big.Int) *types.Transaction { - // Generate legacy transaction - if rand.Intn(2) == 0 { - tx, err := types.SignTx(types.NewTransaction(nonce, crypto.PubkeyToAddress(privKey.PublicKey), new(big.Int), 21000, big.NewInt(100000000000+rand.Int63n(65536)), nil), signer, privKey) - if err != nil { - panic(err) - } - return tx - } - // Generate eip 1559 transaction - recipient := crypto.PubkeyToAddress(privKey.PublicKey) - - // Feecap and feetip are limited to 32 bytes. Offer a sightly - // larger buffer for creating both valid and invalid transactions. - var buf = make([]byte, 32+5) - crand.Read(buf) - gasTipCap := new(big.Int).SetBytes(buf) - - // If the given base fee is nil(the 1559 is still not available), - // generate a fake base fee in order to create 1559 tx forcibly. - if baseFee == nil { - baseFee = new(big.Int).SetInt64(int64(rand.Int31())) - } - // Generate the feecap, 75% valid feecap and 25% unguaranteed. - var gasFeeCap *big.Int - if rand.Intn(4) == 0 { - crand.Read(buf) - gasFeeCap = new(big.Int).SetBytes(buf) - } else { - gasFeeCap = new(big.Int).Add(baseFee, gasTipCap) - } - return types.MustSignNewTx(privKey, signer, &types.DynamicFeeTx{ - ChainID: signer.ChainID(), - Nonce: nonce, - GasTipCap: gasTipCap, - GasFeeCap: gasFeeCap, - Gas: 21000, - To: &recipient, - Value: big.NewInt(100), - Data: nil, - AccessList: nil, - }) -} - -// makeGenesis creates a custom Ethash genesis block based on some pre-defined -// faucet accounts. -func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { - genesis := core.DefaultGenesisBlock() - - genesis.Config = params.AllEthashProtocolChanges - genesis.Config.LondonBlock = londonBlock - genesis.Difficulty = params.MinimumDifficulty - - // Small gaslimit for easier basefee moving testing. - genesis.GasLimit = 8_000_000 - - genesis.Config.ChainID = big.NewInt(18) - - genesis.Alloc = core.GenesisAlloc{} - for _, faucet := range faucets { - genesis.Alloc[crypto.PubkeyToAddress(faucet.PublicKey)] = core.GenesisAccount{ - Balance: new(big.Int).Exp(big.NewInt(2), big.NewInt(128), nil), - } - } - if londonBlock.Sign() == 0 { - log.Info("Enabled the eip 1559 by default") - } else { - log.Info("Registered the london fork", "number", londonBlock) - } - return genesis -} - -func makeMiner(genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) { - // Define the basic configurations for the Ethereum node - datadir, _ := os.MkdirTemp("", "") - - config := &node.Config{ - Name: "geth", - Version: params.Version, - DataDir: datadir, - P2P: p2p.Config{ - ListenAddr: "0.0.0.0:0", - NoDiscovery: true, - MaxPeers: 25, - }, - UseLightweightKDF: true, - } - // Create the node and configure a full Ethereum node on it - stack, err := node.New(config) - if err != nil { - return nil, nil, err - } - ethBackend, err := eth.New(stack, ðconfig.Config{ - Genesis: genesis, - NetworkId: genesis.Config.ChainID.Uint64(), - SyncMode: downloader.FullSync, - DatabaseCache: 256, - DatabaseHandles: 256, - TxPool: txpool.DefaultConfig, - GPO: ethconfig.Defaults.GPO, - Ethash: ethconfig.Defaults.Ethash, - Miner: miner.Config{ - Etherbase: common.Address{1}, - GasCeil: genesis.GasLimit * 11 / 10, - GasPrice: big.NewInt(1), - Recommit: time.Second, - }, - }) - if err != nil { - return nil, nil, err - } - err = stack.Start() - return stack, ethBackend, err -} diff --git a/miner/stress/beacon/main.go b/miner/stress/beacon/main.go deleted file mode 100644 index 65318f1a0e..0000000000 --- a/miner/stress/beacon/main.go +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright 2021 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 . - -// This file contains a miner stress test for the eth1/2 transition -package main - -import ( - "crypto/ecdsa" - "errors" - "math/big" - "math/rand" - "os" - "path/filepath" - "time" - - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/beacon/engine" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/fdlimit" - "github.com/ethereum/go-ethereum/consensus/ethash" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/txpool" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth" - ethcatalyst "github.com/ethereum/go-ethereum/eth/catalyst" - "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/les" - lescatalyst "github.com/ethereum/go-ethereum/les/catalyst" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/miner" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/params" -) - -type nodetype int - -const ( - legacyMiningNode nodetype = iota - legacyNormalNode - eth2MiningNode - eth2NormalNode - eth2LightClient -) - -func (typ nodetype) String() string { - switch typ { - case legacyMiningNode: - return "legacyMiningNode" - case legacyNormalNode: - return "legacyNormalNode" - case eth2MiningNode: - return "eth2MiningNode" - case eth2NormalNode: - return "eth2NormalNode" - case eth2LightClient: - return "eth2LightClient" - default: - return "undefined" - } -} - -var ( - // transitionDifficulty is the target total difficulty for transition - transitionDifficulty = new(big.Int).Mul(big.NewInt(20), params.MinimumDifficulty) - - // blockInterval is the time interval for creating a new eth2 block - blockIntervalInt = 3 - blockInterval = time.Second * time.Duration(blockIntervalInt) - - // finalizationDist is the block distance for finalizing block - finalizationDist = 10 -) - -type ethNode struct { - typ nodetype - stack *node.Node - enode *enode.Node - api *ethcatalyst.ConsensusAPI - ethBackend *eth.Ethereum - lapi *lescatalyst.ConsensusAPI - lesBackend *les.LightEthereum -} - -func newNode(typ nodetype, genesis *core.Genesis, enodes []*enode.Node) *ethNode { - var ( - err error - api *ethcatalyst.ConsensusAPI - lapi *lescatalyst.ConsensusAPI - stack *node.Node - ethBackend *eth.Ethereum - lesBackend *les.LightEthereum - ) - // Start the node and wait until it's up - if typ == eth2LightClient { - stack, lesBackend, lapi, err = makeLightNode(genesis) - } else { - stack, ethBackend, api, err = makeFullNode(genesis) - } - if err != nil { - panic(err) - } - for stack.Server().NodeInfo().Ports.Listener == 0 { - time.Sleep(250 * time.Millisecond) - } - // Connect the node to all the previous ones - for _, n := range enodes { - stack.Server().AddPeer(n) - } - enode := stack.Server().Self() - - // Inject the signer key and start sealing with it - stack.AccountManager().AddBackend(keystore.NewPlaintextKeyStore("beacon-stress")) - ks := stack.AccountManager().Backends(keystore.KeyStoreType) - if len(ks) == 0 { - panic("Keystore is not available") - } - store := ks[0].(*keystore.KeyStore) - if _, err := store.NewAccount(""); err != nil { - panic(err) - } - return ðNode{ - typ: typ, - api: api, - ethBackend: ethBackend, - lapi: lapi, - lesBackend: lesBackend, - stack: stack, - enode: enode, - } -} - -func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) (*engine.ExecutableData, error) { - if n.typ != eth2MiningNode { - return nil, errors.New("invalid node type") - } - timestamp := uint64(time.Now().Unix()) - if timestamp <= parentTimestamp { - timestamp = parentTimestamp + 1 - } - payloadAttribute := engine.PayloadAttributes{ - Timestamp: timestamp, - Random: common.Hash{}, - SuggestedFeeRecipient: common.HexToAddress("0xdeadbeef"), - } - fcState := engine.ForkchoiceStateV1{ - HeadBlockHash: parentHash, - SafeBlockHash: common.Hash{}, - FinalizedBlockHash: common.Hash{}, - } - payload, err := n.api.ForkchoiceUpdatedV1(fcState, &payloadAttribute) - if err != nil { - return nil, err - } - time.Sleep(time.Second * 5) // give enough time for block creation - return n.api.GetPayloadV1(*payload.PayloadID) -} - -func (n *ethNode) insertBlock(eb engine.ExecutableData) error { - if !eth2types(n.typ) { - return errors.New("invalid node type") - } - switch n.typ { - case eth2NormalNode, eth2MiningNode: - newResp, err := n.api.NewPayloadV1(eb) - if err != nil { - return err - } else if newResp.Status != "VALID" { - return errors.New("failed to insert block") - } - return nil - case eth2LightClient: - newResp, err := n.lapi.ExecutePayloadV1(eb) - if err != nil { - return err - } else if newResp.Status != "VALID" { - return errors.New("failed to insert block") - } - return nil - default: - return errors.New("undefined node") - } -} - -func (n *ethNode) insertBlockAndSetHead(parent *types.Header, ed engine.ExecutableData) error { - if !eth2types(n.typ) { - return errors.New("invalid node type") - } - if err := n.insertBlock(ed); err != nil { - return err - } - block, err := engine.ExecutableDataToBlock(ed) - if err != nil { - return err - } - fcState := engine.ForkchoiceStateV1{ - HeadBlockHash: block.ParentHash(), - SafeBlockHash: common.Hash{}, - FinalizedBlockHash: common.Hash{}, - } - switch n.typ { - case eth2NormalNode, eth2MiningNode: - if _, err := n.api.ForkchoiceUpdatedV1(fcState, nil); err != nil { - return err - } - return nil - case eth2LightClient: - if _, err := n.lapi.ForkchoiceUpdatedV1(fcState, nil); err != nil { - return err - } - return nil - default: - return errors.New("undefined node") - } -} - -type nodeManager struct { - genesis *core.Genesis - genesisBlock *types.Block - nodes []*ethNode - enodes []*enode.Node - close chan struct{} -} - -func newNodeManager(genesis *core.Genesis) *nodeManager { - return &nodeManager{ - close: make(chan struct{}), - genesis: genesis, - genesisBlock: genesis.ToBlock(), - } -} - -func (mgr *nodeManager) createNode(typ nodetype) { - node := newNode(typ, mgr.genesis, mgr.enodes) - mgr.nodes = append(mgr.nodes, node) - mgr.enodes = append(mgr.enodes, node.enode) -} - -func (mgr *nodeManager) getNodes(typ nodetype) []*ethNode { - var ret []*ethNode - for _, node := range mgr.nodes { - if node.typ == typ { - ret = append(ret, node) - } - } - return ret -} - -func (mgr *nodeManager) startMining() { - for _, node := range append(mgr.getNodes(eth2MiningNode), mgr.getNodes(legacyMiningNode)...) { - if err := node.ethBackend.StartMining(1); err != nil { - panic(err) - } - } -} - -func (mgr *nodeManager) shutdown() { - close(mgr.close) - for _, node := range mgr.nodes { - node.stack.Close() - } -} - -func (mgr *nodeManager) run() { - if len(mgr.nodes) == 0 { - return - } - chain := mgr.nodes[0].ethBackend.BlockChain() - sink := make(chan core.ChainHeadEvent, 1024) - sub := chain.SubscribeChainHeadEvent(sink) - defer sub.Unsubscribe() - - var ( - transitioned bool - parentBlock *types.Block - waitFinalise []*types.Block - ) - timer := time.NewTimer(0) - defer timer.Stop() - <-timer.C // discard the initial tick - - // Handle the by default transition. - if transitionDifficulty.Sign() == 0 { - transitioned = true - parentBlock = mgr.genesisBlock - timer.Reset(blockInterval) - log.Info("Enable the transition by default") - } - - // Handle the block finalization. - checkFinalise := func() { - if parentBlock == nil { - return - } - if len(waitFinalise) == 0 { - return - } - oldest := waitFinalise[0] - if oldest.NumberU64() > parentBlock.NumberU64() { - return - } - distance := parentBlock.NumberU64() - oldest.NumberU64() - if int(distance) < finalizationDist { - return - } - nodes := mgr.getNodes(eth2MiningNode) - nodes = append(nodes, mgr.getNodes(eth2NormalNode)...) - //nodes = append(nodes, mgr.getNodes(eth2LightClient)...) - for _, node := range nodes { - fcState := engine.ForkchoiceStateV1{ - HeadBlockHash: parentBlock.Hash(), - SafeBlockHash: oldest.Hash(), - FinalizedBlockHash: oldest.Hash(), - } - node.api.ForkchoiceUpdatedV1(fcState, nil) - } - log.Info("Finalised eth2 block", "number", oldest.NumberU64(), "hash", oldest.Hash()) - waitFinalise = waitFinalise[1:] - } - - for { - checkFinalise() - select { - case <-mgr.close: - return - - case ev := <-sink: - if transitioned { - continue - } - td := chain.GetTd(ev.Block.Hash(), ev.Block.NumberU64()) - if td.Cmp(transitionDifficulty) < 0 { - continue - } - transitioned, parentBlock = true, ev.Block - timer.Reset(blockInterval) - log.Info("Transition difficulty reached", "td", td, "target", transitionDifficulty, "number", ev.Block.NumberU64(), "hash", ev.Block.Hash()) - - case <-timer.C: - producers := mgr.getNodes(eth2MiningNode) - if len(producers) == 0 { - continue - } - hash, timestamp := parentBlock.Hash(), parentBlock.Time() - if parentBlock.NumberU64() == 0 { - timestamp = uint64(time.Now().Unix()) - uint64(blockIntervalInt) - } - ed, err := producers[0].assembleBlock(hash, timestamp) - if err != nil { - log.Error("Failed to assemble the block", "err", err) - continue - } - block, _ := engine.ExecutableDataToBlock(*ed) - - nodes := mgr.getNodes(eth2MiningNode) - nodes = append(nodes, mgr.getNodes(eth2NormalNode)...) - nodes = append(nodes, mgr.getNodes(eth2LightClient)...) - for _, node := range nodes { - if err := node.insertBlockAndSetHead(parentBlock.Header(), *ed); err != nil { - log.Error("Failed to insert block", "type", node.typ, "err", err) - } - } - log.Info("Create and insert eth2 block", "number", ed.Number) - parentBlock = block - waitFinalise = append(waitFinalise, block) - timer.Reset(blockInterval) - } - } -} - -func main() { - log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - fdlimit.Raise(2048) - - // Generate a batch of accounts to seal and fund with - faucets := make([]*ecdsa.PrivateKey, 16) - for i := 0; i < len(faucets); i++ { - faucets[i], _ = crypto.GenerateKey() - } - // Pre-generate the ethash mining DAG so we don't race - ethash.MakeDataset(1, filepath.Join(os.Getenv("HOME"), ".ethash")) - - // Create an Ethash network - genesis := makeGenesis(faucets) - manager := newNodeManager(genesis) - defer manager.shutdown() - - manager.createNode(eth2NormalNode) - manager.createNode(eth2MiningNode) - manager.createNode(legacyMiningNode) - manager.createNode(legacyNormalNode) - manager.createNode(eth2LightClient) - - // Iterate over all the nodes and start mining - time.Sleep(3 * time.Second) - if transitionDifficulty.Sign() != 0 { - manager.startMining() - } - go manager.run() - - // Start injecting transactions from the faucets like crazy - time.Sleep(3 * time.Second) - nonces := make([]uint64, len(faucets)) - for { - // Pick a random mining node - nodes := manager.getNodes(eth2MiningNode) - - index := rand.Intn(len(faucets)) - node := nodes[index%len(nodes)] - - // Create a self transaction and inject into the pool - tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(10_000_000_000+rand.Int63n(6_553_600_000)), nil), types.HomesteadSigner{}, faucets[index]) - if err != nil { - panic(err) - } - if err := node.ethBackend.TxPool().AddLocal(tx); err != nil { - panic(err) - } - nonces[index]++ - - // Wait if we're too saturated - if pend, _ := node.ethBackend.TxPool().Stats(); pend > 2048 { - time.Sleep(100 * time.Millisecond) - } - } -} - -// makeGenesis creates a custom Ethash genesis block based on some pre-defined -// faucet accounts. -func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { - genesis := core.DefaultGenesisBlock() - genesis.Difficulty = params.MinimumDifficulty - genesis.GasLimit = 25000000 - - genesis.BaseFee = big.NewInt(params.InitialBaseFee) - genesis.Config = params.AllEthashProtocolChanges - genesis.Config.TerminalTotalDifficulty = transitionDifficulty - - genesis.Alloc = core.GenesisAlloc{} - for _, faucet := range faucets { - genesis.Alloc[crypto.PubkeyToAddress(faucet.PublicKey)] = core.GenesisAccount{ - Balance: new(big.Int).Exp(big.NewInt(2), big.NewInt(128), nil), - } - } - return genesis -} - -func makeFullNode(genesis *core.Genesis) (*node.Node, *eth.Ethereum, *ethcatalyst.ConsensusAPI, error) { - // Define the basic configurations for the Ethereum node - datadir, _ := os.MkdirTemp("", "") - - config := &node.Config{ - Name: "geth", - Version: params.Version, - DataDir: datadir, - P2P: p2p.Config{ - ListenAddr: "0.0.0.0:0", - NoDiscovery: true, - MaxPeers: 25, - }, - UseLightweightKDF: true, - } - // Create the node and configure a full Ethereum node on it - stack, err := node.New(config) - if err != nil { - return nil, nil, nil, err - } - econfig := ðconfig.Config{ - Genesis: genesis, - NetworkId: genesis.Config.ChainID.Uint64(), - SyncMode: downloader.FullSync, - DatabaseCache: 256, - DatabaseHandles: 256, - TxPool: txpool.DefaultConfig, - GPO: ethconfig.Defaults.GPO, - Ethash: ethconfig.Defaults.Ethash, - Miner: miner.Config{ - GasFloor: genesis.GasLimit * 9 / 10, - GasCeil: genesis.GasLimit * 11 / 10, - GasPrice: big.NewInt(1), - Recommit: 1 * time.Second, - }, - LightServ: 100, - LightPeers: 10, - LightNoSyncServe: true, - } - ethBackend, err := eth.New(stack, econfig) - if err != nil { - return nil, nil, nil, err - } - _, err = les.NewLesServer(stack, ethBackend, econfig) - if err != nil { - log.Crit("Failed to create the LES server", "err", err) - } - err = stack.Start() - return stack, ethBackend, ethcatalyst.NewConsensusAPI(ethBackend), err -} - -func makeLightNode(genesis *core.Genesis) (*node.Node, *les.LightEthereum, *lescatalyst.ConsensusAPI, error) { - // Define the basic configurations for the Ethereum node - datadir, _ := os.MkdirTemp("", "") - - config := &node.Config{ - Name: "geth", - Version: params.Version, - DataDir: datadir, - P2P: p2p.Config{ - ListenAddr: "0.0.0.0:0", - NoDiscovery: true, - MaxPeers: 25, - }, - UseLightweightKDF: true, - } - // Create the node and configure a full Ethereum node on it - stack, err := node.New(config) - if err != nil { - return nil, nil, nil, err - } - lesBackend, err := les.New(stack, ðconfig.Config{ - Genesis: genesis, - NetworkId: genesis.Config.ChainID.Uint64(), - SyncMode: downloader.LightSync, - DatabaseCache: 256, - DatabaseHandles: 256, - TxPool: txpool.DefaultConfig, - GPO: ethconfig.Defaults.GPO, - Ethash: ethconfig.Defaults.Ethash, - LightPeers: 10, - }) - if err != nil { - return nil, nil, nil, err - } - err = stack.Start() - return stack, lesBackend, lescatalyst.NewConsensusAPI(lesBackend), err -} - -func eth2types(typ nodetype) bool { - if typ == eth2LightClient || typ == eth2NormalNode || typ == eth2MiningNode { - return true - } - return false -} diff --git a/miner/stress/clique/main.go b/miner/stress/clique/main.go index 74962c6d51..16a8687da3 100644 --- a/miner/stress/clique/main.go +++ b/miner/stress/clique/main.go @@ -104,7 +104,7 @@ func main() { // Iterate over all the nodes and start signing on them time.Sleep(3 * time.Second) for _, node := range nodes { - if err := node.StartMining(1); err != nil { + if err := node.StartMining(); err != nil { panic(err) } } diff --git a/miner/stress/ethash/main.go b/miner/stress/ethash/main.go deleted file mode 100644 index 6905bf01f1..0000000000 --- a/miner/stress/ethash/main.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2018 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 . - -// This file contains a miner stress test based on the Ethash consensus engine. -package main - -import ( - "crypto/ecdsa" - "math/big" - "math/rand" - "os" - "os/signal" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/fdlimit" - "github.com/ethereum/go-ethereum/consensus/ethash" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/txpool" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/miner" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/params" -) - -func main() { - log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - fdlimit.Raise(2048) - - // Generate a batch of accounts to seal and fund with - faucets := make([]*ecdsa.PrivateKey, 128) - for i := 0; i < len(faucets); i++ { - faucets[i], _ = crypto.GenerateKey() - } - // Pre-generate the ethash mining DAG so we don't race - ethash.MakeDataset(1, ethconfig.Defaults.Ethash.DatasetDir) - - // Create an Ethash network - genesis := makeGenesis(faucets) - - // Handle interrupts. - interruptCh := make(chan os.Signal, 5) - signal.Notify(interruptCh, os.Interrupt) - - var ( - stacks []*node.Node - nodes []*eth.Ethereum - enodes []*enode.Node - ) - for i := 0; i < 4; i++ { - // Start the node and wait until it's up - stack, ethBackend, err := makeMiner(genesis) - if err != nil { - panic(err) - } - defer stack.Close() - - for stack.Server().NodeInfo().Ports.Listener == 0 { - time.Sleep(250 * time.Millisecond) - } - // Connect the node to all the previous ones - for _, n := range enodes { - stack.Server().AddPeer(n) - } - // Start tracking the node and its enode - stacks = append(stacks, stack) - nodes = append(nodes, ethBackend) - enodes = append(enodes, stack.Server().Self()) - } - - // Iterate over all the nodes and start mining - time.Sleep(3 * time.Second) - for _, node := range nodes { - if err := node.StartMining(1); err != nil { - panic(err) - } - } - time.Sleep(3 * time.Second) - - // Start injecting transactions from the faucets like crazy - nonces := make([]uint64, len(faucets)) - for { - // Stop when interrupted. - select { - case <-interruptCh: - for _, node := range stacks { - node.Close() - } - return - default: - } - - // Pick a random mining node - index := rand.Intn(len(faucets)) - backend := nodes[index%len(nodes)] - - // Create a self transaction and inject into the pool - tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(100000000000+rand.Int63n(65536)), nil), types.HomesteadSigner{}, faucets[index]) - if err != nil { - panic(err) - } - if err := backend.TxPool().AddLocal(tx); err != nil { - panic(err) - } - nonces[index]++ - - // Wait if we're too saturated - if pend, _ := backend.TxPool().Stats(); pend > 2048 { - time.Sleep(100 * time.Millisecond) - } - } -} - -// makeGenesis creates a custom Ethash genesis block based on some pre-defined -// faucet accounts. -func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { - genesis := core.DefaultGenesisBlock() - genesis.Difficulty = params.MinimumDifficulty - genesis.GasLimit = 25000000 - - genesis.Config.ChainID = big.NewInt(18) - - genesis.Alloc = core.GenesisAlloc{} - for _, faucet := range faucets { - genesis.Alloc[crypto.PubkeyToAddress(faucet.PublicKey)] = core.GenesisAccount{ - Balance: new(big.Int).Exp(big.NewInt(2), big.NewInt(128), nil), - } - } - return genesis -} - -func makeMiner(genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) { - // Define the basic configurations for the Ethereum node - datadir, _ := os.MkdirTemp("", "") - - config := &node.Config{ - Name: "geth", - Version: params.Version, - DataDir: datadir, - P2P: p2p.Config{ - ListenAddr: "0.0.0.0:0", - NoDiscovery: true, - MaxPeers: 25, - }, - UseLightweightKDF: true, - } - // Create the node and configure a full Ethereum node on it - stack, err := node.New(config) - if err != nil { - return nil, nil, err - } - ethBackend, err := eth.New(stack, ðconfig.Config{ - Genesis: genesis, - NetworkId: genesis.Config.ChainID.Uint64(), - SyncMode: downloader.FullSync, - DatabaseCache: 256, - DatabaseHandles: 256, - TxPool: txpool.DefaultConfig, - GPO: ethconfig.Defaults.GPO, - Ethash: ethconfig.Defaults.Ethash, - Miner: miner.Config{ - Etherbase: common.Address{1}, - GasCeil: genesis.GasLimit * 11 / 10, - GasPrice: big.NewInt(1), - Recommit: time.Second, - }, - }) - if err != nil { - return nil, nil, err - } - - err = stack.Start() - return stack, ethBackend, err -} diff --git a/miner/worker_test.go b/miner/worker_test.go index 9db64a240d..683d019d2d 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -208,10 +208,6 @@ func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consens return w, backend } -func TestGenerateBlockAndImportEthash(t *testing.T) { - testGenerateBlockAndImport(t, false) -} - func TestGenerateBlockAndImportClique(t *testing.T) { testGenerateBlockAndImport(t, true) } diff --git a/params/config.go b/params/config.go index 9ea2b150b0..c1614bdbad 100644 --- a/params/config.go +++ b/params/config.go @@ -152,7 +152,7 @@ var ( CancunTime: nil, PragueTime: nil, TerminalTotalDifficulty: nil, - TerminalTotalDifficultyPassed: false, + TerminalTotalDifficultyPassed: true, Ethash: new(EthashConfig), Clique: nil, } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index b74653ea6a..45b7e49ae7 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" @@ -117,14 +116,8 @@ func (t *BlockTest) Run(snapshotter bool) error { if gblock.Root() != t.json.Genesis.StateRoot { return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6]) } - var engine consensus.Engine - if t.json.SealEngine == "NoProof" { - engine = ethash.NewFaker() - } else { - engine = ethash.NewShared() - } // Wrap the original engine within the beacon-engine - engine = beacon.New(engine) + engine := beacon.New(ethash.NewFaker()) cache := &core.CacheConfig{TrieCleanLimit: 0} if snapshotter { From ffda2c64c4260e1dd2cc2760faf1f8d33bdcf670 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Thu, 4 May 2023 16:54:45 +0800 Subject: [PATCH 092/988] rpc: use atomic types (#27214) rpc: use atomic type --- rpc/client.go | 4 ++-- rpc/server.go | 10 +++++----- signer/core/stdioui.go | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/rpc/client.go b/rpc/client.go index 69ff4851e3..fbeb5a1814 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -79,7 +79,7 @@ type Client struct { isHTTP bool // connection type: http, ws or ipc services *serviceRegistry - idCounter uint32 + idCounter atomic.Uint32 // This function, if non-nil, is called when the connection is lost. reconnectFunc reconnectFunc @@ -263,7 +263,7 @@ func (c *Client) RegisterName(name string, receiver interface{}) error { } func (c *Client) nextID() json.RawMessage { - id := atomic.AddUint32(&c.idCounter, 1) + id := c.idCounter.Add(1) return strconv.AppendUint(nil, uint64(id), 10) } diff --git a/rpc/server.go b/rpc/server.go index 9c72c26d7b..089bbb1fd5 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -48,7 +48,7 @@ type Server struct { mutex sync.Mutex codecs map[ServerCodec]struct{} - run int32 + run atomic.Bool } // NewServer creates a new server instance with no registered handlers. @@ -56,8 +56,8 @@ func NewServer() *Server { server := &Server{ idgen: randomIDGenerator(), codecs: make(map[ServerCodec]struct{}), - run: 1, } + server.run.Store(true) // Register the default service providing meta information about the RPC service such // as the services and methods it offers. rpcService := &RPCService{server} @@ -95,7 +95,7 @@ func (s *Server) trackCodec(codec ServerCodec) bool { s.mutex.Lock() defer s.mutex.Unlock() - if atomic.LoadInt32(&s.run) == 0 { + if !s.run.Load() { return false // Don't serve if server is stopped. } s.codecs[codec] = struct{}{} @@ -114,7 +114,7 @@ func (s *Server) untrackCodec(codec ServerCodec) { // this mode. func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { // Don't serve if server is stopped. - if atomic.LoadInt32(&s.run) == 0 { + if !s.run.Load() { return } @@ -144,7 +144,7 @@ func (s *Server) Stop() { s.mutex.Lock() defer s.mutex.Unlock() - if atomic.CompareAndSwapInt32(&s.run, 1, 0) { + if s.run.CompareAndSwap(true, false) { log.Debug("RPC server shutting down") for codec := range s.codecs { codec.close() diff --git a/signer/core/stdioui.go b/signer/core/stdioui.go index 6963a89122..a0ce684417 100644 --- a/signer/core/stdioui.go +++ b/signer/core/stdioui.go @@ -25,7 +25,7 @@ import ( ) type StdIOUI struct { - client rpc.Client + client *rpc.Client } func NewStdIOUI() *StdIOUI { @@ -33,7 +33,7 @@ func NewStdIOUI() *StdIOUI { if err != nil { log.Crit("Could not create stdio client", "err", err) } - ui := &StdIOUI{client: *client} + ui := &StdIOUI{client: client} return ui } From 79a57d49cb670c56dbc279d022bf4845b960566e Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 5 May 2023 13:55:32 +0800 Subject: [PATCH 093/988] eth/downloader: fix error aggregator (#27217) --- eth/downloader/downloader.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index e56321e58f..9a805396c4 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -663,8 +663,11 @@ func (d *Downloader) spawnSync(fetchers []func() error) error { // it has processed the queue. d.queue.Close() } - if err = <-errc; err != nil && err != errCanceled { - break + if got := <-errc; got != nil { + err = got + if got != errCanceled { + break // receive a meaningful error, bubble it up + } } } d.queue.Close() From ba09403113b0c0549da116d58d99c8669aed7356 Mon Sep 17 00:00:00 2001 From: ucwong Date: Fri, 5 May 2023 03:33:01 -0600 Subject: [PATCH 094/988] core/txpool : fix map size avoid resizing (#27221) --- core/txpool/txpool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 4928b5afc6..056b1ebe87 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -549,7 +549,7 @@ func (pool *TxPool) Pending(enforceTips bool) map[common.Address]types.Transacti pool.mu.Lock() defer pool.mu.Unlock() - pending := make(map[common.Address]types.Transactions) + pending := make(map[common.Address]types.Transactions, len(pool.pending)) for addr, list := range pool.pending { txs := list.Flatten() From 604e215d1bb070dff98fb76aa965064c74e3633f Mon Sep 17 00:00:00 2001 From: sjlee1125 <47561537+sjlee1125@users.noreply.github.com> Date: Fri, 5 May 2023 21:59:13 +0900 Subject: [PATCH 095/988] eth/tracers: add `txHash` field on txTraceResult (#27183) This PR modifies the interface for the results of `debug_traceBlock` and `debug_traceCall` by adding the `txHash`, allowing users to identify which transaction's trace result corresponds to. --------- Co-authored-by: Martin Holst Swende --- eth/tracers/api.go | 11 ++++++----- eth/tracers/api_test.go | 23 +++++++++++++---------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 34f4199a83..5e90180df8 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -176,6 +176,7 @@ type StdTraceConfig struct { // txTraceResult is the result of a single transaction trace. type txTraceResult struct { + TxHash common.Hash `json:"txHash"` // transaction hash Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer Error string `json:"error,omitempty"` // Trace failure produced by the tracer } @@ -278,13 +279,13 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed } res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) if err != nil { - task.results[i] = &txTraceResult{Error: err.Error()} + task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()} log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) break } // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number())) - task.results[i] = &txTraceResult{Result: res} + task.results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res} } // Tracing state is used up, queue it for de-referencing. Note the // state is the parent state of trace block, use block.number-1 as @@ -615,7 +616,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac if err != nil { return nil, err } - results[i] = &txTraceResult{Result: res} + results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res} // Finalize the state so any modifications are written to the trie // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect statedb.Finalise(is158) @@ -656,10 +657,10 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat } res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) if err != nil { - results[task.index] = &txTraceResult{Error: err.Error()} + results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()} continue } - results[task.index] = &txTraceResult{Result: res} + results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Result: res} } }() } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 8f4f88b003..fdb02b1895 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -384,12 +384,14 @@ func TestTraceBlock(t *testing.T) { } genBlocks := 10 signer := types.HomesteadSigner{} + var txHash common.Hash backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { // Transfer from account[0] to account[1] // value: 1000 wei // fee: 0 wei tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) b.AddTx(tx) + txHash = tx.Hash() }) defer backend.chain.Stop() api := NewAPI(backend) @@ -408,7 +410,7 @@ func TestTraceBlock(t *testing.T) { // Trace head block { blockNumber: rpc.BlockNumber(genBlocks), - want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, + want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash), }, // Trace non-existent block { @@ -418,12 +420,12 @@ func TestTraceBlock(t *testing.T) { // Trace latest block { blockNumber: rpc.LatestBlockNumber, - want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, + want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash), }, // Trace pending block { blockNumber: rpc.PendingBlockNumber, - want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, + want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash), }, } for i, tc := range testSuite { @@ -853,7 +855,7 @@ func TestTraceChain(t *testing.T) { backend.relHook = func() { rel.Add(1) } api := NewAPI(backend) - single := `{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}` + single := `{"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}` var cases = []struct { start uint64 end uint64 @@ -872,16 +874,17 @@ func TestTraceChain(t *testing.T) { next := c.start + 1 for result := range resCh { - if next != uint64(result.Block) { - t.Error("Unexpected tracing block") + if have, want := uint64(result.Block), next; have != want { + t.Fatalf("unexpected tracing block, have %d want %d", have, want) } - if len(result.Traces) != int(next) { - t.Error("Unexpected tracing result") + if have, want := len(result.Traces), int(next); have != want { + t.Fatalf("unexpected result length, have %d want %d", have, want) } for _, trace := range result.Traces { + trace.TxHash = common.Hash{} blob, _ := json.Marshal(trace) - if string(blob) != single { - t.Error("Unexpected tracing result") + if have, want := string(blob), single; have != want { + t.Fatalf("unexpected tracing result, have\n%v\nwant:\n%v", have, want) } } next += 1 From cc8d40c65ffc3336a4c20d041b2c26142dafd315 Mon Sep 17 00:00:00 2001 From: ucwong Date: Mon, 8 May 2023 00:59:14 -0600 Subject: [PATCH 096/988] core/state: initialize maps with known size (#27222) * core/state : fix map size avoid resizing * core/state : fixed size --- core/state/statedb.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index b89f4bfd8c..a4e22baafc 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -783,13 +783,13 @@ func (s *StateDB) Copy() *StateDB { state.snap = s.snap // deep copy needed - state.snapAccounts = make(map[common.Hash][]byte) + state.snapAccounts = make(map[common.Hash][]byte, len(s.snapAccounts)) for k, v := range s.snapAccounts { state.snapAccounts[k] = v } - state.snapStorage = make(map[common.Hash]map[common.Hash][]byte) + state.snapStorage = make(map[common.Hash]map[common.Hash][]byte, len(s.snapStorage)) for k, v := range s.snapStorage { - temp := make(map[common.Hash][]byte) + temp := make(map[common.Hash][]byte, len(v)) for kk, vv := range v { temp[kk] = vv } @@ -1160,7 +1160,7 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre // convertAccountSet converts a provided account set from address keyed to hash keyed. func (s *StateDB) convertAccountSet(set map[common.Address]struct{}) map[common.Hash]struct{} { - ret := make(map[common.Hash]struct{}) + ret := make(map[common.Hash]struct{}, len(set)) for addr := range set { obj, exist := s.stateObjects[addr] if !exist { From 7ac08ba4e0bf3dc28a8e2fff16482e4dc18d60dc Mon Sep 17 00:00:00 2001 From: joohhnnn <68833933+joohhnnn@users.noreply.github.com> Date: Mon, 8 May 2023 15:01:14 +0800 Subject: [PATCH 097/988] cmd/geth: rename variable 'extapi' (#27223) rename parameter In this case, the naming of "extapi" might create some confusion. Although it represents an External Signer Backend, its name could be mistaken for an API. In reality, it is a backend instance used for communicating with external signers. A better naming choice could be "extBackend" or "externalBackend" to more accurately describe that it is a backend instance rather than an API. --- cmd/geth/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 816762a683..42ded49322 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -288,8 +288,8 @@ func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir s // Assemble the supported backends if len(conf.ExternalSigner) > 0 { log.Info("Using external signer", "url", conf.ExternalSigner) - if extapi, err := external.NewExternalBackend(conf.ExternalSigner); err == nil { - am.AddBackend(extapi) + if extBackend, err := external.NewExternalBackend(conf.ExternalSigner); err == nil { + am.AddBackend(extBackend) return nil } else { return fmt.Errorf("error connecting to external signer: %v", err) From 81d328a73e00454912edf79e74f7d041467fa2aa Mon Sep 17 00:00:00 2001 From: ucwong Date: Mon, 8 May 2023 03:38:50 -0600 Subject: [PATCH 098/988] log: report error when ctx key is non-string (#27226) * log/format.go : invalid string cast fix * log: some polish --------- Co-authored-by: Martin Holst Swende --- log/format.go | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/log/format.go b/log/format.go index b10786efa0..fb476b73e3 100644 --- a/log/format.go +++ b/log/format.go @@ -169,7 +169,7 @@ func logfmt(buf *bytes.Buffer, ctx []interface{}, color int, term bool) { k, ok := ctx[i].(string) v := formatLogfmtValue(ctx[i+1], term) if !ok { - k, v = errorKey, formatLogfmtValue(k, term) + k, v = errorKey, fmt.Sprintf("%+T is not a string key", ctx[i]) } else { k = escapeString(k) } @@ -218,20 +218,20 @@ func JSONFormatOrderedEx(pretty, lineSeparated bool) Format { } } return FormatFunc(func(r *Record) []byte { - props := make(map[string]interface{}) - - props[r.KeyNames.Time] = r.Time - props[r.KeyNames.Lvl] = r.Lvl.String() - props[r.KeyNames.Msg] = r.Msg + props := map[string]interface{}{ + r.KeyNames.Time: r.Time, + r.KeyNames.Lvl: r.Lvl.String(), + r.KeyNames.Msg: r.Msg, + } ctx := make([]string, len(r.Ctx)) for i := 0; i < len(r.Ctx); i += 2 { - k, ok := r.Ctx[i].(string) - if !ok { - props[errorKey] = fmt.Sprintf("%+v is not a string key,", r.Ctx[i]) + if k, ok := r.Ctx[i].(string); ok { + ctx[i] = k + ctx[i+1] = formatLogfmtValue(r.Ctx[i+1], true) + } else { + props[errorKey] = fmt.Sprintf("%+T is not a string key,", r.Ctx[i]) } - ctx[i] = k - ctx[i+1] = formatLogfmtValue(r.Ctx[i+1], true) } props[r.KeyNames.Ctx] = ctx @@ -261,18 +261,19 @@ func JSONFormatEx(pretty, lineSeparated bool) Format { } return FormatFunc(func(r *Record) []byte { - props := make(map[string]interface{}) - - props[r.KeyNames.Time] = r.Time - props[r.KeyNames.Lvl] = r.Lvl.String() - props[r.KeyNames.Msg] = r.Msg + props := map[string]interface{}{ + r.KeyNames.Time: r.Time, + r.KeyNames.Lvl: r.Lvl.String(), + r.KeyNames.Msg: r.Msg, + } for i := 0; i < len(r.Ctx); i += 2 { k, ok := r.Ctx[i].(string) if !ok { - props[errorKey] = fmt.Sprintf("%+v is not a string key", r.Ctx[i]) + props[errorKey] = fmt.Sprintf("%+T is not a string key", r.Ctx[i]) + } else { + props[k] = formatJSONValue(r.Ctx[i+1]) } - props[k] = formatJSONValue(r.Ctx[i+1]) } b, err := jsonMarshal(props) From 5021d36d358ff695075b2821063d36435944bb73 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 9 May 2023 15:11:04 +0800 Subject: [PATCH 099/988] all: port boring changes from pbss (#27176) * all: port boring changes from pbss * core, trie: address comments from martin * trie: minor fixes * core/rawdb: update comment * core, eth, tests, trie: address comments * tests, trie: add extra check when update trie database * trie/triedb/hashdb: degrade the error to warning --- core/blockchain.go | 4 +- core/blockchain_test.go | 2 +- core/rawdb/schema.go | 48 +++- core/state/database.go | 3 +- core/state/iterator_test.go | 12 +- core/state/snapshot/generate.go | 3 +- core/state/snapshot/generate_test.go | 7 +- core/state/state_object.go | 4 +- core/state/statedb.go | 7 +- core/state/sync_test.go | 3 +- eth/protocols/snap/sync_test.go | 19 +- light/postprocess.go | 9 +- light/trie.go | 5 +- tests/fuzzers/stacktrie/trie_fuzzer.go | 4 +- tests/fuzzers/trie/trie-fuzzer.go | 16 +- trie/committer.go | 18 +- trie/database_test.go | 20 +- trie/database_wrap.go | 267 +++++++++++++++++++++++ trie/iterator_test.go | 237 +++++++++++++------- trie/nodeset.go | 149 ------------- trie/secure_trie.go | 3 +- trie/secure_trie_test.go | 4 +- trie/sync_test.go | 289 +++++++++++++++++++------ trie/tracer.go | 4 +- trie/tracer_test.go | 25 ++- trie/trie.go | 7 +- trie/trie_reader.go | 6 +- trie/trie_test.go | 95 ++++---- trie/{ => triedb/hashdb}/database.go | 195 +++++------------ trie/trienode/node.go | 132 ++++++++++- 30 files changed, 1049 insertions(+), 548 deletions(-) create mode 100644 trie/database_wrap.go delete mode 100644 trie/nodeset.go rename trie/{ => triedb/hashdb}/database.go (81%) diff --git a/core/blockchain.go b/core/blockchain.go index de64ab7c39..659b2f02ea 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -982,8 +982,8 @@ func (bc *BlockChain) Stop() { } } // Flush the collected preimages to disk - if err := bc.stateCache.TrieDB().CommitPreimages(); err != nil { - log.Error("Failed to commit trie preimages", "err", err) + if err := bc.stateCache.TrieDB().Close(); err != nil { + log.Error("Failed to close trie db", "err", err) } // Ensure all live cached entries be saved into disk, so that we can skip // cache warmup when node restarts. diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 92a65ab9eb..5ec685c99f 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1701,7 +1701,7 @@ func TestTrieForkGC(t *testing.T) { chain.stateCache.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) chain.stateCache.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) } - if len(chain.stateCache.TrieDB().Nodes()) > 0 { + if nodes, _ := chain.TrieDB().Size(); nodes > 0 { t.Fatalf("stale tries still alive after garbase collection") } } diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index fd5ab1ad4c..18722ed5d4 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -22,6 +22,7 @@ import ( "encoding/binary" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/metrics" ) @@ -100,7 +101,7 @@ var ( CodePrefix = []byte("c") // CodePrefix + code hash -> account code skeletonHeaderPrefix = []byte("S") // skeletonHeaderPrefix + num (uint64 big endian) -> header - // Path-based trie node scheme. + // Path-based storage scheme of merkle patricia trie. trieNodeAccountPrefix = []byte("A") // trieNodeAccountPrefix + hexPath -> trie node trieNodeStoragePrefix = []byte("O") // trieNodeStoragePrefix + accountHash + hexPath -> trie node @@ -248,3 +249,48 @@ func accountTrieNodeKey(path []byte) []byte { func storageTrieNodeKey(accountHash common.Hash, path []byte) []byte { return append(append(trieNodeStoragePrefix, accountHash.Bytes()...), path...) } + +// IsLegacyTrieNode reports whether a provided database entry is a legacy trie +// node. The characteristics of legacy trie node are: +// - the key length is 32 bytes +// - the key is the hash of val +func IsLegacyTrieNode(key []byte, val []byte) bool { + if len(key) != common.HashLength { + return false + } + return bytes.Equal(key, crypto.Keccak256(val)) +} + +// IsAccountTrieNode reports whether a provided database entry is an account +// trie node in path-based state scheme. +func IsAccountTrieNode(key []byte) (bool, []byte) { + if !bytes.HasPrefix(key, trieNodeAccountPrefix) { + return false, nil + } + // The remaining key should only consist a hex node path + // whose length is in the range 0 to 64 (64 is excluded + // since leaves are always wrapped with shortNode). + if len(key) >= len(trieNodeAccountPrefix)+common.HashLength*2 { + return false, nil + } + return true, key[len(trieNodeAccountPrefix):] +} + +// IsStorageTrieNode reports whether a provided database entry is a storage +// trie node in path-based state scheme. +func IsStorageTrieNode(key []byte) (bool, common.Hash, []byte) { + if !bytes.HasPrefix(key, trieNodeStoragePrefix) { + return false, common.Hash{}, nil + } + // The remaining key consists of 2 parts: + // - 32 bytes account hash + // - hex node path whose length is in the range 0 to 64 + if len(key) < len(trieNodeStoragePrefix)+common.HashLength { + return false, common.Hash{}, nil + } + if len(key) >= len(trieNodeStoragePrefix)+common.HashLength+common.HashLength*2 { + return false, common.Hash{}, nil + } + accountHash := common.BytesToHash(key[len(trieNodeStoragePrefix) : len(trieNodeStoragePrefix)+common.HashLength]) + return true, accountHash, key[len(trieNodeStoragePrefix)+common.HashLength:] +} diff --git a/core/state/database.go b/core/state/database.go index 82f620b460..ace462165c 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" ) const ( @@ -109,7 +110,7 @@ type Trie interface { // The returned nodeset can be nil if the trie is clean(nothing to commit). // Once the trie is committed, it's not usable anymore. A new trie must // be created with new root and updated trie database for following usage - Commit(collectLeaf bool) (common.Hash, *trie.NodeSet) + Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) // NodeIterator returns an iterator that returns nodes of the trie. Iteration // starts at the key after the given start key. diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go index ab06cb422f..24b192c26c 100644 --- a/core/state/iterator_test.go +++ b/core/state/iterator_test.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/crypto" ) // Tests that the node iterator indeed walks over the entire database contents. @@ -85,9 +86,18 @@ func TestNodeIteratorCoverage(t *testing.T) { // database entry belongs to a trie node or not. func isTrieNode(scheme string, key, val []byte) (bool, common.Hash) { if scheme == rawdb.HashScheme { - if len(key) == common.HashLength { + if rawdb.IsLegacyTrieNode(key, val) { return true, common.BytesToHash(key) } + } else { + ok, _ := rawdb.IsAccountTrieNode(key) + if ok { + return true, crypto.Keccak256Hash(val) + } + ok, _, _ = rawdb.IsStorageTrieNode(key) + if ok { + return true, crypto.Keccak256Hash(val) + } } return false, common.Hash{} } diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 68c2f574b8..4703b45df3 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" ) var ( @@ -363,7 +364,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi } root, nodes := snapTrie.Commit(false) if nodes != nil { - tdb.Update(trie.NewWithNodeSet(nodes)) + tdb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) tdb.Commit(root, false) } resolver = func(owner common.Hash, path []byte, hash common.Hash) []byte { diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 546132e7dd..265515a9cf 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" "golang.org/x/crypto/sha3" ) @@ -144,7 +145,7 @@ type testHelper struct { diskdb ethdb.Database triedb *trie.Database accTrie *trie.StateTrie - nodes *trie.MergedNodeSet + nodes *trienode.MergedNodeSet } func newHelper() *testHelper { @@ -155,7 +156,7 @@ func newHelper() *testHelper { diskdb: diskdb, triedb: triedb, accTrie: accTrie, - nodes: trie.NewMergedNodeSet(), + nodes: trienode.NewMergedNodeSet(), } } @@ -203,7 +204,7 @@ func (t *testHelper) Commit() common.Hash { if nodes != nil { t.nodes.Merge(nodes) } - t.triedb.Update(t.nodes) + t.triedb.Update(root, types.EmptyRootHash, t.nodes) t.triedb.Commit(root, false) return root } diff --git a/core/state/state_object.go b/core/state/state_object.go index 95fe6f52fa..1e28b4c12e 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -28,7 +28,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" ) type Code []byte @@ -350,7 +350,7 @@ func (s *stateObject) updateRoot(db Database) { // commitTrie submits the storage changes into the storage trie and re-computes // the root. Besides, all trie changes will be collected in a nodeset and returned. -func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) { +func (s *stateObject) commitTrie(db Database) (*trienode.NodeSet, error) { tr, err := s.updateTrie(db) if err != nil { return nil, err diff --git a/core/state/statedb.go b/core/state/statedb.go index a4e22baafc..9dc3b9839f 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" ) type revision struct { @@ -971,7 +972,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { accountTrieNodesDeleted int storageTrieNodesUpdated int storageTrieNodesDeleted int - nodes = trie.NewMergedNodeSet() + nodes = trienode.NewMergedNodeSet() codeWriter = s.db.DiskDB().NewBatch() ) for addr := range s.stateObjectsDirty { @@ -986,7 +987,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if err != nil { return common.Hash{}, err } - // Merge the dirty nodes of storage trie into global set + // Merge the dirty nodes of storage trie into global set. if set != nil { if err := nodes.Merge(set); err != nil { return common.Hash{}, err @@ -1071,7 +1072,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { } if root != origin { start := time.Now() - if err := s.db.TrieDB().Update(nodes); err != nil { + if err := s.db.TrieDB().Update(root, origin, nodes); err != nil { return common.Hash{}, err } s.originalRoot = root diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 090d55e473..87621f49c1 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -602,7 +602,8 @@ func TestIncompleteStateSync(t *testing.T) { if len(nodeQueue) > 0 { results := make([]trie.NodeSyncResult, 0, len(nodeQueue)) for path, element := range nodeQueue { - data, err := srcDb.TrieDB().Node(element.hash) + owner, inner := trie.ResolvePath([]byte(element.path)) + data, err := srcDb.TrieDB().Reader(srcRoot).Node(owner, inner, element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", element.hash) } diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 6a3b482d5d..ee2ef95810 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -36,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" "golang.org/x/crypto/sha3" ) @@ -1389,7 +1390,7 @@ func makeAccountTrieNoStorage(n int) (string, *trie.Trie, entrySlice) { // Commit the state changes into db and re-create the trie // for accessing later. root, nodes := accTrie.Commit(false) - db.Update(trie.NewWithNodeSet(nodes)) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) accTrie, _ = trie.New(trie.StateTrieID(root), db) return db.Scheme(), accTrie, entries @@ -1451,7 +1452,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { // Commit the state changes into db and re-create the trie // for accessing later. root, nodes := accTrie.Commit(false) - db.Update(trie.NewWithNodeSet(nodes)) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) accTrie, _ = trie.New(trie.StateTrieID(root), db) return db.Scheme(), accTrie, entries @@ -1467,7 +1468,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) storageRoots = make(map[common.Hash]common.Hash) storageTries = make(map[common.Hash]*trie.Trie) storageEntries = make(map[common.Hash]entrySlice) - nodes = trie.NewMergedNodeSet() + nodes = trienode.NewMergedNodeSet() ) // Create n accounts in the trie for i := uint64(1); i <= uint64(accounts); i++ { @@ -1500,7 +1501,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) nodes.Merge(set) // Commit gathered dirty nodes into database - db.Update(nodes) + db.Update(root, types.EmptyRootHash, nodes) // Re-create tries with new root accTrie, _ = trie.New(trie.StateTrieID(root), db) @@ -1522,7 +1523,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin storageRoots = make(map[common.Hash]common.Hash) storageTries = make(map[common.Hash]*trie.Trie) storageEntries = make(map[common.Hash]entrySlice) - nodes = trie.NewMergedNodeSet() + nodes = trienode.NewMergedNodeSet() ) // Create n accounts in the trie for i := uint64(1); i <= uint64(accounts); i++ { @@ -1534,7 +1535,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin // Make a storage trie var ( stRoot common.Hash - stNodes *trie.NodeSet + stNodes *trienode.NodeSet stEntries entrySlice ) if boundary { @@ -1565,7 +1566,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin nodes.Merge(set) // Commit gathered dirty nodes into database - db.Update(nodes) + db.Update(root, types.EmptyRootHash, nodes) // Re-create tries with new root accTrie, err := trie.New(trie.StateTrieID(root), db) @@ -1587,7 +1588,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin // makeStorageTrieWithSeed fills a storage trie with n items, returning the // not-yet-committed trie and the sorted entries. The seeds can be used to ensure // that tries are unique. -func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (common.Hash, *trie.NodeSet, entrySlice) { +func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (common.Hash, *trienode.NodeSet, entrySlice) { trie, _ := trie.New(trie.StorageTrieID(common.Hash{}, owner, common.Hash{}), db) var entries entrySlice for i := uint64(1); i <= n; i++ { @@ -1610,7 +1611,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas // makeBoundaryStorageTrie constructs a storage trie. Instead of filling // storage slots normally, this function will fill a few slots which have // boundary hash. -func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (common.Hash, *trie.NodeSet, entrySlice) { +func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (common.Hash, *trienode.NodeSet, entrySlice) { var ( entries entrySlice boundaries []common.Hash diff --git a/light/postprocess.go b/light/postprocess.go index 763ba27529..38f4995268 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" ) // IndexerConfig includes a set of configs for chain indexers. @@ -134,6 +135,7 @@ type ChtIndexerBackend struct { section, sectionSize uint64 lastHash common.Hash trie *trie.Trie + originRoot common.Hash } // NewChtIndexer creates a Cht chain indexer @@ -191,6 +193,7 @@ func (c *ChtIndexerBackend) Reset(ctx context.Context, section uint64, lastSecti } } c.section = section + c.originRoot = root return err } @@ -214,7 +217,7 @@ func (c *ChtIndexerBackend) Commit() error { root, nodes := c.trie.Commit(false) // Commit trie changes into trie database in case it's not nil. if nodes != nil { - if err := c.triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { + if err := c.triedb.Update(root, c.originRoot, trienode.NewWithNodeSet(nodes)); err != nil { return err } if err := c.triedb.Commit(root, false); err != nil { @@ -332,6 +335,7 @@ type BloomTrieIndexerBackend struct { size uint64 bloomTrieRatio uint64 trie *trie.Trie + originRoot common.Hash sectionHeads []common.Hash } @@ -413,6 +417,7 @@ func (b *BloomTrieIndexerBackend) Reset(ctx context.Context, section uint64, las } } b.section = section + b.originRoot = root return err } @@ -463,7 +468,7 @@ func (b *BloomTrieIndexerBackend) Commit() error { root, nodes := b.trie.Commit(false) // Commit trie changes into trie database in case it's not nil. if nodes != nil { - if err := b.triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { + if err := b.triedb.Update(root, b.originRoot, trienode.NewWithNodeSet(nodes)); err != nil { return err } if err := b.triedb.Commit(root, false); err != nil { diff --git a/light/trie.go b/light/trie.go index 38dd6b5c27..6d802a5fbf 100644 --- a/light/trie.go +++ b/light/trie.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" ) var ( @@ -156,7 +157,7 @@ func (t *odrTrie) DeleteStorage(_ common.Address, key []byte) error { }) } -// TryDeleteAccount abstracts an account deletion from the trie. +// DeleteAccount abstracts an account deletion from the trie. func (t *odrTrie) DeleteAccount(address common.Address) error { key := crypto.Keccak256(address.Bytes()) return t.do(key, func() error { @@ -164,7 +165,7 @@ func (t *odrTrie) DeleteAccount(address common.Address) error { }) } -func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trie.NodeSet) { +func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { if t.trie == nil { return t.id.Root, nil } diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index 809dba8ce5..0099e9e169 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -27,9 +27,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" "golang.org/x/crypto/sha3" ) @@ -184,7 +186,7 @@ func (f *fuzzer) fuzz() int { // Flush trie -> database rootA, nodes := trieA.Commit(false) if nodes != nil { - dbA.Update(trie.NewWithNodeSet(nodes)) + dbA.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) } // Flush memdb -> disk (sponge) dbA.Commit(rootA, false) diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index c0cbceff31..41baf67ec6 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -22,7 +22,9 @@ import ( "fmt" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" ) // randTest performs random trie operations. @@ -139,11 +141,12 @@ func Fuzz(input []byte) int { } func runRandTest(rt randTest) error { - triedb := trie.NewDatabase(rawdb.NewMemoryDatabase()) - - tr := trie.NewEmpty(triedb) - values := make(map[string]string) // tracks content of the trie - + var ( + triedb = trie.NewDatabase(rawdb.NewMemoryDatabase()) + tr = trie.NewEmpty(triedb) + origin = types.EmptyRootHash + values = make(map[string]string) // tracks content of the trie + ) for i, step := range rt { switch step.op { case opUpdate: @@ -163,7 +166,7 @@ func runRandTest(rt randTest) error { case opCommit: hash, nodes := tr.Commit(false) if nodes != nil { - if err := triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { + if err := triedb.Update(hash, origin, trienode.NewWithNodeSet(nodes)); err != nil { return err } } @@ -172,6 +175,7 @@ func runRandTest(rt randTest) error { return err } tr = newtr + origin = hash case opItercheckhash: checktr := trie.NewEmpty(triedb) it := trie.NewIterator(tr.NodeIterator(nil)) diff --git a/trie/committer.go b/trie/committer.go index 805d4a3143..e825287fd2 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -23,23 +23,17 @@ import ( "github.com/ethereum/go-ethereum/trie/trienode" ) -// leaf represents a trie leaf node -type leaf struct { - blob []byte // raw blob of leaf - parent common.Hash // the hash of parent node -} - // committer is the tool used for the trie Commit operation. The committer will // capture all dirty nodes during the commit process and keep them cached in // insertion order. type committer struct { - nodes *NodeSet + nodes *trienode.NodeSet tracer *tracer collectLeaf bool } // newCommitter creates a new committer or picks one from the pool. -func newCommitter(nodeset *NodeSet, tracer *tracer, collectLeaf bool) *committer { +func newCommitter(nodeset *trienode.NodeSet, tracer *tracer, collectLeaf bool) *committer { return &committer{ nodes: nodeset, tracer: tracer, @@ -139,7 +133,7 @@ func (c *committer) store(path []byte, n node) node { // deleted only if the node was existent in database before. prev, ok := c.tracer.accessList[string(path)] if ok { - c.nodes.addNode(path, trienode.NewWithPrev(common.Hash{}, nil, prev)) + c.nodes.AddNode(path, trienode.NewWithPrev(common.Hash{}, nil, prev)) } return n } @@ -152,7 +146,7 @@ func (c *committer) store(path []byte, n node) node { c.tracer.accessList[string(path)], ) ) - c.nodes.addNode(path, node) + c.nodes.AddNode(path, node) // Collect the corresponding leaf node if it's required. We don't check // full node since it's impossible to store value in fullNode. The key @@ -160,7 +154,7 @@ func (c *committer) store(path []byte, n node) node { if c.collectLeaf { if sn, ok := n.(*shortNode); ok { if val, ok := sn.Val.(valueNode); ok { - c.nodes.addLeaf(&leaf{blob: val, parent: nhash}) + c.nodes.AddLeaf(nhash, val) } } } @@ -172,7 +166,7 @@ type mptResolver struct{} // ForEach implements childResolver, decodes the provided node and // traverses the children inside. -func (resolver mptResolver) forEach(node []byte, onChild func(common.Hash)) { +func (resolver mptResolver) ForEach(node []byte, onChild func(common.Hash)) { forGatherChildren(mustDecodeNodeUnsafe(nil, node), onChild) } diff --git a/trie/database_test.go b/trie/database_test.go index 54d7529476..cad462f737 100644 --- a/trie/database_test.go +++ b/trie/database_test.go @@ -17,17 +17,19 @@ package trie import ( - "testing" - - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/trie/triedb/hashdb" ) -// Tests that the trie database returns a missing trie node error if attempting -// to retrieve the meta root. -func TestDatabaseMetarootFetch(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - if _, err := db.Node(common.Hash{}); err == nil { - t.Fatalf("metaroot retrieval succeeded") +// newTestDatabase initializes the trie database with specified scheme. +func newTestDatabase(diskdb ethdb.Database, scheme string) *Database { + db := prepare(diskdb, nil) + if scheme == rawdb.HashScheme { + db.backend = hashdb.New(diskdb, db.cleans, mptResolver{}) } + //} else { + // db.backend = snap.New(diskdb, db.cleans, nil) + //} + return db } diff --git a/trie/database_wrap.go b/trie/database_wrap.go new file mode 100644 index 0000000000..b05f56847a --- /dev/null +++ b/trie/database_wrap.go @@ -0,0 +1,267 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package trie + +import ( + "errors" + "runtime" + "time" + + "github.com/VictoriaMetrics/fastcache" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/trie/triedb/hashdb" + "github.com/ethereum/go-ethereum/trie/trienode" +) + +// Config defines all necessary options for database. +type Config struct { + Cache int // Memory allowance (MB) to use for caching trie nodes in memory + Journal string // Journal of clean cache to survive node restarts + Preimages bool // Flag whether the preimage of trie key is recorded +} + +// backend defines the methods needed to access/update trie nodes in different +// state scheme. +type backend interface { + // Scheme returns the identifier of used storage scheme. + Scheme() string + + // Initialized returns an indicator if the state data is already initialized + // according to the state scheme. + Initialized(genesisRoot common.Hash) bool + + // Size returns the current storage size of the memory cache in front of the + // persistent database layer. + Size() common.StorageSize + + // Update performs a state transition by committing dirty nodes contained + // in the given set in order to update state from the specified parent to + // the specified root. + Update(root common.Hash, parent common.Hash, nodes *trienode.MergedNodeSet) error + + // Commit writes all relevant trie nodes belonging to the specified state + // to disk. Report specifies whether logs will be displayed in info level. + Commit(root common.Hash, report bool) error + + // Close closes the trie database backend and releases all held resources. + Close() error +} + +// Database is the wrapper of the underlying backend which is shared by different +// types of node backend as an entrypoint. It's responsible for all interactions +// relevant with trie nodes and node preimages. +type Database struct { + config *Config // Configuration for trie database + diskdb ethdb.Database // Persistent database to store the snapshot + cleans *fastcache.Cache // Megabytes permitted using for read caches + preimages *preimageStore // The store for caching preimages + backend backend // The backend for managing trie nodes +} + +// prepare initializes the database with provided configs, but the +// database backend is still left as nil. +func prepare(diskdb ethdb.Database, config *Config) *Database { + var cleans *fastcache.Cache + if config != nil && config.Cache > 0 { + if config.Journal == "" { + cleans = fastcache.New(config.Cache * 1024 * 1024) + } else { + cleans = fastcache.LoadFromFileOrNew(config.Journal, config.Cache*1024*1024) + } + } + var preimages *preimageStore + if config != nil && config.Preimages { + preimages = newPreimageStore(diskdb) + } + return &Database{ + config: config, + diskdb: diskdb, + cleans: cleans, + preimages: preimages, + } +} + +// NewDatabase initializes the trie database with default settings, namely +// the legacy hash-based scheme is used by default. +func NewDatabase(diskdb ethdb.Database) *Database { + return NewDatabaseWithConfig(diskdb, nil) +} + +// NewDatabaseWithConfig initializes the trie database with provided configs. +// The path-based scheme is not activated yet, always initialized with legacy +// hash-based scheme by default. +func NewDatabaseWithConfig(diskdb ethdb.Database, config *Config) *Database { + db := prepare(diskdb, config) + db.backend = hashdb.New(diskdb, db.cleans, mptResolver{}) + return db +} + +// Reader returns a reader for accessing all trie nodes with provided state root. +// Nil is returned in case the state is not available. +func (db *Database) Reader(blockRoot common.Hash) Reader { + return db.backend.(*hashdb.Database).Reader(blockRoot) +} + +// Update performs a state transition by committing dirty nodes contained in the +// given set in order to update state from the specified parent to the specified +// root. The held pre-images accumulated up to this point will be flushed in case +// the size exceeds the threshold. +func (db *Database) Update(root common.Hash, parent common.Hash, nodes *trienode.MergedNodeSet) error { + if db.preimages != nil { + db.preimages.commit(false) + } + return db.backend.Update(root, parent, nodes) +} + +// Commit iterates over all the children of a particular node, writes them out +// to disk. As a side effect, all pre-images accumulated up to this point are +// also written. +func (db *Database) Commit(root common.Hash, report bool) error { + if db.preimages != nil { + db.preimages.commit(true) + } + return db.backend.Commit(root, report) +} + +// Size returns the storage size of dirty trie nodes in front of the persistent +// database and the size of cached preimages. +func (db *Database) Size() (common.StorageSize, common.StorageSize) { + var ( + storages common.StorageSize + preimages common.StorageSize + ) + storages = db.backend.Size() + if db.preimages != nil { + preimages = db.preimages.size() + } + return storages, preimages +} + +// Initialized returns an indicator if the state data is already initialized +// according to the state scheme. +func (db *Database) Initialized(genesisRoot common.Hash) bool { + return db.backend.Initialized(genesisRoot) +} + +// Scheme returns the node scheme used in the database. +func (db *Database) Scheme() string { + return db.backend.Scheme() +} + +// Close flushes the dangling preimages to disk and closes the trie database. +// It is meant to be called when closing the blockchain object, so that all +// resources held can be released correctly. +func (db *Database) Close() error { + if db.preimages != nil { + db.preimages.commit(true) + } + return db.backend.Close() +} + +// saveCache saves clean state cache to given directory path +// using specified CPU cores. +func (db *Database) saveCache(dir string, threads int) error { + if db.cleans == nil { + return nil + } + log.Info("Writing clean trie cache to disk", "path", dir, "threads", threads) + + start := time.Now() + err := db.cleans.SaveToFileConcurrent(dir, threads) + if err != nil { + log.Error("Failed to persist clean trie cache", "error", err) + return err + } + log.Info("Persisted the clean trie cache", "path", dir, "elapsed", common.PrettyDuration(time.Since(start))) + return nil +} + +// SaveCache atomically saves fast cache data to the given dir using all +// available CPU cores. +func (db *Database) SaveCache(dir string) error { + return db.saveCache(dir, runtime.GOMAXPROCS(0)) +} + +// SaveCachePeriodically atomically saves fast cache data to the given dir with +// the specified interval. All dump operation will only use a single CPU core. +func (db *Database) SaveCachePeriodically(dir string, interval time.Duration, stopCh <-chan struct{}) { + ticker := time.NewTicker(interval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + db.saveCache(dir, 1) + case <-stopCh: + return + } + } +} + +// Cap iteratively flushes old but still referenced trie nodes until the total +// memory usage goes below the given threshold. The held pre-images accumulated +// up to this point will be flushed in case the size exceeds the threshold. +// +// It's only supported by hash-based database and will return an error for others. +func (db *Database) Cap(limit common.StorageSize) error { + hdb, ok := db.backend.(*hashdb.Database) + if !ok { + return errors.New("not supported") + } + if db.preimages != nil { + db.preimages.commit(false) + } + return hdb.Cap(limit) +} + +// Reference adds a new reference from a parent node to a child node. This function +// is used to add reference between internal trie node and external node(e.g. storage +// trie root), all internal trie nodes are referenced together by database itself. +// +// It's only supported by hash-based database and will return an error for others. +func (db *Database) Reference(root common.Hash, parent common.Hash) error { + hdb, ok := db.backend.(*hashdb.Database) + if !ok { + return errors.New("not supported") + } + hdb.Reference(root, parent) + return nil +} + +// Dereference removes an existing reference from a root node. It's only +// supported by hash-based database and will return an error for others. +func (db *Database) Dereference(root common.Hash) error { + hdb, ok := db.backend.(*hashdb.Database) + if !ok { + return errors.New("not supported") + } + hdb.Dereference(root) + return nil +} + +// Node retrieves the rlp-encoded node blob with provided node hash. It's +// only supported by hash-based database and will return an error for others. +// Note, this function should be deprecated once ETH66 is deprecated. +func (db *Database) Node(hash common.Hash) ([]byte, error) { + hdb, ok := db.backend.(*hashdb.Database) + if !ok { + return nil, errors.New("not supported") + } + return hdb.Node(hash) +} diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 6dc38db6f1..fca8c823b9 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -25,9 +25,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb/memorydb" + "github.com/ethereum/go-ethereum/trie/trienode" ) func TestEmptyIterator(t *testing.T) { @@ -61,7 +63,7 @@ func TestIterator(t *testing.T) { trie.MustUpdate([]byte(val.k), []byte(val.v)) } root, nodes := trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) found := make(map[string]string) @@ -115,39 +117,61 @@ func TestIteratorLargeData(t *testing.T) { } } +type iterationElement struct { + hash common.Hash + path []byte + blob []byte +} + // Tests that the node iterator indeed walks over the entire database contents. func TestNodeIteratorCoverage(t *testing.T) { + testNodeIteratorCoverage(t, rawdb.HashScheme) + //testNodeIteratorCoverage(t, rawdb.PathScheme) +} + +func testNodeIteratorCoverage(t *testing.T, scheme string) { // Create some arbitrary test trie to iterate - db, trie, _ := makeTestTrie() + db, nodeDb, trie, _ := makeTestTrie(scheme) // Gather all the node hashes found by the iterator - hashes := make(map[common.Hash]struct{}) + var elements = make(map[common.Hash]iterationElement) for it := trie.NodeIterator(nil); it.Next(true); { if it.Hash() != (common.Hash{}) { - hashes[it.Hash()] = struct{}{} + elements[it.Hash()] = iterationElement{ + hash: it.Hash(), + path: common.CopyBytes(it.Path()), + blob: common.CopyBytes(it.NodeBlob()), + } } } // Cross check the hashes and the database itself - for hash := range hashes { - if _, err := db.Node(hash); err != nil { - t.Errorf("failed to retrieve reported node %x: %v", hash, err) + for _, element := range elements { + if blob, err := nodeDb.Reader(trie.Hash()).Node(common.Hash{}, element.path, element.hash); err != nil { + t.Errorf("failed to retrieve reported node %x: %v", element.hash, err) + } else if !bytes.Equal(blob, element.blob) { + t.Errorf("node blob is different, want %v got %v", element.blob, blob) } } - for hash, obj := range db.dirties { - if obj != nil && hash != (common.Hash{}) { - if _, ok := hashes[hash]; !ok { - t.Errorf("state entry not reported %x", hash) - } - } - } - it := db.diskdb.NewIterator(nil, nil) + var ( + count int + it = db.NewIterator(nil, nil) + ) for it.Next() { - key := it.Key() - if _, ok := hashes[common.BytesToHash(key)]; !ok { - t.Errorf("state entry not reported %x", key) + res, _, _ := isTrieNode(nodeDb.Scheme(), it.Key(), it.Value()) + if !res { + continue + } + count += 1 + if elem, ok := elements[crypto.Keccak256Hash(it.Value())]; !ok { + t.Error("state entry not reported") + } else if !bytes.Equal(it.Value(), elem.blob) { + t.Errorf("node blob is different, want %v got %v", elem.blob, it.Value()) } } it.Release() + if count != len(elements) { + t.Errorf("state entry is mismatched %d %d", count, len(elements)) + } } type kvs struct{ k, v string } @@ -223,7 +247,7 @@ func TestDifferenceIterator(t *testing.T) { triea.MustUpdate([]byte(val.k), []byte(val.v)) } rootA, nodesA := triea.Commit(false) - dba.Update(NewWithNodeSet(nodesA)) + dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) triea, _ = New(TrieID(rootA), dba) dbb := NewDatabase(rawdb.NewMemoryDatabase()) @@ -232,7 +256,7 @@ func TestDifferenceIterator(t *testing.T) { trieb.MustUpdate([]byte(val.k), []byte(val.v)) } rootB, nodesB := trieb.Commit(false) - dbb.Update(NewWithNodeSet(nodesB)) + dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) trieb, _ = New(TrieID(rootB), dbb) found := make(map[string]string) @@ -265,7 +289,7 @@ func TestUnionIterator(t *testing.T) { triea.MustUpdate([]byte(val.k), []byte(val.v)) } rootA, nodesA := triea.Commit(false) - dba.Update(NewWithNodeSet(nodesA)) + dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) triea, _ = New(TrieID(rootA), dba) dbb := NewDatabase(rawdb.NewMemoryDatabase()) @@ -274,7 +298,7 @@ func TestUnionIterator(t *testing.T) { trieb.MustUpdate([]byte(val.k), []byte(val.v)) } rootB, nodesB := trieb.Commit(false) - dbb.Update(NewWithNodeSet(nodesB)) + dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) trieb, _ = New(TrieID(rootB), dbb) di, _ := NewUnionIterator([]NodeIterator{triea.NodeIterator(nil), trieb.NodeIterator(nil)}) @@ -320,79 +344,98 @@ func TestIteratorNoDups(t *testing.T) { } // This test checks that nodeIterator.Next can be retried after inserting missing trie nodes. -func TestIteratorContinueAfterErrorDisk(t *testing.T) { testIteratorContinueAfterError(t, false) } -func TestIteratorContinueAfterErrorMemonly(t *testing.T) { testIteratorContinueAfterError(t, true) } +func TestIteratorContinueAfterError(t *testing.T) { + testIteratorContinueAfterError(t, false, rawdb.HashScheme) + testIteratorContinueAfterError(t, true, rawdb.HashScheme) + // testIteratorContinueAfterError(t, false, rawdb.PathScheme) + // testIteratorContinueAfterError(t, true, rawdb.PathScheme) +} -func testIteratorContinueAfterError(t *testing.T, memonly bool) { +func testIteratorContinueAfterError(t *testing.T, memonly bool, scheme string) { diskdb := rawdb.NewMemoryDatabase() - triedb := NewDatabase(diskdb) + tdb := newTestDatabase(diskdb, scheme) - tr := NewEmpty(triedb) + tr := NewEmpty(tdb) for _, val := range testdata1 { tr.MustUpdate([]byte(val.k), []byte(val.v)) } - _, nodes := tr.Commit(false) - triedb.Update(NewWithNodeSet(nodes)) + root, nodes := tr.Commit(false) + tdb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) if !memonly { - triedb.Commit(tr.Hash(), false) + tdb.Commit(root, false) } + tr, _ = New(TrieID(root), tdb) wantNodeCount := checkIteratorNoDups(t, tr.NodeIterator(nil), nil) var ( - diskKeys [][]byte - memKeys []common.Hash + paths [][]byte + hashes []common.Hash ) if memonly { - memKeys = triedb.Nodes() + for path, n := range nodes.Nodes { + paths = append(paths, []byte(path)) + hashes = append(hashes, n.Hash) + } } else { it := diskdb.NewIterator(nil, nil) for it.Next() { - diskKeys = append(diskKeys, it.Key()) + ok, path, hash := isTrieNode(tdb.Scheme(), it.Key(), it.Value()) + if !ok { + continue + } + paths = append(paths, path) + hashes = append(hashes, hash) } it.Release() } for i := 0; i < 20; i++ { // Create trie that will load all nodes from DB. - tr, _ := New(TrieID(tr.Hash()), triedb) + tr, _ := New(TrieID(tr.Hash()), tdb) // Remove a random node from the database. It can't be the root node // because that one is already loaded. var ( - rkey common.Hash - rval []byte - robj *cachedNode + rval []byte + rpath []byte + rhash common.Hash ) for { if memonly { - rkey = memKeys[rand.Intn(len(memKeys))] + rpath = paths[rand.Intn(len(paths))] + n := nodes.Nodes[string(rpath)] + if n == nil { + continue + } + rhash = n.Hash } else { - copy(rkey[:], diskKeys[rand.Intn(len(diskKeys))]) + index := rand.Intn(len(paths)) + rpath = paths[index] + rhash = hashes[index] } - if rkey != tr.Hash() { + if rhash != tr.Hash() { break } } if memonly { - robj = triedb.dirties[rkey] - delete(triedb.dirties, rkey) + tr.reader.banned = map[string]struct{}{string(rpath): {}} } else { - rval, _ = diskdb.Get(rkey[:]) - diskdb.Delete(rkey[:]) + rval = rawdb.ReadTrieNode(diskdb, common.Hash{}, rpath, rhash, tdb.Scheme()) + rawdb.DeleteTrieNode(diskdb, common.Hash{}, rpath, rhash, tdb.Scheme()) } // Iterate until the error is hit. seen := make(map[string]bool) it := tr.NodeIterator(nil) checkIteratorNoDups(t, it, seen) missing, ok := it.Error().(*MissingNodeError) - if !ok || missing.NodeHash != rkey { + if !ok || missing.NodeHash != rhash { t.Fatal("didn't hit missing node, got", it.Error()) } // Add the node back and continue iteration. if memonly { - triedb.dirties[rkey] = robj + delete(tr.reader.banned, string(rpath)) } else { - diskdb.Put(rkey[:], rval) + rawdb.WriteTrieNode(diskdb, common.Hash{}, rpath, rhash, rval, tdb.Scheme()) } checkIteratorNoDups(t, it, seen) if it.Error() != nil { @@ -407,42 +450,48 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) { // Similar to the test above, this one checks that failure to create nodeIterator at a // certain key prefix behaves correctly when Next is called. The expectation is that Next // should retry seeking before returning true for the first time. -func TestIteratorContinueAfterSeekErrorDisk(t *testing.T) { - testIteratorContinueAfterSeekError(t, false) -} -func TestIteratorContinueAfterSeekErrorMemonly(t *testing.T) { - testIteratorContinueAfterSeekError(t, true) +func TestIteratorContinueAfterSeekError(t *testing.T) { + testIteratorContinueAfterSeekError(t, false, rawdb.HashScheme) + testIteratorContinueAfterSeekError(t, true, rawdb.HashScheme) + // testIteratorContinueAfterSeekError(t, false, rawdb.PathScheme) + // testIteratorContinueAfterSeekError(t, true, rawdb.PathScheme) } -func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { +func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme string) { // Commit test trie to db, then remove the node containing "bars". + var ( + barNodePath []byte + barNodeHash = common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e") + ) diskdb := rawdb.NewMemoryDatabase() - triedb := NewDatabase(diskdb) - + triedb := newTestDatabase(diskdb, scheme) ctr := NewEmpty(triedb) for _, val := range testdata1 { ctr.MustUpdate([]byte(val.k), []byte(val.v)) } root, nodes := ctr.Commit(false) - triedb.Update(NewWithNodeSet(nodes)) + for path, n := range nodes.Nodes { + if n.Hash == barNodeHash { + barNodePath = []byte(path) + break + } + } + triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) if !memonly { triedb.Commit(root, false) } - barNodeHash := common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e") var ( barNodeBlob []byte - barNodeObj *cachedNode ) + tr, _ := New(TrieID(root), triedb) if memonly { - barNodeObj = triedb.dirties[barNodeHash] - delete(triedb.dirties, barNodeHash) + tr.reader.banned = map[string]struct{}{string(barNodePath): {}} } else { - barNodeBlob, _ = diskdb.Get(barNodeHash[:]) - diskdb.Delete(barNodeHash[:]) + barNodeBlob = rawdb.ReadTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, triedb.Scheme()) + rawdb.DeleteTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, triedb.Scheme()) } // Create a new iterator that seeks to "bars". Seeking can't proceed because // the node is missing. - tr, _ := New(TrieID(root), triedb) it := tr.NodeIterator([]byte("bars")) missing, ok := it.Error().(*MissingNodeError) if !ok { @@ -452,9 +501,9 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { } // Reinsert the missing node. if memonly { - triedb.dirties[barNodeHash] = barNodeObj + delete(tr.reader.banned, string(barNodePath)) } else { - diskdb.Put(barNodeHash[:], barNodeBlob) + rawdb.WriteTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, barNodeBlob, triedb.Scheme()) } // Check that iteration produces the right set of values. if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil { @@ -475,6 +524,11 @@ func checkIteratorNoDups(t *testing.T, it NodeIterator, seen map[string]bool) in return len(seen) } +func TestIteratorNodeBlob(t *testing.T) { + testIteratorNodeBlob(t, rawdb.HashScheme) + //testIteratorNodeBlob(t, rawdb.PathScheme) +} + type loggingDb struct { getCount uint64 backend ethdb.KeyValueStore @@ -542,8 +596,8 @@ func makeLargeTestTrie() (*Database, *StateTrie, *loggingDb) { val = crypto.Keccak256(val) trie.MustUpdate(key, val) } - _, nodes := trie.Commit(false) - triedb.Update(NewWithNodeSet(nodes)) + root, nodes := trie.Commit(false) + triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) // Return the generated trie return triedb, trie, logDb } @@ -562,10 +616,10 @@ func TestNodeIteratorLargeTrie(t *testing.T) { } } -func TestIteratorNodeBlob(t *testing.T) { +func testIteratorNodeBlob(t *testing.T, scheme string) { var ( db = rawdb.NewMemoryDatabase() - triedb = NewDatabase(db) + triedb = newTestDatabase(db, scheme) trie = NewEmpty(triedb) ) vals := []struct{ k, v string }{ @@ -582,11 +636,12 @@ func TestIteratorNodeBlob(t *testing.T) { all[val.k] = val.v trie.MustUpdate([]byte(val.k), []byte(val.v)) } - _, nodes := trie.Commit(false) - triedb.Update(NewWithNodeSet(nodes)) - triedb.Cap(0) + root, nodes := trie.Commit(false) + triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) + triedb.Commit(root, false) - found := make(map[common.Hash][]byte) + var found = make(map[common.Hash][]byte) + trie, _ = New(TrieID(root), triedb) it := trie.NodeIterator(nil) for it.Next(true) { if it.Hash() == (common.Hash{}) { @@ -600,9 +655,13 @@ func TestIteratorNodeBlob(t *testing.T) { var count int for dbIter.Next() { - got, present := found[common.BytesToHash(dbIter.Key())] + ok, _, _ := isTrieNode(triedb.Scheme(), dbIter.Key(), dbIter.Value()) + if !ok { + continue + } + got, present := found[crypto.Keccak256Hash(dbIter.Value())] if !present { - t.Fatalf("Miss trie node %v", dbIter.Key()) + t.Fatal("Miss trie node") } if !bytes.Equal(got, dbIter.Value()) { t.Fatalf("Unexpected trie node want %v got %v", dbIter.Value(), got) @@ -613,3 +672,29 @@ func TestIteratorNodeBlob(t *testing.T) { t.Fatal("Find extra trie node via iterator") } } + +// isTrieNode is a helper function which reports if the provided +// database entry belongs to a trie node or not. Note in tests +// only single layer trie is used, namely storage trie is not +// considered at all. +func isTrieNode(scheme string, key, val []byte) (bool, []byte, common.Hash) { + var ( + path []byte + hash common.Hash + ) + if scheme == rawdb.HashScheme { + ok := rawdb.IsLegacyTrieNode(key, val) + if !ok { + return false, nil, common.Hash{} + } + hash = common.BytesToHash(key) + } else { + ok, remain := rawdb.IsAccountTrieNode(key) + if !ok { + return false, nil, common.Hash{} + } + path = common.CopyBytes(remain) + hash = crypto.Keccak256Hash(val) + } + return true, path, hash +} diff --git a/trie/nodeset.go b/trie/nodeset.go deleted file mode 100644 index 4ebbb3329c..0000000000 --- a/trie/nodeset.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package trie - -import ( - "fmt" - "sort" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/trie/trienode" -) - -// NodeSet contains all dirty nodes collected during the commit operation. -// Each node is keyed by path. It's not thread-safe to use. -type NodeSet struct { - owner common.Hash // the identifier of the trie - leaves []*leaf // the list of dirty leaves - updates int // the count of updated and inserted nodes - deletes int // the count of deleted nodes - - // The set of all dirty nodes. Dirty nodes include newly inserted nodes, - // deleted nodes and updated nodes. The original value of the newly - // inserted node must be nil, and the original value of the other two - // types must be non-nil. - nodes map[string]*trienode.WithPrev -} - -// NewNodeSet initializes an empty node set to be used for tracking dirty nodes -// from a specific account or storage trie. The owner is zero for the account -// trie and the owning account address hash for storage tries. -func NewNodeSet(owner common.Hash) *NodeSet { - return &NodeSet{ - owner: owner, - nodes: make(map[string]*trienode.WithPrev), - } -} - -// forEachWithOrder iterates the dirty nodes with the order from bottom to top, -// right to left, nodes with the longest path will be iterated first. -func (set *NodeSet) forEachWithOrder(callback func(path string, n *trienode.Node)) { - var paths sort.StringSlice - for path := range set.nodes { - paths = append(paths, path) - } - // Bottom-up, longest path first - sort.Sort(sort.Reverse(paths)) - for _, path := range paths { - callback(path, set.nodes[path].Unwrap()) - } -} - -// addNode adds the provided dirty node into set. -func (set *NodeSet) addNode(path []byte, n *trienode.WithPrev) { - if n.IsDeleted() { - set.deletes += 1 - } else { - set.updates += 1 - } - set.nodes[string(path)] = n -} - -// addLeaf adds the provided leaf node into set. -func (set *NodeSet) addLeaf(node *leaf) { - set.leaves = append(set.leaves, node) -} - -// Size returns the number of dirty nodes in set. -func (set *NodeSet) Size() (int, int) { - return set.updates, set.deletes -} - -// Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can -// we get rid of it? -func (set *NodeSet) Hashes() []common.Hash { - var ret []common.Hash - for _, node := range set.nodes { - ret = append(ret, node.Hash) - } - return ret -} - -// Summary returns a string-representation of the NodeSet. -func (set *NodeSet) Summary() string { - var out = new(strings.Builder) - fmt.Fprintf(out, "nodeset owner: %v\n", set.owner) - if set.nodes != nil { - for path, n := range set.nodes { - // Deletion - if n.IsDeleted() { - fmt.Fprintf(out, " [-]: %x prev: %x\n", path, n.Prev) - continue - } - // Insertion - if len(n.Prev) == 0 { - fmt.Fprintf(out, " [+]: %x -> %v\n", path, n.Hash) - continue - } - // Update - fmt.Fprintf(out, " [*]: %x -> %v prev: %x\n", path, n.Hash, n.Prev) - } - } - for _, n := range set.leaves { - fmt.Fprintf(out, "[leaf]: %v\n", n) - } - return out.String() -} - -// MergedNodeSet represents a merged dirty node set for a group of tries. -type MergedNodeSet struct { - sets map[common.Hash]*NodeSet -} - -// NewMergedNodeSet initializes an empty merged set. -func NewMergedNodeSet() *MergedNodeSet { - return &MergedNodeSet{sets: make(map[common.Hash]*NodeSet)} -} - -// NewWithNodeSet constructs a merged nodeset with the provided single set. -func NewWithNodeSet(set *NodeSet) *MergedNodeSet { - merged := NewMergedNodeSet() - merged.Merge(set) - return merged -} - -// Merge merges the provided dirty nodes of a trie into the set. The assumption -// is held that no duplicated set belonging to the same trie will be merged twice. -func (set *MergedNodeSet) Merge(other *NodeSet) error { - _, present := set.sets[other.owner] - if present { - return fmt.Errorf("duplicate trie for owner %#x", other.owner) - } - set.sets[other.owner] = other - return nil -} diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 5bfd246501..b3cdeadb6b 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -20,6 +20,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie/trienode" ) // SecureTrie is the old name of StateTrie. @@ -212,7 +213,7 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte { // All cached preimages will be also flushed if preimages recording is enabled. // Once the trie is committed, it's not usable anymore. A new trie must // be created with new root and updated trie database for following usage -func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { +func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { // Write all the pre-images to the actual disk database if len(t.getSecKeyCache()) > 0 { if t.preimages != nil { diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index a55c10a60b..2da7e6ccb2 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -25,7 +25,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/trie/trienode" ) func newEmptySecure() *StateTrie { @@ -59,7 +61,7 @@ func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) { } } root, nodes := trie.Commit(false) - if err := triedb.Update(NewWithNodeSet(nodes)); err != nil { + if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil { panic(fmt.Errorf("failed to commit db %v", err)) } // Re-create the trie based on the new state diff --git a/trie/sync_test.go b/trie/sync_test.go index 70898604f8..9114501ca2 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -25,13 +25,16 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb/memorydb" + "github.com/ethereum/go-ethereum/trie/trienode" ) // makeTestTrie create a sample test trie to test node-wise reconstruction. -func makeTestTrie() (*Database, *StateTrie, map[string][]byte) { +func makeTestTrie(scheme string) (ethdb.Database, *Database, *StateTrie, map[string][]byte) { // Create an empty trie - triedb := NewDatabase(rawdb.NewMemoryDatabase()) + db := rawdb.NewMemoryDatabase() + triedb := newTestDatabase(db, scheme) trie, _ := NewStateTrie(TrieID(common.Hash{}), triedb) // Fill it with some arbitrary data @@ -54,23 +57,27 @@ func makeTestTrie() (*Database, *StateTrie, map[string][]byte) { } } root, nodes := trie.Commit(false) - if err := triedb.Update(NewWithNodeSet(nodes)); err != nil { + if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil { panic(fmt.Errorf("failed to commit db %v", err)) } + if err := triedb.Commit(root, false); err != nil { + panic(err) + } // Re-create the trie based on the new state trie, _ = NewStateTrie(TrieID(root), triedb) - return triedb, trie, content + return db, triedb, trie, content } // checkTrieContents cross references a reconstructed trie with an expected data // content map. -func checkTrieContents(t *testing.T, db *Database, root []byte, content map[string][]byte) { +func checkTrieContents(t *testing.T, db ethdb.Database, scheme string, root []byte, content map[string][]byte) { // Check root availability and trie contents - trie, err := NewStateTrie(TrieID(common.BytesToHash(root)), db) + ndb := newTestDatabase(db, scheme) + trie, err := NewStateTrie(TrieID(common.BytesToHash(root)), ndb) if err != nil { t.Fatalf("failed to create trie at %x: %v", root, err) } - if err := checkTrieConsistency(db, common.BytesToHash(root)); err != nil { + if err := checkTrieConsistency(db, scheme, common.BytesToHash(root)); err != nil { t.Fatalf("inconsistent trie at %x: %v", root, err) } for key, val := range content { @@ -81,9 +88,9 @@ func checkTrieContents(t *testing.T, db *Database, root []byte, content map[stri } // checkTrieConsistency checks that all nodes in a trie are indeed present. -func checkTrieConsistency(db *Database, root common.Hash) error { - // Create and iterate a trie rooted in a subnode - trie, err := NewStateTrie(TrieID(root), db) +func checkTrieConsistency(db ethdb.Database, scheme string, root common.Hash) error { + ndb := newTestDatabase(db, scheme) + trie, err := NewStateTrie(TrieID(root), ndb) if err != nil { return nil // Consider a non existent state consistent } @@ -104,11 +111,16 @@ type trieElement struct { func TestEmptySync(t *testing.T) { dbA := NewDatabase(rawdb.NewMemoryDatabase()) dbB := NewDatabase(rawdb.NewMemoryDatabase()) - emptyA, _ := New(TrieID(common.Hash{}), dbA) + //dbC := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.PathScheme) + //dbD := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.PathScheme) + + emptyA := NewEmpty(dbA) emptyB, _ := New(TrieID(types.EmptyRootHash), dbB) + //emptyC := NewEmpty(dbC) + //emptyD, _ := New(TrieID(types.EmptyRootHash), dbD) - for i, trie := range []*Trie{emptyA, emptyB} { - sync := NewSync(trie.Hash(), memorydb.New(), nil, []*Database{dbA, dbB}[i].Scheme()) + for i, trie := range []*Trie{emptyA, emptyB /*emptyC, emptyD*/} { + sync := NewSync(trie.Hash(), memorydb.New(), nil, []*Database{dbA, dbB /*dbC, dbD*/}[i].Scheme()) if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { t.Errorf("test %d: content requested for empty trie: %v, %v, %v", i, paths, nodes, codes) } @@ -117,18 +129,23 @@ func TestEmptySync(t *testing.T) { // Tests that given a root hash, a trie can sync iteratively on a single thread, // requesting retrieval tasks and returning all of them in one go. -func TestIterativeSyncIndividual(t *testing.T) { testIterativeSync(t, 1, false) } -func TestIterativeSyncBatched(t *testing.T) { testIterativeSync(t, 100, false) } -func TestIterativeSyncIndividualByPath(t *testing.T) { testIterativeSync(t, 1, true) } -func TestIterativeSyncBatchedByPath(t *testing.T) { testIterativeSync(t, 100, true) } +func TestIterativeSync(t *testing.T) { + testIterativeSync(t, 1, false, rawdb.HashScheme) + testIterativeSync(t, 100, false, rawdb.HashScheme) + testIterativeSync(t, 1, true, rawdb.HashScheme) + testIterativeSync(t, 100, true, rawdb.HashScheme) + // testIterativeSync(t, 1, false, rawdb.PathScheme) + // testIterativeSync(t, 100, false, rawdb.PathScheme) + // testIterativeSync(t, 1, true, rawdb.PathScheme) + // testIterativeSync(t, 100, true, rawdb.PathScheme) +} -func testIterativeSync(t *testing.T, count int, bypath bool) { +func testIterativeSync(t *testing.T, count int, bypath bool, scheme string) { // Create a random trie to copy - srcDb, srcTrie, srcData := makeTestTrie() + _, srcDb, srcTrie, srcData := makeTestTrie(scheme) // Create a destination trie and sync with the scheduler diskdb := rawdb.NewMemoryDatabase() - triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code @@ -146,7 +163,8 @@ func testIterativeSync(t *testing.T, count int, bypath bool) { results := make([]NodeSyncResult, len(elements)) if !bypath { for i, element := range elements { - data, err := srcDb.Node(element.hash) + owner, inner := ResolvePath([]byte(element.path)) + data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash) if err != nil { t.Fatalf("failed to retrieve node data for hash %x: %v", element.hash, err) } @@ -183,18 +201,22 @@ func testIterativeSync(t *testing.T, count int, bypath bool) { } } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) + checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData) } // Tests that the trie scheduler can correctly reconstruct the state even if only // partial results are returned, and the others sent only later. func TestIterativeDelayedSync(t *testing.T) { + testIterativeDelayedSync(t, rawdb.HashScheme) + //testIterativeDelayedSync(t, rawdb.PathScheme) +} + +func testIterativeDelayedSync(t *testing.T, scheme string) { // Create a random trie to copy - srcDb, srcTrie, srcData := makeTestTrie() + _, srcDb, srcTrie, srcData := makeTestTrie(scheme) // Create a destination trie and sync with the scheduler diskdb := rawdb.NewMemoryDatabase() - triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code @@ -212,7 +234,8 @@ func TestIterativeDelayedSync(t *testing.T) { // Sync only half of the scheduled nodes results := make([]NodeSyncResult, len(elements)/2+1) for i, element := range elements[:len(results)] { - data, err := srcDb.Node(element.hash) + owner, inner := ResolvePath([]byte(element.path)) + data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) } @@ -240,22 +263,25 @@ func TestIterativeDelayedSync(t *testing.T) { } } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) + checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData) } // Tests that given a root hash, a trie can sync iteratively on a single thread, // requesting retrieval tasks and returning all of them in one go, however in a // random order. -func TestIterativeRandomSyncIndividual(t *testing.T) { testIterativeRandomSync(t, 1) } -func TestIterativeRandomSyncBatched(t *testing.T) { testIterativeRandomSync(t, 100) } +func TestIterativeRandomSyncIndividual(t *testing.T) { + testIterativeRandomSync(t, 1, rawdb.HashScheme) + testIterativeRandomSync(t, 100, rawdb.HashScheme) + // testIterativeRandomSync(t, 1, rawdb.PathScheme) + // testIterativeRandomSync(t, 100, rawdb.PathScheme) +} -func testIterativeRandomSync(t *testing.T, count int) { +func testIterativeRandomSync(t *testing.T, count int, scheme string) { // Create a random trie to copy - srcDb, srcTrie, srcData := makeTestTrie() + _, srcDb, srcTrie, srcData := makeTestTrie(scheme) // Create a destination trie and sync with the scheduler diskdb := rawdb.NewMemoryDatabase() - triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code @@ -273,7 +299,8 @@ func testIterativeRandomSync(t *testing.T, count int) { // Fetch all the queued nodes in a random order results := make([]NodeSyncResult, 0, len(queue)) for path, element := range queue { - data, err := srcDb.Node(element.hash) + owner, inner := ResolvePath([]byte(element.path)) + data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) } @@ -302,18 +329,22 @@ func testIterativeRandomSync(t *testing.T, count int) { } } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) + checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData) } // Tests that the trie scheduler can correctly reconstruct the state even if only // partial results are returned (Even those randomly), others sent only later. func TestIterativeRandomDelayedSync(t *testing.T) { + testIterativeRandomDelayedSync(t, rawdb.HashScheme) + // testIterativeRandomDelayedSync(t, rawdb.PathScheme) +} + +func testIterativeRandomDelayedSync(t *testing.T, scheme string) { // Create a random trie to copy - srcDb, srcTrie, srcData := makeTestTrie() + _, srcDb, srcTrie, srcData := makeTestTrie(scheme) // Create a destination trie and sync with the scheduler diskdb := rawdb.NewMemoryDatabase() - triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code @@ -331,7 +362,8 @@ func TestIterativeRandomDelayedSync(t *testing.T) { // Sync only half of the scheduled nodes, even those in random order results := make([]NodeSyncResult, 0, len(queue)/2+1) for path, element := range queue { - data, err := srcDb.Node(element.hash) + owner, inner := ResolvePath([]byte(element.path)) + data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) } @@ -365,18 +397,22 @@ func TestIterativeRandomDelayedSync(t *testing.T) { } } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) + checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData) } // Tests that a trie sync will not request nodes multiple times, even if they // have such references. func TestDuplicateAvoidanceSync(t *testing.T) { + testDuplicateAvoidanceSync(t, rawdb.HashScheme) + // testDuplicateAvoidanceSync(t, rawdb.PathScheme) +} + +func testDuplicateAvoidanceSync(t *testing.T, scheme string) { // Create a random trie to copy - srcDb, srcTrie, srcData := makeTestTrie() + _, srcDb, srcTrie, srcData := makeTestTrie(scheme) // Create a destination trie and sync with the scheduler diskdb := rawdb.NewMemoryDatabase() - triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code @@ -395,7 +431,8 @@ func TestDuplicateAvoidanceSync(t *testing.T) { for len(elements) > 0 { results := make([]NodeSyncResult, len(elements)) for i, element := range elements { - data, err := srcDb.Node(element.hash) + owner, inner := ResolvePath([]byte(element.path)) + data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) } @@ -428,27 +465,33 @@ func TestDuplicateAvoidanceSync(t *testing.T) { } } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) + checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData) } // Tests that at any point in time during a sync, only complete sub-tries are in // the database. -func TestIncompleteSync(t *testing.T) { +func TestIncompleteSyncHash(t *testing.T) { + testIncompleteSync(t, rawdb.HashScheme) + // testIncompleteSync(t, rawdb.PathScheme) +} + +func testIncompleteSync(t *testing.T, scheme string) { t.Parallel() + // Create a random trie to copy - srcDb, srcTrie, _ := makeTestTrie() + _, srcDb, srcTrie, _ := makeTestTrie(scheme) // Create a destination trie and sync with the scheduler diskdb := rawdb.NewMemoryDatabase() - triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code // at the testing trie. var ( - added []common.Hash - elements []trieElement - root = srcTrie.Hash() + addedKeys []string + addedHashes []common.Hash + elements []trieElement + root = srcTrie.Hash() ) paths, nodes, _ := sched.Missing(1) for i := 0; i < len(paths); i++ { @@ -462,7 +505,8 @@ func TestIncompleteSync(t *testing.T) { // Fetch a batch of trie nodes results := make([]NodeSyncResult, len(elements)) for i, element := range elements { - data, err := srcDb.Node(element.hash) + owner, inner := ResolvePath([]byte(element.path)) + data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) } @@ -483,11 +527,8 @@ func TestIncompleteSync(t *testing.T) { for _, result := range results { hash := crypto.Keccak256Hash(result.Data) if hash != root { - added = append(added, hash) - } - // Check that all known sub-tries in the synced trie are complete - if err := checkTrieConsistency(triedb, hash); err != nil { - t.Fatalf("trie inconsistent: %v", err) + addedKeys = append(addedKeys, result.Path) + addedHashes = append(addedHashes, crypto.Keccak256Hash(result.Data)) } } // Fetch the next batch to retrieve @@ -502,25 +543,31 @@ func TestIncompleteSync(t *testing.T) { } } // Sanity check that removing any node from the database is detected - for _, hash := range added { - value, _ := diskdb.Get(hash.Bytes()) - diskdb.Delete(hash.Bytes()) - if err := checkTrieConsistency(triedb, root); err == nil { - t.Fatalf("trie inconsistency not caught, missing: %x", hash) - } - diskdb.Put(hash.Bytes(), value) + for i, path := range addedKeys { + owner, inner := ResolvePath([]byte(path)) + nodeHash := addedHashes[i] + value := rawdb.ReadTrieNode(diskdb, owner, inner, nodeHash, scheme) + rawdb.DeleteTrieNode(diskdb, owner, inner, nodeHash, scheme) + if err := checkTrieConsistency(diskdb, srcDb.Scheme(), root); err == nil { + t.Fatalf("trie inconsistency not caught, missing: %x", path) + } + rawdb.WriteTrieNode(diskdb, owner, inner, nodeHash, value, scheme) } } // Tests that trie nodes get scheduled lexicographically when having the same // depth. func TestSyncOrdering(t *testing.T) { + testSyncOrdering(t, rawdb.HashScheme) + // testSyncOrdering(t, rawdb.PathScheme) +} + +func testSyncOrdering(t *testing.T, scheme string) { // Create a random trie to copy - srcDb, srcTrie, srcData := makeTestTrie() + _, srcDb, srcTrie, srcData := makeTestTrie(scheme) // Create a destination trie and sync with the scheduler, tracking the requests diskdb := rawdb.NewMemoryDatabase() - triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code @@ -542,7 +589,8 @@ func TestSyncOrdering(t *testing.T) { for len(elements) > 0 { results := make([]NodeSyncResult, len(elements)) for i, element := range elements { - data, err := srcDb.Node(element.hash) + owner, inner := ResolvePath([]byte(element.path)) + data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) } @@ -571,7 +619,7 @@ func TestSyncOrdering(t *testing.T) { } } // Cross check that the two tries are in sync - checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) + checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData) // Check that the trie nodes have been requested path-ordered for i := 0; i < len(reqs)-1; i++ { @@ -585,3 +633,116 @@ func TestSyncOrdering(t *testing.T) { } } } + +func syncWith(t *testing.T, root common.Hash, db ethdb.Database, srcDb *Database) { + // Create a destination trie and sync with the scheduler + sched := NewSync(root, db, nil, srcDb.Scheme()) + + // The code requests are ignored here since there is no code + // at the testing trie. + paths, nodes, _ := sched.Missing(1) + var elements []trieElement + for i := 0; i < len(paths); i++ { + elements = append(elements, trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + }) + } + for len(elements) > 0 { + results := make([]NodeSyncResult, len(elements)) + for i, element := range elements { + owner, inner := ResolvePath([]byte(element.path)) + data, err := srcDb.Reader(root).Node(owner, inner, element.hash) + if err != nil { + t.Fatalf("failed to retrieve node data for hash %x: %v", element.hash, err) + } + results[i] = NodeSyncResult{element.path, data} + } + for index, result := range results { + if err := sched.ProcessNode(result); err != nil { + t.Fatalf("failed to process result[%d][%v] data %v %v", index, []byte(result.Path), result.Data, err) + } + } + batch := db.NewBatch() + if err := sched.Commit(batch); err != nil { + t.Fatalf("failed to commit data: %v", err) + } + batch.Write() + + paths, nodes, _ = sched.Missing(1) + elements = elements[:0] + for i := 0; i < len(paths); i++ { + elements = append(elements, trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + }) + } + } +} + +// Tests that the syncing target is keeping moving which may overwrite the stale +// states synced in the last cycle. +func TestSyncMovingTarget(t *testing.T) { + testSyncMovingTarget(t, rawdb.HashScheme) + // testSyncMovingTarget(t, rawdb.PathScheme) +} + +func testSyncMovingTarget(t *testing.T, scheme string) { + // Create a random trie to copy + _, srcDb, srcTrie, srcData := makeTestTrie(scheme) + + // Create a destination trie and sync with the scheduler + diskdb := rawdb.NewMemoryDatabase() + syncWith(t, srcTrie.Hash(), diskdb, srcDb) + checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), srcData) + + // Push more modifications into the src trie, to see if dest trie can still + // sync with it(overwrite stale states) + var ( + preRoot = srcTrie.Hash() + diff = make(map[string][]byte) + ) + for i := byte(0); i < 10; i++ { + key, val := randBytes(32), randBytes(32) + srcTrie.MustUpdate(key, val) + diff[string(key)] = val + } + root, nodes := srcTrie.Commit(false) + if err := srcDb.Update(root, preRoot, trienode.NewWithNodeSet(nodes)); err != nil { + panic(err) + } + if err := srcDb.Commit(root, false); err != nil { + panic(err) + } + preRoot = root + srcTrie, _ = NewStateTrie(TrieID(root), srcDb) + + syncWith(t, srcTrie.Hash(), diskdb, srcDb) + checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), diff) + + // Revert added modifications from the src trie, to see if dest trie can still + // sync with it(overwrite reverted states) + var reverted = make(map[string][]byte) + for k := range diff { + srcTrie.MustDelete([]byte(k)) + reverted[k] = nil + } + for k := range srcData { + val := randBytes(32) + srcTrie.MustUpdate([]byte(k), val) + reverted[k] = val + } + root, nodes = srcTrie.Commit(false) + if err := srcDb.Update(root, preRoot, trienode.NewWithNodeSet(nodes)); err != nil { + panic(err) + } + if err := srcDb.Commit(root, false); err != nil { + panic(err) + } + srcTrie, _ = NewStateTrie(TrieID(root), srcDb) + + syncWith(t, srcTrie.Hash(), diskdb, srcDb) + checkTrieContents(t, diskdb, srcDb.Scheme(), srcTrie.Hash().Bytes(), reverted) +} diff --git a/trie/tracer.go b/trie/tracer.go index 04b2f12bf6..2b5de8ec47 100644 --- a/trie/tracer.go +++ b/trie/tracer.go @@ -115,7 +115,7 @@ func (t *tracer) copy() *tracer { } // markDeletions puts all tracked deletions into the provided nodeset. -func (t *tracer) markDeletions(set *NodeSet) { +func (t *tracer) markDeletions(set *trienode.NodeSet) { for path := range t.deletes { // It's possible a few deleted nodes were embedded // in their parent before, the deletions can be no @@ -124,6 +124,6 @@ func (t *tracer) markDeletions(set *NodeSet) { if !ok { continue } - set.addNode([]byte(path), trienode.NewWithPrev(common.Hash{}, nil, prev)) + set.AddNode([]byte(path), trienode.NewWithPrev(common.Hash{}, nil, prev)) } } diff --git a/trie/tracer_test.go b/trie/tracer_test.go index 1b9f441084..5f61a1d6b3 100644 --- a/trie/tracer_test.go +++ b/trie/tracer_test.go @@ -22,6 +22,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/trie/trienode" ) var ( @@ -69,7 +71,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { insertSet := copySet(trie.tracer.inserts) // copy before commit deleteSet := copySet(trie.tracer.deletes) // copy before commit root, nodes := trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) seen := setKeys(iterNodes(db, root)) if !compareSet(insertSet, seen) { @@ -135,7 +137,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { trie.MustUpdate([]byte(val.k), []byte(val.v)) } root, nodes := trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) if err := verifyAccessList(orig, trie, nodes); err != nil { @@ -143,13 +145,14 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { } // Update trie + parent := root trie, _ = New(TrieID(root), db) orig = trie.Copy() for _, val := range vals { trie.MustUpdate([]byte(val.k), randBytes(32)) } root, nodes = trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, parent, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) if err := verifyAccessList(orig, trie, nodes); err != nil { @@ -157,6 +160,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { } // Add more new nodes + parent = root trie, _ = New(TrieID(root), db) orig = trie.Copy() var keys []string @@ -166,7 +170,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { trie.MustUpdate(key, randBytes(32)) } root, nodes = trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, parent, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) if err := verifyAccessList(orig, trie, nodes); err != nil { @@ -174,13 +178,14 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { } // Partial deletions + parent = root trie, _ = New(TrieID(root), db) orig = trie.Copy() for _, key := range keys { trie.MustUpdate([]byte(key), nil) } root, nodes = trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, parent, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) if err := verifyAccessList(orig, trie, nodes); err != nil { @@ -188,13 +193,14 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { } // Delete all + parent = root trie, _ = New(TrieID(root), db) orig = trie.Copy() for _, val := range vals { trie.MustUpdate([]byte(val.k), nil) } root, nodes = trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, parent, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) if err := verifyAccessList(orig, trie, nodes); err != nil { @@ -213,7 +219,7 @@ func TestAccessListLeak(t *testing.T) { trie.MustUpdate([]byte(val.k), []byte(val.v)) } root, nodes := trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) var cases = []struct { op func(tr *Trie) @@ -263,15 +269,16 @@ func TestTinyTree(t *testing.T) { trie.MustUpdate([]byte(val.k), randBytes(32)) } root, set := trie.Commit(false) - db.Update(NewWithNodeSet(set)) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(set)) + parent := root trie, _ = New(TrieID(root), db) orig := trie.Copy() for _, val := range tiny { trie.MustUpdate([]byte(val.k), []byte(val.v)) } root, set = trie.Commit(false) - db.Update(NewWithNodeSet(set)) + db.Update(root, parent, trienode.NewWithNodeSet(set)) trie, _ = New(TrieID(root), db) if err := verifyAccessList(orig, trie, set); err != nil { diff --git a/trie/trie.go b/trie/trie.go index 14685c3df8..e63b2d2830 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/trie/trienode" ) // Trie is a Merkle Patricia Trie. Use New to create a trie that sits on @@ -95,7 +96,7 @@ func New(id *ID, db NodeReader) (*Trie, error) { // NewEmpty is a shortcut to create empty tree. It's mostly used in tests. func NewEmpty(db *Database) *Trie { - tr, _ := New(TrieID(common.Hash{}), db) + tr, _ := New(TrieID(types.EmptyRootHash), db) return tr } @@ -571,10 +572,10 @@ func (t *Trie) Hash() common.Hash { // The returned nodeset can be nil if the trie is clean (nothing to commit). // Once the trie is committed, it's not usable anymore. A new trie must // be created with new root and updated trie database for following usage -func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { +func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { defer t.tracer.reset() - nodes := NewNodeSet(t.owner) + nodes := trienode.NewNodeSet(t.owner) t.tracer.markDeletions(nodes) // Trie is empty and can be classified into two types of situations: diff --git a/trie/trie_reader.go b/trie/trie_reader.go index e3f98a8061..51855320a6 100644 --- a/trie/trie_reader.go +++ b/trie/trie_reader.go @@ -32,9 +32,9 @@ type Reader interface { // NodeReader wraps all the necessary functions for accessing trie node. type NodeReader interface { - // GetReader returns a reader for accessing all trie nodes with provided + // Reader returns a reader for accessing all trie nodes with provided // state root. Nil is returned in case the state is not available. - GetReader(root common.Hash) Reader + Reader(root common.Hash) Reader } // trieReader is a wrapper of the underlying node reader. It's not safe @@ -47,7 +47,7 @@ type trieReader struct { // newTrieReader initializes the trie reader with the given node reader. func newTrieReader(stateRoot, owner common.Hash, db NodeReader) (*trieReader, error) { - reader := db.GetReader(stateRoot) + reader := db.Reader(stateRoot) if reader == nil { return nil, fmt.Errorf("state not found #%x", stateRoot) } diff --git a/trie/trie_test.go b/trie/trie_test.go index a03a68283d..70de460227 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie/trienode" "golang.org/x/crypto/sha3" ) @@ -73,18 +74,23 @@ func TestMissingRoot(t *testing.T) { } } -func TestMissingNodeDisk(t *testing.T) { testMissingNode(t, false) } -func TestMissingNodeMemonly(t *testing.T) { testMissingNode(t, true) } +func TestMissingNode(t *testing.T) { + testMissingNode(t, false, rawdb.HashScheme) + //testMissingNode(t, false, rawdb.PathScheme) + testMissingNode(t, true, rawdb.HashScheme) + //testMissingNode(t, true, rawdb.PathScheme) +} -func testMissingNode(t *testing.T, memonly bool) { +func testMissingNode(t *testing.T, memonly bool, scheme string) { diskdb := rawdb.NewMemoryDatabase() - triedb := NewDatabase(diskdb) + triedb := newTestDatabase(diskdb, scheme) trie := NewEmpty(triedb) updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") root, nodes := trie.Commit(false) - triedb.Update(NewWithNodeSet(nodes)) + triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) + if !memonly { triedb.Commit(root, false) } @@ -115,34 +121,39 @@ func testMissingNode(t *testing.T, memonly bool) { t.Errorf("Unexpected error: %v", err) } - hash := common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9") + var ( + path []byte + hash = common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9") + ) + for p, n := range nodes.Nodes { + if n.Hash == hash { + path = common.CopyBytes([]byte(p)) + break + } + } + trie, _ = New(TrieID(root), triedb) if memonly { - delete(triedb.dirties, hash) + trie.reader.banned = map[string]struct{}{string(path): {}} } else { - diskdb.Delete(hash[:]) + rawdb.DeleteTrieNode(diskdb, common.Hash{}, path, hash, scheme) } - trie, _ = New(TrieID(root), triedb) _, err = trie.Get([]byte("120000")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } - trie, _ = New(TrieID(root), triedb) _, err = trie.Get([]byte("120099")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } - trie, _ = New(TrieID(root), triedb) _, err = trie.Get([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } - trie, _ = New(TrieID(root), triedb) err = trie.Update([]byte("120099"), []byte("zxcv")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } - trie, _ = New(TrieID(root), triedb) err = trie.Delete([]byte("123456")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) @@ -192,7 +203,7 @@ func TestGet(t *testing.T) { return } root, nodes := trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) } } @@ -249,8 +260,8 @@ func TestEmptyValues(t *testing.T) { } func TestReplication(t *testing.T) { - triedb := NewDatabase(rawdb.NewMemoryDatabase()) - trie := NewEmpty(triedb) + db := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(db) vals := []struct{ k, v string }{ {"do", "verb"}, {"ether", "wookiedoo"}, @@ -263,13 +274,13 @@ func TestReplication(t *testing.T) { for _, val := range vals { updateString(trie, val.k, val.v) } - exp, nodes := trie.Commit(false) - triedb.Update(NewWithNodeSet(nodes)) + root, nodes := trie.Commit(false) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) // create a new trie on top of the database and check that lookups work. - trie2, err := New(TrieID(exp), triedb) + trie2, err := New(TrieID(root), db) if err != nil { - t.Fatalf("can't recreate trie at %x: %v", exp, err) + t.Fatalf("can't recreate trie at %x: %v", root, err) } for _, kv := range vals { if string(getString(trie2, kv.k)) != kv.v { @@ -277,17 +288,17 @@ func TestReplication(t *testing.T) { } } hash, nodes := trie2.Commit(false) - if hash != exp { - t.Errorf("root failure. expected %x got %x", exp, hash) + if hash != root { + t.Errorf("root failure. expected %x got %x", root, hash) } // recreate the trie after commit if nodes != nil { - triedb.Update(NewWithNodeSet(nodes)) + db.Update(hash, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) } - trie2, err = New(TrieID(hash), triedb) + trie2, err = New(TrieID(hash), db) if err != nil { - t.Fatalf("can't recreate trie at %x: %v", exp, err) + t.Fatalf("can't recreate trie at %x: %v", hash, err) } // perform some insertions on the new trie. vals2 := []struct{ k, v string }{ @@ -304,8 +315,8 @@ func TestReplication(t *testing.T) { for _, val := range vals2 { updateString(trie2, val.k, val.v) } - if hash := trie2.Hash(); hash != exp { - t.Errorf("root failure. expected %x got %x", exp, hash) + if trie2.Hash() != hash { + t.Errorf("root failure. expected %x got %x", hash, hash) } } @@ -402,12 +413,12 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value { return reflect.ValueOf(steps) } -func verifyAccessList(old *Trie, new *Trie, set *NodeSet) error { +func verifyAccessList(old *Trie, new *Trie, set *trienode.NodeSet) error { deletes, inserts, updates := diffTries(old, new) // Check insertion set for path := range inserts { - n, ok := set.nodes[path] + n, ok := set.Nodes[path] if !ok || n.IsDeleted() { return errors.New("expect new node") } @@ -417,7 +428,7 @@ func verifyAccessList(old *Trie, new *Trie, set *NodeSet) error { } // Check deletion set for path, blob := range deletes { - n, ok := set.nodes[path] + n, ok := set.Nodes[path] if !ok || !n.IsDeleted() { return errors.New("expect deleted node") } @@ -430,7 +441,7 @@ func verifyAccessList(old *Trie, new *Trie, set *NodeSet) error { } // Check update set for path, blob := range updates { - n, ok := set.nodes[path] + n, ok := set.Nodes[path] if !ok || n.IsDeleted() { return errors.New("expect updated node") } @@ -445,8 +456,13 @@ func verifyAccessList(old *Trie, new *Trie, set *NodeSet) error { } func runRandTest(rt randTest) bool { + var scheme = rawdb.HashScheme + //if rand.Intn(2) == 0 { + // scheme = rawdb.PathScheme + //} var ( - triedb = NewDatabase(rawdb.NewMemoryDatabase()) + origin = types.EmptyRootHash + triedb = newTestDatabase(rawdb.NewMemoryDatabase(), scheme) tr = NewEmpty(triedb) values = make(map[string]string) // tracks content of the trie origTrie = NewEmpty(triedb) @@ -487,7 +503,7 @@ func runRandTest(rt randTest) bool { case opCommit: root, nodes := tr.Commit(true) if nodes != nil { - triedb.Update(NewWithNodeSet(nodes)) + triedb.Update(root, origin, trienode.NewWithNodeSet(nodes)) } newtr, err := New(TrieID(root), triedb) if err != nil { @@ -502,6 +518,7 @@ func runRandTest(rt randTest) bool { } tr = newtr origTrie = tr.Copy() + origin = root case opItercheckhash: checktr := NewEmpty(triedb) it := NewIterator(tr.NodeIterator(nil)) @@ -821,7 +838,7 @@ func TestCommitSequence(t *testing.T) { } // Flush trie -> database root, nodes := trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) // Flush memdb -> disk (sponge) db.Commit(root, false) if got, exp := s.sponge.Sum(nil), tc.expWriteSeqHash; !bytes.Equal(got, exp) { @@ -862,7 +879,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { } // Flush trie -> database root, nodes := trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) // Flush memdb -> disk (sponge) db.Commit(root, false) if got, exp := s.sponge.Sum(nil), tc.expWriteSeqHash; !bytes.Equal(got, exp) { @@ -902,7 +919,7 @@ func TestCommitSequenceStackTrie(t *testing.T) { // Flush trie -> database root, nodes := trie.Commit(false) // Flush memdb -> disk (sponge) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Commit(root, false) // And flush stacktrie -> disk stRoot, err := stTrie.Commit() @@ -950,7 +967,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) { // Flush trie -> database root, nodes := trie.Commit(false) // Flush memdb -> disk (sponge) - db.Update(NewWithNodeSet(nodes)) + db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Commit(root, false) // And flush stacktrie -> disk stRoot, err := stTrie.Commit() @@ -1121,8 +1138,8 @@ func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts [] trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } h := trie.Hash() - _, nodes := trie.Commit(false) - triedb.Update(NewWithNodeSet(nodes)) + root, nodes := trie.Commit(false) + triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) b.StartTimer() triedb.Dereference(h) b.StopTimer() diff --git a/trie/database.go b/trie/triedb/hashdb/database.go similarity index 81% rename from trie/database.go rename to trie/triedb/hashdb/database.go index c105c730a2..eaccfe944a 100644 --- a/trie/database.go +++ b/trie/triedb/hashdb/database.go @@ -14,12 +14,11 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package trie +package hashdb import ( "errors" "reflect" - "runtime" "sync" "time" @@ -58,10 +57,10 @@ var ( memcacheCommitSizeMeter = metrics.NewRegisteredMeter("trie/memcache/commit/size", nil) ) -// childResolver defines the required method to decode the provided +// ChildResolver defines the required method to decode the provided // trie node and iterate the children on top. -type childResolver interface { - forEach(node []byte, onChild func(common.Hash)) +type ChildResolver interface { + ForEach(node []byte, onChild func(common.Hash)) } // Database is an intermediate write layer between the trie data structures and @@ -74,7 +73,7 @@ type childResolver interface { // servers even while the trie is executing expensive garbage collection. type Database struct { diskdb ethdb.Database // Persistent storage for matured trie nodes - resolver childResolver // The handler to resolve children of nodes + resolver ChildResolver // The handler to resolve children of nodes cleans *fastcache.Cache // GC friendly memory cache of clean node RLPs dirties map[common.Hash]*cachedNode // Data and references relationships of dirty trie nodes @@ -91,7 +90,6 @@ type Database struct { dirtiesSize common.StorageSize // Storage size of the dirty node cache (exc. metadata) childrenSize common.StorageSize // Storage size of the external children tracking - preimages *preimageStore // The store for caching preimages lock sync.RWMutex } @@ -114,49 +112,20 @@ var cachedNodeSize = int(reflect.TypeOf(cachedNode{}).Size()) // forChildren invokes the callback for all the tracked children of this node, // both the implicit ones from inside the node as well as the explicit ones // from outside the node. -func (n *cachedNode) forChildren(resolver childResolver, onChild func(hash common.Hash)) { +func (n *cachedNode) forChildren(resolver ChildResolver, onChild func(hash common.Hash)) { for child := range n.external { onChild(child) } - resolver.forEach(n.node, onChild) + resolver.ForEach(n.node, onChild) } -// Config defines all necessary options for database. -type Config struct { - Cache int // Memory allowance (MB) to use for caching trie nodes in memory - Journal string // Journal of clean cache to survive node restarts - Preimages bool // Flag whether the preimage of trie key is recorded -} - -// NewDatabase creates a new trie database to store ephemeral trie content before -// its written out to disk or garbage collected. No read cache is created, so all -// data retrievals will hit the underlying disk database. -func NewDatabase(diskdb ethdb.Database) *Database { - return NewDatabaseWithConfig(diskdb, nil) -} - -// NewDatabaseWithConfig creates a new trie database to store ephemeral trie content -// before its written out to disk or garbage collected. It also acts as a read cache -// for nodes loaded from disk. -func NewDatabaseWithConfig(diskdb ethdb.Database, config *Config) *Database { - var cleans *fastcache.Cache - if config != nil && config.Cache > 0 { - if config.Journal == "" { - cleans = fastcache.New(config.Cache * 1024 * 1024) - } else { - cleans = fastcache.LoadFromFileOrNew(config.Journal, config.Cache*1024*1024) - } - } - var preimage *preimageStore - if config != nil && config.Preimages { - preimage = newPreimageStore(diskdb) - } +// New initializes the hash-based node database. +func New(diskdb ethdb.Database, cleans *fastcache.Cache, resolver ChildResolver) *Database { return &Database{ - diskdb: diskdb, - resolver: mptResolver{}, - cleans: cleans, - dirties: make(map[common.Hash]*cachedNode), - preimages: preimage, + diskdb: diskdb, + resolver: resolver, + cleans: cleans, + dirties: make(map[common.Hash]*cachedNode), } } @@ -369,13 +338,6 @@ func (db *Database) Cap(limit common.StorageSize) error { size := db.dirtiesSize + common.StorageSize(len(db.dirties)*cachedNodeSize) size += db.childrenSize - // If the preimage cache got large enough, push to disk. If it's still small - // leave for later to deduplicate writes. - if db.preimages != nil { - if err := db.preimages.commit(false); err != nil { - return err - } - } // Keep committing nodes from the flush-list until we're below allowance oldest := db.oldest for size > limit && oldest != (common.Hash{}) { @@ -450,12 +412,6 @@ func (db *Database) Commit(node common.Hash, report bool) error { start := time.Now() batch := db.diskdb.NewBatch() - // Move all of the accumulated preimages into a write batch - if db.preimages != nil { - if err := db.preimages.commit(true); err != nil { - return err - } - } // Move the trie itself into the batch, flushing if enough data is accumulated nodes, storage := len(db.dirties), db.dirtiesSize @@ -584,9 +540,21 @@ func (c *cleaner) Delete(key []byte) error { panic("not implemented") } -// Update inserts the dirty nodes in provided nodeset into database and -// link the account trie with multiple storage tries if necessary. -func (db *Database) Update(nodes *MergedNodeSet) error { +// Initialized returns an indicator if state data is already initialized +// in hash-based scheme by checking the presence of genesis state. +func (db *Database) Initialized(genesisRoot common.Hash) bool { + return rawdb.HasLegacyTrieNode(db.diskdb, genesisRoot) +} + +// Update inserts the dirty nodes in provided nodeset into database and link the +// account trie with multiple storage tries if necessary. +func (db *Database) Update(root common.Hash, parent common.Hash, nodes *trienode.MergedNodeSet) error { + // Ensure the parent state is present and signal a warning if not. + if parent != types.EmptyRootHash { + if blob, _ := db.Node(parent); len(blob) == 0 { + log.Error("parent state is not present") + } + } db.lock.Lock() defer db.lock.Unlock() @@ -597,18 +565,18 @@ func (db *Database) Update(nodes *MergedNodeSet) error { // Note, the storage tries must be flushed before the account trie to // retain the invariant that children go into the dirty cache first. var order []common.Hash - for owner := range nodes.sets { + for owner := range nodes.Sets { if owner == (common.Hash{}) { continue } order = append(order, owner) } - if _, ok := nodes.sets[common.Hash{}]; ok { + if _, ok := nodes.Sets[common.Hash{}]; ok { order = append(order, common.Hash{}) } for _, owner := range order { - subset := nodes.sets[owner] - subset.forEachWithOrder(func(path string, n *trienode.Node) { + subset := nodes.Sets[owner] + subset.ForEachWithOrder(func(path string, n *trienode.Node) { if n.IsDeleted() { return // ignore deletion } @@ -617,14 +585,14 @@ func (db *Database) Update(nodes *MergedNodeSet) error { } // Link up the account trie and storage trie if the node points // to an account trie leaf. - if set, present := nodes.sets[common.Hash{}]; present { - for _, n := range set.leaves { + if set, present := nodes.Sets[common.Hash{}]; present { + for _, n := range set.Leaves { var account types.StateAccount - if err := rlp.DecodeBytes(n.blob, &account); err != nil { + if err := rlp.DecodeBytes(n.Blob, &account); err != nil { return err } if account.Root != types.EmptyRootHash { - db.reference(account.Root, n.parent) + db.reference(account.Root, n.Parent) } } } @@ -633,7 +601,7 @@ func (db *Database) Update(nodes *MergedNodeSet) error { // Size returns the current storage size of the memory cache in front of the // persistent database layer. -func (db *Database) Size() (common.StorageSize, common.StorageSize) { +func (db *Database) Size() common.StorageSize { db.lock.RLock() defer db.lock.RUnlock() @@ -641,89 +609,30 @@ func (db *Database) Size() (common.StorageSize, common.StorageSize) { // the total memory consumption, the maintenance metadata is also needed to be // counted. var metadataSize = common.StorageSize(len(db.dirties) * cachedNodeSize) - var preimageSize common.StorageSize - if db.preimages != nil { - preimageSize = db.preimages.size() - } - return db.dirtiesSize + db.childrenSize + metadataSize, preimageSize + return db.dirtiesSize + db.childrenSize + metadataSize } -// GetReader retrieves a node reader belonging to the given state root. -func (db *Database) GetReader(root common.Hash) Reader { - return newHashReader(db) +// Close closes the trie database and releases all held resources. +func (db *Database) Close() error { return nil } + +// Scheme returns the node scheme used in the database. +func (db *Database) Scheme() string { + return rawdb.HashScheme } -// hashReader is reader of hashDatabase which implements the Reader interface. -type hashReader struct { - db *Database +// Reader retrieves a node reader belonging to the given state root. +func (db *Database) Reader(root common.Hash) *reader { + return &reader{db: db} } -// newHashReader initializes the hash reader. -func newHashReader(db *Database) *hashReader { - return &hashReader{db: db} +// reader is a state reader of Database which implements the Reader interface. +type reader struct { + db *Database } -// Node retrieves the RLP-encoded trie node blob with the given node hash. +// Node retrieves the trie node with the given node hash. // No error will be returned if the node is not found. -func (reader *hashReader) Node(_ common.Hash, _ []byte, hash common.Hash) ([]byte, error) { +func (reader *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) { blob, _ := reader.db.Node(hash) return blob, nil } - -// saveCache saves clean state cache to given directory path -// using specified CPU cores. -func (db *Database) saveCache(dir string, threads int) error { - if db.cleans == nil { - return nil - } - log.Info("Writing clean trie cache to disk", "path", dir, "threads", threads) - - start := time.Now() - err := db.cleans.SaveToFileConcurrent(dir, threads) - if err != nil { - log.Error("Failed to persist clean trie cache", "error", err) - return err - } - log.Info("Persisted the clean trie cache", "path", dir, "elapsed", common.PrettyDuration(time.Since(start))) - return nil -} - -// SaveCache atomically saves fast cache data to the given dir using all -// available CPU cores. -func (db *Database) SaveCache(dir string) error { - return db.saveCache(dir, runtime.GOMAXPROCS(0)) -} - -// SaveCachePeriodically atomically saves fast cache data to the given dir with -// the specified interval. All dump operation will only use a single CPU core. -func (db *Database) SaveCachePeriodically(dir string, interval time.Duration, stopCh <-chan struct{}) { - ticker := time.NewTicker(interval) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - db.saveCache(dir, 1) - case <-stopCh: - return - } - } -} - -// CommitPreimages flushes the dangling preimages to disk. It is meant to be -// called when closing the blockchain object, so that preimages are persisted -// to the database. -func (db *Database) CommitPreimages() error { - db.lock.Lock() - defer db.lock.Unlock() - - if db.preimages == nil { - return nil - } - return db.preimages.commit(true) -} - -// Scheme returns the node scheme used in the database. -func (db *Database) Scheme() string { - return rawdb.HashScheme -} diff --git a/trie/trienode/node.go b/trie/trienode/node.go index 5ebfea8896..8152eab6c0 100644 --- a/trie/trienode/node.go +++ b/trie/trienode/node.go @@ -16,7 +16,13 @@ package trienode -import "github.com/ethereum/go-ethereum/common" +import ( + "fmt" + "sort" + "strings" + + "github.com/ethereum/go-ethereum/common" +) // Node is a wrapper which contains the encoded blob of the trie node and its // unique hash identifier. It is general enough that can be used to represent @@ -65,3 +71,127 @@ func NewWithPrev(hash common.Hash, blob []byte, prev []byte) *WithPrev { Prev: prev, } } + +// leaf represents a trie leaf node +type leaf struct { + Blob []byte // raw blob of leaf + Parent common.Hash // the hash of parent node +} + +// NodeSet contains a set of nodes collected during the commit operation. +// Each node is keyed by path. It's not thread-safe to use. +type NodeSet struct { + Owner common.Hash + Leaves []*leaf + Nodes map[string]*WithPrev + updates int // the count of updated and inserted nodes + deletes int // the count of deleted nodes +} + +// NewNodeSet initializes a node set. The owner is zero for the account trie and +// the owning account address hash for storage tries. +func NewNodeSet(owner common.Hash) *NodeSet { + return &NodeSet{ + Owner: owner, + Nodes: make(map[string]*WithPrev), + } +} + +// ForEachWithOrder iterates the nodes with the order from bottom to top, +// right to left, nodes with the longest path will be iterated first. +func (set *NodeSet) ForEachWithOrder(callback func(path string, n *Node)) { + var paths sort.StringSlice + for path := range set.Nodes { + paths = append(paths, path) + } + // Bottom-up, longest path first + sort.Sort(sort.Reverse(paths)) + for _, path := range paths { + callback(path, set.Nodes[path].Unwrap()) + } +} + +// AddNode adds the provided node into set. +func (set *NodeSet) AddNode(path []byte, n *WithPrev) { + if n.IsDeleted() { + set.deletes += 1 + } else { + set.updates += 1 + } + set.Nodes[string(path)] = n +} + +// AddLeaf adds the provided leaf node into set. TODO(rjl493456442) how can +// we get rid of it? +func (set *NodeSet) AddLeaf(parent common.Hash, blob []byte) { + set.Leaves = append(set.Leaves, &leaf{Blob: blob, Parent: parent}) +} + +// Size returns the number of dirty nodes in set. +func (set *NodeSet) Size() (int, int) { + return set.updates, set.deletes +} + +// Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can +// we get rid of it? +func (set *NodeSet) Hashes() []common.Hash { + var ret []common.Hash + for _, node := range set.Nodes { + ret = append(ret, node.Hash) + } + return ret +} + +// Summary returns a string-representation of the NodeSet. +func (set *NodeSet) Summary() string { + var out = new(strings.Builder) + fmt.Fprintf(out, "nodeset owner: %v\n", set.Owner) + if set.Nodes != nil { + for path, n := range set.Nodes { + // Deletion + if n.IsDeleted() { + fmt.Fprintf(out, " [-]: %x prev: %x\n", path, n.Prev) + continue + } + // Insertion + if len(n.Prev) == 0 { + fmt.Fprintf(out, " [+]: %x -> %v\n", path, n.Hash) + continue + } + // Update + fmt.Fprintf(out, " [*]: %x -> %v prev: %x\n", path, n.Hash, n.Prev) + } + } + for _, n := range set.Leaves { + fmt.Fprintf(out, "[leaf]: %v\n", n) + } + return out.String() +} + +// MergedNodeSet represents a merged node set for a group of tries. +type MergedNodeSet struct { + Sets map[common.Hash]*NodeSet +} + +// NewMergedNodeSet initializes an empty merged set. +func NewMergedNodeSet() *MergedNodeSet { + return &MergedNodeSet{Sets: make(map[common.Hash]*NodeSet)} +} + +// NewWithNodeSet constructs a merged nodeset with the provided single set. +func NewWithNodeSet(set *NodeSet) *MergedNodeSet { + merged := NewMergedNodeSet() + merged.Merge(set) + return merged +} + +// Merge merges the provided dirty nodes of a trie into the set. The assumption +// is held that no duplicated set belonging to the same trie will be merged twice. +func (set *MergedNodeSet) Merge(other *NodeSet) error { + _, present := set.Sets[other.Owner] + if present { + return fmt.Errorf("duplicate trie for owner %#x", other.Owner) + } + set.Sets[other.Owner] = other + return nil +} From c79850764227da2d514201f8e5f93bb56e8f81b3 Mon Sep 17 00:00:00 2001 From: ucwong Date: Tue, 9 May 2023 01:24:43 -0600 Subject: [PATCH 100/988] miner: initialize maps with capacity (#27228) * miner : initialize maps with known size * miner:some reverts --- miner/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/worker.go b/miner/worker.go index 9afc65ab1d..936a9e74a5 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -628,7 +628,7 @@ func (w *worker) mainLoop() { if gp := w.current.gasPool; gp != nil && gp.Gas() < params.TxGas { continue } - txs := make(map[common.Address]types.Transactions) + txs := make(map[common.Address]types.Transactions, len(ev.Txs)) for _, tx := range ev.Txs { acc, _ := types.Sender(w.current.signer, tx) txs[acc] = append(txs[acc], tx) From c62da24dce53f942b16fdb0984449a3aa9c16f24 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 9 May 2023 09:57:42 +0200 Subject: [PATCH 101/988] cmd/utils: report the blocknumber when block import fails (#27213) When block import fails, the error displays the number of the first block past the import batch, not the number of the failing block. This change fixes this problem by identifying which blocks fails and reporting its number. --- cmd/utils/cmd.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index e1bafc53c3..c9e02eb68c 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -211,8 +211,14 @@ func ImportChain(chain *core.BlockChain, fn string) error { log.Info("Skipping batch as all blocks present", "batch", batch, "first", blocks[0].Hash(), "last", blocks[i-1].Hash()) continue } - if _, err := chain.InsertChain(missing); err != nil { - return fmt.Errorf("invalid block %d: %v", n, err) + if failindex, err := chain.InsertChain(missing); err != nil { + var failnumber uint64 + if failindex > 0 && failindex < len(missing) { + failnumber = missing[failindex].NumberU64() + } else { + failnumber = missing[0].NumberU64() + } + return fmt.Errorf("invalid block %d: %v", failnumber, err) } } return nil From 0fb1be09303ef509d7824f0b9415a3645149437a Mon Sep 17 00:00:00 2001 From: ucwong Date: Tue, 9 May 2023 13:29:32 -0600 Subject: [PATCH 102/988] event: initialize maps with known size (#27233) event: initialize maps with known size --- event/event.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/event/event.go b/event/event.go index ce1b03d523..25a2c2e457 100644 --- a/event/event.go +++ b/event/event.go @@ -61,7 +61,7 @@ func (mux *TypeMux) Subscribe(types ...interface{}) *TypeMuxSubscription { close(sub.postC) } else { if mux.subm == nil { - mux.subm = make(map[reflect.Type][]*TypeMuxSubscription) + mux.subm = make(map[reflect.Type][]*TypeMuxSubscription, len(types)) } for _, t := range types { rtyp := reflect.TypeOf(t) From a742943c78d38e3c5e987bf1417df51e12726055 Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Wed, 10 May 2023 17:42:55 +0900 Subject: [PATCH 103/988] node: fix typos in comments (#27236) --- node/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/node/config.go b/node/config.go index 35115eaa85..1765811e8c 100644 --- a/node/config.go +++ b/node/config.go @@ -75,7 +75,7 @@ type Config struct { // is created by New and destroyed when the node is stopped. KeyStoreDir string `toml:",omitempty"` - // ExternalSigner specifies an external URI for a clef-type signer + // ExternalSigner specifies an external URI for a clef-type signer. ExternalSigner string `toml:",omitempty"` // UseLightweightKDF lowers the memory and CPU requirements of the key store @@ -92,7 +92,7 @@ type Config struct { // USB enables hardware wallet monitoring and connectivity. USB bool `toml:",omitempty"` - // SmartCardDaemonPath is the path to the smartcard daemon's socket + // SmartCardDaemonPath is the path to the smartcard daemon's socket. SmartCardDaemonPath string `toml:",omitempty"` // IPCPath is the requested location to place the IPC endpoint. If the path is @@ -396,7 +396,7 @@ func (c *Config) NodeKey() *ecdsa.PrivateKey { return key } -// CheckLegacyFiles inspects the datadir for signs of legacy static-nodes +// checkLegacyFiles inspects the datadir for signs of legacy static-nodes // and trusted-nodes files. If they exist it raises an error. func (c *Config) checkLegacyFiles() { c.checkLegacyFile(c.ResolvePath(datadirStaticNodes)) From ae7db289b836a22e0df52d35b02902966fe11443 Mon Sep 17 00:00:00 2001 From: ucwong Date: Wed, 10 May 2023 02:52:26 -0600 Subject: [PATCH 104/988] p2p: initialize maps with known size (#27229) --- p2p/dial_test.go | 2 +- p2p/discover/table_util_test.go | 2 +- p2p/discover/v5_udp_test.go | 2 +- p2p/dnsdisc/client_test.go | 2 +- p2p/enode/iter_test.go | 4 ++-- p2p/enode/nodedb_test.go | 4 ++-- p2p/msgrate/msgrate.go | 2 +- p2p/netutil/iptrack.go | 2 +- p2p/nodestate/nodestate.go | 4 ++-- p2p/peer.go | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/p2p/dial_test.go b/p2p/dial_test.go index cd8dedff1c..13908f11ea 100644 --- a/p2p/dial_test.go +++ b/p2p/dial_test.go @@ -584,7 +584,7 @@ func (d *dialTestDialer) Dial(ctx context.Context, n *enode.Node) (net.Conn, err // waitForDials waits for calls to Dial with the given nodes as argument. // Those calls will be held blocking until completeDials is called with the same nodes. func (d *dialTestDialer) waitForDials(nodes []*enode.Node) error { - waitset := make(map[enode.ID]*enode.Node) + waitset := make(map[enode.ID]*enode.Node, len(nodes)) for _, n := range nodes { waitset[n.ID()] = n } diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index 217905eb73..527afbb77e 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -175,7 +175,7 @@ func (t *pingRecorder) RequestENR(n *enode.Node) (*enode.Node, error) { } func hasDuplicates(slice []*node) bool { - seen := make(map[enode.ID]bool) + seen := make(map[enode.ID]bool, len(slice)) for i, e := range slice { if e == nil { panic(fmt.Sprintf("nil *Node at %d", i)) diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 9aa5f975e8..392a95b61e 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -198,7 +198,7 @@ func TestUDPv5_findnodeHandling(t *testing.T) { } func (test *udpV5Test) expectNodes(wantReqID []byte, wantTotal uint8, wantNodes []*enode.Node) { - nodeSet := make(map[enode.ID]*enr.Record) + nodeSet := make(map[enode.ID]*enr.Record, len(wantNodes)) for _, n := range wantNodes { nodeSet[n.ID()] = n.Record() } diff --git a/p2p/dnsdisc/client_test.go b/p2p/dnsdisc/client_test.go index 6de7fead22..abc35ddbd3 100644 --- a/p2p/dnsdisc/client_test.go +++ b/p2p/dnsdisc/client_test.go @@ -439,7 +439,7 @@ func testNodes(keys []*ecdsa.PrivateKey) []*enode.Node { type mapResolver map[string]string func newMapResolver(maps ...map[string]string) mapResolver { - mr := make(mapResolver) + mr := make(mapResolver, len(maps)) for _, m := range maps { mr.add(m) } diff --git a/p2p/enode/iter_test.go b/p2p/enode/iter_test.go index 5014346af4..b736ed450a 100644 --- a/p2p/enode/iter_test.go +++ b/p2p/enode/iter_test.go @@ -75,7 +75,7 @@ func checkNodes(t *testing.T, nodes []*Node, wantLen int) { t.Errorf("slice has %d nodes, want %d", len(nodes), wantLen) return } - seen := make(map[ID]bool) + seen := make(map[ID]bool, len(nodes)) for i, e := range nodes { if e == nil { t.Errorf("nil node at index %d", i) @@ -231,7 +231,7 @@ func testMixerClose(t *testing.T) { } func idPrefixDistribution(nodes []*Node) map[uint32]int { - d := make(map[uint32]int) + d := make(map[uint32]int, len(nodes)) for _, node := range nodes { id := node.ID() d[binary.BigEndian.Uint32(id[:4])]++ diff --git a/p2p/enode/nodedb_test.go b/p2p/enode/nodedb_test.go index ba3f8c762b..38764f31b1 100644 --- a/p2p/enode/nodedb_test.go +++ b/p2p/enode/nodedb_test.go @@ -273,11 +273,11 @@ func testSeedQuery() error { // Retrieve the entire batch and check for duplicates seeds := db.QuerySeeds(len(nodeDBSeedQueryNodes)*2, time.Hour) - have := make(map[ID]struct{}) + have := make(map[ID]struct{}, len(seeds)) for _, seed := range seeds { have[seed.ID()] = struct{}{} } - want := make(map[ID]struct{}) + want := make(map[ID]struct{}, len(nodeDBSeedQueryNodes[1:])) for _, seed := range nodeDBSeedQueryNodes[1:] { want[seed.node.ID()] = struct{}{} } diff --git a/p2p/msgrate/msgrate.go b/p2p/msgrate/msgrate.go index ff29c9620a..4f08792242 100644 --- a/p2p/msgrate/msgrate.go +++ b/p2p/msgrate/msgrate.go @@ -329,7 +329,7 @@ func (t *Trackers) MeanCapacities() map[uint64]float64 { // meanCapacities is the internal lockless version of MeanCapacities used for // debug logging. func (t *Trackers) meanCapacities() map[uint64]float64 { - capacities := make(map[uint64]float64) + capacities := make(map[uint64]float64, len(t.trackers)) for _, tt := range t.trackers { tt.lock.RLock() for key, val := range tt.capacity { diff --git a/p2p/netutil/iptrack.go b/p2p/netutil/iptrack.go index b9cbd5e1ca..a070499e19 100644 --- a/p2p/netutil/iptrack.go +++ b/p2p/netutil/iptrack.go @@ -78,7 +78,7 @@ func (it *IPTracker) PredictEndpoint() string { it.gcStatements(it.clock.Now()) // The current strategy is simple: find the endpoint with most statements. - counts := make(map[string]int) + counts := make(map[string]int, len(it.statements)) maxcount, max := 0, "" for _, s := range it.statements { c := counts[s.endpoint] + 1 diff --git a/p2p/nodestate/nodestate.go b/p2p/nodestate/nodestate.go index 3adcd6c463..1e1757559c 100644 --- a/p2p/nodestate/nodestate.go +++ b/p2p/nodestate/nodestate.go @@ -333,7 +333,7 @@ func NewNodeStateMachine(db ethdb.KeyValueStore, dbKey []byte, clock mclock.Cloc fields: make([]*fieldInfo, len(setup.fields)), } ns.opWait = sync.NewCond(&ns.lock) - stateNameMap := make(map[string]int) + stateNameMap := make(map[string]int, len(setup.flags)) for index, flag := range setup.flags { if _, ok := stateNameMap[flag.name]; ok { panic("Node state flag name collision: " + flag.name) @@ -343,7 +343,7 @@ func NewNodeStateMachine(db ethdb.KeyValueStore, dbKey []byte, clock mclock.Cloc ns.saveFlags |= bitMask(1) << uint(index) } } - fieldNameMap := make(map[string]int) + fieldNameMap := make(map[string]int, len(setup.fields)) for index, field := range setup.fields { if _, ok := fieldNameMap[field.name]; ok { panic("Node field name collision: " + field.name) diff --git a/p2p/peer.go b/p2p/peer.go index 469a1b7974..a4b22fb6d4 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -510,7 +510,7 @@ func (p *Peer) Info() *PeerInfo { ID: p.ID().String(), Name: p.Fullname(), Caps: caps, - Protocols: make(map[string]interface{}), + Protocols: make(map[string]interface{}, len(p.running)), } if p.Node().Seq() > 0 { info.ENR = p.Node().String() From 2169fa343ae0c769fd5a757d5d15bc2cb1d52570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 10 May 2023 14:54:14 +0300 Subject: [PATCH 105/988] crypto/kzg4844: pull in the C and Go libs for KZG cryptography (#27155) * cryto/kzg4844: pull in the C and Go libs for KZG cryptography * go.mod: pull in the KZG libraries * crypto/kzg4844: add basic becnhmarks for ballpark numbers * cmd, crypto: integrate both CKZG and GoKZG all the time, add flag * cmd/utils, crypto/kzg4844: run library init on startup * crypto/kzg4844: make linter happy * crypto/kzg4844: push missing file * crypto/kzg4844: fully disable CKZG but leave in the sources * build, crypto/kzg4844, internal: link CKZG by default and with portable mode * crypto/kzg4844: drop verifying the trusted setup in gokzg * internal/build: yolo until it works? * cmd/utils: make flag description friendlier Co-authored-by: Martin Holst Swende * crypto/ckzg: no need for double availability check * build: tiny flag cleanup nitpick --------- Co-authored-by: Martin Holst Swende --- build/ci.go | 9 +- cmd/geth/main.go | 1 + cmd/utils/flags.go | 16 +- crypto/kzg4844/kzg4844.go | 110 + crypto/kzg4844/kzg4844_ckzg_cgo.go | 119 + crypto/kzg4844/kzg4844_ckzg_nocgo.go | 62 + crypto/kzg4844/kzg4844_gokzg.go | 98 + crypto/kzg4844/kzg4844_test.go | 187 + crypto/kzg4844/trusted_setup.json | 8265 ++++++++++++++++++++++++++ go.mod | 11 +- go.sum | 24 +- internal/build/gotool.go | 27 +- 12 files changed, 8890 insertions(+), 39 deletions(-) create mode 100644 crypto/kzg4844/kzg4844.go create mode 100644 crypto/kzg4844/kzg4844_ckzg_cgo.go create mode 100644 crypto/kzg4844/kzg4844_ckzg_nocgo.go create mode 100644 crypto/kzg4844/kzg4844_gokzg.go create mode 100644 crypto/kzg4844/kzg4844_test.go create mode 100644 crypto/kzg4844/trusted_setup.json diff --git a/build/ci.go b/build/ci.go index eab011752d..7933724d74 100644 --- a/build/ci.go +++ b/build/ci.go @@ -207,9 +207,9 @@ func doInstall(cmdline []string) { csdb := build.MustLoadChecksums("build/checksums.txt") tc.Root = build.DownloadGo(csdb, dlgoVersion) } - - // Disable CLI markdown doc generation in release builds. - buildTags := []string{"urfave_cli_no_docs"} + // Disable CLI markdown doc generation in release builds and enable linking + // the CKZG library since we can make it portable here. + buildTags := []string{"urfave_cli_no_docs", "ckzg"} // Configure the build. env := build.Env() @@ -221,7 +221,6 @@ func doInstall(cmdline []string) { if env.CI && runtime.GOARCH == "arm64" { gobuild.Args = append(gobuild.Args, "-p", "1") } - // We use -trimpath to avoid leaking local paths into the built executables. gobuild.Args = append(gobuild.Args, "-trimpath") @@ -299,7 +298,7 @@ func doTest(cmdline []string) { csdb := build.MustLoadChecksums("build/checksums.txt") tc.Root = build.DownloadGo(csdb, dlgoVersion) } - gotest := tc.Go("test") + gotest := tc.Go("test", "-tags=ckzg") // Test a single package at a time. CI builders are slow // and some tests run into timeouts under load. diff --git a/cmd/geth/main.go b/cmd/geth/main.go index bac74f2a6e..b4a7b5fa95 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -107,6 +107,7 @@ var ( utils.CachePreimagesFlag, utils.CacheLogSizeFlag, utils.FDLimitFlag, + utils.CryptoKZGFlag, utils.ListenPortFlag, utils.DiscoveryPortFlag, utils.MaxPeersFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 300d39b94a..b67671e03b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -45,6 +45,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/eth" ethcatalyst "github.com/ethereum/go-ethereum/eth/catalyst" "github.com/ethereum/go-ethereum/eth/downloader" @@ -454,6 +455,12 @@ var ( Usage: "Raise the open file descriptor resource limit (default = system fd limit)", Category: flags.PerfCategory, } + CryptoKZGFlag = &cli.StringFlag{ + Name: "crypto.kzg", + Usage: "KZG library implementation to use; gokzg (recommended) or ckzg", + Value: "gokzg", + Category: flags.PerfCategory, + } // Miner settings MiningEnabledFlag = &cli.BoolFlag{ @@ -1747,7 +1754,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { cfg.EthDiscoveryURLs = SplitAndTrim(urls) } } - // Override any default configs for hard coded networks. switch { case ctx.Bool(MainnetFlag.Name): @@ -1857,6 +1863,14 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash) } } + // Set any dangling config values + if ctx.String(CryptoKZGFlag.Name) != "gokzg" && ctx.String(CryptoKZGFlag.Name) != "ckzg" { + Fatalf("--%s flag must be 'gokzg' or 'ckzg'", CryptoKZGFlag.Name) + } + log.Info("Initializing the KZG library", "backend", ctx.String(CryptoKZGFlag.Name)) + if err := kzg4844.UseCKZG(ctx.String(CryptoKZGFlag.Name) == "ckzg"); err != nil { + Fatalf("Failed to set KZG library implementation to %s: %v", ctx.String(CryptoKZGFlag.Name), err) + } } // SetDNSDiscoveryDefaults configures DNS discovery with the given URL if diff --git a/crypto/kzg4844/kzg4844.go b/crypto/kzg4844/kzg4844.go new file mode 100644 index 0000000000..d54376965f --- /dev/null +++ b/crypto/kzg4844/kzg4844.go @@ -0,0 +1,110 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package kzg4844 implements the KZG crypto for EIP-4844. +package kzg4844 + +import ( + "embed" + "errors" + "sync/atomic" +) + +//go:embed trusted_setup.json +var content embed.FS + +// Blob represents a 4844 data blob. +type Blob [131072]byte + +// Commitment is a serialized commitment to a polynomial. +type Commitment [48]byte + +// Proof is a serialized commitment to the quotient polynomial. +type Proof [48]byte + +// Point is a BLS field element. +type Point [32]byte + +// Claim is a claimed evaluation value in a specific point. +type Claim [32]byte + +// useCKZG controls whether the cryptography should use the Go or C backend. +var useCKZG atomic.Bool + +// UseCKZG can be called to switch the default Go implementation of KZG to the C +// library if fo some reason the user wishes to do so (e.g. consensus bug in one +// or the other). +func UseCKZG(use bool) error { + if use && !ckzgAvailable { + return errors.New("CKZG unavailable on your platform") + } + useCKZG.Store(use) + + // Initializing the library can take 2-4 seconds - and can potentially crash + // on CKZG and non-ADX CPUs - so might as well so it now and don't wait until + // a crpyto operation is actually needed live. + if use { + ckzgIniter.Do(ckzgInit) + } else { + gokzgIniter.Do(gokzgInit) + } + return nil +} + +// BlobToCommitment creates a small commitment out of a data blob. +func BlobToCommitment(blob Blob) (Commitment, error) { + if useCKZG.Load() { + return ckzgBlobToCommitment(blob) + } + return gokzgBlobToCommitment(blob) +} + +// ComputeProof computes the KZG proof at the given point for the polynomial +// represented by the blob. +func ComputeProof(blob Blob, point Point) (Proof, Claim, error) { + if useCKZG.Load() { + return ckzgComputeProof(blob, point) + } + return gokzgComputeProof(blob, point) +} + +// VerifyProof verifies the KZG proof that the polynomial represented by the blob +// evaluated at the given point is the claimed value. +func VerifyProof(commitment Commitment, point Point, claim Claim, proof Proof) error { + if useCKZG.Load() { + return ckzgVerifyProof(commitment, point, claim, proof) + } + return gokzgVerifyProof(commitment, point, claim, proof) +} + +// ComputeBlobProof returns the KZG proof that is used to verify the blob against +// the commitment. +// +// This method does not verify that the commitment is correct with respect to blob. +func ComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { + if useCKZG.Load() { + return ckzgComputeBlobProof(blob, commitment) + } + return gokzgComputeBlobProof(blob, commitment) +} + +// VerifyBlobProof verifies that the blob data corresponds to the provided commitment. +func VerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error { + if useCKZG.Load() { + return ckzgVerifyBlobProof(blob, commitment, proof) + } + return gokzgVerifyBlobProof(blob, commitment, proof) +} diff --git a/crypto/kzg4844/kzg4844_ckzg_cgo.go b/crypto/kzg4844/kzg4844_ckzg_cgo.go new file mode 100644 index 0000000000..76ff0a45cc --- /dev/null +++ b/crypto/kzg4844/kzg4844_ckzg_cgo.go @@ -0,0 +1,119 @@ +// Copyright 2023 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 . + +//go:build ckzg && !nacl && !js && cgo && !gofuzz + +package kzg4844 + +import ( + "encoding/json" + "errors" + "sync" + + gokzg4844 "github.com/crate-crypto/go-kzg-4844" + ckzg4844 "github.com/ethereum/c-kzg-4844/bindings/go" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +// ckzgAvailable signals whether the library was compiled into Geth. +const ckzgAvailable = true + +// ckzgIniter ensures that we initialize the KZG library once before using it. +var ckzgIniter sync.Once + +// ckzgInit initializes the KZG library with the provided trusted setup. +func ckzgInit() { + config, err := content.ReadFile("trusted_setup.json") + if err != nil { + panic(err) + } + params := new(gokzg4844.JSONTrustedSetup) + if err = json.Unmarshal(config, params); err != nil { + panic(err) + } + if err = gokzg4844.CheckTrustedSetupIsWellFormed(params); err != nil { + panic(err) + } + g1s := make([]byte, len(params.SetupG1)*(len(params.SetupG1[0])-2)/2) + for i, g1 := range params.SetupG1 { + copy(g1s[i*(len(g1)-2)/2:], hexutil.MustDecode(g1)) + } + g2s := make([]byte, len(params.SetupG2)*(len(params.SetupG2[0])-2)/2) + for i, g2 := range params.SetupG2 { + copy(g2s[i*(len(g2)-2)/2:], hexutil.MustDecode(g2)) + } + if err = ckzg4844.LoadTrustedSetup(g1s, g2s); err != nil { + panic(err) + } +} + +// ckzgBlobToCommitment creates a small commitment out of a data blob. +func ckzgBlobToCommitment(blob Blob) (Commitment, error) { + ckzgIniter.Do(ckzgInit) + + commitment, err := ckzg4844.BlobToKZGCommitment((ckzg4844.Blob)(blob)) + if err != nil { + return Commitment{}, err + } + return (Commitment)(commitment), nil +} + +// ckzgComputeProof computes the KZG proof at the given point for the polynomial +// represented by the blob. +func ckzgComputeProof(blob Blob, point Point) (Proof, Claim, error) { + proof, claim, err := ckzg4844.ComputeKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes32)(point)) + if err != nil { + return Proof{}, Claim{}, err + } + return (Proof)(proof), (Claim)(claim), nil +} + +// ckzgVerifyProof verifies the KZG proof that the polynomial represented by the blob +// evaluated at the given point is the claimed value. +func ckzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Proof) error { + valid, err := ckzg4844.VerifyKZGProof((ckzg4844.Bytes48)(commitment), (ckzg4844.Bytes32)(point), (ckzg4844.Bytes32)(claim), (ckzg4844.Bytes48)(proof)) + if err != nil { + return err + } + if !valid { + return errors.New("invalid proof") + } + return nil +} + +// ckzgComputeBlobProof returns the KZG proof that is used to verify the blob against +// the commitment. +// +// This method does not verify that the commitment is correct with respect to blob. +func ckzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { + proof, err := ckzg4844.ComputeBlobKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment)) + if err != nil { + return Proof{}, err + } + return (Proof)(proof), nil +} + +// ckzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment. +func ckzgVerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error { + valid, err := ckzg4844.VerifyBlobKZGProof((ckzg4844.Blob)(blob), (ckzg4844.Bytes48)(commitment), (ckzg4844.Bytes48)(proof)) + if err != nil { + return err + } + if !valid { + return errors.New("invalid proof") + } + return nil +} diff --git a/crypto/kzg4844/kzg4844_ckzg_nocgo.go b/crypto/kzg4844/kzg4844_ckzg_nocgo.go new file mode 100644 index 0000000000..ed840c75bb --- /dev/null +++ b/crypto/kzg4844/kzg4844_ckzg_nocgo.go @@ -0,0 +1,62 @@ +// Copyright 2023 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 . + +//go:build !ckzg || nacl || js || !cgo || gofuzz + +package kzg4844 + +import "sync" + +// ckzgAvailable signals whether the library was compiled into Geth. +const ckzgAvailable = false + +// ckzgIniter ensures that we initialize the KZG library once before using it. +var ckzgIniter sync.Once + +// ckzgInit initializes the KZG library with the provided trusted setup. +func ckzgInit() { + panic("unsupported platform") +} + +// ckzgBlobToCommitment creates a small commitment out of a data blob. +func ckzgBlobToCommitment(blob Blob) (Commitment, error) { + panic("unsupported platform") +} + +// ckzgComputeProof computes the KZG proof at the given point for the polynomial +// represented by the blob. +func ckzgComputeProof(blob Blob, point Point) (Proof, Claim, error) { + panic("unsupported platform") +} + +// ckzgVerifyProof verifies the KZG proof that the polynomial represented by the blob +// evaluated at the given point is the claimed value. +func ckzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Proof) error { + panic("unsupported platform") +} + +// ckzgComputeBlobProof returns the KZG proof that is used to verify the blob against +// the commitment. +// +// This method does not verify that the commitment is correct with respect to blob. +func ckzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { + panic("unsupported platform") +} + +// ckzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment. +func ckzgVerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error { + panic("unsupported platform") +} diff --git a/crypto/kzg4844/kzg4844_gokzg.go b/crypto/kzg4844/kzg4844_gokzg.go new file mode 100644 index 0000000000..3f03bb5273 --- /dev/null +++ b/crypto/kzg4844/kzg4844_gokzg.go @@ -0,0 +1,98 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package kzg4844 + +import ( + "encoding/json" + "sync" + + gokzg4844 "github.com/crate-crypto/go-kzg-4844" +) + +// context is the crypto primitive pre-seeded with the trusted setup parameters. +var context *gokzg4844.Context + +// gokzgIniter ensures that we initialize the KZG library once before using it. +var gokzgIniter sync.Once + +// gokzgInit initializes the KZG library with the provided trusted setup. +func gokzgInit() { + config, err := content.ReadFile("trusted_setup.json") + if err != nil { + panic(err) + } + params := new(gokzg4844.JSONTrustedSetup) + if err = json.Unmarshal(config, params); err != nil { + panic(err) + } + context, err = gokzg4844.NewContext4096(params) + if err != nil { + panic(err) + } +} + +// gokzgBlobToCommitment creates a small commitment out of a data blob. +func gokzgBlobToCommitment(blob Blob) (Commitment, error) { + gokzgIniter.Do(gokzgInit) + + commitment, err := context.BlobToKZGCommitment((gokzg4844.Blob)(blob), 0) + if err != nil { + return Commitment{}, err + } + return (Commitment)(commitment), nil +} + +// gokzgComputeProof computes the KZG proof at the given point for the polynomial +// represented by the blob. +func gokzgComputeProof(blob Blob, point Point) (Proof, Claim, error) { + gokzgIniter.Do(gokzgInit) + + proof, claim, err := context.ComputeKZGProof((gokzg4844.Blob)(blob), (gokzg4844.Scalar)(point), 0) + if err != nil { + return Proof{}, Claim{}, err + } + return (Proof)(proof), (Claim)(claim), nil +} + +// gokzgVerifyProof verifies the KZG proof that the polynomial represented by the blob +// evaluated at the given point is the claimed value. +func gokzgVerifyProof(commitment Commitment, point Point, claim Claim, proof Proof) error { + gokzgIniter.Do(gokzgInit) + + return context.VerifyKZGProof((gokzg4844.KZGCommitment)(commitment), (gokzg4844.Scalar)(point), (gokzg4844.Scalar)(claim), (gokzg4844.KZGProof)(proof)) +} + +// gokzgComputeBlobProof returns the KZG proof that is used to verify the blob against +// the commitment. +// +// This method does not verify that the commitment is correct with respect to blob. +func gokzgComputeBlobProof(blob Blob, commitment Commitment) (Proof, error) { + gokzgIniter.Do(gokzgInit) + + proof, err := context.ComputeBlobKZGProof((gokzg4844.Blob)(blob), (gokzg4844.KZGCommitment)(commitment), 0) + if err != nil { + return Proof{}, err + } + return (Proof)(proof), nil +} + +// gokzgVerifyBlobProof verifies that the blob data corresponds to the provided commitment. +func gokzgVerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error { + gokzgIniter.Do(gokzgInit) + + return context.VerifyBlobKZGProof((gokzg4844.Blob)(blob), (gokzg4844.KZGCommitment)(commitment), (gokzg4844.KZGProof)(proof)) +} diff --git a/crypto/kzg4844/kzg4844_test.go b/crypto/kzg4844/kzg4844_test.go new file mode 100644 index 0000000000..0d35667a9c --- /dev/null +++ b/crypto/kzg4844/kzg4844_test.go @@ -0,0 +1,187 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package kzg4844 + +import ( + "crypto/rand" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + gokzg4844 "github.com/crate-crypto/go-kzg-4844" +) + +func randFieldElement() [32]byte { + bytes := make([]byte, 32) + _, err := rand.Read(bytes) + if err != nil { + panic("failed to get random field element") + } + var r fr.Element + r.SetBytes(bytes) + + return gokzg4844.SerializeScalar(r) +} + +func randBlob() Blob { + var blob Blob + for i := 0; i < len(blob); i += gokzg4844.SerializedScalarSize { + fieldElementBytes := randFieldElement() + copy(blob[i:i+gokzg4844.SerializedScalarSize], fieldElementBytes[:]) + } + return blob +} + +func TestCKZGWithPoint(t *testing.T) { testKZGWithPoint(t, true) } +func TestGoKZGWithPoint(t *testing.T) { testKZGWithPoint(t, false) } + +func testKZGWithPoint(t *testing.T, ckzg bool) { + if ckzg && !ckzgAvailable { + t.Skip("CKZG unavailable in this test build") + } + defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load()) + useCKZG.Store(ckzg) + + blob := randBlob() + + commitment, err := BlobToCommitment(blob) + if err != nil { + t.Fatalf("failed to create KZG commitment from blob: %v", err) + } + point := randFieldElement() + proof, claim, err := ComputeProof(blob, point) + if err != nil { + t.Fatalf("failed to create KZG proof at point: %v", err) + } + if err := VerifyProof(commitment, point, claim, proof); err != nil { + t.Fatalf("failed to verify KZG proof at point: %v", err) + } +} + +func TestCKZGWithBlob(t *testing.T) { testKZGWithBlob(t, true) } +func TestGoKZGWithBlob(t *testing.T) { testKZGWithBlob(t, false) } + +func testKZGWithBlob(t *testing.T, ckzg bool) { + if ckzg && !ckzgAvailable { + t.Skip("CKZG unavailable in this test build") + } + defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load()) + useCKZG.Store(ckzg) + + blob := randBlob() + + commitment, err := BlobToCommitment(blob) + if err != nil { + t.Fatalf("failed to create KZG commitment from blob: %v", err) + } + proof, err := ComputeBlobProof(blob, commitment) + if err != nil { + t.Fatalf("failed to create KZG proof for blob: %v", err) + } + if err := VerifyBlobProof(blob, commitment, proof); err != nil { + t.Fatalf("failed to verify KZG proof for blob: %v", err) + } +} + +func BenchmarkCKZGBlobToCommitment(b *testing.B) { benchmarkBlobToCommitment(b, true) } +func BenchmarkGoKZGBlobToCommitment(b *testing.B) { benchmarkBlobToCommitment(b, false) } +func benchmarkBlobToCommitment(b *testing.B, ckzg bool) { + if ckzg && !ckzgAvailable { + b.Skip("CKZG unavailable in this test build") + } + defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load()) + useCKZG.Store(ckzg) + + blob := randBlob() + for i := 0; i < b.N; i++ { + BlobToCommitment(blob) + } +} + +func BenchmarkCKZGComputeProof(b *testing.B) { benchmarkComputeProof(b, true) } +func BenchmarkGoKZGComputeProof(b *testing.B) { benchmarkComputeProof(b, false) } +func benchmarkComputeProof(b *testing.B, ckzg bool) { + if ckzg && !ckzgAvailable { + b.Skip("CKZG unavailable in this test build") + } + defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load()) + useCKZG.Store(ckzg) + + var ( + blob = randBlob() + point = randFieldElement() + ) + for i := 0; i < b.N; i++ { + ComputeProof(blob, point) + } +} + +func BenchmarkCKZGVerifyProof(b *testing.B) { benchmarkVerifyProof(b, true) } +func BenchmarkGoKZGVerifyProof(b *testing.B) { benchmarkVerifyProof(b, false) } +func benchmarkVerifyProof(b *testing.B, ckzg bool) { + if ckzg && !ckzgAvailable { + b.Skip("CKZG unavailable in this test build") + } + defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load()) + useCKZG.Store(ckzg) + + var ( + blob = randBlob() + point = randFieldElement() + commitment, _ = BlobToCommitment(blob) + proof, claim, _ = ComputeProof(blob, point) + ) + for i := 0; i < b.N; i++ { + VerifyProof(commitment, point, claim, proof) + } +} + +func BenchmarkCKZGComputeBlobProof(b *testing.B) { benchmarkComputeBlobProof(b, true) } +func BenchmarkGoKZGComputeBlobProof(b *testing.B) { benchmarkComputeBlobProof(b, false) } +func benchmarkComputeBlobProof(b *testing.B, ckzg bool) { + if ckzg && !ckzgAvailable { + b.Skip("CKZG unavailable in this test build") + } + defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load()) + useCKZG.Store(ckzg) + + var ( + blob = randBlob() + commitment, _ = BlobToCommitment(blob) + ) + for i := 0; i < b.N; i++ { + ComputeBlobProof(blob, commitment) + } +} + +func BenchmarkCKZGVerifyBlobProof(b *testing.B) { benchmarkVerifyBlobProof(b, true) } +func BenchmarkGoKZGVerifyBlobProof(b *testing.B) { benchmarkVerifyBlobProof(b, false) } +func benchmarkVerifyBlobProof(b *testing.B, ckzg bool) { + if ckzg && !ckzgAvailable { + b.Skip("CKZG unavailable in this test build") + } + defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load()) + useCKZG.Store(ckzg) + + var ( + blob = randBlob() + commitment, _ = BlobToCommitment(blob) + proof, _ = ComputeBlobProof(blob, commitment) + ) + for i := 0; i < b.N; i++ { + VerifyBlobProof(blob, commitment, proof) + } +} diff --git a/crypto/kzg4844/trusted_setup.json b/crypto/kzg4844/trusted_setup.json new file mode 100644 index 0000000000..37108fee3e --- /dev/null +++ b/crypto/kzg4844/trusted_setup.json @@ -0,0 +1,8265 @@ +{ + "setup_G1": [ + "0x97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "0x854262641262cb9e056a8512808ea6864d903dbcad713fd6da8dddfa5ce40d85612c912063ace060ed8c4bf005bab839", + "0x86f708eee5ae0cf40be36993e760d9cb3b2371f22db3209947c5d21ea68e55186b30871c50bf11ef29e5248bf42d5678", + "0x94f9c0bafb23cbbf34a93a64243e3e0f934b57593651f3464de7dc174468123d9698f1b9dfa22bb5b6eb96eae002f29f", + "0x82b8775b874067bdd4479ac237f8d56036a742c17901354caaf38bf8c70e696650fbec76f0cd941ed8c658f44ea359ff", + "0xa7ce299c79c7d7e4f1adecd754c5aff8a720728ab27f5737b7b399f72724407ac54965088596375b8c876665ed8e4ff1", + "0x81ca4c808a76a6f217f8b0540ff400199295da69b2587b7be6aeb56447fa4fac08d154a27c4aa6082bc40660078d36e9", + "0xa70bad5311c97f1f3fea5d3375da1a11ba948aca41609ea28666dd343e07af766834e1256dc685ac1dcd915073250864", + "0xa91c2911a658ba79f56abe30716a3398387630e785b351b07344022a04b2f5c90de5573bd6e8048fe8878dde19336c5b", + "0xa8c560283fce9813bcbaddfb78cff93efcbc39b33025cfad94ebd40942a9fa605d2a947dc3a1f03c2e454075892e96bf", + "0xaa14f07fbd2c1ce7bd995e335c69b5f675ea573517c1834e787b30ab4fa10aecc62ecc5e617ac8a539af1aff114dc9ec", + "0x87f03429aff126b7c5a918423da278e17b5f48a4cdd6d34dba77a75f4f99e26a417e65d6a8579bcb2eaaf1d4d8c64dce", + "0xb1ac81ba91ede78315f712d524e9d821a152203f04141ba77f4e481ad5881473dff14a71788ce941f0905b429e7ee5b2", + "0x8f5c2af611ddfa3edf7e442d00e56a24d615bac848c05070c908c741ba18b67eb2e82e6651c9b3c70fb8edbf051810c4", + "0xaa4115b19221e4d17cc335d4f9b0aad22df566231f2286d550e97ff2875cbc419edfa189c4ecb24001123b95c6aaa2da", + "0xb363ba913969df0debd4e2712ae6e9177ce82e169ce7e0ff1d7616ef8e352aff3efb40fffbf7bff1b21cb8a33e19b455", + "0xb1013d778727d20466778cea47e1bf56a77168a8ce1b33bb1265f66438ab2bf4a7df4f4142b8681f2993ea9baf798d17", + "0x83b7250ee17d8529207db97b73c1c4a92ac076951a577ce2fe3a2cd633b461c1820c139ab36a895a5962e143c6198386", + "0x86d180bd2f0a4919764e6f4e846ec0d5ebe44060ec1e529ed15101d7e531bf1b8f9412916ea5aeb93b37b2d7c6bfb408", + "0x827451462c79d74b504c01bda199481b3c70416f66a95b2216686ca4d48da48932b0d323d0cd630a1e86e8033e832e5f", + "0xb789d217cb12c334fedff0ae01f85b96e968fb98761755d1ba3ee17934e8fbd83172225df7c0c6cb99432a30a0ef8c24", + "0xb730e5412dfbd646b0d2fe084a1a32eb5596c3fe8a5bc0f430151804f9e67f05f70b522e9aef08082b0afdc652a1d213", + "0x9987653bacd9bc1659b17f6964aec06ea63b787813d4601bee0479706aed5595ac82c87ed4f96f0cd30c19e1d9510a91", + "0x9506a9ba38f1d26c35a17c7e2554e28eb347a19cef523846a2559fb80fb40306b2f85bdc2c9fb98c2267df21c1ee3589", + "0x98dda58de74c0cdaef97b2826b4a9d53c9e9ea592dc0a755ccf5b3fbc1264979578563f5979aaa246e679918053c5f83", + "0xb00aaa16841ab53883af481e2f925050f5f7bf7d8088bc696f55f30593bdbbaf434f5d2b46095ed097b6cdb96c8fbc3b", + "0xb463d656480f89335d3a840a7b9398877003985388871b148ba708c60f9857c7585ef17c8b2ae67fbb191c04ad61e692", + "0x80af54f3d0584126e23635276d650292baf7e3e12bb06468708107bcd80937d36575721ee7472c5f085ffa71dbf438ad", + "0x94ccb8ade84e834685110c96908b42e10d2184208f434d7f98d96cc158e0c0c95135979600e5e9f465d5846b0bb3c787", + "0x8e13674b00c633d7cceb4f6ecd61e4f99420d6cccf9db5e81f8c90f6c661bc76e10939b83b56c225fce8565f525d4fa4", + "0xa46a15b2e671c1a1df2490768dec1093caf537e1a21fbc11ff8ba8b21b9f2be8d50257027d9357df20d9fbb1307d7249", + "0xb8ed532d48b0533a3084d7a5eea7b401255c5825e9a1b80ed81fd530cd69e347d152b1ad8a899acff7d68e0103bbfbde", + "0xad6b7df980ebaa24177d830c4aa522d6179a9a489257f60ee6604cccc2cbe90fb1f72aa9d5bee0d3a88f73b179485f56", + "0xa56855e9fcf62ceef3043991a93ec24f8f6b5667ef5fb7ad1771249ece68a73580ec3cf3e58a009ca4650c01241ad172", + "0xab2f25517d4b0b33d317eb78d091d3c3f98dc352b8a3e4650f7005f9327129e23d95f38eaeda5e9b51c50a31d20a4c20", + "0xa2d4071385b8a421da86f39739eaadcdea5685466feb6ac083cba0ea4c71dbbdf655032097276d703f9a77a4ca6fab03", + "0xa8681d7c258984f01e92e92c95738692b7bbd59c3a802adf4dda8d34add69590b080391c09e98e3b75c085c9f191e5e5", + "0x97685643da6c07b5e5fe91393122813ba11c8ef3dbd43a03b3a22a7a1603201fd516c1929418eafb14039270694c239a", + "0xa7bb3b85d6101e4fb0bcf540f52041cdb3e819d517465e342b832f0e91346a9a18bdb38845ea4d2b71ab87ef3bf59f96", + "0x8afc90b7d35336fdcf8f81cd024e921e244520ecfcb5a3994f2bbd595366b68bfa792a8dceb11e1e889b11432c9dad6b", + "0x94d9db7bd04f962d8d6caa3b7aa0f19acbd58a09d35ae187158d77e537d2fc65215f51f1afd62d4ba378e7d176a680f9", + "0xad62d7c01b14b6f97e6084ec9f9d084f106a7ff3d603032e6e34c027cdce4b0fe3c20ac7931f1209439a59c9fede4815", + "0xa5b44a87bd0ada7498e011e495a2818a8694746c4e7dc9d24c0c1096f54be6439e08c1b11c10d7c4bf68fe392000e971", + "0x828626c6609acc599f1bf216e9a4310fc3cb227e0d2e47bfe3360239427c8b0cc300cddf92456a5c36620596a6d37027", + "0x8380f91baac6447dd39886455ec5d99b874ac114a3c6a6ded18fc4ef69c2208ec19732428d8329d200a69f31792b852e", + "0x85a8389b522b0a686234450165514127006baaa3907f6eb29c976522591a542ffb681b3b88c4886814fd7ba3cc8110f7", + "0xb8ae7949ddafad37c0bc4d48325a7cbcd3096fb92c04a027c650a03cc609c7eac250d6a7ba341616bc36f64f1b4c8be4", + "0x8f9b9d2c2ab5c85abe946ed9986e0f304281b277d4d48c7760ea2331b55a9e9a1c4d53a6bdd83fa6294f421ca7431e29", + "0x9464b906ea8bc994b31e03c5f2af2be0724a43293fd42cbd2263b2de75a2ec04832d1100ce62ac2c0708f05fb6bb3ce6", + "0x93d923f6805e7cf972d8387b352d77215724a3e1f5489c4114fcf0b25fc2231963eda872387a1369a02b2e8b888d6427", + "0xaba4af392884eb7283fc5611ddc1cebfecf9477462e951bdae650e311606e129b4424452a3a14717146f954a7fa1cfc3", + "0xa8d0bab694d116e4f21fa19ff8fa4c6fe4061dbb54cbceda8235a7e05159737f87e008beccb90df0bac9c7d572281903", + "0x85743e3ecbac7ae04a81a09c2961397aa4bd20401533cd24d5fc0693cbfbdd2b37bbee6dec2ae5d0a66250d1fcba6944", + "0x80ae913447d7d3f6c54f9cb584aa1603308146daeb3024c8e06ede66ddc97821df09f9591453e9b617b828a02d54c719", + "0x803c2a64bb1c68890b5f1909be3aa180830ee3ef316d3aac38bfd909e2b19d890525e18e8fc2f405ee70ac14f5569b3f", + "0x964d2968724eb790f2f42263fcaaa1869c373b57b3eeee904f8b36f13169f07d5e29cb2b03c74d3a7adb772e91d5a59a", + "0x98a72ce71a57262aa058643a5cd39af64cc9eee88bef7edb003143983f29d87c7f9658b1ec89712f79f6f79dc24a6a45", + "0x91f3479c5d7c76acd2d51883961179efc975c714720187cc9c0aa7aeff71ca1b3e2db5b0a90fd3ff6abf880ebc49fe36", + "0x84312757edd09f111420bfede10ed3c1fa39d1723ddb9bd4d0004c829f0c1eb060e9648fd75f2e5427a67a5b37945a9f", + "0x95edd726cf4042a082d786262304c51d8d5e6a89b1b58e825a11febe5f861d5ce076bdcb2fc0a5dfa95eb2e5b0ffc32e", + "0x96500da38f942871d78fcc46cda1e72944c7888b538b82e2a979f149e5061a20c7602860f82b76510d02efdf3a911f5a", + "0x8ac62eda98bef8864df243696b53651a02a391b898535d2d76ac5a8e9322e0178a290c83f5afe72ffe80ad56183469e3", + "0x8ab2d4427fb6d3da5cf6c59835bdb39fb0c2de82c213b5de77edae3304458ea505511bd98fda95bdbbb9058bd5e92c34", + "0xab67c4344a5080930029ca3b803883ad05ca004ddefb48d5164e71a1c6dd96b27aaec70f62b39bb126ce1a57bbff1453", + "0x86c6bf91686bff714a873a78b0fe449db5317a5172a0a14eb3a96b2997b888d5d3f440de8baa32a6966fe44c3625b014", + "0x81d4f1e9d9e550125290d993a4886d46aac8cb29dbbba1e608aefc3432569c5faf14d8b49fcb485d9b75b649ad6b2fa5", + "0x8594140f253ced6fa98dd90ab4f38899916bcc6f1052572f182e46c00752f3053c390512338a0bc8f8c27a91916b855f", + "0x911284d4fad4999bb37590206d582b9e62ffbb815f414fd829f5b2843e6f0e1a132cd64464c131d5a0f476469a37daa1", + "0x8631a6a4987410982db9c0ba632023a5b613f553b6b8ffd3cfd501b2417523ba8cf06741c62f24b405554bd93e39e626", + "0x906ac35d22794a10a7273fdbca499fd921799b1ce9414643779dce9e1ec37920a5aa2caceb4b70a0eaf56c6032ef1b43", + "0x87374cdb8b7a1ce3c182b31eec465d435e35df782fe3a11f421462b48cf56c6fef2a9cb8ee4fe89672ba7804156d9e3a", + "0xa1f825e0246eee506c8ce40f849a17f75e8a0d6fc3f68b6a4dd431173b4fe997d30dca53005829e4e2422a4077ce35c7", + "0x875ad0379abd9873f6634692e33e9b36353e1a0d15b13d3215eb591244e1f236eb2f8f75274ca7f096179d1714fa68b7", + "0xb87b4e1acc09c5701fd9d75375ab896f178c1b3648fb9a2e2c6e1478778156decc32cd390766f3e80b36beb1e3a6bdec", + "0x836ca80949269eb52395776ac5ceb35b7df717a981c5cbbbb627f73c274aa8164e973a7b01012fa72a02404e878a9918", + "0xa770b13a8f07f74e5a75842b18f2520f6d0be42c865a29dd81bfe485e69a83c40ad10ce229afce276ccc9cb46c54b912", + "0xb4b919322bba2866baeed38bf0e2389d4fe6ab6166597e87dbfee75acac7c2f5ad3bef55293b56957c103d5825051bb5", + "0xb6171f1bbeedb3ee1af368c9c9f327d1dc3e55aeaffbe15f14db8038cd72540b62fe65f44ad0b5486dcf4023f0e91af8", + "0x8e42d0c1e8e8c2ccaf06edcc3c686aed56b8c987f9d68f20937fc088120a410cb92fb0ab45bba5db70b86876015a6b72", + "0x937bcff1af9685fd0d1f6616acf91d97ac9fcb1eb96d49d1c880c9945c1fcf1414f63d59fb78348d08a8546f6e83e407", + "0xa6eeb4873c0531fbcd407c2e702c68e4980fa77c9c032b9913b89031702cfa56f335fc413576c37ac4d523357a841203", + "0xb3962b5eed69cfa27fb94edba74b6cedd7569352ea71861494dd579da96d9743655b6308e54f8a42ee6d7e805c1bc0f9", + "0x8eea944dce7202b033ce734c9e88e82dd760c916e00b217cf1f00bf6ec5f20e21885d5fe95d6138871d167de4c46359e", + "0x81e6c7b356e2703ee333a9dfeb2b54260636422b9bda118e0523a20ce83b30fefc2f019e8291a8db05d207f0fa7332fb", + "0x83817f6164dc9e8e2506252511cb9871a8c9b595dde45f67e75ce3505f947b3fb3b804c18c054ad13b1518a98f59f008", + "0xa9ab4dbe7699e7982cd750d7effe031f273fab6b2e024a0b4f8beccb5c280903bcd3f2400b9cac7e8c94e157b4658ab6", + "0x84d2e3bc66fc6b59a1ee98b8981ebca0901d846c40d207e5bb5004ec9339d28956d16f054af52453f6a7ff3fc66c346b", + "0xb24bf0f69c3e86f610b6d27885ac5f4556fbb14e8286681538ddbb0b4921aa0d5604fedef0daf4a514ae15268a640174", + "0xa4be967f7f31995562669bf9587f5463bd1d9873fe9169687790e75961efa5ce2252fd21276d022f580de23527282838", + "0xa3f3c4e673b302bdb91fa3cbdec88499752e6ffe37e2215d69b8a426f4da98c3a10e4c659e77c656172e4e8b1b1a41bb", + "0xb704ffbb3434563bbbce69ca7e812a8bd30757b1e90630bf3261735f9ea221524b36f97dec324ffd209bef45bdf6f2b4", + "0x959dde49f15c663a2de000195e182a11d8c396c1380f98322cbe5521b697bc3bec3223ca9e94ee2734c4ffdfb6a19e8c", + "0xa469685143cd82b78d7b1854c350da63819d9d86670e9b35a72381d0362cf5c3f1d24e22ef2ea6a12176c9dad39fd51c", + "0xadb97ef4463e5e13d91b75a3086d72a841a60be278e9651d9ac5f76c9537bac5eac33424a1ea00522b3357fcefea0738", + "0xa4597b2ced7566576e71b4f105b5ee48aa4ffca93901e9b626f7059824f53be3e8f3560e6861285f3d97fe88054fee83", + "0xa18d9b1b81564447f798ce5966bf10c823aedb14b143972eb4dbbba9312fc79f46635aa016cd20c53be90f170f06fb84", + "0xac4724069177d3c6ac1b72ea2a7d6bc5ac3d4b2a4dbad124152fbd170c9c1038cdcf255d162a25c14ae8df11a3849945", + "0x892683f64179ba84f6a447c5c7489e3cdf02474d2837dd7bf3b82a4dd05a6461ce94fff28d65b9539cacaf47dddedbc1", + "0xa68ad797bbc1b2909e216a0b3f39aa6c3e4dfc7a49f81a206b530ec0c6ba30f871e4a0053625aeb99448026ae2e0a6eb", + "0x964ff8badf35b6b93be6d97209d87f4ac8847be1c2ac4bcafa1db5c3f604f61834c85b3dcf58af50d09bd03ff8d78f27", + "0xb76dc9ec64b1fab7be269097a18a77144623d37bc656934fa1562817c922485e69b18ef40413ee309e100fde645fa7b2", + "0xb2a812be6e69f284580ebdec5ae2cdffd587bc7eae10989e9d2f290498b1eaa934b148ec7783edec300be5d7a9b34af0", + "0x85ffcabc623f8ffc58c5f640f857e27b7c105359315a3969f346e1366acb2af88f4acc025b299b9c324a8535c380a2c5", + "0x8d0140f79fb8ef02d13b1d51c4ba1af5b5ffb19322f88912215d4198f9a592f7ec6800c8a3ca853a3b68f9bf0353a13a", + "0xb3174deb53c1ebb6a1e16c915cac287573b70fe4e0036e8e971e8e807a77362ede632f6e3f29cb87a80a318213946ff1", + "0x8c58d603f6420e3f55522ec2853065125af4e7773a909e28296552f7f8ec4691ada9211d834dca38e118f432b6cfe03b", + "0xaa7ac268e155ff074bfc197844e21fc2a9f9aec9b50d9cda63f50d3c4fbbf9221e6fac3a6ba0f7e4cde71fecd493a15d", + "0xa191337721bc9fd2d3ec2ca6f6f97ca2462ef5e207464bf9e746a650a67d69abb5f578a8238521cee3f704b275845e47", + "0x93521abea8f38c103ebed3313a3af8f27f03c9a54681847f4201bf9f72f1f63064b18175986fca64f80b4380905e894c", + "0xa1b9d063d6538885f9826b84944123d7d6027dd030aef29fd6229f4cf5d32404f7dd0e899a0c8f4b6bdf4649e8a8966f", + "0xa15d5497f0fd2fd0b2c2e5df58a25a72a9d99df8215951ea58c15569d312c6f096f78034f6a8502f808e649f6cb9283a", + "0xb3c275306852612362e1073d0f4da3ce598dc5fac3f3eefa22ccee35dd57a4caae347b43342cd1f6a6e068d3ea9fd30c", + "0x94eb678e0700bf39caf428c65bbf2fbf7f601c39e382570a4df9186ff1dd5a958d78e051a5fd084e4f75536a14b7690b", + "0x97b13995bbcb8e824bec28488994a830a9c1f34ae4c1a16d5528d57f09e4c8b5d81677ea9f979f0acb8cac629ee09c85", + "0x817c99ad48bc05bd4fd29f952dbdc5ef56bb02f3442c18e3b91cb6d72ac2d2a5df901c099165ded1bee62c3ed13c41e8", + "0xa884acf980f6470e11cff347692d8a7cb7860d4822112f7bfeb02efb05948ea98c837d5d98dd7a104aa36eb8f016a0f4", + "0x95debd2ed23a23a16a393f59f666cfc864f63751238b73981faec4a85b4c04cfa11520c9e4cbe4e23fe80e86c260093a", + "0x937b4691c59453bc6cf6468ed5b17dbb25496bfa3817798562cd5fd86ab5ee35745991afea2fe271ce0fbe5a990c41c7", + "0xb4da98c879e6b475c540ff2c5501299f0e3e97b7b93beb45faef1253f7de96968898505e672cfc4a3ee7e20c1f72c256", + "0x8ec9d806f344d0c675bb5ecd47c54defb5f059a5233dfb2d459632b9b22edd6c4b8c47fd7899ab13e35f37ede9b124f8", + "0xaab4408410abb4d2cd98694f71b5452e6fab2690daa3066b3f9747e7dc40b57259d52e6fddeaeeca227b733d049b9694", + "0xb85a12f39808961c331038159255140a61dedc56050345a2eb13b1f7d140ae07b353d68d22f2cf60925fe66e598213e9", + "0xb61bc3bd68bffdbe9731f48fcd523491da04dab83add49fde390070513b9ad87a489010f1ccfe6f54e9a48edaf88b5f9", + "0x8f50f6d8235824cf25031f09e4b139bd89c1090269dae95a5aa0dacaf5f9b59c329a5a3cdddf9efe6c77cd61f481dcbc", + "0x91a543b85e18f34361d7df5ece8504d456627fbce65abff437007e9109359538a03996e35393a40f0586f962921eccaf", + "0xb7557bc52931324dd4c58d0e63c89a8dbdd2d00d0baf79d81d7a062aedd2de9dd743ea30fb031b18c806ba03175d7e1d", + "0x8e056b842a9af7aeb6c0d113a3acc8bfb5c6a8980fa81869747f75abef76b7fd20cb67694e70016e3de6e7821cde030b", + "0x966c00fd6472bb13ffa531d8eedc145ffb7733114e0f4a6a9fddb34ab7601f6cfb056460f757636230b692453d8b31d6", + "0xa25d85947c6939547fbee088e0131988053c5bb23aa2bd48ca764f4ef2b29235a817b8918d1de6865695977a95711e9d", + "0x958567f217ce7a6d74861777801663d7175eeeca8ff62e240582fb603ac91dc402331034fb4855632352df2328fe0233", + "0x85e53f3802a7d32dec2db84fad7f8c8fc856037cc0cd4ef9a8988e97ab580d4b929023f1fcde7633828b5e8bcdab08c7", + "0x878d1fbbedee7f7ff72eaa3848d7f6bc3cd13b40149278b3afe5e3621e6d1f0386f8ede32971d3f33be189c927bef6f7", + "0xb041e880e4ecb254f6f8d92635a1ef3be3d5d885c751f247bec2d8a016aada6a7fd2f7c599f458ee466886abe721bba9", + "0x920747dac9f35ba0b2670f82c762a71ee9bfb9e490825fb7ed613bf2548ef4ea00bc01e9d2c952dd9c56f3586a3ffb49", + "0x800005cefda1ddb860fd8974342fe315d227902dcb5f3736f8b9ad1fa2f8fbeff8c8ba0eb3f0c21a6706f288ef4bb13b", + "0x91f2b822b728fc5d1f15b69a303985bab14c08df5e929decbfa5aa5689f3cd93ccfe19ab10499d31df9d38c84039e492", + "0x957a909486abd85b1e627a4739c7d212cd03f2b62952045b704c415acdf2e6c0cc627af93f382836603f33d1a716ac7d", + "0x9733ec7a30ed833cc1e7e0ada4badddb1cd1908bcbd3d4e4694576421c94090a9297aacd7f42d9d305b87d711828304a", + "0xac2785a0dadfd246fe12b63f759e9f021006cff4f06b2b5a9986f0b02a40f29513feb1c9044af6e27d1c5029b1e1db35", + "0x948b22bddf55f4b4bc26892e83f70b882a0458582ed87fbbc81bbd037c946d833c19162327354240c42e05cfef55394b", + "0xa49c5d81544028d56f4caf8699477bcda589c65f6754dd40a487ef88d93925008dc7fefa6d458619d51a54b3edb5e5c4", + "0xac57b8ca2d0623f5c4137cada67afd6935fb75fd82567f2c57cb22e89a0562d3c0716d5e903fc06694a8c2edbc9a6f1c", + "0xad52af6a0cf838bbca5a97aec5d87fee1aec4fcf5e802b8bbad1b110c31ed777de0b0ebf74384bae68289af20e351bb3", + "0xb0c7c48d734e5a1b37674465eb07a629dbdf8f9080c44a578f3dd687261d9d1cc5cbdc084488c745c9114fd998bfefb2", + "0x8a2b2ccd4c52d15bf7aa4a8847b8015bd53f58ee484589339b4510ef08a27db56178c15b4d79a9c6eba1ac0b641eaa61", + "0x98f659a37bffd7a9b7759bb111412ea9e9eec483645511590f683064eaf15e1b101b5eac3b98f79ea38662b1956a06d2", + "0xaf6cda3fb2479b6f2d959f2d03e52b49afd12bdccd7a65a1bf6b91e345387924d5e355363f79bbe32a4624287cf4c1ac", + "0xa24d325d8c2dbf9d2e346e3504154018937efb74246ee0658e68d148d9ad0f4bfe348ea9bdca77d4467ea1b3dc2fae5f", + "0x81a729dad3798121027c29e9310d56e36a48c1c479cffe674cbf9131c562f541d7e6c52c2718025d3470b05b67cdd321", + "0x95bd5cd6d9895c775e58cd4296ebefa51ab9e324418208c3c4d073be59410497a4d0daddba6c1e7373abc08e13d32b89", + "0x809fa97a229b056def6b548902d8d90c873e496db6cb1b2d448709b9ae08d9b9762559666cd96b6bba396eebbab4ea4e", + "0x8bcae63cc680494606e44037a3bf6dc7bae2e723e5ec3ac0451550b8ca7914ee1d4bed0f40adc3dfa45f8f80a36c11a5", + "0xb3474711a0f933cf269e97e4e1e98762ddbbf49dd72e468f1e8a2f89514c1c35cb8db32d08dff50f93e50db43bed54f2", + "0x9788a37c3d95310627deec58ba6d9e0324618469275276632a3fa7841fb127c8fefc1b7392064f2eecb508056bd346c7", + "0x8d031fdb156023e185fe5fcac67b966baf9c098fddead4a6f1a3cef54d8e912d0de2d1e1d3f3f05da538eac4af5b6973", + "0xa5efe72b86a714dbbae40fa69fbccf41042e0647d177cd60275700257aa583708130a64b2f9dcacde4fb636b5cbd5aac", + "0x824092ea32eb7a8c619182d926f292cedce7ac3d3fc64f60d00fcd767649e1d6cffc20dd9c1d1c8ef6f64be315d1e2b3", + "0x900ad22d3b63376b1ac80c7343a58df23c03c4e7d6e5740dc10d8cdee793be07fec09cfbdf29e1d1c6484d3077630d6a", + "0x826815005550844ac5a6e831de0e25fadc49aff808cd601d70743d4873a341e3f0cd40d490422c87df3f3c40921fa723", + "0xb39d189aea740c52b03660c0abc8e796cab72193ed44a4b1f59fd1ec0e283ef7d5e157ed23741eaf289cf968597c0900", + "0x968ed61662d1e656e039900912ab61173b49d2e24aa6b7d3af07c3b04a2c89c4516540934aa543bb48ee14153780d10a", + "0xa433b8b689007ecae7f1df15d442b0570664a2db6318de66c6e5fd68884615778d296bd260ab7d07469bfb5f6d8c94ca", + "0xa69ed4a0f39920d1a62a01214daec143fb7596212e2439583df9ba508784ef4d2fe86334f0f9a6b7a3342ec0a72ef15f", + "0x96f260d9cd88757e7c45201d57bd816f1cfd37587ba17a64997bf7716ca1c2cfe16a7119c36acf1754231f303058a9cf", + "0xa51f2bb09d30028eeb0860e2de38094623e5b5514fd5d591a7d4a9731cd4b9c4c12c5dd6ef409e009dafb10d185d5346", + "0x8abe821036140ccb3ff9063dcb5e8b8724cff1cf0784b8f44486c8380fc51715cf55b443cc20870f426c4874be93caeb", + "0xacd73facb964d9012ad12405dc866beb52d8de3ef81fe966cfdb14d22a19bbd2e7ad3a29cf029617b9d6510ed323c6a2", + "0x8f18f6883c8e4741cd6c52e0d3335dd71b5571446ee28e8c27cb0625f77a9f5bd0720d960e5e8970257907f503d58a9a", + "0xb66457a91e7ddcf56c8ce4936a209c69ee53d71236b72ea386f7719c8b8c9b4ba4ea19039a8de17a0a869da427da42e7", + "0x80b1de58bb3ac5f264e0273061f485e49413de604b5ade73ef81bc249f5e89ce97dbec7d99b088b5a2ff65c0bb93fa76", + "0x8bdf276c88f80371ef0ef7e1224929681629aaebc8cba3c0db0b258be3c26cd17268f56369832f564b1679be33e98c69", + "0x943cf6fc88678816da42e4f337c730eb2dd59f8d738ea638a799e8b77214ad7e74723056bae96b100f9a972155885d26", + "0x91c8c1a8a61f47119005869c11edf0b69d0bcf40534b82e46aa96bb6107f940e582b6733f855144accb8dc21d79acc39", + "0x96ba98bd291faa0904ca0398d6c50eb5bc2ab5a389c359ca42b8909f41f4fc37dcedc370ece777d5035074a597da503e", + "0xb4598e6f889d319713a9896161a6c9bd8575ca30c21d3fdd37cff15dc0141ce28dc536f73957e6fc8f6185fc0adb731d", + "0xaf1ed593a0547c26ff729c159ef14bd0818f25e7c1c6c51ce8ce5425bd2526086eff9fa3341279daf82e480bfe431230", + "0x8c02b9ad3aebf156c80fec9b012241f3794d736adfbe4a272faf505ab818cb121ad2ad7c2eb1716e252d0a2e7ee6b246", + "0x8d2a8a31784c446eff4c2ed7b004009f08b86c87a4786a0b7be3df36ca9130a0ec42a58d09dfede1279a4a6d3d37b501", + "0xa78b61be13005b1718a3aa3deba103ce71e1ff73163c76815f9cbcc101d993f119ca128a25c51a12fa52f46550c4b609", + "0xb990d81d7aec9fc50d798eb8c38b40b162004f78730e9ed4a103faeea0995bb654893e557e5eee9b74046ddcaa70617b", + "0xad56d68777d0ed53d3331b0cfd44503b27435278416ac2268965d8ef711fdd819c16ef5499d8d7fddadd229c3d0d4bd6", + "0xb5110140b9ee542ec03c945cd6180ab1af205537704fd408fc4490d799d87a3f3aa0f1f0ae9c8daa55c1757f7bb53cbd", + "0xb7d8a4080c5eeb00be4540a00e65e744f4c7792b518c9fd2dbdd25abd0dd89e76563618cdb92e4cda0fe3ba4597508dd", + "0xa880b33af98cc0bd1065767a2600145e6e326c3cee25602dd22d531c26c4b8543f846fadf679e26749c929310779d858", + "0x941f124078990e03310cacd79e4a38667f4dac4dda4dfa3173a03c14aafbf538fdaa01b940fd5be770c1cde0a84bfefd", + "0xb234e9d0f04da6efc5aa5c77bf71cb05001cd193178fdd546e4ec81875830113d3d4f1512e7405b16d0b3aead285999d", + "0xb857bf6f62c4b19ca9441f700ea6676ffa3b0c7138299533ede59a9b9cf9b94295046e7eafcf1d4ecaf0341898ed6b15", + "0xa2b0d74f17d3387566bb4f17dfef214cdc6b61dc50698fbbe298a7e2f4a82d20aefd719c5e82bbf4ba4fee0e2e35b4c6", + "0xb5ffae433aafad3fd51ac137976e2c22661d8a286b221e0107baf19f5c8f2f6c7eac1e785f145bf7c16a497310fbf51d", + "0xa69e9dfb14f8c6cda716166cb69f06879718656c9f46730d94f194e2888fec371a11c9701071bf8690e57996fa91d213", + "0xa1f51ecd5c5d73155013dcf02b327cdbae9f9c2fbc62f73959050cd3a0bd66192213d1f4bb56a85cd21343722ff3f57c", + "0xab3e54b8f4829f1115694a4be7d16e8214c94387ae783263cfe145f965705d51943176191c706f6211c8be2699dc79a9", + "0x8cd6a64c5d30149ca4dae4fb7e8974dce1200aba9be9c8cf9af5d43e40098746ecff7bcde7ff84a0072138dcd04c2771", + "0xa52f6fe24305bcff685f2d047c9a8d9a1f70c2b416cfe55fc137c6b5b185029f3644890418873665712dba4886e3fc07", + "0xb2e8e3d2ba2d64815bafb678dfc1180534186eca415bd8cd32b303bbac6cfb637b17200aa7cacb953e656ad19dd5c9b4", + "0xb5412d1073b3b80bf0d18f791a6d02727cd9c40a86ab0f13ccfd847bf4e767b8b79aba3935194398da2c9cf17c6bfc8a", + "0x8bbaee84aca9089585d5ff385dc2ee6e653d0fcb9088f98bc5fb1c6c83db026d9a73d77c33c6cae3268be90805d862fa", + "0x9691343d1a8b7fcebefe2584b28ab5808764ed79d8f28168a65ca90b0094e7920fa43e56b960331209f4b8465cb8a5bd", + "0x8ea475e12088d558f5cf6dea2da71837791093a622d5cbee608a95b4c8a61296255c1545d454562e371ea0e2cb2e0b1f", + "0x951d6b404667ccca099d01328562790d1e8446231d7d22bc2b1c4c6b15785bf59f2099accc58817a06d24d59ff4e6a2f", + "0xa5d012687f341eb9c783c1c2040388eb7ad662cfb2b84cd94d270bcc99116939aea80440d7ab726f9abcad22fcd90274", + "0x818fb57b7a8cc59f06af054ce09dfef812f8f115eb2473d06c8f20fc50cf17423331aae1f843bcae57fe4e2926ad5aaa", + "0xaad27bde8eaa2e7fb1a9a5ab531eb41f475afdc89b7f02085f7289f8f84d172fe516d0104560a40c89e97db7e5e836ee", + "0xb8cd923efac1b09d9c6b1d97a0c1bce9fe4eba1d872eaa3c0df34dcff2e7ea2354f1b31b69c6b266944ec8cae2a16865", + "0xaf628e772d609224aa7cd3eddbbfe965fdae6a05cf6d14959c5c26c4806043afd5fef803091bec710c6854ec095ba18e", + "0xb662e1d32704d96919f5dbefc3cc40e7d41d4124c5865b46408c2ee5c40926eed71fa3df71fa7ad349d476d9a525d7fc", + "0xae4c5512396f9c26381394ff8e22b1d6267e3d3a5d3fe48457450694520c5e173716572b68fc1dc352761991abd262b4", + "0x86b530978a7e549e6ca014168fa4aeda9438bcd3a29f7edb1f4e9c712c16faa58b81b028c25a8e90b421b61a1766d7d7", + "0x97b32f1371f76dac7a449295365780d1bd03f290a041b3d19db3f14bee6365a614ca356e7cbd6f966260420b451f6117", + "0x8be97569ea08d0b6c4d46e9565ae14f79d1990f192a26ec935a865cedd6bb5f69f608b069f7d645877c5081fb4a68c54", + "0x9733488f48de05f57f623752b80b37c91f6c9afc0f9b4df4cf400f3f82b137bdf06fee82190f2a4ad4aad20e964cc214", + "0xa794f6dbf155666056529748a792be13011bee6ca10e0d55c82c3e84c5dfa1f370c8e8abf2971a75c73a4ddef3da3319", + "0x95ff5d16c0d9bd679738257a1f7f309f257c20469f2fa41bcfadc671ad65acb249793defab591f515bb3d8072e2e05f3", + "0x8d849150bf8dc3452839256ec4eb65cc9ef87aa0f90dfea4d1d486f16ee855d6c480a8fa4b6cf8d536e435f9fb7bf507", + "0xb61c29121dca2bbc6024ad2f487bb57b926786ae60a9e7a721440787752432ba9c7e1df86ef0d74c2592d23f0e89326e", + "0x819630a678e4a5e6adbde9b292f5c8f2b6e3f2ecc9bcec60ba0f8502e503f697b0ded4f0f7157b60ddc976ded66713aa", + "0xb3525b071e26babf669ae2b98319b3516c083e797d74bd5b9b0e1f67792a2e8ab2c60921812690b5928de66290ff7b86", + "0xa344c6670718b9824ae62b309813bd31984eefb5efee38052cd06812308edcc39fdee165f8164629267bc0e98fb50ba6", + "0x81d78d54738817dadee7bf70a468a51728de0e9775f8779fea5d0d95e55b2004377b4e2db595d420f017af18a384d9aa", + "0x848c97b9413ba6ede751ece925ba57b8f8ae27168c5d46347d39e0232a5eb42069a85f1ee2d30d8b94fde574642be5d1", + "0xb020048c5a5a2d186df628550c6f61a204f16e6eb991283e975de520c4f916badc999b3b7e9402ccc39db5c0b510e2d4", + "0x9298c1aec9664ab3fe328f532428e9b037efe8412ccfdd15e33c9c82dc3631e49f84e0d2d75dced85e3a4e0fd0f3f2dc", + "0x8c4a78841f51e2f8b91defb0a3844933999f9884e2b324bd89a01e482756758b1b5a278289163409947c73106bf934f7", + "0xb328a9db915c4bea1783218c7668e2bd7a8fa62e52d3a005a43590041d34ff388c0555b044ec5ff85368352a3643b7eb", + "0x8a395d89469d374c1ec472c4d571ae670849549d05124907faae5a086519686683c1773d22d290ebdcfb8dab926d10b5", + "0xaec52b8a883f4ff68fa5f418cc91c8e9d08ef324544356b0ac56a7f0980fab6b376b8f567e357ba96b408652b8e568ed", + "0xaf80f0c5d50ab23d8ad99c7fba504f2f02b7307b5ae5ff529142bead28d69c3d55f4e2226c44549548fdf761ce30cff2", + "0xaf73700803caf7b06f5453a620253731de33a458da01f5790106e9418fb59e7aecf6fc1d1b650e1c7b3456f7a55d4301", + "0x8be3ee3caa86cbe21ce9998fe1c0de73ba6481125ef28e312002377676317b5ac4c27180086fb83794efbf86438ad27e", + "0xa0439d051d06a7fbd5ab83f32f0f95364bc043d9d934ac64df7031223e731d7992206879d567e77f35badcb7623f03fc", + "0xb99de1a16670fbbe3ec26ccd37399e2a23c96813c26428deda4f74dd3afdbd28cbe47e074379f6094b85176f8ab349fc", + "0x8a943a039aa33f38d3887de4e77566d446e87225bb8333e3ea991466c15c6487077c6decb9cc10e5de6af03e6b81a10f", + "0x80b109fb49ab810121fd411e4cb85773a1004af2d257e85ab5b4c99aad8d66e5803a8ca7b95587197e88abaaef0b8d42", + "0x892148bd190b042fe9b7914b8aab073c0d19001158087077a5946690dd60d99a1ef372ac01e372a434d00b0568a75fd7", + "0xa266dcc9ccbda054e396e1605eabde6cf79a028b697898090e9f34a4a4e0b771c121b8d470b14130a79cebc19f8d6e58", + "0xb1ab30b97c76392712b173460c227247cac50597c036f674361c63c3638a4c03420fa5b7efdacd0496a9b83956cf5d06", + "0x8a33c46084f669455ba089b369b9c8493a97c131f09c66f9347873504f35d6b94a09483b2775656ab32a12c7b9766ab1", + "0xb77a7c1402edd9ae448b7a606ba2eed192a9bb8f852b647b6ed689b0a3ccb81a4632edbca4c113750f62643a0626e2a2", + "0x8586e85e3bb07b07a39ecbd822d2adbfbf1fc66cf2377fbe6b1bc38369f86292c6cfdb5b405a0bc4d584c0600178321f", + "0x80cfe5b1b032d5a28662d13772fe112e9b73c997f8ef0fc796576bb39e02189c3ec0228d192c981061dcccb9dd3c4f39", + "0x873c085029b900d1fcbe93f8789d635e3a8fa558766701ba9fee76dcf05abb6cef518f2b56c4ca5e26f3847cf23bfd72", + "0xae8075937a23505f51a1a26f7f54e35caadff44ffc43465368daa9c330b553cb4548adbdb04e24c3977e35a08841c36a", + "0xb1c7076afec527912f7648bedef633ea0e3b02e5fc3fc495779b93e8a9f64eb503f46a1372c8dcd8fc2572c198112da2", + "0xb5233c4545bae360b07c4411776218a1d9040bad1e788e099f90149c58258ecdf01dbf246ddea48ac8fc2dcde6f34f20", + "0xb62655a8376ce1ca225dba04cb29f1a95d09e1a20b58f0330c478c6acf931ae52268779d6cab87d9074a362b9e82b205", + "0x9684e676088b409052773bb740bd3577bf0dc15d0392ea792393a158e643b165f8cbdd91cf355d5425682c77f2a91f34", + "0xa892744cc0c428c97bc929913ada86c36f280f49bd1603e21bf6b6abf8ed195cb05b22e586f0c841ee02f234731985cd", + "0xa62c089a73c6dcf3f7d957719c7d452962ee851d6ed8c4b57ade8a1e57156762c348fe5f20adf6d6ce47b4e98f93d60d", + "0x91b29be6022d43937df9c597d19e23cbb83cb6f5b764e1f7db6cf60dd9b3e9c79f1f617c3101c60fe6c7af9b5719fd5d", + "0x91d13fe99d7dd7b4744fa2fde41bb51f4edbefb2189ef3ca5d337ee84ca3f728e300aec19b96dee18aec090669c85400", + "0xb17a5328808ca929b794dbf0bf3a3fc318f8df144a892ec0ac2163a0f7c3a4614d7ec433b66bc491c05a286fe986d986", + "0x84a9e84bbecfc2aaf8bd623d79bd4240c630b81ecd55a50198de21758255207238179a345700e65d9bc6eec1a1a1985a", + "0x8d428be451efbe630740449ab3677ce6f69d94d75c5a9d91d14b2493a838260d6418be3d4658fd15218eabe3adfe455d", + "0xaf11126224f6ff0e88a09dbc0de6db3c70e3db3f6e154deb448d044100f989ea41c6c0259a8ecefdcf531f892a957d82", + "0xa51716b900a00277aa932bb03fb61eab3bd8e74edfad6153a06f85aece6f832af710f1477d883dd8e48931deca12bae9", + "0x9542a82039c2d3c538f15da884f090622c5af556c16370d21bdd6544208cb17e0a30e511b0af4a618e8ef70d0c43af07", + "0xaf76f93250bd7bda2b5e30e6f88416ef6fc8ce0cb614515a1f8d81dec717077209493cb47b79e8b1a62e09e394038338", + "0x8fa8d657f1d584b06d5bf41a52bc2c73853e4092290789df04eb8952c6eb236df601a1c6cc81de420a424d8e748dfc38", + "0xa6e93e27421b9e32b170d240b4cf2710c97b49dabfc0ea25759c5f61937eb3da8d45a6400f8bcfbb42bc9a7ae9b66ef1", + "0x81848c8d66d34d274b21dfc10bb36fb9497a1b152aad64a8f7c874e58d31d5dd5f39e30e6000b6d7b444e573da1e043f", + "0xb85692a84154f87869d97cb5f16c81fb0559e097fc37473bb11dc9cbd311ab91a46b01aa9debcada590992c2473ef0fe", + "0xb565371692ab0f0d899d8139d3eaacd213e7d23d6f5df6ac3409c961aca019ce861fb4ca8317f462be01e8c1dc7af154", + "0x82ae2bda0228d36343f6153fbc41fc5c79fafbc03c99a7926c624dfa28ed0a1d215e11ab83cfd438fe5d85d7fee50363", + "0x923f38a2f839e165fd197e1711ad52673deed9774e0590ff63ff9a9985f99612aabe003b9a98db2407c2878abc6d9b0a", + "0xaf8d5e1048de3b813308544705eeb0facbd604a0ed03e66c1d221be64cad35d71748d2a55d1ff3049e1e5053c7b1f712", + "0xa90a4b3b9d3b7c87c34f85c7643fd67dc771caa940c9e2ea81294ce6c072eaed698368a0e8056d7b819ce3d73de4424e", + "0x93a106e914d2c6892fee866602edfbf8d03dea1918d82d511e528b99c8423c260c0d103bfaf9992e0e24638b913af737", + "0x864cb44b1adf5a59ce7baeda0ddec3a0ecedd42923205dfabf30dcdb216a7b760d8895dedab52ee09bb09e999486b521", + "0xacb5f2bc1257c49c7df89837502e699bcb9652567c1716513f258f021755092954f2dc65b9766ffd9a10584bba424c7c", + "0x86653b3a479bf6e10e781e316e61437af1abc988f59399bed8fb4ff128f5f6d53f50a293da58774acd42b8d342e52429", + "0x926b7b90eb7d81fdad2a8a59e13b1573970e15c10515954b7c232c37955755b6758178314439ee6c3b0c881d4092c838", + "0xac05f011011a354f0e16fbbfb7e9dff03b3cf403dcc449eb5c71067128e314badf4d4dc5dca4b8616994ecdb15909c93", + "0x8e063c6601e553f33abc64f9553db5a19ea794a1f254d5a5f7b8ff2db4ed9d180f68ec919a0f83142c5710813baef4a7", + "0xb6e891dd4d44fd54120b7b8716292c27d4bc8744d96253a841433cf4b07895606db4a3cc5872c480616b863073bf77e1", + "0x8dc623d7928234bfbb8cd0b4fce5c8d9a9db848ab0af967ba9c49daffdf719cf8b55e1dad0b7e421571b8770cdfe9df0", + "0xb5b53f7d6b5d1af75e5a1720281feefb8c9039ef7f1e1969d83bed5a2f73cfbca91dbf4fb8179d9b0d3bd06d1207089b", + "0xa5dbce9e6db637e053b4b4d3df07b724b50d11eacd3327ddfc5aa8f37b9a5bf628cc9b428328e16cacc552c1dba505c9", + "0xacb82d6c9af9af0dd426a07b1aec81b388b61042bd601546cde248730ef85a09016bdc66dd014447fbb56fdcc23011a7", + "0xa41692e96f1d775b3a9378b3634495a8350dcfa52b4b2b7773b39d36f7d349fd5ee9a2b3e72769ca98f2319319890216", + "0xa0b4bd6a68ac5735539cbbdd78ee4faaef7d6488eb7a11e091d94e315cfcc49a90f204f636dd8033857378ddd67cc153", + "0xac3dab32427b0583159482f73f94236980d69f9f8f781b93f44aeb43dbeaa740c77898c38c57677b42c248b9bbb1d673", + "0xa6cd1090b97826486f59a056ed90cde29f2ed821211391f2f16e66f1e8914398348cf6f0df6d3acaadab31f0382bb5bb", + "0xabd1252b722aa56010e3bd4119f2a28a852e9ac1a8ce68c96b6da9d00fac0c9fa70e67cd4afd45e0a8042a810b8e0a91", + "0x9194b629ca80b3bfefc0144553017343d0915aab59faa3d0e2bb3720dd3c8fe07804be6e582c6d57c764be96cd40f2c9", + "0xb6bece03ae1c5935eb38b14f0f64d9d0b4410c02ac309e085a233c74bc3e67ce63edea56ea37f4532e8b864aecacadd0", + "0xb753eb9184f5b30e77bcb5d3487323e0f1178f1ab3e15130953381272209a97c3e8084e810dcebf1ea7b22f0a90b9c77", + "0x87dd4a76955bc98326823cffd653fb7b7eda5df1a971b72ec2a4d25fb3958b9d6092369539361069e7e4f1dc9343d929", + "0xb0f1e8b25a2687d98cc037272473b4e3f33cc8d49a3c83a335d48b8a0d3ca5f84e8e2bde304ade6f7d50e5f3539d639b", + "0xafce1c0205adad1ce52fcca71a99cd6df9da5b748209c2ed1013b5b7d484b937bfbb26db9e9f8e77c081e0a0384114b4", + "0xb363d31209c075b94441d1a8ddcc6bcf9eaee78f8adbf0992d5c7e7d638a02d58e19203247443c35d700fc8ac8a1b7ef", + "0xa0aac7dbb08a10f6cc2c6a4d37aea6bc3dc034d933f49de3dcc79bc0b7a011b1e27df7cb882d155287436b72092a1da7", + "0x86dde01fb7090c80fb404afdc9ec64ac40909b64c4e16460a4c862c3a3f857ebfc0c3122250306c266cb1e9f9f245934", + "0x8b3ebbbb0ccc466c72afb4c27ad99d2d4e98b5aee9c05bc283ea3332e5f67a3d9263b71d16b20db31ad4d8f48174b0d7", + "0x8610c492ce130e76c06b7e0204617087ebd8f285cc3f007897c253a0e1af50f80a825ea7fa3167f882e146402fd342b7", + "0xb17f04a257d3142005b8517dfb57d28661604eea9050ce39c60ba9a05d23897114c59c55af199ed186034e456e111cb2", + "0xa04cd806847686ffe023db1721fffbc26160582c239d5bdef08f4730e2fbb64c341fbabf1fd831af6eb84a113ad7e2f7", + "0x879018340deed1fc762e1b8f3a8b78a40539d6f917215621b725c0a3aa347eeff60765e5ad6f4a36bbea51ab77f88726", + "0xb421e65891dd0c6641e8ddf479b065163897a418d723fc6dce19046501e01c616bd19c9d5fd6b395e65abe0ef956d53b", + "0x89350af1d432a8c209b69f937d2aa20a24d5eb95c5b4cec097ca3dbbb3ea9efcde2a8c56c58f8d7901b96a627c45df9e", + "0xa32d6b31cc9efbad4bcffd8b0ffa46b8fa97ddf3453ed151d7de1d03a02cf233f07415584893155d2d7e14b9534921d1", + "0x8efad47caa32277eb04137c92def618e0715c1e77b5053b0cdd60fa03256fa1c9fba9aa86fdf1c04cda9c5450863d58f", + "0x8dff9d309f7294ba750158e70474c978d1dd98739df654945f5f29fedc607caa06b2866c93a0c7b830ff9b26955833a6", + "0x84bb00fbaa4358a2563abf96d2434e4a26acda87b189cd8d2aabde1323dc1eb2eefcdaba3b90e9ad1215ee469745b72e", + "0xb75acb924159ecdcf49df587d5ac1b1b04291600a4f530fb7cb6231e7fd1029f8cfc957c891a59182518480c2947f472", + "0x8d2c671ad0d442664a0cf267b39be742b1d3760935137e4c50195695bdb99254c4a4d5830634059d96dfb2b4e214b067", + "0xac27b31843caa8140e729a01e7d0229d7c221feccc89ffc173c11a419af3db0f8a47a41cac358e15ef41f679a3f0b96b", + "0xb0b3e33c590bc00faeb83f4b160748fea4fad3e21dfa324bc14a138ee8c5e18743b6bb27cd0ad7c7c28c2b3e92040b0e", + "0xb0d2882c5a0a21fe05b522f2e8a4f43a402bfc961874deec962a1e3d039e411d43bd3d95a26d930c2509aec8ed69e2e0", + "0xaded1e47b3ea6ea7276736fbd1896297b9ead21dc634d68ee56c20fae3da90170f30ad0642be10929ecfe7de5ad8ce5e", + "0xaefe525c0dd24d6c0a66b43ebc6403ac75bfc322d1a22f76340948cf3536d2ae87290ca80acd3e55d2df9aaf0fe6bfcf", + "0x979d1510d3271ff1f06d9cefe30badaece436fae8de70b01ac843850f678aa5f48821dea48ce1c363fa35eec37283f3e", + "0xb8e8d10692f1bad943052fc366291c134a0fc7ca4696feb216aed46eb32de7333a9ba4f553389e7e58c8fa96ba023f58", + "0x913353bc585c0248a54d4705b5e29cc778f304472446eb4baaf30bafa30f2ad0643aaf21196a6c4d177b11eb4e2ad5b2", + "0xb25a0e3b9f983c47b8faaae8549fa7d00d12d7145e1b232d1813ff94058ed603957a340beff25711075cefacde767661", + "0x8515151729ce9a7984af3b94f74880a2402ff853b99f924d581fd3935d8ecfc80e2a1185918a5b1c4902106bd1561ff8", + "0x88e4282ded5e2163874f6464236d5bdcc3c484a0fef8ed0da8d0177973e8175432b75afcde2a4d7d6aefeaed52fbeaa7", + "0x81c31113f2a5ff37250f395d6722a43cebe2a267a0ee40ac06faccaffd7d6eb522103f0431a325aa46a54e606b14de84", + "0x9302ade30ccd62a803b9610a397661298941a644b1ee9d293c63a6c3368fa3557dcf6bfd0c9b44c5c2a6be06d1baf663", + "0xb4ff9f1f6a2a64c50b0a16980ca7cdcc297c6f93e11c580019de52f58381fd0f60a66d3e010fa7ab56bdd250e7b2df2b", + "0x8e57eb61ed3c919dfa0f0cbca2cf559cbede5bbb1e89ae4849b380339cb1c567c98fc2c671211fff4df1a058d46a42bc", + "0xb3d5b45b4096eb088523d16bda1c6aacda01473533314961e6a8de36ccfb35d4b717eeb1ee1bce47ad3b80e9e5084d4e", + "0xb933ff4d3c5a77cd7cd32926266d4f05198178ce350f7215e512e71b07177ac1ff89ba183e424138e1fbf088ecf86c24", + "0x8cf430a6e4eafd23bcb5ec8ca3d711bb56ae719c8621ecee964ef3bae7c53044f7ab3d5d0b911e09c7543e56c1e82e11", + "0x8b3c34f5321c9ed48024196e1e941fb7a5975a045a5a9de88d7f200fc7ffaa0b3e500ab7b535e02bc5c35fbe420e2c3a", + "0xb3c235b65fbdd5c4c2aa45271b9e51674f9a0383a8ac383b0de53125a67c87261540a95b8f81ffe67ecdbf3955b13814", + "0xaaa93ce79ed6e7084fe906c9a1002435ed6829ee3d1380681b902d35dc9e5a23a214ae12dd4fb76691b0016f28d43651", + "0xb4c9533e50ec58f75ea82e2aa7f735c4257bdc1ecd0da0b6521d1442fa61f19e4f73cc90972b47a762f5cd9af591d957", + "0xae0255dd70befe7eb979d41f9a7407040937e7a879daa64353c66d524d3d3cf1d5e854886a6c32c142f4673c56a4df1d", + "0x805fc5ea840d1c2e6b35ce586309698530f056b41de7a403d9e7d81efc2d7068976e8e23bc0b9ee256f39b15bc4f7ecd", + "0xa8de5055b6d2310b6ccb211a397077b211683b05c7e68e55ff05b546c5c81522e6097a3c3b4b4c21fe06667071beaa4c", + "0xa4014d39b23c13efb4326956c5ee476b1d474663950c9e3e45aa1345037be862cfa14aa1d03bb388085bdb4ba9d70a59", + "0xaebe9a9ba34d6cd3692a8bc0b0aff5648e16b36d6c123e636e9260386642e29d52ba71ef7778481c1b1cfeca7fe6acba", + "0xb59706380c9271918ee16a04e84e91046caf99623a0120aeb37a7a98d4c954d3d880960086de6cb180c8b922ca1d7405", + "0x8dc0713371808850f2137a89c33fd55ec2df6a028e22b2679e09f7084d5c471451187f6488fbd9b5100b84593540e5f3", + "0xb492c55e470c35c7a7efa536f3e7c1e586b623c6669ba6eceeebaa1f81fe3b8b927c2e522fb12e603ae246d9566e4d23", + "0xa5148eadcedab9ae08f5db6265326fa415aef46d0b24155910210338500be6d77bc9fa6f6e284a4c2552dac09167e450", + "0xa0af7b66c8a1319ffbe7a0180795b442cffde153f9a871046d6bdef959378c3068813c516e280371825af06ef2320b15", + "0x95479ffc4903f252fe58632e833d63d963469e89744d5c91315d38eca21b98f1ad6fb3ca77d620a6f97d9ca3aefa1f7e", + "0x84861bdb5880f663a5d9b5e89b59a940611a233d82a9895a330464f7e9b7a6965c2420704f3adc61f876584d06771f03", + "0x933c374f176381a3a63fa98d238d3b7d337aa745528e271168f5b550fb703664c3128097b927b5922b4ae8fad30d5e40", + "0xa3ed2c5080c52ad1235fd93c9bbf128b48ba8abe364247104bbf298582930bf3faaa4f4b6103062a4696e68c44f79555", + "0x94668bae91eccfa8ad459588f927bd1a169af834a76132b2f2d5cda26a91094cb94661e3c59f7547b290f827eb43125f", + "0xb704404a487a7dce87ea8207dd5d813378a345375e8e2c07de349c1448a39af8672bb4436779b3485adc46df2212f409", + "0x9347dacaf6dd678574a4f1a95df79369e3f5543c565b1580f907ecfd17b5d6e1ee3322d83601cbbc6d6ffe0bd2833a83", + "0x92841abd813bd9934bfe945e428193e33ae6d4dd235a16edfecd6e4184abefb8a1f85015ee83caf9532dda380fd678b6", + "0x95c14a1d3a1e1ea18f8a61f34b85ee8a794c95d3b4b0ce6ffc89013c9a80291a9a2487b00bb3de51ca2e4290fead7482", + "0x962fb52a2134123ca31d91027fe9fb62dff4e0542c66b55899a163e50f6ff2c4c4b9c1f5b5b3d6c6dbda40e757c0bd3a", + "0x8aa06ae95b0ff361dea2792e465436d810b86f803ba6121ff93fddd9ba60ce47e846eb2d248b28f2c47bccc9457c1ece", + "0x81adde02ddc49b6cc89561716a839fdee2879c78d1ea0fc0418a6cd4a2a8189a2bc245bf2d1e535dde07e93b8a5e18c0", + "0xa7a5713055455728d6d982a6650d1edf1a3b4612c9072ee8ee0bdaa3992963a6fe91ca242fe36f839595d09f6a47aaa5", + "0x93900cefff6f918dfb12ccbb256adec89fb8da019324b811398eea03f6fd34f28a6eac2ce5580904cdb289879bd4b4d1", + "0x820262cbf7864213e768b5a38f39d27dcfa7baa5abca557ab575b07c33917f7b0f06f0a6abd81222fe8a5a69d95d774f", + "0xa33114d4cc3cc84258fdf252e754c8bb1feb6a130785d35a78b4b05d0f782424a5ce0f34be3c1a14e3bb1bc0246bf0b6", + "0xb966ca0a11f0361e611ab2a8907f78a3d639980cae405d380f3a080125c734059acb08431a42ef3a60ae9331a07e6a5b", + "0x9305d107311654ee727182a1683f322a78fc637bc214eae311f8778773e5bc52063bb0a902a5a962a4a26fa0cba3b06c", + "0xb3dc808231c75e681aa2bc4358c41f01e371bfa5bd504e7bd2282e35e72a2889a51747cc008dd4d8b2a070c8e4c2d7a5", + "0x8f05cc76848367abf2020461b6bcc1ecc412ae9f114d44715875f25f34d8cd26b84b01fd6c0640648676b8d2d5120814", + "0x8798c23f0ca8a7b23152ce17086f31e2a80533067f15ab4a7b43c127a5d8af3297115a3cd7978ace811fcc38805abccb", + "0x99a917f54253059a45103e15e92e1bbdb03e80584a85b658f231aa5947b29388f5b04588de1ed6de998741d360015313", + "0x8b0ce3f6afb5aa83ff229ae1ee0f986ec4d31b113070c7ef3c1ca3613d74e3f23cc1cc81957bddc709a5c5bd85cc64f1", + "0x9035b71e4cbdc7c410fc03a85543aed34a1c0a98e07ddc933e64886f1796416ff3a0f7754b5246ec93d617aad0f53d5d", + "0x87478f69c45394f94c67b7196f60aca42823ad92ea86a427d705576fa6a9bead40b1a4106767b8a20411e757f8762b68", + "0xb36901adf577f159b4263821a48fc5888e7bbd6c9f3857968a9cd02e1a1a788c08a566b7bd5bb6be294fa5ab92b4ff6f", + "0x8a738b1392aecb35a5a1f12920522997c9016a0455354e41d2e1b81d8ec9b30a90f71492c7bc122505b2ecb0654545ec", + "0xa5a422515f17f2bf4b9b6c4b5b94df27ce80826cc3ad2a8579eb6666c67a96355e60bf227b36e1f082d749ade7a38a92", + "0xb6d0e36a98e0518b14728bfd79db76c408f58220111e8c4dbf5bcfbd7a85bc68022456196f07b9f40158037a3c3eb90b", + "0x82ad91b812d08bfa815a93b47bd3656b493853bad52656450eb408fc915e430192ae123fb9daf4aeef4608800e818b74", + "0xb8ae5b30118dda7b972464e14a96853147c4b362e9cde22130250447575c0d8d05053202db4c650467dc16330cb54b36", + "0x835d913a3d15ff205497b98107eca77058beebe1aa35ffc20241bbc2a9b4d2019ba41fa3c9b43fe2265a1110b5c2fbe7", + "0xa283d88acbddb50983356f2aed99c2f153b6a8f489b0597d8db08ff7e3b04392609e01aceb37fe985f59773327258195", + "0xb6927dc3318931eac59c6e21def3ca79154beeaa4c57e11ec1f3362aeb33445366dae770e533aaf33c273eaa4f54275e", + "0xa6033a62119e077b438e0170f27835597e21c1d6e4acbd53fec7df69bd1372148f90966732fc5c004857cdd44b8a03c2", + "0xacc764a116e31d63f534b3e0e42a3f899d817d3ec32fb4504045bce7ba3a952ddc81a33d48c5b0499eacbef4268bd5ae", + "0xaf5d1f6a67dc6361e19f222a24163be388033a3fd0d33ad204f4411302668436f933c4a91c6472fd4262397417e3c588", + "0xa2b1fe93eb481d4fec6fccbd64945a12cfeca85aa8b8bbadc4e4ecab2f3ef65616294dc168d6c955744b7c6acd712012", + "0xacb6d3e123572ec20d0ecceaf4916401874f0298218b36a0ce089acef90329204611968c7397c2a518c0a78d02a9285e", + "0x88e4457b1c9b56957b76a08e98c569fb588b081e0e420a0d859b70296f648a8d64ff35ca61a39d1b8ac3613ea5fdc2eb", + "0xa7d1643b3bbef49b2f9fff326061cc27a7f65228e40929562de73e1c66a9d164d42bfcc3dae9103b2acf27606f18b031", + "0xa66e3b97efb7ce4e81534453d3d41ecd4b5b6e9bb829b07b5afbf11fc6ea30382a0059c33c97afd906656ec19432830d", + "0xae9a17d0044abbf3e6aa2e388a986754d6b0fa35d115e410f69ad4aa114db1af5dd0389222b838cfd859d436aded1b5c", + "0xa4a66a163365528b08333f15c6673ca48d7a9b6d17822f1e5390fecad122bcf7ec5656eed2f22fbc6ccb6dd96ee260f3", + "0xb7dd42c938c2ec50c3b3fde92ff629a571e46f8ce128fde7c2d8f18796ba1b1d7eaf7337212f55cf5cfc540c7d2dbf31", + "0xa36bcad22f3408b3bfd45d272f3387cdfbff57e014226dcd1db54bf3f8d1d896fc4fd16640b5d1484c9567ab9322a37d", + "0x8c9831fd5f74ffac203aa6b6ce03acfde8a2fd939b79236a01931d28b424fd8f6b6e44522d28e086aa12f0b110e5688c", + "0xb48bc95abd331d901610335299580ecec02a263d2b03bb0579cae3aa87ebf5e93dd110e7fa4306d31974099fe6e8f58b", + "0xa15e27a87bcd8ba69ebfb6228c3c48e19d79b22978d3a63af553b3083ad13e48dca496896cec195e63b8a4e2c40cae7e", + "0x96f3de6fa492dd2d653888311bc918ab832d6342dc7af9155bc7070004e89ca940b7672dce0a1b4976a7c3018f13e49b", + "0x81a022bee3593997f556ea53e2ee484188cfba0be4b831ccc048ae4b5a6df9e3b4d57c436caae5cba92486abb71813b0", + "0xb9d8e46df67e481c84d5520a9613aa92750c8e8a1e8f376b8ad7b71a3ebd95d2d191ce538e6f7fde3ac5943f70c670a9", + "0x8f0b52365d944f59d2ed445b6ecc4f88c687fd281c1913912c8e6075c3a59667060b42f2c1589a5955e9f3791e23aa02", + "0xad07429bab813045fd909b928ba4eaf262b6ea40b353aa43157e1e683b2752c5bf19eea7ab6ebb8daa8ee91241fbe84f", + "0xb90a99ec1f31c43060ef649e047bf24f2fa7fa9daf904136c6a5846d9479966b54090ded7093e481c52d872c6377eb65", + "0x8cb05fab3ee23db24c9bac109db52895b200dd115209bfa41fde510b29d9871907d44f689fa0f5474d12314a711f6fa4", + "0xb00d8f280ee21866b01ba3de3bf943a7d0825ed67db03d13a0b69f54a4ab389df1cb10909e831ec0af8f1675fa7dc399", + "0xb383d14fdc47df80be46390420603e7f505052b1a44ebf595354726f2b487f7f18d4243709d347e1e584c28167a0e988", + "0xaa951f60d1e069304222a8eb0338a94c8b3b4515d7cee833864b6c222ad76f6c48e0346c5603c35a3b52edb6f9381911", + "0xb887070ecae2884109eed80ff9341f5fc514d59158f5dc755ea46ba396f6783b8a86ffd2fae4419cec2ed57f4dfd4327", + "0xb1a6f1e4d25f4aade76714e52bc426beaa7592b975f07d0a6b372a3f94e7a3ab0e8829575bccc953195ba0c9bf46e68c", + "0xaa64bc4e0d9502d294f0d3e6a1400dc38f28e87c85d3429ab3575c821e1229f1dc8e2c13f03080006bc897e8fc3555c8", + "0x8f215476d94bc2af7d2e0eb68783292e314c9a4f812f3065cf064f427aae165990dc9665011af502f5713f3664317989", + "0xa578c8991e9e29bf3ad7be44bce3817e1c4af3e4a8ba3d82643378da78538787f581b9caea7602b87619e5f8cfb337fc", + "0xabe5453b650106cf65bf2b7faf8ff973b7b3be0e6f42983daaa5359dd4ca225edb7228bcca3d71bcb8d77241b320fa90", + "0xb7ed1d027dfa91d0ca5d797295e359bdb1b0221b1f5eabd2ef76ea3bf456f9aa9788dd00ea24fe0add9e3d9b09ae2428", + "0x96ba0f0c5ac0eae3f0031f8b7a87543ac369c22122681cade0ea33a6ca370cafd360ea6b80758476ab94cb07ad6820e6", + "0x966f6191951b998202b8a63e3b10ece69616b989e9695cda84a450cb953acaf9c4f902200b7492eb66cb9ae0cdc8ecf0", + "0x8d7bf21f76ca0e3b3758c293e66e977f83533d918dc445a09f4f38975ccf7220855627de6460d318290daa03a5f5c68f", + "0xb10dcd91d6602852783bb76b0a286523a0942e8eaaca4e0ee5bc76cf19d33bc631f6d0fda1c1ca51bb3d5d5c7dd43728", + "0x884d502d934e2b045357e981506900849e6eb051ca3ecf3079b485b348372496db97da384f8d2b5a52216b4d223c90ea", + "0xb074162e5d33171477ed48f2f185b1c83e8fc2e7906681f96ed97da8ee86be7476d65e61648383c2766ad9853ead35b5", + "0x90bd3d8b475da20c6e32324e30bab475f2059cd81fa67840a6c831026cf3d5806496a3a25192128da4b819c1b7cd6bd8", + "0x8da4889258cd6ffdf1608af8325230f74abe6a2a511872c2dd10123b491cb09407fb979d80fb1185ebedf421ba22d0fc", + "0x96fe1d9137c24fba18b1ac431ccffc01ef1792623bc334ec362751b7bac73c4d4f7e9bdc2d595ad4731c71808adea15e", + "0xac816ee0b9103f0bbdb50cc05f9c5c8f7ff2f14bb827541c51ae5d788f979c00fe4796b86eb9e3ba5d810925c1f34a17", + "0xb231e98ecb3a534dfda5b40916fd4fda270e316399c9d514dd510f0602cbc29e51c5ed60107b73e3c9721f7ada779f91", + "0x80115e104f22ff2653ba7c4e1cc417dc054663d488f861a9bbec4b9e907dedbb985e6e78f31dc16defa3aaf4f88dabe8", + "0xa0dbc25dde933e6114f2ec22445f1e209836585997b14100f3f8b7e62f5fdc6aa2a85ba5ec39a5197c9d4dabc9a5c452", + "0x8d2deffdeb1f0abed8ba62187f5e1cc06a1e2bc49b3e15f73c3d8e574dfba7efdfb762ab512cce53d7db790a7354c56b", + "0xb73f4897e221927feedbbf209e3d5b9c08f52bb732dc0d710822576abb7ba5ef0e728d2d95c802a00eba925ce99d734a", + "0x970761c7ee891b3ed08253d2c0d28478145d0776e2429c85b4734e5eb7a6416d197d0b1ad3392b37ce8d86fcaf9de7ec", + "0xb4c9e2acb4c05236357be37609abc437612244bb4421d69486050e390d5ddb52887a1b3e1bfe968a90f1695d892ba8cd", + "0x87caac2c93e192c34b5dabc36abe26a844a33bf63e9b01a668c90b70701360a0417ae3248173450c64034685d913f4f1", + "0xa16ac64cd1a7ad46cde1c93024fdeff724afe228818b72bb66176c7daa090acf58e7fc0aabc582ad22486e46f0b96c5c", + "0x936bdd6d67d666274c29765690f4ad9c4b9203e9bc9dd5af558a8d908dfe8d6d4346f6fbbfa69158cdaccb0058ed0193", + "0xb39af8d43ce9d120497888fba0dc95ceeabdd3d84421c1a30fea226e03b78cadca0eee57db524f6ccf1f6235fadd1470", + "0x847da75509ca07fde2277aac9e7622c5874256903a92f7a56382ad3f79d1b3b0cc0b06b2a6b2bd1749ed567e68816d31", + "0x969407bab3f8106a49be63f17ddd603e185afc1c9fc0ca0e90ac415f53923e3c6a69fe488d33403521231c5008bc11e4", + "0x82e25ef35abbd9b98c55a45e7a71791925639afd92780e64a154ad8a94e9807f2643854250f30bff1c5e8806632778f7", + "0x8e6da5cb8cd80d6b8e2321ba3f034ece1813a7b6ee3afac73371a51434a3e66221188162cd9b9ec035326e7e04e74b25", + "0x9868bc3e60478fd0ce37d35e0e4f7695f1ffb7cf2e05842b3a09e832af33c7ba48448935d425196fdaea9c3e8a5122e7", + "0xac7733adfeba1da388eee6540a127d0eadcbd23770f2deec39edc0bfb1002beacb9a8c7106baedb22e664f37771c1410", + "0x912581c23e3ad0d7eb886cfc22633fc704e530b6b4977086f68f1d9f839bbca3bf0162acede87c853e8ad8137b5cf345", + "0xa0315fee6285a33d4ec60f6c1557ebe4473e8990ade0feff7e008d3be1a709f5f486abe784398734d9ea1193929697e8", + "0xa44a08d6fe0a22849a8f518ed9b30b78367de205c3301fc8159ea273076488299b35c362530436dbb7e21b6b9f36835c", + "0xa591ea6ef83f2ec78a402a86ae5b82e330998e18ce66126a89046f169dee58634dfc531b1286277eed49f571df5202a8", + "0xa60d86619b41f59b48c800a302775656266725b44ff8318014fb668f331bec82b3b543ca848a7d40b2718f29e5ce6cd1", + "0x9420d0219d407583fff43c560964e1da06b105043187ea156771b1e4dfb5d5851d06fcfd819c7d8bb6568fa1bdacd916", + "0x97ba0b6731c78eed331530be7cc374a7f4a7cb2144ac73b7c000ca36036f68754d4edccf73ce373dd6c6be55177d89d0", + "0xb4e07b5c1376900fa2dfef8fd1a5a4b6152df7b805d5efc29057d1df2343f8bc841284ed23d2bab5cd1431fb95f71b60", + "0x8017de31e62a24bed74460dbdde1717f3a9cc17e2e2ca9848d77c3b5c364e7e1d58ac0eabb3daa2b7336edcc8a418b01", + "0xab6e409231b778bbc1ab74c3062a376c5287c0cbd7d19d4ac1d5da1a8d0571864d0723944da72581783cd7b6b0d529a6", + "0xb5f2fd4ef29a2ac847358abf2b3e7a3567b8653a4b9ed8da70809f2affc6ab44c65cd17f255db0cd8315e4801bb1a408", + "0x91b61d5d047e9c672d7312f563b8da90d9c2c1c1268913656f061028748a351e116f524593b1be7117a46f168b3e829a", + "0xb6c10b09ecfb92168906191756cb824694caa32c6f2f9b19c51658d44dc330dcd344e7b04333392a8a93c73346a3845b", + "0x9431d01a121e6ffa15c32e724dadcebff65f806c11717b050c106c0c80e43e622130f41224533d13be4a8d14a66ae1e7", + "0xa1248085c85855b4df6eb5a02df0dbd5de5a8a82656e1a5f61214885fcb75428647c8545a848960701d61c3002840647", + "0x9867caba8f4be9483df9b48e2bfa024e79e6797adc2198f2b5115d7283931fe4cefc382323edfa1e850c3970bd1a2d53", + "0x89e88c50c43d7e966e60d49b3afea792429563c93550b10584c91e4a827a3617971eb286c39205e2af4e7dfbc523fd8e", + "0x8ed261502f95814410fb081e7348eb09f3a3df22cc3ca82a2f071abca0190e9f041e8714b811418caf7e1753cf284e9e", + "0x87ac65370073b6bb85a945e138e4d0a5d71ed88739f72b9ba747d2a03b5d4877e8e526026348d2578c752bc4102055ed", + "0xb07de38d07906dc2838be840c291f467d9b695c62175c5afa46d80f34674d061107d6fec6847ba5f17f2d8729f31f5f5", + "0x899348bd385a7c3d38f9d740001c9a543dd8496b58807a6a73180c94f3aa5c15a56cbb85cd7124458e2ae44a454a8a58", + "0x91b70c3543b8e21cbcc8a40cbe00cf2ee0372ba9ddc7f610b711a070110508159e6a52e8778b20f0194ca09b109881bb", + "0x8ab84d75831ec1e708ec74eb6d6de2b13bf97e2d2262ece39e5ba5a4a3049c8303023e40fce5e87b237bb1dabfff5246", + "0x914ac70dd91ccb6d7b83a5ed0a9250c66e77a815aca17416f1796fc0e1c26bee7acec5de11e65061a44d2d9c35f5d19a", + "0x8867260f8024f533fcb75d9c3f2ab113d349504b40f650a2c92bb46aebae3a55de6a113cb6387bf00eeb2bd4719d87ea", + "0x9976dd4e56b16fe11533dce2734e2903a3ec986dca6540bd9ca8b758a59a1e45b1e69c0b8f094d42cf7e015363ce37ff", + "0xb48c840786653a0f3ed6b07f8f980284c5eb2dd22e9ecd5a0566754a1534300e129b39a8a6d4fc48bd403b351e714f05", + "0xb1633aae7c5e5c51a82aa4e4bf9f92c0cd30cc1067b03364825ecc492fa43391ea075195f2f73b99a11dc49f670c0e89", + "0x8769a592f503bf8ab03d767524d9ec2223c502ebf15b69eb4b3d53325ab366888afbb668bcb380230b5bd74b32d90a44", + "0x87439671fda66bf5989fe1fa2aa32519ef908aa6ab3eb34eb5b7d908e9a7db2d679170cf3fa0e0a388a355b8c51d306c", + "0xae1ca219832c90554a91a7258ca5598f8bcaaa7059c574803b2688d8026df9083985c2f8f4ad3aa9b122efe64e0b2481", + "0x94916e6dca309d9c7afb9aa4c0bc89a3de875a8537cae1fd32258b34782994e5be5c4987577d697ddc86b8d68dbbcbaa", + "0x8c5361b85176adf77ab1949d34edd562d8c16979e33b59d09548ad372b8c913ef385166bae53c8fef814a529fceafaef", + "0xb968172a6a831c6ae53e876dc4ef8686879cdadff0aef4147c4dc3ccbc173f89748b840a30ad393eaab69e422363bb86", + "0x8fabda060f8bb2bfcd675803ff0a3f834e2356152f88bc79c23f58fbfa6b0c82850f281f7b8fd2a5e16230aeb4077320", + "0x8e5c887c318335c5561e63fd3c3f64edc669c0b03b217e3ae40ea29245885442864dde15751d7c6ab177a91fdc1f7235", + "0xb2f67f9d64650c6b51b88e7ee6d6a796b453131c93a7791cdb2d0a4922d3c913a4ac988bac5b4b9bfe61469886e1e7a4", + "0x96b836824dc2a12ffecc6a053f7549b7faad9808e98bf20f3c9146fab05098df56fc2833a6002eb39c935fd8757d4716", + "0xa4aa33fa77b62605f751bcad91333659e9345967845226371e5f38d5a7f72405d0e30777b485b730e6c62d8216790cba", + "0xa041bf3467320df4bb7baee569cd685a65c9d0e431824b7de93ee47ab8b3ab20298d60746fea7fefb5bc82d3f7e25dd6", + "0xa85842f11f490bda22e9f73409de0909a2e61efc6d8be0c3f561d881988b4d2e6924ffaf0a4c40843481892b272943cc", + "0x94de0ecf58ef27228f5afb12496c53b075bb347f900b2df98f47ceda8675bc2941aec04d1c8ca0dec0233430f2759824", + "0xb1795a70651be509c0955b07d58a1b8655a2e6c292b939b6c156f0c0983abd7e416cb0cf14afac6ceec85f2c46b83a28", + "0xb6beb936ea1f1639ae59eaf53015dc1855ca0f798d9ed72607edbc6c119741e10af5354c29571af8befd83b8255a8f58", + "0x9424188ceb15c1b470c4bb17c71a37af56c87625e7b7fa752099802673c3a5a99d16e7d6dd8f8b680e89b75cbe7920f9", + "0xb9e22b5df8318bc0ff81003e8208ff3217ba1a84edf6a0b326b7180208d3a9144c6fa54c57ce6d6071ccb1a40eaf4509", + "0x8e5fb55da49feb7a9152528ad6a6766af75cce249eadaaf4806c6d4162f65f3c7311bcf8da72b96f6636cc019546c05e", + "0xa55f751de82aed5842f94d1ba1e29976c3d0146267b11eacaa4fc765da8d2acf617d3a65a2a74aa983130851f8c57d05", + "0x9647758fc596b78fb52db58f2ec31cea186d9d4f68692f56e474961b277396af4a51781b0a358a6a6aa8138e46443a43", + "0x9461f6dc72988b44c662865cdc01c0f970f078637859cbe6314fb17d2cfb3451b222cfb93a5c6eecafd1ddb36de075ef", + "0x93b30bbf4fa0926cc5483ba9803c8b001aa80322addcc866bc514f2a10aa43bbd86008e4671ea26d8e0d2ffd4bb8f2f1", + "0xb44020d0f062a001bd6dca2bc3ce61b17efc7a121a9035709f01a8c34708ed0c1c85cfe98c534189e0669eea719c88fb", + "0xafabce43f35e0d3201b60226c72c30177c4c5d75bac654fd2b58b3ce9de7d83ef01be60514817f1e7bdb525c910b8bca", + "0xa97bbab394253ebb02ba47ad391db3aec1b4d03e88ab3e7505730640558c11fbfce42d53b7f85787cb564208d3dc826f", + "0x805a34cb0c8c7ade28c69dfdde46b7a283e539977602aab165316e973c62bc65396b6fe2c96750ba028c550de03100ea", + "0xa0be38fdba281e0c248933ed73f1119f90e34d5b4435bb704a5fb7c20805e195518a2a424bb483f16500d74f440d4a53", + "0xabbabc7db0a20030c6e687b89162e704720a010d7ac53b9766a9ccb7e02d4ea1926792f5263d715cb97d67f2010288c2", + "0xb9e471a7a433a678090fe4324739dffe238ed7e9a867159e0b43fa80c9c0798cac6b58bc09a389223f94f22fec43e18b", + "0x9818e9a42ebf415c6d970c87261645f876d709751c8629d1ffbcba4abc8e3a2a1db8c4c6a6324dbf433c43fff62803d1", + "0x8290ed53eecdb61157cc458dd081b9e890bed5e4cfb643d11b549b2c65fe68fb981d4311473510781945b0ee763a84aa", + "0xae730a7c69866f22d8f9b0d8e17d7564c25763cc77a5eb718d5651b9c5198b2b9d3eed1c066f4985b2f6d7edb0a109d2", + "0x88325e421a1be440175293efd498cd167dcd0914c8827ebf64ad86788f1fdeb3c16d3de7a681f958b0f49046c54fd804", + "0xa8f592d6ba7fc3ab8ce8260f13f9c4886191530cb1d7505d0beae54d4c97d09712930b8f34ad74f1ac5ebedcea25dc8b", + "0x81c0853b0310a96674a92a144a14c48fcee0d72a772451ed046c284f16fd6447f67389ff7841d752a025da172d62e73e", + "0xb9f50526ce4bee12fc3fd8f3582f3829b90840f6eba06f37b53febc1d0987bbf58107d73fe4373d79e53827270bcd817", + "0xa2ca28f619d4821f450b9431bdcdb129d4f35dbc2a4976e4d416dbd14e378d4d60a517457aa0343f7a5e60a7e246e22f", + "0xb9576225cf7e13374d3975703b3850251d53ccafc6feeedd07be2b0bdea63b899139a1fb446dcf76f62f3c03beea0486", + "0xa88df9f6e95df995345c6265af546158499fc0d89447d3b387e7708fa037f95ac9c4e20ed35b749b8d8a7471dedeea87", + "0xa853ec333af8f35d51ddd6c4d45972b68fb36219e34278efa6cce02bf8193d72c6014ba6961f8448785b0a43a31a688d", + "0xa1ead9282496e590bb43908dc64341595cd22b844624e02f2daf597f708ab0d336bcacb5862bce3ce23d1a9616fc6179", + "0xb97398d8ebb52535a1ce3a10b2255d358142ff653def823ad9e9ce4ca5f372c6e7c9301588ae5d914b2b921a0fac7442", + "0x8d0d292c7e9122b8d001b3a3323f9d37dca61de5a595f9402ab0e53e941c83f80237a853abe4aaf012a35cf59df48c68", + "0x830535a5a8268d5ce4e7462fca4f809348908ae7ee117312244e0a9c30b09d91b6f798654d8064091078400346614e04", + "0xa44a90d3d307ee3a3c3838ce43a873311789a9b9292c62a01622bb813a02f6defd21b0889cb6dda6d7225009cc6d2641", + "0xa219afe00a9327f2c937afabdf5f10bca0687f48d8f7a2a046a52e6924af613f38cf82454df4f412f5991ba20b7db74e", + "0xb448ed4b15ced4de098781793a6e850ea1547d514646fb8f1c137c86e14231ac4340b308bf07813fb813cd02e47c015e", + "0x905fb68b8f5bc14834a06d61f3da686bee77b3b590a33c640c82f34e68ab993f8c4897df463973d6d9f0d53f9ac5cf5e", + "0x991cb6857dd0b3ee6597aa2fb1f4ccc962cb038228615466964680795587240e6ccf7861ec220a53ede1e2e9752e1cb7", + "0xb823dc0249ae72e2de91108cd4ae6d6af3e464f12a53a46ca583727c7351a67f2d12c911534e234ee187389fcbf1f621", + "0x981ba6bda1816036e75a864f635629a141905a4805c706260e7a5e12b82dfa9de4f4058143065b10a1012adca6b7d083", + "0x8bd8ec0e77a6867057e5393d82132474eba9fcc4bbe025544bab0ada4ebad3d296ceffa3788acfea0a44406e2ab637bc", + "0x93eaca3a7f9a0dc809eb9f604905b0cab18750a9bfa42d98d99728a6de6e0f1e05b6e98bb3b0d9862a69eb57ee2e18f3", + "0x90b077d7b7b1651ac0d723978b3e408191c2b8b08247fe2a7fd69afe0615dec09e43771cd845c2cd064b56295e53f634", + "0x847e8f607332129e95eb1f3e00003b087e92ebf1ac9477304b0d54ea38419fe8581122d21bef8d034f788a9c92f4ec00", + "0xb0301becb003dc7cd56ea7d830bf0fb4b85bdb33606d8d9ab2b70c6415ab5c8f4934bb7079ced16081b8f6d16b77c0c0", + "0x9068fbbfcc95fff7ef79ab64063dd9bff0c40b4855eedb39bfced9250cc351b5b3b1bc6c2d038cb6d59a12a41b3db664", + "0x84857e081fa1c6c08bf7b0bcfe7c6d74b57cbad1b67676e99686bcca0b17715ede19f826517dce3f84cfa014e11909b0", + "0x98fbfd6a94ac3e4b53b811e4d275b865486a52884352ff514889313c7a15b07822f76d428533a0f8d3cb42f1e6f72356", + "0xb4faa1b1245aa6339b5bb987f3423d187f6e7e5d4b4b341de87ebdea53b124932cd0e586470cf4a3b1060a126e4ce7e1", + "0x973e88d073071c2cf5ed643d770a45f6be7b230896caf72a2cef10e56ff0a4e032d6ae1ff4c19bba2cc29f29ba70cc19", + "0x8d40b3285879fb9ac0b6c9d92199afaf4716fe21edcd56b1a1fcb6ed298b5ec5b3b64222eb6f0cd1086d41872911068a", + "0xb5e338a02076ad851778d590ada4af1c217d035c2505b891163689a554e5a957219410bbb435bbb38c8a1515146f8789", + "0xb1d3e990d027a38fc8a38579e39e199d9984dc6d857bf51e2ed5fae061c8723fed3c74662405378c29342bc4f1fff7ca", + "0x8679f10f866804b19dd0b14b24068c1d32908a52149d33ab03394990cc60c0f388eef02bc0db819f92f8197b1fc60c17", + "0xaee5157db1cb7ca8013b0c19201ea1e7af32e4117896b3f8ec0ef0b2a4ded6a5e7c893281865cdae7deff4532a6a3fe0", + "0x950315818b710d3903b679dd0de0619059bea7dac3bf4edc8fd4a6dba81b7aff9bca7cf1972940b789458f287609439b", + "0xade345a6171b8e8afce7a455cb98024d0d91dfa347632e1a5a40721868bfed1c1959300f1e1e39a551d99a4e1abb563a", + "0xadde1719c13b3ec224bdb6b44dc2c5f2daad54e7ee736209653a0198a769180019d87fe6bdc37ec1b48f0212ea5a8927", + "0xa3397eba3ed2ea491e8d0328333689f66b2bbed0e1892d7b14b2aa45460a12e4d592d78a5d0ac20bd6d34c88b8f1f7a3", + "0x8613160aca85f0154e170b1b3f1052ba984f5c422c4c25e0771a53469c274130a31f875a0ba9650f77fabd910cb10467", + "0xa91ae4d048c56d5b2383a9d8f6396837543b609d8b0be139ebd5fd31fe4a90071656442ca7f14136cb8205734d929b5b", + "0x8e42732269c77887f105d1c326488025f9938cbade678bc6b39941311360408ea6baf274bbf5ffff996756cd2390bf1d", + "0xb96e1ca66d51a186237fef402bc4e14f8f96a138db377b7e2c3243954b6f47ca75cf4fb5dd081aaee634b5e2efe2a065", + "0x81d1c20d76ed054923c17b362b50205050f185137ea10559e35ee7e191bd89383b68179c0aa4531eb61abdc239ae6891", + "0xa350b5778e26ee808466619f73900e09bd387849d072c0c014517d16adb4e3394673238c4f4e705d30b4ec2edfe5a695", + "0xa13657433e39c0241d48075ae8ab1efe3680c96d078685c5dc0ac3c49d468db98f2094dd4204f44e8e90bf54059b5807", + "0xa96255abe489be9d42ce6fa76ee90e4bb6a36421fb78068432cc935632ea5b5bb2ab70790ef79422f93d35d1034568b0", + "0xb745d643480edb577b1f92ded38a522236fa1be2944ad8102ca64c3d55f6297b7e0aa1beb082261af1cc334f5a723614", + "0xb235ccbf94e2bbd3c794bcaf84266141c0e04ecdcd7d2def83a7eeb86a2ff4dd3ddbd8245296b27344770f3d5d332f90", + "0x935f3e4e9dceb4f58404ba1a489985001827e96bf6be227a8ac4e2eb8a950d4a446320ce3a245d09d2d74776c7033a3e", + "0x99cb7f3d6256ee8918f40642f5cb788f0047a04c482146e70687c3298629bf082dd98d4a4c222fbfea3afa3d7d806f00", + "0xad6abd2fcc67af691e76792432b83b8cd9b0a9e5e73de21f89ab54081ea002ffd904d77ab8efb6906790987e29c53ff9", + "0xb6de4c3a45ed7898abc037a47507f46f7327c057a911529d3a671286f98e79a421f4586a7ff3235f1892d0cbbd0e7bff", + "0x9120311b071d38214e39f4b48ce6299ae9297c7b76ab364353d3816669cba56592fe4c7f1f93507bec7ddc1df471f0f1", + "0xa6daf71681485d01ae7fd4bb81a326d3d2764bbed5d3be45efcbc04aed190163ce8f9d04a84bacf25ec151790f8fe917", + "0x9534da45c2a497607f7440f61943f4c16878a18f0bbce00dd644de88383470705b489225f5be4428d1f988256b70c926", + "0xb2d1b633b4832dab1a530a1d85415e7fa3e4a1fd383ddb898a79c7ad028f2dd8fbd56b83600cf481eb14a073cd65431a", + "0x8c43dc994dfeb5f22df9560518df32deb1af43f254acb8e6f93eec3fb3ac80081b39610800d0822246e130e8c5f7a067", + "0xa18174ffb85d13b7edde5822f22872ece12383d79fbbdb8c02bcc9f654cea904ed8c03b8709d70736dd4b308ecc1607c", + "0xa54e4bb27d6d561261a3fc48705781399f337448c0afa68c074918d2c14ea7d51263199b01070b7161c3db8b9949717d", + "0xa7457cba2c5b455584980ab6d0bb5253dbf2cafea4efe5bd769020b970dc35fba4109d002f5934610b8b4a158252ebdc", + "0x877d4111f50f77463b60e07843b4521b2c44629a7deff20dbabd412206a4fe03f976de1a3897b9df7eed16217f03e2c2", + "0x84d1ab99732fed1470f69fdb499dd3de795b055354e89d522c6a7df4d6a5375052c8befa4dc7615d29b3d92ce7df2f24", + "0x93bd139c343d8b83403e04547072c3e546c67445220afd06c119f7119730288629439640302d0628e74fa596e305c0e0", + "0x8157b5ab48d026684f6b51b802b4d8e7f85ef82583d1e8dfeca042b47a0e0f58e30cfdf4738e6d51394b260a4ca7e19f", + "0x8f03d5c1720540c29a1dee44ef5c7f8b209094ba8376d8e5eb9b52537d9843912b68562eff742f0a7a07f5faf6abd1ba", + "0xa15e4999a0028b8b083c2afbf4968a1f0397c26cda8dd7f6c134c6a860e740ac4bf1a1936849a4f2080e0cc9f8e44387", + "0x8b71fb85363158c7afc3c41422e9a32ecb2d1f9d3c01fff00b77e0ec6a8661e95b552a7f05f4acebee751448ed750684", + "0xb34125432d0704c0638090fc4566780d2d8038d803f96e19ff748325f8b5579cb8867e12491921feaf3c0df949f36aab", + "0x968196e10bcdc6cba28331a229acd54b59edaa83cad0f8d14f39d787467bd5ea725a3dc3d50accc334e74c81fd762cff", + "0x968abfa40af365986e68c47b4eb3562a72793fbd66a7d1b3804a5bac8137f0a3cbbf5cd306097cbf1a3b95c3414fb061", + "0x85395fa84223dcc16b7e620a7ef6f902f7b29dce7760f57baafb37d985755e65623768b8bd745c8de7d00e2035aba7ab", + "0xb57ad86ab3f5cb00ca0855088921865893b6e539edbbd504238df2f9b2fa7c7bdbf2d6eec6ba8e2a70a4c4fa3f459a97", + "0xa2f203ed1f07cca3f8c0d35ccf7a63216ab98c9e71557e829dea45e2c723583bfbaa7a83d66521b08a0718c63973a6b2", + "0x99a3522974525f4ed10623bae83dddace6f9495687cb9cf4ef52c8530b05672c2b226d3fc5058c56462ab3737a068baf", + "0xa4a50d127ad06067f1eac2d61c0a1e813fceba2e5e895467b5e6045c9b7308d3678bed9212b98e44c19a1783e0f57bef", + "0xa62d103ecc1d5e1d5cb98a0bbf9682ad65774d63f67f95bcbfb0cdb5e2437f2279043e4426d490f534961a2487782cce", + "0xb12fdaa5ca77456e6e96eccf97a303ee2d73f547916ed67378835402136c2aa03e63912edf5a67785f7ac1636f6ddb51", + "0x91315750043c4e08c7e4359b9cba25309eedc9c85672851f05a0651dd9b9329bef00a79cfe73ddc308d97cf548486b47", + "0x947115aa6cb3c635bda7f3c5fc3dd0e4881500d74db4c0579e4b9039b75b131eb5db54174b1bb970064740551e6cd1c7", + "0xaff091a9c7e86c80646cfffbf154ecbcfeb66877c5b773b6e8759649ada1094270e57970cbf2b0a4bcde9bbfa9689b1c", + "0x81e3cb9116f81e583b7579f9af06931a5337fae0d57d9ef777003f32e0eb619b75b74137385f9e30dfe0e10c2120b02e", + "0x81ab49647db2a5a6f47ec757d8427325fe721142377a287c547fbe04ea280acb32d71f3dedf7ec0f67b43ffc5d748342", + "0x84b0e16d8478b798694503ac4a87ff31affe0ef6d2bad47abe0fcb3a2571fc8e4e9c966276a5f4968b2675827a115818", + "0x9567b2edd65974393cf2181d235f877f5827a6d5ca16e77165ef35f6c66370f0c55a2dca5387c02ae73a66b81f01798c", + "0xaf19f841026271e284548b2cfe9fe7d6f9acdb4759ca76fc566de7a8d835408f86627185fe32e705f94e6a719e463cd3", + "0x83883e1c9d215c90948d066d2210528552093a726f0a27b8342b611e4b8639f6d2a5f95bef8cfea4312c1f2203f34986", + "0xa48019b2da37a232b7999f6b668e2758f82132e15ea93608bb2350d3188297c8ff8c791977f2a083ad9773570bb560db", + "0xa1fcc29974eb065a350cdcb4283b2a813f02421b872eb3c15056ef96e2d5ffe2fba0e10ba19a4d271937cf08838e4106", + "0x86f9ec59a1f5a5796e498247c0ef1457ea7ab098247f363329a336a1ee57afb31cc18d35e008a5263e7c401fad5719eb", + "0xa903f95675c14cc618b02f7a0401ab67170b4a143925979791d76aacc90ad1faab828fe904f13d155425b2ffd79c008e", + "0x8f652c4982220b8e9868a621a91eee85279b13b0c2974472fbba11775e6bb1d8d53309f500fbdacdd432170bc76c93a8", + "0xa9b02cfa052b5808c1c9ee65ade446a6ce20174bd2e9d9c7388a1973b0290debbb6fe82697f09afee6ed01c9dd99b905", + "0x8b4c700fdbcb13854c7b1d257a781fb7449a9e3236b962871f11b31b1f2e69ecfa6039e2d168ebdf2f142f93b91f5882", + "0xa9ba2295980603515f80f0130993f1be434281fd4442ce7e68b2fee12b24e440bc0282df67707e460bc67a4706bdf8b8", + "0xa382b85dd64b70296a2d16d1d15d6de80687dec9cc074445fac8de7bad616a95972ec399bda7c2cffa4247bd04413b76", + "0xb6adb37da1c6cba5ddfaafa3718aa66fe2821b43923ec371cd4eb9e974ebf3d0e94dff1ffc1347cee5c9e19af7c76be9", + "0xb5b531ea7f93c4756e5799118654ebc478a3ab57ea51125fd31c012053c759c8a52c8830b53208f74215e437d059eda6", + "0x89c88a5ecee1931dc027d1553b5aa82dbc5fed2a4bed329809467f79f2712fa5529c0f80ce6891817927d0b66d356db6", + "0xb4ad1964f73d3b7bc338909df2ab8889c4faad9b3b8a5959ea81f44c6c4bec95f0fb6e8fea1fb7e09789c690423e2b85", + "0xb573bcbd8f484e350db04eb263187ae4e99ecd03494058e68221aad8d044db82957f4bf23f71a9634b2ef9612a78ecc8", + "0x93c3dd86f7c3105fe482f62b0a56fe43338aef50f0d10f237ca774f834151273aa653e17bf919e54aeb35343ed790c0e", + "0x9069c429e7c6507a755871b301b31c3b4233006c51bb66ea2c9051c6caa52e933ad81a8e879129e0c1b099a124bcb295", + "0xa22203e5bb65593bd22cd5bc6e95a2f5c9a9aac1e14d948a7e0aebce4f009a56623026e0980bd194a633b42f15822ad5", + "0xb1585de69b3014634da2ba76218321ff4ce8476b653ea985a7330290b1bb1445db3e1f3c510f9ae7c22940157e2df36f", + "0x802a70ea7fa057a03d12538c3ad6b348a8e694bc6b483cd62c97af8809627a161223557f1d5196e23f13eddce15c814f", + "0xafe8b0e94d8d9b44652602c5ad15bb0140456d90c95af4ba58cff528e2834e0036572af867488f27cb2d27d81cf02e30", + "0x93bb332d924bcacc41b4b9bf726647d7cbb642847fee5ee7dbf3d2a0489d71802d959a3e905a80ab1f34097328632f00", + "0x8caad1d29fe712bf09d505ccfc724574c8edaf5fc743953b2771cdae006ad9792a889e0c8136409b8f92e2cab5ba09f9", + "0x8678be67412da4d43d74660df98744c54365cf10aa59e522c59afc3836d115380416cb1ae497ba4b50ad31a23ece8b92", + "0xa48e64a5447ebeb5f6b0e0fea29fd5845b378e83f6b06b79b604081e5e723930a0d4c6025627382f6baba8d47425cd27", + "0xb8914eefa2f5613dfe99f11212912dd53d678ed349fe871781074d5b6eed1fc7f2e5bbfad3356a685c52a3c8a26e7963", + "0x836ba66155facd2a1839f603644aa5520cecaad130fcd5cf379139056d3e163bf35f172a4a1f015924b89137f83d366a", + "0x835b70cc340b57a09b1fecac678be381ffa4c4951f6742322c2751cf1c748ffc2b9bee8f155c007d88ca69c12bd9db20", + "0x8e98b4ae7c68941a48a70f703c3d5bc9a4cf6c20c61eb4c1338095920c4f23aa9eeb474a0430dc28d355b15dc6e83b22", + "0xb24be8171a105f203c5bf2ab0797dca8ce61ee07307e1d82fd26fcc064bd8a8a5b6bcae8dd611f8ab650176e694da677", + "0xb057bec8ca008dbfd4982ce4516a4925a61bd68e7a36b182575c6a4044c7a413ecd1dffa66ae3cfe2213763dd0f55a01", + "0x8d270924c541120a18d587cee51711486f09a39444182800355c4193a76789614c6925e6a448f46c1891106f866f08db", + "0xa0ebf85c44453153764bfc817364493166833b0f84b7a7c505a955cf3a7d4c1b4d2dd00145220d8a3207758a82dd8e4c", + "0xa56fbc83a3f1034337ca0d5aa89a0a18f900c3654d171d47ee86b0720c6a965c09c9b06678e3f25b151b115d129ff7bb", + "0x833618f5d13b7919206c8e9666997ef26c04a74844f57150e7268bea540e30b93eb785803535566765bdc899d4f10667", + "0x987daa13c00dcacdfb1f0eb13c38ddf773e7e8e19af125604ede42c6d0907f9ed1e4b8b8c9118b14f9449026802a6200", + "0x99b6e669cd7532b435d01b20dfed29211042beea6de58acd68b6eba26baa1687d80aadff901b5607a2553df047ac51d0", + "0x82c81899cb76ae21838558a1946425c719cf68d07950b0f106b859048107c13e4e83b0f2762ac8590cdd044c3e731f6f", + "0x8f1c5f634e38f47cc6967f2a80a449f5bf69585622c333d784263e3f6f027bccf8910da76435a84155a6fbe9a8adc4cc", + "0x92d3b5515744115dd20742be1a72a455c6d481855f4366a0e960104665db4ecae8925182f32d4e1d9dd7fb9aa246726c", + "0xac86e14775cc4ef22cafa8ac3298bff27fbefa9b7004ccb16d2937128492a2c1319641062f609d27b9314aa225301d14", + "0xa07e1ac19f4c374d68084415fa4a8068c0be540c8b9d81c0837347fe096547d8318bbd804b7642820e43c284af663258", + "0x839266a2fe6dddc446d4b515eb538a27b5a3a5e1a8246f6df77c2de8267e172bb7522aa7985e0503c68db9cf93399b95", + "0x8a381fa29e553fb57e3780f915a86048aa82a8a09059c80154df9490271aa6b99baf6bb217df43c8ea1265e85f07adfc", + "0x8d8806db0093161d7f83aaa2cbf0bfb8cabf823cb54bec094f886da6461397f41d54c39f216d7ff4a8262d12aa8ebfc7", + "0x90aff3f98394674791e194b57c3f4e6e019471df1a74dc47bed725d4c47399e91c88a955612be47e89002f451ebacb55", + "0x8bce2d60f3e82042ba94cddd02543b46cebb8770e9b7833b4e79289d4c491df7f4da0ab69778cef92dd81e5a6f0eb71d", + "0x8246fc9424b5d5ae0a3344acd7d6962fba6b68cde09332c262d7b3f379cac2c650d80cb5ed4baeea16a5557efb6878d9", + "0x92ea8547fedbf440517522c687f1d652ae4637cd072147ef31338a40e11017bfdeac42a32808d33522a71136cc3bf26b", + "0x84f6a64600184c54d3d5c320498282947b8a8166f09ccfdfd6d285cff374312da57087fec3838a49eac5b93315f03b80", + "0x86dfa1485e343c861286c057109119ce8e20abc646a4411696a3bf4718ce03d37fe14b6ea1600d8a7b172fcca6d08ea1", + "0x8dd3404facfe49c2f096d2e74641c474c9c54cd6121771061db3c1757cdb1cd6813d3ffd79e3b839b348d34b7b4f1ba4", + "0x8870cf255b342ffbaa2dcff41910a37afb29ca6a721774953dec182d95b426a481eac7bc107c4c2ef3df9f70e04e0b88", + "0xb0b843ccc630209b9ab35a69f3aad58c76b2cd3cbe94579b5757350460633217246b342fd098e365fb3ae88d5b7d13f0", + "0x804fe307b2d477085f8d9800c8a11c2dbf6f662d684d6a0d2fd415cbe4a09255e47535a08796a805188e1bad779ce121", + "0x93d91029bce430ecc5f41a460c02cefd3fdcb8c3e761ba26a020e108e06520cbe2eb0c04139aad0c0fe58ed34d8b2215", + "0x830867ec984210b314e7f23dc5b10e6d9ca53789cc447e29ebca229f4c79c9120618a540a9d21e4ba2ed8a811d6c456b", + "0x8d7a89ae9d7318d6578c1fa75b3babfa7c9df7099eefc2a9983ffa96627f4e7fc99dfde21b92fef5e0034dfaee35e97b", + "0x8eb68f5875dac63cdbbeb5df2fad7c1426939ecb6e3b6a48f737bbac1179ed4cf5a1e6919529878169d6d8552fa5ad56", + "0x861e26c9a31d21839735cca8a384b981f7346b026cab7d60fa95a7ad7a4a370cfb409812ca285090c3f1c3a95e5194b0", + "0xa02ab98589d48b2240209f54b0be78edb56b614b1aa02095ab5a9cec6a04faf065eb7b81bfe45aead551b1f774c60161", + "0x88124374273a2425bd5932a6b446986756379c7eb93d3ba0c5d7cbc3477e6267d9c67e5e956cf6df841bb263d1a8e224", + "0x91a766128a4c718a45db571606867bfe6e1b1049f0ccf71a01138d5443014c9758000a8be4dae0caca56321e3f992e99", + "0x8dbfc433e2477b9d86f221e9c49fb8db67c85438fd54b670ce44b68b62d4c0a9cd56c37a2127fb2adef22c07643fdd3d", + "0x880cb650f01191db0dbfe63215d208f70f924380fa22baa0e5bcab60f61ece3c6d4cca0e4363291f6a10aca9649da69d", + "0x8532214650619e201bd330865a3228e9ffaf1f64ddd33d206be5616c691b1965814f8bc507fc8a695c8291c2f8713dae", + "0x90e81d5a9d8fc976a3bf6ee6d3022107d3a9441ff212305cbc7c35bc9163321cadb352632181ccdc1450f91f51872b00", + "0x94d656836edd68384df1fe61239d40a36a0fadd59abead673e4a2ae58de5e2a6bcc4b980dd9b517e7212726b8ac94ee7", + "0xafa70edfed2d81326f26f111982aafad55f510de95555a4d05d9916a600f3ca6c1e3f66d6b092c91c1fce6c407e022a8", + "0x95cfbd616c2a59acde8152578737d3ed329aa82a950dcbb9378bebc3ec8beef9be2759a937381ed5aec1a46d486d1afc", + "0xa0a1ae94bcd07ba44c30bf50cbe0ddca2fdb5db82ae73e53c2efe9446c2464fea8e5de31da4afb99c6405798f0f9a59c", + "0x848e10f6c12a6adcf711ae3af8382178c46b90b9ff9970350f14b1a1b565a7efd91eb96871277b86040d26561acee099", + "0x815e749e4a56c3b982b50ef5ed249c4defee558647a5c6062022c3ef42b5ebb219ba770f0de74869bea14a98eec02360", + "0xa4d88794689a0f2e194988114ab96d28f77a29cfff606228ebe030a62eb4fba25cefd59d3d5f2fb66acaeda866f5c24c", + "0xad59a8541eb9641c3045d5cea6e3930b35886da4c96906f701ed3ef90cf74431df3c444174d9071a1657efc8cebdc739", + "0x97ae83289d535707039e9df8ebc73262f881ee8e288f73b9f0d6fd209385d3e2b761fb87ca852e10cc4818384ee155de", + "0xb47983e11702462a23e26c8d6407b01b67ad532bce3f1e0626fe3164886603bbc803c688729a64a69d119b15235389bd", + "0xb447011409a07a2d9074e08502e882098799f3b649e947de44c79ecf86a63045a19985857ec500638a3baa2b228a79c7", + "0x870f506356aa4f8df7d61449a7c7a8689705388b8b81dfe08fd79e8a734c998a7ba71f1f6e9df085b8aa5813a4ec4adc", + "0xa07abf6abcacd7612338b455c1461ff484dccda7430d4e9c5f9b4e5c1cb65055f4be650e6d67179b2c62709cd52a9b07", + "0x988b73c2a71f3b1d6b4734d231c089ad6cb07f7ea6f4b8fcfdd34aa33f09feab6cda91232c06b47e90ae9930ea46beeb", + "0x886443bb8d7d6c7634f55da1c5695f1691750fbf9ad2d63621589f91a0205ed4adbd4b905c62effaab235e740a172040", + "0xb66caf1ac38a8a66c43767e8597ddb66fbefd888989ca1ed56abb96ab9fb41937927a792ce422577c68286e53bb4856b", + "0xa84be3b37007cc932429ba2b4064ab7fabbd0b77400bbeaff09f8c6b818b5cd127ff8497e131dd8bf4323e092c690219", + "0xa99e9898b6f9b7b1b9ef6f28f60fe2ea71e961b64b262cceae41003f6aaa16fa3dc1c2ab63bf63534718ad812e882a35", + "0xa1cea8f3f5605a5c60144fed53943d3f259e3e33545eb0dfeb211a9dad8d99cb3cd3b2cf5031b85778ef6520700eac4f", + "0x8b979026924097a06b3827ad28f3efd7f0e5aaf7920ebe5347fabc61b000631f0ee973b61b7468fcc60ba6e4381ee478", + "0xb5dd7393dcff33d6d337328167ceaa7a04a98e0acf1dcbaf454247e85793fcc9a7d280ab14693cf2cee01afdf44506d4", + "0x8580c90d72c0c83c6c003dcc340553ea547eca5989780493c2551ea9f04225d77ea76acc1bde20fef1a0bb7ec01685c4", + "0x8c77db66f09e76ebf7ac14fe2fadabd41291f7ec5971060580b317f6af0daabe099f9db2c3d09c4c6edfa41211da0c4a", + "0xb6dec051200c25f150d3b9a7802f5b7c361b074528c79dccefa77d26ea2f67562a6d9fb8246369c6a60f832fec6b7636", + "0x8620173e19eac12fdc7796df12bd3648c66f78fb83a8e6f6c9077c34027a3acd0884ef2e3455a3de0fbfd4ca130ed545", + "0xb44e3ae4047f917fe1af378cacae2813f8774307c20d54c565b674de197fdf90e1a6da0733e948c3218353c613d23fbc", + "0xb330af874ac5d749a4ce1a23f4fbfa67f71e8fd16f6da07c714218be431b2a30cc4ad2594994a7a35f5aa06bf87ea3ff", + "0xa5be67aad05a965685aadfe03d66ea1136e6979cef00605e92912fe8f84be7351a6acf6b73c567a20ce6045a703cf557", + "0xa1672ed63df30aabe34e8eb81209ff31f4e5eee620b58074d92d9cf2687e40217169df59be8af7374aa5a9107c5f51c1", + "0xac01de17b74e2dacfe3db539910b6c370de94e646b6f2dd2a828a381b04f2979f8a62bac473659fe7b6e126f15ed7aed", + "0xb978099cd3aec49300ef9ce5561aa30da4d37cb5c697e0b5cbc3c42ccf2f96e53e948fc579cbd24605101176a353a962", + "0x8c8c439d9da3627e9f74da784bab8191552b945bb5bf9abb673659c939a60903e11f37300dddcbc8a495adf5c038234c", + "0x8b4570ac55ea349560a4e7043fa17f264dbaae15a2f3dbc5ef8a6579e1f9b5a440aeda94122982fe564f78b615de3e1f", + "0xa76bbb163db2ba26f5dcae8267d1a890815a76196af10444d3a04c1debeaa3c7cd51102fd0bff8944710c743f5393745", + "0x8d3ba2494b612f93b4ebab77e6f207b636e2d09a3e4a9666d4ddd5859fdbb9747a88eddb7749356b141a071584677ec5", + "0xa8bfd973dee352ae653f7c7bc7df2b32d790653a3f1f2b239d71677992938cabe941fa609e915e607809b5fa954c9073", + "0xaeb4c1ccee15753d4fbba545ec4ebb05c7428427f087fdc0852a18439b19b1669a3c744a0ae2e7f74c46905f520c3231", + "0x8fffac3ff9de863257a836aff3cdb705fe7f4bf604c2cbe10180d81c0956f723b69438bb8a3aa094fc755e386234dbf9", + "0xa583153b241d31223ebec9a95e11ebc4a657b14056b8ca052aebdd9866140dc4669bef4f02b5ffdf667ddc9a87e0bac4", + "0x93177005082ccf2143f24c063d20068fda393948bfac34af57ca58cfbcd0bf9a0de46f8f41312e83a502b7ad69b8f2ce", + "0xa79b0967599894340ef2408b48f42e6ba4f406e5ccaff13b46414ee38e5329ffc145f6c34d8e8acc6aba41c23e57e7f8", + "0x809a356a76d54a05e5006f2cddf0decf73e5392b57ead32ab56bea9fe13c1ad090cd69a8e297fa6e017b39361906360f", + "0xb051226cb44ab1bf94a9cc0e4f246751d68f32ffd12f1d077d3318de642f3997fbfb0f2ae1dd103264542c2bd0293e57", + "0x8cac28256b1a82d0be373d884d00e9ff2e384d5afbeedda706f942b1d222694f126ad44f9453fc8a985cf69fe11ad70d", + "0xa13b073290de7a2f01a65e429e1adb78cd37eb23c24d6fd5a1632cce2275496179e3c22e0b7f59fb51d526402c0f3f7a", + "0x92dab68d1dbf07e5b058120422ae610806809ddecd2aeb9d11d8fcac738c72eca584b88ff52c95817b79b9e0369e3ba6", + "0xb24267fbee28883cc8649c243b13905874e5d97a285b9c6abec749a53e106db0a6fd6fd8671d5b7c9a1851da75a4ac5a", + "0x99cdf977dbfc10084b698c81cffb431a9eabb55b1323e1b15baed5984a1ed212ec5f6c58372f965fe18de0100292e26c", + "0xb021c697c56989bc8c06636cd623c3672e8885598fd2014f5e560fa2f721f9487cfdbcf4adfa34c178ac84771fbb77a1", + "0x8fd7e3ad3330d4eb1a0bd42801d95ce40a82b43c366abc823e25311aa1ed882446d60b6309e1a1e201e725326736257a", + "0xb1b3c641ef4cbd5e9c69955217f53373cbd104916e04d012eb40a24d798e76bf05ed0a218862ce02619ef694c42be170", + "0xa376d0296c0105789e9fe539a5d22bf62ee36a2de4c9aa0f5e57210ae49e2cfc5209fe0f467ed19dc95b9746595255e0", + "0x8a0ec125a145e373929ae33efb978bdaf16041eba684ada612c244bc3e28c7027886e6308373a5ea53c9c3d8e868ce1b", + "0x93fde45cbf04cc386507b03eeb93c885da12bfe519df9fbdac5ada735934ea6e1a6cce066d033be66163b078e96e2100", + "0x80c1839ee1d2ddcae1fed77d5f8091ae3074409461e04153db801e05b44a7658c6ccadd33ad682e51e211dd9e3c80f72", + "0x87112961553b4a243875ac8d46bb6e274325699ccbdc40d7d9b7f7e58d3fd164f86b0b1df5df5f980785cb3918dc9b33", + "0xa011463964a319c1ea11c7c55c607bffe0116fc834b8a1d3684df33f77f6e51dbe16a891307c9f51d5b4d205c4530072", + "0xb316c4be33abd10400a4925f9d20ba02ab1feb50af39b6f6120d6dbcf1bde0a8dff7e08c64bd1f5c43543b013e242483", + "0x9555b696d428c4b74806a7d08b9ff17c8512a86cbb13040360ce248de241facc42c042d3779c28fe98dc3ca96a47b2fa", + "0x819f54bcfc58a7b793d185d8ffe411bde6207b77cf22b0d5e1b3d9843e4638009c907fdec1966b485f95870da57f131a", + "0x82c3f9623bfb8a8ff3573197497c175fcb314addafadd025528f805b7a63c87b0e54b48d46c0322110b0043f7f77153c", + "0xabc023b35318fd97ec81933ce55799d8c36c3d55cf59b9efb302b276a76a37c517d5c690287f216ffc5d1fc082e116c3", + "0xa6579226d602a7ceec06d402d38f217b836c8804e9da202bfaf1f3f4f15c24762ad6a2414ac022d8de68fb76ba8a725f", + "0xb701d6d60387d4e2308a77cebd210e868eaec10d86532ea18c0c6393475b3976a3eddd79e469458bae4f496da7398fcc", + "0xab202a2acd4ff874cfc147ad1b02d4515ace254f8b828f619df2537698f4e1b2687e004c70a152d605a73ab1ae40fb3c", + "0xa7e09ef6c86ec7475eb3ed69e57e0cbe86114ca5c0748069d00b6e3a1e2ed74e4366adfcb4d938023560fd91d0f64612", + "0xa9fc42b05ceaff4312d5dacd78fd2394dfb8dc87d52efb0529595877727747827c1c7e3a3da81255356033fce1f97513", + "0xb0150a1dadde09cd60ec3686256b4378f47dc6a55c092c60a3a3f0bbf586013dc37ed53ba7a91c72791c0d52e4c49c2e", + "0xac88e91b48f031df297c29fbb2cd0d2bcc767be5e0a7db87acc87fcc0f4300cce6deffc0b1cb6fc7e51c6ab13ec2ea24", + "0xa8fb1542a956fdb1dcf90da2672d40c90a4aaa2f1232318b4112816bab660657eb97e3d0fee9f327793f6ba9bf8df2cd", + "0xb78191d1ec4615b03b21d7730d48fd9643c78c31feea19866429073f4cbb0d1a67f7d7ed210ab62b760c679515b20acb", + "0x967c20d53d46011f59ae675a26aaadbb7512d9f7fe87b7a20c3a84c76569d23920121063235e37cee2692bca3af69039", + "0x9766abf0251cefbcfbf85ab1322f62267c22e6556b7fb909413a7819f635e3ac1670da6f5f72d3bb4b739e12eae5ccc6", + "0xb0e9c5c327fba5347474366eed1ff60b986a41aabab00abe18a91dec69aa54197d3f5680603057f05d5efa0a48dbc92b", + "0xae2f5defdbd14e2c7eaf595b017b4a97edf521f561ca649b6bc2e66382478b5323aaf84f0b90f0147e20ad078d185248", + "0xb841bb6e04d2409a419dff4bf97dd3d4f06f6fa4e5e23e4c85f23533b7f25fe3da9285ba033c6eae7e5e447e35329c0c", + "0x85e26db850536cb6d3de259f662a88d23577fd56d1f99b3113ef1bb166456324d3f141a7ff63dbccc639cff68e7ae5a5", + "0x8cc36d89424da80bcc2b9d9969bbd75bab038c0cf836f561080e14bb691e8e0c17306fd6d42522030d4640a01d5c0704", + "0x817e72d50f68dfbdfc9d5611eef7c6b490ef1509559801fe1ff916050429a5f79c8d03c60d2bcb02e72310b3c4c9d068", + "0xa15ed72881c49b545413102975fc69649fd5417f5b7ea9091f8209974024785496fa0682352c879953cd1e9edb3fbee7", + "0xadafd20b962921334f4be2188f9ced4a5914389d0afcdbb485096d3848db85152e2881aed0fdfca11f9c8a9858a745eb", + "0x8d8aaea706815f1ec45d9ee470698ff199c40b1ff2d75bb54afd4a29250b094335538dd41637eb862e822c4cf0e2bebf", + "0xb8480d2a79cb6ada254435dd19d793598adda44f44a386ccb1a90d32cd13fe129a8d66d8babd67044de375ee59d8db51", + "0x97c17d6594ccefd8f17944fb760fd32cc41a9b046f87893bb7ab2260090de291e8260ffc63e774a4b6b1dfe0e5107ef8", + "0xb5b7e1d4d9683de7193120be850395762ac9a5669cded9226f5ca2a3de13eb13b2900af083645ec35345894de349433f", + "0x9405d473872cc9f9b9c57bb9976d3ec6892ea429cbd1b12f22962b74d88448d4ccdfcc6d5c6ffa068d560d7bdc3208a1", + "0xb99cca139a3733b365f4718beb4ff4a5fd6aada0173471156640d8be2cc69f2a70d959b57688f927bca2329c3b30477a", + "0x94872ec872f19279fd26abfb132b4a7fd8c485fbdf04515c7b416fc564e61a7b0fc5da9f1a380d2b3db989f1832ac1b4", + "0x92aba716538bd66e35a7bb877cd364c1b8dc3055a9cba2da23c7d9c0a010209ba8afab455da99747fb4bcc8fd3144cd8", + "0x95ec4c205be3dd5df181220c96bba3f4e3b526fe5369035edfcf706c1eca43f29a4c95cfcf94cecfc974e01547e55125", + "0xb48c719d7cbda1e79b3f7ee9c17c13bbac197bb015b344f79bc6785b28a1e9484e2349178178a2fe94c46132c54983c3", + "0x908c495c355a0555544ec6f0b8e0dd0926ef2c5c640fcb89049e6178697625b85492722d42bb5c966aee2cee9981607e", + "0x98ded9cdfa92bc8e3664ae90af87f88759503715f6eaccfc983e3ab53f7b3af6802999da93caa7eb3530402ec4d8901e", + "0x993266bb366ba46d532973391af7204aab46a3189c83ce7cfd2713bc11e99066b1a5a012bead2fedb09274e7b362e8be", + "0x88d462a3a17f84326b1e4177799d6e9c5f4ef57152cb83ffff4353a8382ac8be7d50381723aeca77d33d8f07fccf69f7", + "0x80438d9eadea15c90008ccf4758d4e3fd5a7bd02809eed5b683f2c96a15d24524ffe75683b7167d42a47161c65d533a2", + "0xb9e7dbbd3d3d0d86e347831cf99657fb269930087920637ac6cdf185d5eded3f09cf3eb27759ce3f4b46f41411e2fdce", + "0x8f0215f23b4945470f74b99607c12c36eca41aaaf99747f522d8531244b668d6ab8c1096b9b5697208c3931e1fefaed4", + "0xb2c8d8515ff16beae04c855b4365e450e0ebfb423acf5da2501fea76259f862bf29738a858a4093b98c2a444396249f6", + "0xb27364a7258c30a59d1f13d358eb49dcef298a92bfa699b3b91817d2f324be8fff91c0b71cabf26747802a92582e7dea", + "0xaee7d6f71fd674cdd8dd1f22195981e7160990c16647c871835d988e881a3d4c52345e74f7a54768fd97a65fdbd84567", + "0x91356cb2024f7703ccd662f50baee33409c28ff13bb5eb92fa93f303913e9bf31bf83b0babff4b5e3649003ae95492e6", + "0xb744e4754043d3ed85c3bf6ccda60e665568dd087548ac70670b90328509d0d5013cbdd07bf603949067e54d8094fc2a", + "0x8146cbea5899401a80676850d0b43b02d376b4b8f02ed63a7d92532d13689e2c02846df79cffa0f33ff81c3bf492339a", + "0x94bba8a1508c6296d3dd5d2e609d6d732ab2541849deea5436a4a9034e1e6f1c8d26f6b781fa34dcdae7cbf8899d006b", + "0x80260b321d932e1179667de4916428c1b77ee1ea537a569dc64a12da5ddc85d09896939718ce08ea7e0fe8f8b115c408", + "0x89d4640cbbca5d105dd67250f3bbfaa96d7ce19a89f8d6e188353f3a9b8737f2db1707c506f8ffe1d3144dd1da371920", + "0x92f5962946ef7190fbb7bd3935427157ffc815a52ef44397ead3aaddddc82e5f85b1edcca1e9082a500960e19b492614", + "0x8b89240c9b7257cbbfcd6e415fd035ce33bb46c773569d217c82ecee5dc2d66eedc9333e0b043616b0cbf21744909b60", + "0xa3d23484916d2c0ad1b81fc7df70c97d711040799cab076223e0ee02a45a0fe9ab564faf7a225982468f3e62e32424d0", + "0xb31751386bcd471b5858d001fee15d566215e34d2d62556c51ddc60a834d3f1acf18c415c23a36b581cdf4791f461ce1", + "0x860a99003b841221dc5ea2bd7e226e5aad72db8a5959d5d4dae8a86114d30b9e8915b2314ef867e9c2a477d9424a2d94", + "0xac925b330cafddc7d95d115a9e62b2c135acd22b5e35a4aa789f4318f03aabef818805845f2532e9504bb19f69171809", + "0x95d8180cae0815d33bf8854f4590be652f95f72fc29f0c519ca9bf3f490ba4a724b23d9054e08e3d31bd61d609a8f0dc", + "0x994f223740ff95764fb88de1ad6dd90c9c58c0dfbf8482e1dd9bafc20c099a6772acf40569c54143f6697fab72772296", + "0x971d93cb1e7aec5defa52815bf202b11de6a2ac9c5d4c0eb236cf2c4941460731e12b718f4a5b980ec6f4c54c3d17deb", + "0xa341095fe5adb96dec2be367f09804ef4fe77d553102ddf7d643b7277992708e84be9a7748a97a56f065002a97dd7cbe", + "0x843709280fba29d446779b1ac6e31bc3ec8ab8082e8b063ef8d2f3733ee77a4191b55772302964bf867fe1044dbfad65", + "0xb7ccc71fd0d0c9642c32d292ae88ca369d1fb5cabb97b1745c621aee41da8f94bb580c1ab23664c1baee65e97b21f0b0", + "0xa9b41f31be84f8ba061570633bd9e5f4d8af6fcc5276c25d9ab67b2b88c1f8c2a87eb19280cd4fe7b4c04da8b2d02d7e", + "0x93eb14ce0632cd325429e1c23340da9655d3d7c2b42a4594bfd5a4e07815afc9eb1ac737228771492020f6528c0b7c61", + "0x959aedea532471b9610150657b895c5f51ca950aaca910df137dbda2d17184173cf2638a2a0efea3f61d82b6ef8a7c3e", + "0x8ebfb50bd48fbf9a6f782454ea900acf0c7143164de9b5b46c1cd072c69b76143ac4c99bd43139b5e55f847841fa6a1c", + "0x851499b3a1eae6da530a47d3e8bc068e6e7144b744d5eca5394f96253df65094e5f3c34abfaf7c7d78c4d5a5d4863da4", + "0xa8d68bf15b900cc47197739856557b43a5eb233b6c095f21a14a90ac8c36caaa1a54690c95840f0a4d2e2ffad0874a2d", + "0x81a6ff8fb1dc4d4042089d4cfc10cf826e39083aa5983e53f4866f8f4c10cf06cd8608c4cb1b785f8d309bdb9b2dda63", + "0x82f658bd1a95fac0b65d337efc95d856aa65541d49aa993b094d70e527e7d478970eeb3daa2904a1309d755e1d677691", + "0xb46ba4f3d8f287eb92390e5d930df4f1a40abe500c9aebf62e2eeeb2e5ecfe5296b09fa22d6c9cfdae28d431fd10a00a", + "0xb5b38508befa4623166f6213cfd160782fae5b7c3c7ec279b42a83d43a7adcfaa6c5b34cedbf98bba357fa663eec896c", + "0x89b8a0fb37a0c45eb1f234ae9c7be65c8a708f08d431728572169b33f8288b1e17b7d4b18de9fb76afc37ae609290623", + "0xa7d1f5779c043900f3ddf29b6b7ae4301699c0ee9e70314fcd3bb2643f912fb1225a0164f45c47419ab762420bf8e5ad", + "0x89d2a69fc014068aa6d0b79784b8953f3519f563b5c9f774f4b148334d822aa645b662d5efe7dc6f9cccc2f67268c3fa", + "0xa698d3f0b1b6b72b72358d5fd5e49e928cfde69bfda10e163b9b43bb9604362b32af1909d28da5e0364abcf5e96cc226", + "0x91c12dc25c48aee56484172de8c6aba0d9f5eae8db848a7b53d76001c292d115ec57d816c2cf10bb9e901b2707dcb71d", + "0xb0740219e084d56db4829daa30b2812115b2e95ae85ee96a140b7c4012860e8017e19b482e981547e50e25bd4ba76716", + "0x8c84d4fa255e2de7cd23b0bbd110687edc47ed7fa87bd42658fbaf3831c6d68cde3ef403ed6c585f8654d0cd32074bad", + "0xa530d3272aa1740a73e15cb9b31c5e2e54c404db72274b0840c19b164642389acdab4514b9b2bf9688ce51392d8b6793", + "0xa601f52bf7b3226fcab93c67dccd95c1d6673270671c4a099b867bd5578d5711fe9acc9b935b867ca780ba4a394279ef", + "0x8a238082dc8ae33314fe1257e7bec69e905c194ded6f894267bce97443166fb443628490755e1d453545f389b5beaa2f", + "0x88a9737f3e9ded874681fb6cc8abe0f6e1ce18a05ab599b2f855f73e6fe5bf804de5c5dddeb11057aeca6613bba72c8c", + "0x8a5cf70293eb99ad3c34992c47299646c8702d1035b75e4784cbec67b28cd4c88eb8c721f4cb8982d3c6a42d1b9f7fae", + "0x8a62228b84fa7463a6a8392a7af767b661382175633c5e00b36979d816a53b388f31afedfc47a5d8cbcb645e8d5928b7", + "0x92836b5a41900a1c1ceec83cf4f15c6177dc20f95eed23a203810116ede2a072a8d6c96532ef32c93ee21acfb14448b9", + "0xb4e538d7bf40c263dd1ede65c81883dd31f9237a0fc8d134a2b480a1a681dd89cd2edb19e63070ee69e96cd12069ce3f", + "0x913eceddd4c9939cf82c7e9ca5ac300cd79dc5a72b8458cd69e9f8929168eb19e5f21eac12a3b09eb8d3998e28e3801f", + "0x81f4a3e7195661b174aa2059796dd88d3206bedeb7d7cfbb7e61aee335a01ac50bb8edeb258a68949492d4ac6215d95f", + "0x913a393eba8eb88d1076effa8d2a30258d83635ccb346f1bfe099fb5fcc69d0457ce5a79363a618f9e8b43f53728433b", + "0xb11d721b08be428254665bd64a8864d78c5112e252feccca113631b2818fb729129fcff1e739178507ece41b807ffafd", + "0x92603fb7d50d11b59fe376720aa57412b866fcd5da90195a5a401e6222201b30c29f8797dcc1b41ee2cbc6349bd5ee1d", + "0xa466c5d41cd4a8d1f47a650ca67b529ad3873ba3fd3a36db27f7a5869b74b42381788bb1a1c100ed184118839b9879e5", + "0x85c50607a86d4f76826220286784fa9b6ccbaadccb661fb3489fd35a3a8917d6999ac891190f2297afac3c37abba2967", + "0x966320c2762b266cf7eac7aae39221599df4fd608036f6101cb8c68192fcbfd5f61c7f93172aa2be0934486fdf4816f6", + "0xab69525f1c77b6706592cdd5b98f840184b49efc6fc2687d6dad3b014f6a12c4d5cbcb5120d8869246da010823534d8b", + "0xaa2c9df15c06b58d7b9bdf617df8bcda83ccaaf6ddeb8074db931f7f03dc06a7914e322777e297226ee51dc8268e80af", + "0x97035b62f8db4df6e787cc2c940f2298c7d26c2127c7a76e4660d132a14f43c8bac8dd4e261605611b2e9c08929f2bac", + "0x8ace33e696953806f594427f137e84ea6b22ca9b48c3bdf3830b3e951e5a463d4a7067c68d2033eff452295a741fa1cb", + "0xb621fe49b12580bc8ec68fa39d5133875da23524a5ebc793c35040fa3436350d0f3e4bb4e53eaa23d312a7847e2eb2d6", + "0xab7d6ccc0de9c7ddea145e83fb423a535cf26d470af3326d1d6a9a579592b32ededb078bae4613028557877a9fe71642", + "0x97528eef76389dd77d33ee7daebbb290814911beb725ef1326c3160b9003c3043be09bf3f84e4818bc2a7960ce1acef5", + "0xa408eaf5c675b50dc1c655f83b9595dabed68e74e6d2eca5a4948252667413cfffb46358400df5d35f92657811ae56e2", + "0xb36537726b26b474e184dce0ad868a66f0944b4105ff6d35a2cae0f3a520fd14a66630388aeba178d400b5fe104e521b", + "0xb2b88518d10bdcb111c82a261076367e34718f1d0a1a06b421891b4eca1e3c1f904b66e65dc914ff1ea5991f6a638a02", + "0xaa3172531879a5c8f594ce96277b2c8c8d4a2d0f4bbe567ae40d5b36fa6108e00f0b1dc94b81f36c9eb6d1e9ee1896ca", + "0xa53975587f10667a9474ae2756faefe43e7f81bf9e051049de175a8ec085530fdee3d5e3db15d4be874ecacf49f31691", + "0xa1abdc58bff4fad0f6562338daeacdac8e37f9f3212aa252b17389bd9c54db58706129a63bd0695d299d043b5ef0e2d3", + "0xb8588fa1090597fe0f6275e5779da11a4d128c52fb8954e475c4940f1a3e10fc23ce1f61e9aabe8a75e82824f718a94c", + "0x8a1981c536747d4cc06315c794f1536db7ab3c9dfa024a0df854b948d93bee72083b6c9c4c4a7ce999c98b904813a659", + "0x95b2b1ed525d629eed454bd6bd059b01869423c3463a56689a7c39cffbd3453c962426a1126ed631b25ae8cd7538302c", + "0x8032c60f083477693f533c2d8ae391d62ea754b8eb41ce9cd59bc469b980dd959a8ac840ccac54b404a9d08a6f9e4b98", + "0xa72ccc14eeed758d3d43c51d68341fd7e98880c3687e122238d77dac8d987c8edb3067bb63baf13a0e57fe02334545c7", + "0xaac3eb536a5061a8ec788ce131582dea691957ce8b9c6af5ab7224bdf0fd15c77bc6bc63ad037bd83e0ae52fda738361", + "0x97dfa193800e57e6b19d1b7fbab40da6dd1463f043eeec34b316ba6bee21b6bb633ec0c4fe107c9dab6e06e07e0acdce", + "0x966ee3cf2f54777968fbc34f08c8de121ae7c1d6b2cdf1f1f9c675828d22ccb909bfdffa2e3f2ce51b0cc85bb29f8504", + "0xa9df6dfd12f8c43c28b929280355cb23ab0ddd2cc2e4fe76603a2e5dc2ef5d1aca2edf89b304a27345cbb1f24a86cad6", + "0xabbceef80c744e5a1194313f7b84b5dee1c9861cd4bd3d0d12c433e5f2e8c6ef6f10b860abf3b788aa04896f708426bf", + "0xb1dffdd81711e9782c992c4b14583ad9d6c39ef88974682a72e717e21923da6892490d7efd121423fdc638467e62e064", + "0x817f30dd799c422da33e13ac2bada8cce3930233ddad495f714a1c789b7aa8f41ff6e688bbffc5f2e8dfc72e5243b645", + "0x96760a79e4414ff1d19fee65b6e65b2dd6665323981ce8b4ee93d0a9c410b018ac086c08fcbc7a71720e1e3a676f2b3f", + "0x95445cabb75909262975a5b06381af2bff5c4c6cf51cc84adbc0b7f2a985117f35c014e33672cd5216a9737d3f37e067", + "0xa279c905fd9d49482d213f5eb98256d020c2b90bebac45004d6f152ee4ddcfc72a7e6b188ce3b6c93ebb9ba9b8be587f", + "0x8591e8379a78af8860e6a0e002be5b25aa4b93c5e556f5ae2e40400f828dfa19d93a4910823e230a51e2c1ea5464d437", + "0xa6fde17d41fd9f03605ab6ddfc992e36535a23b2c39608d30cd6d72588f1ec6afb9db193e88eb609e104e73ddde779a7", + "0x93e2cb6352a5eec063151e5c9a822f6fd475a072dfde2464af4afaf6a730a6af1fd74c424c09727328a7f23505b91407", + "0xa7b1e4f703386fdd16f5fc9b59ef1dd682bfe5a23bd42b3c4b1385bff894e758ab09674dd6d0ded5b32a0a0526aa6d98", + "0xaa7f01c450e619c4bb42d6cb1a90a94dfe132a641728a642997b71e2c3b02d09a7695b544712b2e14416e7de0252fb11", + "0xae840b870a938668d0d4404b76f5d4d252d8ae1e3619661df0890ccbab900e3d8dbd5dc9f96013413e3f1e30dc541db3", + "0xab7552930ab07b0f5d50edea3a2e5ea3ac1a05cc985246ca066fc3350bc58949dfb99d4f6a6408d1bba64d3de47a3c2b", + "0x8053634d4c730b5e90d68c2830a73e93f1c9e522ae0e00a04e2ba15a1b7b4fffb8b25516ceea61719f886c7763d46219", + "0x880c39ca4cafa622bc767d3127d62143434d0a1d7de8dce1a2f94cdcaa023a7096641a46e6b97e1b1ce9c233c873a519", + "0xab9d46e46cb2f382ee7d21b6da01578b786b7998e0fc2b5d5a4e1a0d93aaab997b5c481c2d9a741865d6460ceef57a5b", + "0x857a5957adc3a888cf93f144aa809c70a211932742a258978af5e657f4f57fcb6d9e39dbe8d3128fac6c592dd5bc4ddb", + "0x8c98656861fb8c8a03d491db45077f1d136a759177842ecf6c1ca36923088237e928558433d5b631590f395db56f96c1", + "0xabddacadd7d536e91d36609fd0047f5db113be0f4d84abc7631ffc5c00df919c085c049c013a05131150b0043d51f892", + "0xa8b14af12cfdd0e11c8487334efbfdd22c8b4fe6bf350333d42ac8c704efe54f50a4bb51d9d802e5185ce72e4b21aa58", + "0xa8badc2bb3cad0143db1bb3cc81751f9974ff3f0e2ee35921d04985409def84ac2803a657571699eba34767b773666e5", + "0xa6739a05d270efdab18462e8536f43dad577158e1c1655fa130da97e469adce9bb7cda6f9ac26f4a9ba3f9b22329b066", + "0x842ed6efb4395603e7fef0bf92326c0c63992da4ce7912f850c4960f7a19e0b2ecc720d9510f15ba6f73a2c5ada8ea71", + "0x8502ede859944047898d533e1923ef90e1b5c17d985c9fb4c6aa39d50636de4c5a4df278f2f62cfd3ad08bba4c5ca6cb", + "0x8c738573226dd5617b3ca1dec8780000a77f3fa8de241cac99b0d9b1b6c90cbb8aa2009668005f2c5c7abb09c0ab3f99", + "0xb101335c403d769313bd05c755a9196769465f7068fd6f9e00937f3cc843d48f013f5931f999bb5c0082d4315134f5d5", + "0x925ace190259b321981fcf8bcf52c6852b206099f25c0f278439ef6edc4320d6f926cd6fccf1b4cd224bc52e5c681612", + "0x95f5855ad1bf14224e51f7d5e0d229683c0d38fa324b1abe9d595685d3497955e30289618c4775f6083bbf923ff3a37d", + "0xa3d3c7100962c8b60c40b830af834ddc48858e7eba5ebe2874ebf74e505c25cf52e661b49d7619f2f2a039e1df02f5c8", + "0xaf7e66c1d5dca63e6be117b210c616efd533e77199d67d8f694e4278841963e0a46e4e44f0416e69bce6a7156e1872ca", + "0xab796760166d1e1fceb20f9bf19b1b7cfcd327650cc7cc35c161ddbb3cd4846e9a971b541f303cf62fdc0124688fbd41", + "0xb920211c5b440b3567942dedf62a65ffbcad1e3516f58d14d8f8dbe86f45c4b9745fbce43f5219b7052b27a3a04df12b", + "0xab6d5d25b9fc46b0824df1628993e44535febd7c62185b6795550388185035ae12bab60fa34848f465fb4f4a8add3544", + "0xa6539b67dfd6f3976cb6b304f4d152532b3f08c02bb97730c03c746da0f7b38ba65536faa43953d46e5e7687a86c356e", + "0x95bb225586b1c82d894ababea7e5dfa8468bc0e10a2ef34e5f736fd1611114cddaf1a5c58bc9d664b667adef68b5c25c", + "0xa16eefa4e6161a8e7bac63cffb2dd5cefcae57144e63b3fded581abf7ce32016a654aaa582fc25bfa51c83f352e09372", + "0x8b742428f6af81261a47a0df061e480ef9176694d361ecb57967bea67e11cd44df686e38e35b7d4a6ee02ebd520aa1c0", + "0xa2a4f2307f646384a0238a711c2dcf7000b4747b8df1d46c5da962fdb106c5339790b48682e8ec2532b8d319ccafae5f", + "0x81910c1d72f6731d27d3a4059ccb0316faf51fa58e0fb3d1287b798ea8f9b00bbbde31fac03f93c7e9a1cdbc9502d5df", + "0xb846b933c2acd71e9f9845f1013cea14d35cd4b8f7a371b9be9bec9d4b3c37a2d0da315ba766c3a126f8e2893f10af4b", + "0x8ffad59284b41b75064c277ab01c5b4b3a4f3c4b355bf9128160b1a55ed6b0d91366f7804006b4e6991525d3435d5235", + "0x82ff36a72533fd5d6745d0c3a346fce4f62b6aca0b8eccd11399b482f91cdf6a5a4135c627043008cb137ef4ccd935d0", + "0xa11c27f6eefe54cf32fd86333d9ccb59477a655bb0c35dcd028eea58d4cc40ef9a26cf3432fad4e9d058a27b419b8f04", + "0x96642ce0eea3c2c0fd155a75bec3b5cd573d41e8081632c56528464cd69a1141be3180c457213128bcd37f5fae47f7f2", + "0x8349a9e390e05150bbab2351b77a3674f1af000b6eb6752927ef838b6f0a1200e6fd7201dad8565e3caf3802f204246c", + "0xb8ae7fea6275ea61935d3047d8156e8fbc4a95c9fefd1c36439b2111b9ebeb7ccc306e0f8c875fa772f7b433cff848aa", + "0xb366f056e23905bae10ef7ce1728b317b83f504d128f5bd34701ecb0d25ec08491969625e23d5a2fcf0048af610664df", + "0xa3d88d506ba46b73bf07729aafe9698e788fd688647a6b4145761275257d262cc450c7889b8a40d698455baca55e3da4", + "0x891ebaac7a7a408aee4ba61605f44f9ca5a6d5e046eebfd8f5108b6dc4479482806dd01686045b4c7760051f22bce468", + "0xa6ddb74e3e3725e6f2d9025532ee3f357ee35289e1cb38dcd5b2ea8ebc0bb697416fb3aa73e1eba632d593d40fdb030c", + "0xa7dc097f440ebd31ec1a005648468c702bb77073ac8cfa32b050e90a9e1cf388f138abdd18f07951c752f7e19f706af1", + "0xa200f25299f9a0542c196adc2e00289f453411066b88b125d3f0e6b17e98efe9da8096312a2f1841e01837da90a65440", + "0x97cd3a9d4185d77d4c7bd4ee80928def7b660d8b949b0face798c62a7cadce1000997af29504d28ccf9070fc3016dc56", + "0xb9ebaba1a15eecae6b1998ae6d08233d05610dc0933b16922076b2dc4418cbeb4e5cbe099bbded3139d8a47f2b2eae10", + "0x86f5fe8fb36b419fe6fece1c5c4b9d64468b4aa0154bb5dca466a243b6fb1227c3b8bdaf7ce5c2d4fd05c061979f87df", + "0x8050e011011e7918ebc25825d9863c91046fc3756703bdedf936dec2815cbd10c2403ce6f4a0b4f576cdfa1347efdb85", + "0xac22132a482d2950be9442167be214ed9d24519073bf5ef1c8e3e6f4a77065da198a851950330fe4d62b2a1272835015", + "0x819e2e8e3ac43b6ae4885899346f3b558bd7658ef7d380070588154694957596695a925a001a9fec7cf3655326c50c2c", + "0xb00f40c084d2eafa36811e0d822ffef874a0d4bebd4817690408a737624be05c920a08307cfa0c1195505c5e7a5fd878", + "0x8355768c09515a593c8fc8289baa3b6cf7fc10d302abc93f72090ad99a70a1ef1107eccf839be722132259500a565d68", + "0x8bf0615d2cd11b03546ab7a0c90c0c938776aca8a8b989a709c367f0f5eea7b0a7cdd78f96050cdd5d0a123d01b99c53", + "0x827c2cce458464fdc716a2198fc67b3cf2ed7802a1f53f7a2793b2314789998b13ea61343c723da8863cb63def6a285c", + "0xb609cfe6acfccd632759700bbb0a06fc7903a6c0c5875c2c3bd85c65bfae7b29b03e77092f29d565a6a89b85012396fc", + "0xb73ddbc330e872363bed36578b245b666d42923393a1341816769ce0af24b700c19ea0f579e4f9aff1c3ff369e63da8b", + "0x976d658085e5978807e13b150c7aa539b44ab8855a386bb58a52d9ec9b5e21ddaf89a18b043394d6cf47bd589d04b240", + "0xa213897312aa28cbb2c572e643d3aed003c84bc2ca571dc5fbea8a0b642313be94db0047e293078d975fbc6800751a87", + "0xb54f2914f6a7508b6686280d3cc955730458ff035978be29645fba161ed54ef3d4086f956e68d2a48c49afe904edff5a", + "0xaf99e470055062390904673e18d04427c16afeb7b9f13ad83bc2599e9a92314bd91d6f1f81b55419a4d668bd889ec8c5", + "0x946ff0cff4030b73a1342a9173fe697ab20cc5e43ea6158573f2def601e12a174da431f8170bd31ceed4be48c90b4f6b", + "0xabc51f8bb5f74cee819ee383cbab739026c453bb55336fdf423af2c2ac6712ba90006d62dd72d8cc1b2ff6cac900c8b6", + "0xb43623a56c5fd1bf28bc356fb4a875d72dd4cbb00c9c863646a3376937088f9932a4a0aa26afe2ad69840b06242ec76c", + "0xb0f371952f99eabf7ed368a142ee07d06bf2b7ec1ff852fd948b8c53eaa52300753fb9ff6765201e35873b5167583f3a", + "0xb3906488172c09e148c571ef0712f88bc9f1ecae0db95380f61901660fc1aa090d0740378d5b9b76883507bed100093c", + "0x945373b5e6ffce11d39a722df7b24eb929b14a967d211be3b969f48fe1ad3dd4280317d1ca772a69b033f3bf26c02c4f", + "0xb2ad3490389fe5bfdd5ac7eb5bd61facff8d57a8f9969f4938ea56f4a85eaa2c1179a2e5b4f87d9e6409925c75b61828", + "0xa4d61547e405319cbc20cad16a2bfd9e6d093a064522c332dd22134ab05e893bc84786b21b4c71a6265bbd06da2ef4b1", + "0x86749c26715d22b185e1b25dd34818e96aad319d7add22a98486ef9f9808b5e4b938c6320d391dc4e0fb5d57bd41778c", + "0xacc554d5b866693a453a9ec46d422c8b410458fe8397384b927a62bf5f2b1fb9706c8c21af9845050fea8a91786e3577", + "0x8eb7e763d297cd93a7a54dbe4654c39c0ebfd73fcc34d3f1338de0c347676f445d32f270664fcb7b33347bd377c9f867", + "0xa1b469e3f9dabd36b13149c83aa5b7b5987eb0ecc1ce6b68c72acb39ed503a11ab4451e658576a92df4aa51d1bc709f6", + "0xb1ef105cd0259486be8f265a73ea089d5b7fab7bd7547932134539963467fb917b2206aa72446e2fed5a8185b04d345d", + "0xb3e211c1a14925f6de451271728a3c1e555ebebecd4bae29bf666927868039d4ec99d9f9aa98d835da7845a5c863dfaf", + "0xa416632a50500f29b6bb471bf00b37558975ac91e5c5b5004b67e130be1acc954a8ebaee7efcaf6883187ee9173d1ccb", + "0x8c655a85f66b5f28ab8760c94b6cf01cdc36fedd19a09c261e432fa7eda7928c3c88355384e689f1d2715d419fd8d898", + "0xb1fa9f82c9866d4f296755bef5b7c39fadd09374f38ef9954aa57b1431a1ea4cc17a9750da844fa1f5848f0ab7ca295c", + "0xb45cdf1a9eaaf85c0b07bfe239da618ee649ce90b417d90b08eb518b1fd88c0d25cd29fa7a0d8058d6616627a3dda306", + "0xa2be1552d3c4142755e0371a9543032ee82ad669d7edd24c4e2941bde3b78c5c6df427228fc45812a55943b3663cdbda", + "0xa28feb053e86dd9e2f9ccbb7c38467e2425fd580ba0f63190036fb47d01eb198ba8590b5cf68d1c0f47638e9dbdaec74", + "0xae06b849e080efcdba86fa03a0c9dacb38a15ba911aaec624d15787c3e11ada6909b1e33a2e3de928a23818d833eade4", + "0xb4888445d86bcf4d1f6a9c2d253f277596795084c3d45a4591b307b7ae4ba177d6ce871c2cacdcf9457f9c132f244722", + "0x87a568aa2f5471214f63932b0d48e589898e82a1f4c1055a9e73120763430537c233e9a3cb6cc178df53768e4c58c993", + "0x81e0ec97cdf91ae66d065234492a1119198c396e2db204b7edf192c88eb4238e0a45bf7e245f3714bd864244cba0ebed", + "0xa954a3785588d4bb3cfd7cb27df45c82e6958051f916594d76cdb35bb07e4f88e2831a5cda35fe1f3c99f32a275f0668", + "0xa9c9f4d54339d414342e87b03679baf29c219d28b6548f01891cf94d0313a64d3384658d82373d6e838d886235ac446d", + "0x8ef46cb24432b419b4cc803e60b3ef5872db8ea614dc37643e4592fbb2891cdff61f6b2a10653d9e99e6c7359ca4c590", + "0xb23eeb458c05ffa5d58be21cd0699974694dc61a9a928fb1eb509954a3dfe7d8a71620a2d4046a448de0fb213be7e97d", + "0xad631be8e17285f6310fb72ba913c564fc66d14460c4e8c4b0c68c572a5c2a45b088ef60eaa9d317403bacf534d57a23", + "0xb7130f5607f236374f5e023fd43cc6dee38286ca47d504c9e75c6504957ac2bb9134fd59d8bb1010d545c56ad9c71c4b", + "0xb83cb511757d80781e26b5e9b3e0597c4cf9a976a3fb60c84efeab2b6793e46282612da45b1bb8b45af4b7f39877feb2", + "0xa0c5f8b0027ee11cd5f86515698f689ad514cfa890ac4ead5502b5ede9d7d7ad12285f5806c9c85ab58f89bd9f188938", + "0xaa8e8f9335c6e34bca3472b5f412ce93ab1ed5f9e51c3affdf986a5badd2ba3ca1ee69eae53ba8144927f082371b4cf3", + "0xb2a4f775a10cd9caa776123771f08e928ecdb22dcb91efc440c69e37c6b467acfa6112c2776d4a530bfd6df3b04fd50d", + "0xa0c553d5d2a9b0525f71a5a0a539d579d937275df9220a0c3c322d6c0ac7fbd2fc55335a1a283e687856e2b30398e4b6", + "0x8ab800ab4c810e8f6a9d42d2dae9be89841bc7328bab06b88bbe1256f720ca99c056fbe4e1378d7cf805586ae18dcc55", + "0xb9a8766f4f4bf796e2517a8a7a05bafaa6d3ec601a85c466d33b8a7e0498fa1dd4e2a9e42161fe2362c81d4c8ee1fbf3", + "0x8cb7d054162e9f41245b0914e7dcf6108ec11456b39b473ecf6c40e56b172fe5be4e7b0753a3685667436796a977b977", + "0x9131d0395897f5591ad56b62ef83a3ed9e7b3951080b33ea606a15742f78a283f924373e813b877f32762dd69884658e", + "0x8d784d7f0884cce988305d314896dc6dac2d2934cf5d650904e1397f9b9dca397eb7f3accad60ab5e34cb2e494bb640b", + "0x8819629608ca1535bfc156c1e17f8fce5821d81e6661bca75a1754a5919d0404e31e65bd509387383a4111535e949f5a", + "0x820a6f46e251a1e6d92784aee18fb0d265d7e2f0a5b7e0b15180273eabdefb34f1d575e1d8e93dfc2be1114d10abf31c", + "0x8d10d0e0557beb8db344c2d8bcada724e720823fc37ee7c51b322c3269559ae932bb2ea07e50d7ada88ede788839dc8f", + "0x911a333e2f7578a0ff6533284176cf235036047a11534acb649a0043a326723662bccddaf1970b7c37b5146977277b88", + "0xa4be2104cc5d6fce4a46de5de8d210559a6b743b6347b8d9990315bb56cbf80695ff936afadfdcc415d88b23ce6863ce", + "0x87ec5877ea8f1123371c49263dd9fedfbde41846a23e12073ef80f7afddf5a0ddab298cc02e861a90188ef1282139ecf", + "0xa3f1dae70745b8284b1353aa6902ebe3cf5580e24e02490d42b2f509ffec7e8e777fdce4f1a92d83bbb23cbaeaddac57", + "0x8ed5a0733b42482d88da7c24e85a841ece65f6066dec060bb267a8d1f1ec165ad5f7964c2908d3fbdc2999c580eb8990", + "0xb124a1db23f4875e0caff1c7f4b9a411564b93a9ec3ad8143bc7a70b8305d380b934c194de8201f7e3699e905a1f0115", + "0x8af58886d4ac5578a29c2e309a68f19a62edef5285d0757c42f0ec2550c633c0e991c4cd7a60df4523cdde40c3909345", + "0xa63fbdbde883f54667c6cacb356db1fb976bad147b790064ff25ae72be53bb6f4d74b22ca803996e0d95d216caa3fa81", + "0xb99fc9012ad938b36246a4471d29f0a2b37b2a3be6fbfae7ec9fdccbfd14d48fdbede0d88ef3b6cc273f2488f4cab55f", + "0xacb6cd4e1672eabf530d38f50ae651db8bc4025c2557c59ac4f1a278b4741f1e2cda978e5d1337f9e5aae77c95ccb872", + "0x8f8f6964534e4a9294c61c76206674d836d4d56970e9c14ad6835adc6b0d256402742d8a4879764569d9082ea6a750cb", + "0x969607ac6ca9bbef4fbc2fac22b12714a31f5d6103dfb998c3b6f2776283ebc7346e81a22da168af40752f28ff60d97b", + "0xb633f60cf6eb8ed588c545c04972ff156cee767edf31720c9715be3cda8c8de0290b623b22cb8fadb1690bf3665a7be6", + "0x8235bc2e818e4d259bf2c9fcc9646ccf83b7e238044e26be417d1d0dd5283d7b38c86e8c88a5447645be191516e2993c", + "0xb503052246ea840a4083bb4a8978029af3e242e831518bcca015f2c2df504e98a48c9002b6b9fbb97e861a0a3c5b4b5c", + "0xa145ac57d7c028c3cbd2a2bfea25caa35a9b5d69cb491b13eaadc2b0d927a590decb7c4995541f8f29089a2cbde6429a", + "0x80b4c0938058fa5d03c948777f13c70f46fc025d4d6c2f2051915b476eb0c0bef902374d784df57ac368c01e1fd51c00", + "0x92eb253e3b1770b36c4b2869a944caeed7b5c8a5b8356b25dcd4102df79fab8dd2c9d01e3253070f1206d149c43f64e2", + "0xb7979ad6187f7921e725787b0a99050f4c98762c63fa64a467f7f110932f6d07556453a95e3a2c0162bf1c9c41424c90", + "0x8808ae4c7cb38202c8c8bca0321e827580155197a700fa54b6a15b0f14b001327d4c9a0923168bb5afdd1b45d6a78367", + "0xb16a4ceee9de5f49a99430e18aefc192f3c1ffdc4b41392069f690893bccdca760e6dadf4127539a763e4f60aef37dde", + "0x8ac113da7ca59ca97d6bf7d6e03f1e9570867bed27230515475f965ce9ce0b424c85810e18a584ae5a3d5c2c80c6d4a0", + "0x847ae1b0ef5cb11be37320f3ab5e30f59d7910ba3d7cbf8265c74df25f4b8f56f1ac96cf49fd166c3b6985d1e8091e6f", + "0xaaa9b04f50ed6778e2481842cda30c7dbc7d462b40c7602a438ca9f2c1599e83fe6423f30d7789fd240d2e3166836f5d", + "0x8c18492569faa8cfa1c2a05a0edeea3f63d003e38d9ce23c4a5b31cde993a4ec88c9db83011ae15b578e0d0f6b72ddb8", + "0x838b400217af9241755032c21a3ac4610f77f3ad76abc43f0c59a59f9bd52f2251e46fcf1552b6ee0220f4f2902e54e5", + "0x8675f8de084c6c05644deeed1ff45090096c72c0db6bb2ceaf1c0d070bd10ff1e83b2dcd89b6f99bf132d3e131ef6d0f", + "0x89611bc63c83d56131bc2a8653278b234b4635aa7a05033d71a8377a5d188ffed7506a50a5c37a33d199a42b9e55fea4", + "0x90c290c17f1687a87023fadf74b1e10ad0c0414cf08629b2a313347f0f6913bbe511e5d18d1c3264b47f65dee7887d4a", + "0xa590bcb6391506035466dea82617f11dd9417c9f379d32b4c3bbf723840e1a3124d2327deb28849aacac278470d7ae20", + "0x97c55f459ebdf94ade7bc3bb18b329bbe2bccea345f0b4dc38cfff2839749b8f9365e8a1cf31722649c165e265344c35", + "0x8159d02fd03c1d0b3c928658b3df1a27a57699ed8a573e0c3a179e97f50b6c1a6467b7055e42f9f9c6c858459eed517f", + "0x84d4f009c052f3bf76b2b972b3d8f7a4b2d78605a566478670c33016aab06828a1737a36d3c9173583e7bed0aee84fcc", + "0xb99d7558944ac2d61f5a800c24ee47fca719e69f7284956be94596623cf434a214c042aa46d54019de3556540ea53236", + "0x8d1efbad46f69b80efc5776d8afe95dc0a8182d57318b9f2d6fb5b7d5c48e7181e6bd61a8446a553c58f7899ea7a7c78", + "0x84a9cf6a9d64cee7e7d8f0b678d3606c9080ab3ecf62fe0d6f994a681de68b30534ded61db1445a257b2c5427e97b36c", + "0xb6a5d2c55a23841a4263b10cdf784be6fdfe1b25350a4af510ca294949716711363ca19f9c44ab1c347aa3fcd60f0573", + "0xb1b5b6dbe6945db539fe7e2de07d222c88d7b91753118593ad9890c55c4c3d83b4194f886ea7f66ccbb348f5a23a2a22", + "0xa8a58169edd3e58f87fe8529f5cf7da7679807467ec707ab96faedf75085185a78f2ef912d9180a5e820adfad32ae4ae", + "0x874c1f416f866756ae3e93360342848afdea0048a575f977fb1f8a57325e50da122d3e9f423e308f0acb1b28fd47a6eb", + "0x95cbe8b47ec42a5c72ef7b1f91e3de0b1f648ae8069416c48d5529c9cffb104ba4dcbe87cc06e4e798a1b23bf1595f9a", + "0xa1b6e9c5d63ab1262559727872d1140b74a4f01c12366ed2d401c64007faf7917ec591b631c6bb4dd44b39aa43c7f965", + "0x89e6f4a05679c95d45b54e760056378a5eeacc72624eec8b5f19aecf8ef0d8acfb2d807d3b88c6b1206827203f219905", + "0xb7f7b30cdea6377d5f16d200b987e3b4a6f28387faa701dc579cf7b3c6887d74ca43609c5bc36414a6dfd0317ec75448", + "0x83474b58135f3e2c5e8355e31ae44a77721db71cb2919c3f3403f44903622d4116e812ea9ee9ca073938dee780f4aa22", + "0xa3e4cbbec770630c5e2f3b67059a55b1217435bb70ba5b5010244e241ad6a3e6b8d9261d8a0765c4b42bf795fa4e96d4", + "0x87d3ebf0fc03ad67299f3b9cf9c9ff0890b1d0d2d1a0ca2a62147444922d207663329e49898d79bd8e09ee48a1560fa5", + "0xa1d33282cb17c7a4c5cfeab4dee8875d324aca8d0513567c4e5eae180d1e8ac98b2ef16b31afa7c3f2ec25cf3e8bbd11", + "0xb10b6cfe3ba563b41ae0d66813105948416ce0848ba3b34b8e96547e8842086b632a52904e56eb61d93e0cbdd402d305", + "0x84c4feb35c8d3583ca17245e6f7e73cb488aed515c2ef671b09a04d8eebe6b7579e5b1fc8634fcd4c3bf8100d2cb98de", + "0x918d8fa2f52a9b3957ba412c24cc579dbd1f0b0834b909a6ac0da5dc602ceec17046f61b3d4a2658f724757ca8041fb9", + "0x87296e4775fb887bb00dd3265f202f31a8fdeae5c6ad8ec63508476cc57d330827d0d241c68091bb724a2ba921694a7a", + "0xa8908019d96c506b314c84b22c475157daa36016a9b94feecc4571e869918e4e5a9e39fb7c9ae0f73f9f868bdc50e2af", + "0xabedfabf75a93e7521eb339ce2e22e0e887f94ea28d3adfa42d1e0523686c6cbee4c96b2bbab3b8393feda1099b24d4b", + "0xa464d6bb17386cb431520cdbb3818beb3951b0255d72f58c300fd780aea1fe4dbce5532f5321e80e16db2f9b9bfe8a1b", + "0x8cb8fe0df930e1e19446ff0183c7034e35e33442da346df8a802160120a5f4d8abac236763114a650dcb1a1d38bafb37", + "0x975c47ea6412bfa97db9cf12c2b4c07ebbda436716aaa7253b2343138b36de6c897386833849f539bad7659d9319abce", + "0x8cf94457a5a708cc91bca9615e599b0c0afa92a7f2d9c83704e05a3dba56a90c4eedebb6d2d25b3080786e16c27194c6", + "0x950d02a5e41c8f704184c7c59715fdf3b48d86b53b04dff7c21738c7c38c9f4f75349ac1e70ca18a0744b01fb8b13504", + "0x9458faad893db4458b330ee283d6a90f68346332c99cbe8e121c890bfca908f0c91168072aa221c3c078d7fd5e4b44d9", + "0xb0262948c113fa2a122dc6208250b62ff35b12d3aa1e5735e95198424cf16a4829e9211c9edad83989c537572c5b41ad", + "0xabed7125de7dc52b0b42cd34fb350d4c6c45016319ab776b52289bc8c2b341a15d48165c0eb09511a1a5a5ed7ff39e4e", + "0xb4c352b4a127afb5b0833d210dc2c216bea666e7c5a940a3372988c0b02dfd236e4ac7c124664bcbf353132d6f061f3f", + "0xa334c5919909dadca50f3124de06400df660082b527f1f32b386b9216d021d38685f1839bafbaa7950eea6c1cb14bf53", + "0xa52f4534e9de29f91039af3fce055f2f6726fd9b10595a43ae41f7b466cc4ea6314487081e867ff4b5e35cd622fb428a", + "0xa68c6ba9673896bf49ed145935773fa50d95ec0103f97a6f1ed698d93b4dd78111325f797e47fe153fb3852f4590ee89", + "0xa5c456d516a557aaca80441705cda63d081181199097e83b22e9cf7b9947a8bb78cc476642f04a5ca3b13032319591eb", + "0x8a359a3dacc7b45da2b826dc27700178553f6a52e9705451f24c6d6026a0c597328acaa10b3b5a883b6353eee4eca594", + "0x807217b435d73c1374bca84d2d3e069db756176220a01607b81438a70f69232b82099c676fff361dd909271be8d5d555", + "0x965d0f46eb0804f19dd700d8721349287335c70e992efdfe89058ec424b87acccb3fbb18d84b727ff5ccb6f6783e9065", + "0xaeb5f2a0bff1e6115bc2fa73093019f8c679efec91d03398e24651be187265f7ca80369a1dfa61e8701385dc0ce9a0a8", + "0x85732f872228dd5d691f1507ba00cc94e054baa59a764565401e9e9b3287d2d0cd0f2af290b28b5e3c80da9cf23ded63", + "0x8e9a315c5b40e7cdb866b8a7e6ec01eeb27a52a76a88d5956ac3e66fd9ade3ec954acce816227b57fea6ae9244f1303c", + "0x80436457879607efd008f959cfd7507fbe22e417c701f59b5a36e878a04e51e87eb38c48c0992333656b24a4e671bfb3", + "0xa012f6d166cd1d98098544bcddfbdfa956ce60011694b640b012da3a0a22ac8a054a9e205aa9fae4df764ad60c65a6f2", + "0xb8225afd6e4d45520678e243d97bf48f87c2b8d2cbc24b43f94bf6e7f60b7768d4c3b30d28a490e7c8a1c3a104ac8317", + "0x8437fc2ab6d90716419f544a1d16c607173fae5bdc242d8224d7714c115cc54f2246d1062ecd77d5a9cd3ebed3a8adc9", + "0xb113c6c63125930882c18f548c1baa69a26f9f3dcfbedf5be41aecd61adb896ff9622ce038f0ed27a5ac602b6020740e", + "0xb893aee6291a3962fe17ea41322de7edbea6ebd51d2c564fe23ba8a4cf4b6270b7ac72c87f2cbca209be1ba607ecab75", + "0x92e6a7494114cb4dcf2b86ba61f57f6db7e4d52895ba6c896433139eb2ec9c9604f3e9100c690e1949e32f5b7e29de93", + "0x881a323e772a639553cbb401e2b6a255094412addcece2c99ec9e1346aea2f4e9eb247552435eab74799ee4c7a927b6b", + "0x8d5d3ec378922311374fcb998fe5a42176448b629a6475abe494fa56abd5faa5835af37624c138beeba649f7803a4855", + "0xb1a082ba449e93cc15fb4dc5114351437599fbd4d28eb6b4746d1bd242172518f94b2ca8b1f76c08d9f6ef260d9cfbb2", + "0x8fd2b7728a3c61cd8e0c607cf40e935dc45d52d040ef1259f62e3eeb30bd3a6cd030fcf407fa0b21423b23a795a02b90", + "0x9214aee5787f4666c3e2aff70949dd679d4203a2c3e7b6f88c548b80a3e52d7763f2bc2b7df714eef053f60eda4db331", + "0xb15df25b62c6f4ac9edc414ecacfe8eec055bb07a1220e327bf35c5e452da7620df03416a449197bfc8d948445c5f734", + "0xb41ff69731e7f4308fa18ad286d3ecd7be21afef3d32f5133a0bae877a347f8773c6e9d9b3b850d054236a6f186e6913", + "0x8d9d13d1b7d9df41cf5d30dd62b9d1d2c4933d62b6cf8d1830bd1ae4dd5fa3de36bfa1fc4d57681ae13996f85ad2551e", + "0x8011a7fd7534b248db40050edd9752c960ffd89b0300a91520759ad51da1698454affb4aa8907946605a02ca09a7f340", + "0x9159054fbc10164fa19f68736c2a683d374681e6e9d5e56f7496aeebb0969b8eb1a91e377b3a2928879147a7fb60b3e2", + "0xafd4980aa4661fe05bf9040f6551d980af562da69ec5072104d8ea34a8ebd28baa0b70e0fe3c11f631005693fb99213e", + "0xa92879cac7940c6d363ab3d0ba7f7f24bad0b16142c78969a737c27ebb09a62071540bec1822ae6224d943d02804da50", + "0x89338d27ba29343279dd83827ae17a53e7d634bc77bbd848f3b6a352fe92f6021dc1c81ea6693b3cbcb1f24188edc757", + "0xa2490a856c273b6eb5242672f817e60a157a1dfdf25b1d32e0f4836a9c2371fae72c93b94d78267b3cb142b4f4d7148b", + "0x8efcf5d06107554f896084e32e8dc95c49fc5da3f8c4be4ef6f2ed89914233eaacfea886040bfff14759ce28a1eeaf3b", + "0xa3516280b169a6832e997a4a45daf46aeaec1d8953387f493cacc2835a5791d4dcb24a0c0ad5de79988d76f843d79994", + "0x95eb7531a46bdc51acacf7fd9e7210bf6d5ca59b0efe58f79422394447adcca6f4ea991600e8558da8e19e029701c5d7", + "0xb1fcb4177f16187c76b421c29f715f1551ff365bdce9fe17b74425f76dd90fb4ebe828ffff3d20f75ac620abeb9381a8", + "0x886246027be4062258b232926cc82b6a51591138561ddd0173ec6e4b7ff750e15d9ba175f569c266148c653ac905d498", + "0x952c089dd09dbe531f2fd4137c971622fc1d85a78ff07de634f63853f62110dbae3646564addef8f2a070f5a16396ef4", + "0x812ed85f4559fb28732d17c8fd7c6b09a70da454a2318a0276949df0a5dd2714b14096656b7b5b6398f54c74eb9ca49a", + "0x9340db62e43e43144e1afb1da748e81a1b00f7b0600e8eed117e92ffcf801b9d89b494ffb003b4ebd5bb4e0eb96c9374", + "0x9287c0745b4bbe24b56784ac28bec43ed2abb6bb15bf11ba2b18b01801da7d162aef88e967d2f10fb9f52f6645d7702e", + "0x9615bc232ba6053fe86c6328eead899bd62c4f975273f72595407fe36ea43e30eeac7524bc17dbe78b4692d42ae81c04", + "0xa387899b521b1a89e860756bd0986b302f3c06271ece653425d6c697e0b330a3ed7789efe0e5a1b32e60257a12fa0147", + "0xb4c99909fbb92b1f39e9b2fabe05abf58af834b6c15ab0f62304ccfc5047f187a3ce35388ef293d2857b777f9938bd55", + "0x97dcb90d2dd9291366b557936931550d665cd05bb1b19a7a53a31c2a39d264789477a47ae14f6bdeb171e78941a9d9e2", + "0x81417b4a3e61ab9b48e0ff1afa8b523bf63ef95a6d6980092408b61f4293fb202395b10a5d12dcc54961370c134d5b0d", + "0x9135da893ef0a9d45a719207659cad4a0590218303d0e02016bcc5d14f54de5fb8de642efc7826b3b3212f714114600e", + "0xa00d0f8e2ea06b13f5a75a6dbd1f2ba7ce3f3bb3e62cd3b53f8b6ab39431fd2ce156a1aa4a1988613d4a2b6d91550147", + "0xa3f8f17dfdda07166a7e5503366dbef45ea6b6eaa1dbe02b8051dff58453f1ac24762c82f6db6de4370869f9b25d6d51", + "0x847c2b79076f9284d9a866a72f74f62fd73cccbe2df18c0fe34a35416d4825d364e24f95f728bc0e6a5215b08b6f0d2a", + "0x9816284cd6b8b35e1f5409d3a5899af5f4524a4826470fd164fcfe863994ee3aac77cbc16831f0866b9f0ae561903d61", + "0x8ab1f9feaa8ba2e1691acbfbd5460a4bab531344ce4accbabdbe5ba8cedb5d5fc0967def4365d755ecb62d83b7ffa4bc", + "0xb0cb477aee9bd113959ff7b7675f81ef251b76cccbb67cf68ba571fc08561736e32c18aae93fc8d1912e7eb2fc0ecca2", + "0x8cc41304caf0357d13a25ecf66336bece67d5d319bc5a50328a96199d7ca4fad05dbd7b5edda58be73141bb06e269c8e", + "0xa7b4d91a884abad5337925c34d7fd5f2aea5a09ff3c027cac98c646b5058f7fe2cbf47208930509e2a4eef1468f64c89", + "0x97d942e97efe46594e8fc86828ad3ed1c9133a8067f9b11bc0f4ee3815affbc0c7c46a91c40f989d50f1d8df96982ada", + "0x95a7d369f3ce7f7ad7ddf85bc994667ca25a0c2f11b9312d06654599410d5325ca3ea74f33f21b5aeedfb582a9e40c62", + "0xb0a05b564a754b46fc7aa4f5289f02bd9f19708b5ecb9db5c36bb7505c8b56ec22b53fedefc1df289c0f636c97e8ec47", + "0xab6e2801ea8bc600f9159d05a3b39e8b0973fb9c2696b3f2685424757a6953a9f8ddf5e29c97399c4821b8d7fd9f1bc4", + "0xa6fbbad2ad3ce8e4f9b939080e9e7049eba9f76b8ffb57f7cac2aa46793a064743239ce287e156d49cf4936517632290", + "0xa606632b62194aec737403ce5a9b6316178c1d27baffdac83981baab63e75d51caa414ea92465ef37d6d687b4fd90141", + "0xa5a99b7bf8f4c109af04c31af9b5f3148370319c8483796cbb5ef555ee1d4858b2c1acb82ab5e26180254399fd7a0625", + "0xab2b00f64355ad294436339636e7764403b821d4dd4fd74a6bbdc2aae450f14d7dbe8423336e793a393f4580f1b9e35b", + "0xa6c98a6ad7f36f16633fc216c12ca34e596b292524753ca1067eb75ab52facd28ed3a7c55e0a0cf1d3c9115a2a0d6524", + "0x84acda31e618eaf0424a37cb3c386585a3870b2c24020550a16134ad8802d427c918e2854c98e5def58a2363a8e1a314", + "0x9911ec15af39af1a18003ae120da8d909ad4bd43ff03078091d54de71de70e19786b2aaebaa5d55d9b2877004da2c271", + "0x8cb5a148f065e36b67a219bdb347a625a7a4be8f20dfb1cffbb38fd4d843c2b1b1886c1f015793bbcb02af04ed91b170", + "0x815d9adf22a36533fd4a3efae3c4326213ba2aad48724ef958cdd6f0dd5059b519e12d91ed5d92f1418a07b62b108bfe", + "0xae5c244f309467ada13e2fcd8942886f563bd996a5c65aee73a364c2ecab49be3ba6bc8a387f3baad44776f4f1042eb8", + "0xa47d93b35f57ad890239a6f2f69ef8760268adbe614d5877802db4b6cc75cc093baf101f75be0f7b4d71ad8724dbb9f7", + "0xa0d089701b965df9fea938e337016ab20e0e567e736e6652955f1a93760b4a9f128be5a594e71df8e7db47c3f88c2fa7", + "0xa9d9a7170a860e2860f785edbe18ad909ecfa489cd3a2abc580869c7eb8e9a2db93c1c473a5f1474ec0d51dfdedf95e1", + "0xb665abdd084abd292548c336e3e6fa1c5ed1a53d2e61a10ad6a4c66487d8a9e101632ff468b012506135907f0896156e", + "0xa10ccb363b26beb9622e1d91021d08a3bf02bec96a059ead01961ad51610992ef03558c5f77e074442836c9d2ff44e0a", + "0x96d6476066264eb3090ba3544dbfec7c8a0d90985a1697985db0d04773f6d37d5899a9d4fb5a3207c320ca78c37492e6", + "0xb4290ff9213e2ecd30d303b2b4ecc66c2614b8df246e70ece4e55bea9a1f5a0bae9df6dcbd8efdcf8c4b0f2f4cb44d48", + "0x8ef10b2e53e6770a36b6403678ffb86f5d85e3e87bb1b3ce9f1f0cb0cf32f1fe991c565595389ad83d8c8d54a47dcc82", + "0x91f950ef60014e3dd28f7661e6275ab6f085c803988b7d6dbb2cab25f10b0372e271267245761e1af97da6f48c230205", + "0x97c626e7114396daa337ada4f08da5129464d8e8c68a407c8798949817337578733fbcabf454a22b57926485c28d9d62", + "0xb596984b609a9858b1adefd15a546d4b8a417c8b54504efadffcc805caf8935b9c7f55d9e6b34592241195f513453572", + "0xa3fdd36f3eefffe0cd2a9e6cbfc4eb9c3a499eec25230df8786b23f5eb71efddde062940ac23d5b2885081da48d3c1c1", + "0xaa1822db9ee136d0a51910f0a59bf0d2af6819e4ec0b859b790e01bb08c1def87e9613b355525d4ab7d088b520a6a3dc", + "0xa9089edfa96fdb7204a68c4ffcb7e0a875106886a0c589dbc57a6709e7822747affb07035b99d056baf11d0852720489", + "0x85664ab9d32ab0cc2d2e61901b2682f88a7259c2da4ae6263b917ae8afc232614b4ee56539a868a24940eab74142198f", + "0xb90e06a1a117659b52b364359e2265daaa8981954e9a9c37e3256cbabf133dd4900974a895dde6ec6b394fb36b5bc1c8", + "0xb414aefaa4833283dce85add23d1cfd776567735f2ba9018cd791d652bab55bb0cc0cb38b88fe47e3b4b877e63edbd75", + "0xae579eae9c0b09c906cc2824eeebe5b4ea031547055c8ad635194f3e864c7a184dc21a3eca9c43c01d9a2f272cb2ce81", + "0xa7b1d13997c283c13f770d5203cb09b5d3ca7d45324ec89c069928e1ed1a17c57510e0ebaaf54a21d27b0f9f057bccec", + "0xb15d4555520565b76ec21d87e094ece2e04c7c4bbbf560264da37604f1a484ecc3ce8143b04759fe716411293876d0a6", + "0x810bb0773c06caae8cc06ffc92303d51eadca1e1b0acd57ed23f5feda70378e180619f68b8db98e61d792568f49a8316", + "0x87dee32807e2e5f2c884822b31098e5be2a4d950ae728e3281a39e661937c4b7e9fc025b50f437f01d69e5c33dd751a0", + "0xb46810bd73d077a6b73757d22b5939c02a3632e81287073b00ebee30cdd402e89c318e0b03d01fa331193842f3a1ae53", + "0x95a136a7bdca77f764d2c2d4795a8fc9e5b9097d73bb3956b7a45b42185a99c949db8ac5627ca263206cab9cbecbc31c", + "0x967eee3c3afc138a482bd120050dcb9b45a9fe258e5e4b678b1d67b4691f4c5d89cd260210fb50f9cf2d3e2e2802968b", + "0xb2d59a9ed0448b88f8eb26d8017a129ebaf27f11e0a031130266796e5f777bce93cf2c7e0fba8f8ccc997315db9aeb9a", + "0xaec708d3093b12caf29efbd8afe3ace1de24496cee72270223aeaefe4f0ba3a7acea7f2f5f85c1f274aaf5188616133f", + "0x8563ec52704c1c7ab515451a8f89f87201d30a12c95812ac95fde2af033e5019615a07f28b540a92781ed35786b5614b", + "0xb1c8f819a4ceb17d35ab997c14f81ae2af9d4510caffc61d4a19e9129e0bf7264482a10f329054908f99909999b6f538", + "0x8a65668637ba24358800076d8edc90979d6e614e6a683dff7859ce7d686014e6de85298f523ab060c9a9a4c4b8862cfd", + "0xb4df02dd6f4d3908142654a42af60fef034379b1526c12be66afcfc4f1177991811646495aa85702f3461060732cce80", + "0x8991bef253f0bb9b86e68e81f78116c51097004b0309e199025e45ac7ea55f8f6b2bdc58886899d275424ebd405ffac0", + "0xa74f1048548fb41e57f679d632280fd2e4cc6ab88c81675c59fe143b74dc7ccf050db53dac5611ed6b45b6a0b1b7f3dc", + "0x92011c668bff7ea995a71e4774e3fb5d521ee2552bdc33d9a65afd9677572c2a303a940751ffea470af898b01b9285ad", + "0x881a0e6042771492633b46b6101f96a48a93aa3860533dc207cdc90783fbe52b4a9ade1eea9117cea004bae802cd3fbd", + "0xb3e578bfd77a3a13368ecf8139b69f729cc720aab25853cc9e2f505c2e03e75cb779d685698af8cc4aba8d1c17f5ec29", + "0xa025b6e8dbeb68e7ac4a595b34089fed0d24eb29a7be235048205e35a97634d6015ab24c21a017b5012c3175677fd0bb", + "0xb751acd86ead936ed0f22d770872cdb5aeca3b1ec75a5a1e65748b665f8d1c859b5620d761d5f0a2a86331188e82b2a7", + "0xa05faf0bdb81caada6c662ed2fd145eff5db5c423258d6609bfd4c467edf3ddba6480ab95ac9f4dbc932f4887b070c82", + "0x8fd1faccaa7cf1d59be37bad69b7a99b7641cbfe930d778e0f712ae1fe9e78d53f37d7d5d3aafde48452eaeb65d980b8", + "0x86042bc710953f0042940625d8b69ef57c615f9631fc49aae169ca595446e9d55e149c92994d4bce7b544877d7b6f22a", + "0xb396047f716c5fa8ca9234c7026f1772d83f41be03410b4a32a376e5a038d252b8f36cb813bc3684f1b50326994c31cb", + "0xa2eece2d76db005f5d95f5f480bb3353ec67a9c27896fe54a2cd5cc7f802507d8d518596601bb3d2798842b96fc03df2", + "0xb738c1264d094f7b7edd27b0ddd8e29716c73bcf7b450ad7715fd21e1052998675873ccbec486fe45a8f72d9b006f239", + "0x826c4c5fea1596e353f6c15d91a9bbacd9ea592aba4d22e735263062eac44f073e5defb794f8ae4afb7d4dbcd1ace959", + "0xa8f1d170f63ae3b05ca9996347a1b3987136e7bafd02774698829986d48da3d421d269d31743bfd3e7917c5ace7ce729", + "0xae6871a8278f24d816657889ccdef509df0fb941fe6c5839cbfb704e81b942ea2a324fe0ac9881b385bc97410fd94b0f", + "0x8aa6bb564b6a0354be89c4ac10309f941162fb3a546259c5d789d4608cc628f69ecf814b59bb8bce364162f7552e628e", + "0x8ed85481cdc58fc540384213dd1b86f80af8908683d7d2c63ef5f8c4ac2e90f0e5f4e07b1b841eaecaab1f7e091423bf", + "0x88741d9c9d875e2c1ee5b95bafa4d8a22d72a728260297d048e4f0cd1c5f1eaa94fc233be3fa15a69163f218d62ab17a", + "0x8a99655974ad5c0f27b49d88a9c52a5375e16b9ac4f22b1e1bde53ce0a21589022c0ea926a4c2d7c432a53656ccffa37", + "0x8e2628878858764824471fd613cf40d1bbb3fa84ed081a762da0d6d491d54688723273d87a587ed1d3067976ab74fe1b", + "0x8f1a6162bd6cbd2353265bb348311073bcfca5a86f41cd0c63ab91b14aabbeffade5ae8a94f8e91faa386223fc2bf849", + "0xaabe8cd92f0193d12b032a9bab4bf4f02ebc0b24d1ac09f8ca8906621d6c7d4bb436b2dd879a1a1cca2b44ebb5642995", + "0x91cd27988ae8100d48ace10ac9cac4cf1cc8539bb492521a8a6489f8575a737f2a1d37fcdbe88dd651179145a59af920", + "0x8baefbda554bc0a0b425f2e132c7de061fdd120ebd452ecff0d78cc5bc5b15401997231727a37e9bc4abf1a553a4cbd8", + "0x971b12e25b989511477c04602f48f584485a0a0773b46643190263c0288c2434969bdddb1e55dc1f5b1b028c1c53eb32", + "0xa0e47f42444a16e51323af6f519c0dd2271a85746882818d02373ba33c2e2f7bd6a1c321497377e4781f72427fa34224", + "0xb52bc02de867d7b20cd247cbf496e03d940be2d7ca5755145e9a0168889db345fa9ab17c41635ab275a459fc9d02ff16", + "0xb01db7077e9f01e675c62f5095400cdc68a059e1a5005027033ac535a0505f45f89faae4fb9831f7ff9cbad3b55db02d", + "0x81ae065f1d55f4643a2ee120bc1245b9730455ad9e5402df8d6fcbb1bec71e40f1bfe7b8e67f96fff76d1478cd3973ca", + "0xa1be3723920044be80f398279e2f8432aaed45a36cc4fc71c87f5dbfd52225379e94600793f40aedaac2391caa57d155", + "0xb682f74fe46d4b647196b7c14804dc0b35e36cdff59671d7164ece874107964ff9f76c29b23c190796a9a3aa2df822fb", + "0xb8152e458970ab53f6b5bf6101008c5c31d2f58993474eed6bccda074555f7ad2351810d78676b62612e7eba2d86247d", + "0x9132a8fab2010360ca80adcc08b3a01658dc8ba8f60bbc45e1144c1219f69b985436c36c65cd7910a8aebd91ea1d3d38", + "0x805cd373a0919de801b6bb7a6ebf55530037fa41a1993c159e90213c492165c42b5642dda5fe7283ac4e3ade6e63a155", + "0x91f20d77fb7a8276174989faed41fa6da841d35b074c4a756c2b4730a7efb9b124ea6c7d5eb150a8b1126636cdb2ff0b", + "0x8cda3ffbd0ab6846dbee6cb8c0360842837a65f83b6ba17085161a7371a4466172354e494a8614cf2f1f4726d0a7262b", + "0xadc603e61dc36ee605dd7f2761ed568bf91b9dd3d40903eb7d77b11d10e4f762694fbbbcece72a7ec26976054139c768", + "0xa6accdb3df5029f19273a39bc30cb622f87522ca5a63372dfe61d993dd783ca5e918218b5c519d25e535d8b8238339a2", + "0xa188897269053f2494bd0de8cf098e41010fdd01f5a49d7ddd7b294ea748f1139e0d92fa7841dda9f8dc923ed6f02615", + "0xb26ad5dde632259293d91109fad4f742ab74de91f68ed2416ff53c060d1ea4377a875b2ce960cb7962c37a5fd47e85c8", + "0x82cfa86a17b27f375172d66b389df727734480a224b91585fb4782401d6c49d4dd347b8d1e8df6b9c0c1d2f8ae658de6", + "0x82911748e1471bf5d7fe3ff111ac06dcaf5b8a43c76f6583ca491e0aa845b61cdd443613c5728863c163952d86bfd482", + "0xb7b0d4ff87df02b5481183066f6ac0d1636718fbddc19889e92a71a168fbe338ffe780a792ec5642aaa4024d0964db69", + "0x8ec21f08594ad38e9ac365e5246aa5c2c8e34ae66382ac483b47771c33390ccace4d906695b1ac0f1c9204c46576946b", + "0xb9617d746596b26b84f2709a03b64fe77e9a10d0c85535d92d28dae9de3bbf6455a247f775dd9f67061792cb924e3925", + "0xabb2ff3f16309fcfe0a3b1bc928ca5cf618706cad3645b029bd54e5305682754e6ca47e364ff21b1750f45041eeeb358", + "0x867abcb8029b35a54552c57346024ae7eea38e9ae4bdbd68bb3c1de3935126880f237d9aa95d6644dba8ddce67e343e7", + "0x86eb4283147a9e595d639f29a967310acbed9ff09d9043868fd18f0b735d8619eb4ee0250764f35a51e00b58543bcc66", + "0xaf1779d2115ca7021533bcf55a100b4d3ff4e45f8ce6a6d98df22881526a429d97818fa1867ede09918a438957a03534", + "0xb10b36d0b69b0dbecb6f7efb6c612b0462c346079109970a26541a21aa2b5b81c1e121ed0d5c81af00ea8eb709a83dfd", + "0x911f81ed75fed55f1fabc5f86f9f38490e006820e5380963a739ebc0f87a1dd3b7da8c69dff1e580c5ad2246bc08e2cc", + "0x8379449499da9159cac2c09c61777955e61c63378d051bd28b59c78409ee5d09c43e7a6c246572bf34233a314511bbdf", + "0x84b48ec8895049bd03dc3256bd0d63f6e9abb178221f7d47703b447c709fc5fda47b19a3439f30f10d2670194f390915", + "0xab3bb5afe824d8aa20f97ead4c40aaa93350f33d980b5783cf56c8552a4298c989b7b188d023711a2eb79631f3a8c317", + "0xababba2722186a3b2272feebaf2ff46c93883b7265a6a4fba039d5fc0e7fe81b7d4dc2cef7738406f156f693ba3a55eb", + "0xad50302a51eeebe63085d3c1705eee9142bf8717d07c5d87e0e4ef5a12207dd5432994c72b9493f9ceb558a20929c9f6", + "0x8bcc3d83a6b8998e1a1066347c647ab122eac80c9c505d5cfbc370f466349671d8da4d500201226c15c1f62162efc62f", + "0xaad6946b5d5df34ee6f7422fbefc6de33dcf4461868ed7ee7f47fe9b8eb2f7a89759c73b7a029d422b02afd0f550e722", + "0xb0fe1d9a30759d83084b4c567b586e5a8f5a080bfa93b4a3feba59edaec33b6a2ebc98ccd82aa9d8cf0bd254d5f03baa", + "0xb993c4c2b77fcfbdb213bfd5f8d655d1d41a52583de63b432e2732df2f9d88c4c6779f314848417c06a089fcb970c0f2", + "0x842ea3aa645e5852695405b6ff2184e55bdfcf50be2319761e717b7b52d904ec47ad3abf986850c643003442e302ef30", + "0x8093b0ef1f6c84a8253d086a6fda6be8376f925f416a9d1f44ea72489f60fbd8b53cee616cc5ece43e2a202653c0640d", + "0x8c75f10b6aa848d84baa4120e75d3edb7f8471473851326cbd9ed7b29b22c5403028f49430bfe4320c3f4227827e667c", + "0xb4fde4f20ab98f76f55afd533f1b09ee4ffbac9486399714514fd694fecd0ad1fdafe13b2b80721829c7a59e4c951a76", + "0x843b2ed867cd8edc2eee84497dbd49f3dc481e7ece69310d06225325ef032a4e72907e16e7b6215ca775f88983d55e5c", + "0x9881e5caa9706e4d7ba6ab81525090e29ecdf1808931f3f2b11ff9ff5cc97f83f3e14fcf18abf18159c3fcf4cbc27042", + "0xb6c4acc868c05c955eb36a24652314be37004bfc14283600523729d466c56018c99a45a41ec0389449fcc3f8aa745638", + "0xb6820864d07715dcf4a9ece336464aeef9ce381ca7dba25acd48f60af056a3405c22792cdc57c641e782896c0ea05b25", + "0xa1bb482e35f71772486675cb4ee0fa5709b757083d18a29d4f4344e6ce901b2edb2889b7eac92c498b90c7d3844c450c", + "0x8cd8d8d47de859d0c68bdbe1834a1c9a34e92636600fc592a08f96d66426c5f41f388138f42c9b8ad72c596f4bf85496", + "0x801cc0631310656864b25d980c9e99a98fec2316414819afeaf182d3e7ff93b32a989e2ce63f5ea9301745080854188c", + "0x8fcc6b2b656f7960d9ad48c091c1ea71b6f0f61553f7695049c770afd509ee58ca8e1dcb403aa2c5acfbbba58676bd44", + "0xb997b9a6b994e3eb2de8723ec485d8181fd674de19ac9c2f50704785d9f5a28fe3ad194eb052b5ce122ab5e6e6968a70", + "0xa909e7002b82b371952ca9d0832f531db15882180e97c12c56da649fd65334904fbbc3f097b6a954469221d181e718bf", + "0xacfc712e1a61504814e37b3aad0d7a5cafce5901ffa43c13bc5f70507800ff03ed261367ccd09db7429cc5dbb892a7e6", + "0x8d634a07b69ad87e41d941aca08550ae9cd72fe31f3075511d030c364fd6578a36f3f0f3785d19305a1e772486ca097a", + "0x9746ce2d890248002c1bfb755e06f4f4570cefa7636e10319bf491c654b83608766e95fe9c77f1a6a630f5add77b71f8", + "0xa9dfa56bf82297f709f1b4bdbe4bc194bf22c0424815bafa6c1a536f2d15f35bfdebe0867ff20781a49274075622861e", + "0xa723af2702c6b473caa4a64142464f201bd1e2f765454fb0236082fe3ad77f22b4353e5981e6bc37e974c7ef797f875e", + "0xa42a1a0c50befa6864fa35c25a17f5309684c53257376f8111fe96c84a5e09376fad9c8545e1946f360e16e1e4c941e3", + "0x84231f6bc3038320dc13f3ac014977326dd13e5b2ba112c084d366b5255729b2abe665aca8a41d7aa6645412765887ca", + "0xa64e21d651bed6dce8dcfcb4caa60791b9345cd7b6a100f5bb78f7423fba5ea0d0cb3668f3415c27af29ac35e5dab0ae", + "0xb8eeb2128ea14d81fec5b1103d8511a3dfdab925212363c75c5cc01515fd94be8db2335bb84e221654380e58e9f2be67", + "0xa92e9cb287981b33a5e697eb1e757bd44f45efdda1759122fb27dd4bd4ce3694f1b6b2082ce4e6e3919d9d7a0b7c8a12", + "0x88f22b83fd9dad63e800b0bef709759f380c6dd9af7058100413e7b09c7517eba258d6367e0cb1a41b7762b86b2ef137", + "0x8353d45a2096fb4bde82ca22381bd2ed93fb58b236b16e68bb37df3024672067c4378d7f04a4da4d116e7d57a2211f7d", + "0x9076205bf231de091fcba7f5a4fe1d4a359f07236efa39f5715f206e5cb7eb3d9adb56af8181f63a9d3e965dc909556c", + "0x93ab7f56e8d37b47d3a8cbd222f2dab4bdbf94a1152302752f0a731294f4dc214fdba17977f11aaff2eea9517fdd5789", + "0x96d9883ee108c88342befc358325356dfe5d72c521d71e4b3a58d6773ea3d1a1de1a20572aa96ca0e8483eba62466504", + "0x950e0d61ce4e76fe0cdc3d59c5bf23d8e1cfa9d6ee13b9fe41e6ddc0fd52081bb16bcdd973d319c20709ec517fe15626", + "0x88809c1e272b552d46137165e5396917d107547b65059fa646b742489e8892acebeccbb3eb8f2d676e3836c985cb1756", + "0x945f13ff081b74403a19dbb04173780f04766f7624ac6b77f46464df5f4f3b547c459f41fb1842164d8f1c126ad6be65", + "0xabfbadc599bcab1c2b7cf1fc5aac7798d9f617d6afa0469ee23230c0d004fcd3de0ea645feddc74e676ecab1fcdcd8a2", + "0x83ea1571b064d05e1b7f4527b20ada121024a4b2dd8f7d551945488ccfddd671ed2ed3895578afcb3cf958f9a2c75c29", + "0x8fa75050bda001409f2bc0a275d8dc0fefaa47b3a0ae132758bd711eaed0851d6bf3e4b7f355377a93fb8eb02b3ac6f5", + "0xb2fff49083bb30e2661e2d8978149e0d0588dc972222f46d5d120d01dc5c9978830c442827c8fa295f6b8e6d8c786198", + "0xa352c2dbe4f18b311bf0690d77fbc9439a1b8088c806a9d89071b3ea04ff387325cdc04a091d2bde5fd087bcd0f4f482", + "0x948ea89408826ded81549cce823dfd7605ffc2279ca7d0964b1ab3d5f35f4b174e81575291edeb9eaa4baad3610ba3a4", + "0x998073b618140b04ec394ffe4af02df044d923a5cbc8f06f26c9eb4ece17abedd4f72e10c9738bd16863327c0f6ee20b", + "0xb3bfdda0d6960af897ab508bd9312d9c166157f78b45157b46fd2e38ab2e430e8a19335d8a611366cf74642bda77bc78", + "0xb8dae3e2ec5eb97ce3b5e9be719bb747e6e8f28dfb1a6b7bf5063822b502a5422cd586bacd87ef83c0af081ea4d30a57", + "0x859713ddf0ae843ba690fd8177ce6c08e2fe5fc1c8893d829d39a199e04758719bd3046034926de40973a992ecbfeda2", + "0x866f150d4b6a015b03ce8ad93a70644b55ca1818a0f50d24795698c62f3abe59d3b8abe4c11ffcbef20127d3b7afb970", + "0x9145367ce9e2a5a6140db58cb097767b5a6e19eb36d1c03acadef612af95eba80048f2b02c6fb46eaf38c75288e3e4eb", + "0x8c298aee778f4af13329975754e9b428e127680f26be139307d43268dc63892ac98284d78ced0ecd384301e26d5b63e2", + "0xb4c2cc9256fc33ed09531abd7c3e34f8f24830a8a2cf2d684cdde46155f43ff2715c94e7dfc7377765ec0cdefb21cd2d", + "0xb9193113b81bba4ebfe40e97be436515254bc67a94939220e5e69a197765bba40dac3369e5cde115d1bbb65e1c826038", + "0x8474d72b7cb52768c484ff92d014d7733003b511c0c915649f65dfceced47ecd933ce876eae254cdf2f6357ea865580e", + "0x808e9a59f947b2b39af51deab4c164878e02d95773dddf1123091e27de87cfffc07aecd7c9cf3e08c0b9f525bd87fff8", + "0xa8e0049eec8eb70c12446596ba5c8a29823704be3753312c34cb271000b6c154b1022812dd02d1352cd263b655437d6d", + "0xab7894a75e40d888a4d0539582cfd6b458da009a5017e561c14d312335a75745ce134b57466fd30c250ca07e0529c8a4", + "0xb30c5c0abfd35ded7a3da8f9c95e3e1c320857be1af317f6ff5e35101d3f31de3735ff8741f6460ae1e63cee543081fc", + "0xb15557ec268b4eba9628ccec0a5f3c947e624b61edc876e2ad8c36ada061fda76f69c8afb95270b85f4672171678d078", + "0xb7ec103d6695fa64107f66622148902019ff3acbff7b77ad80993bdf209b73990b0fef92dddc5fb66aed77cdb59af9d3", + "0xb3d002f0a35808e3785d58d0074be620416ee9381bdbdc889805ec2acfd169e1ccb60045d87cae3e90d5da94cd58bf80", + "0xa17c44ade6eca0942742edd237661ed406a129a968fdab28a58d19308d207a1e7853099a4a3c1c181695fcf265107a55", + "0x91fe5c0d672fce368e229e735eef43868e31265502e2876e54aa44470a257d1c126ed73d6df860f42d8e1dd425d8987c", + "0x8434fa331278fcdff2c8c07596a051847425fd7cf09af31bb235d208ef6e282cae173d6ffb73c0475307453d6133ae7e", + "0x940188d6c20924edf1d9343ea85ef9e08d9d87d2a188f8b69514a22cae10aa2d3ea8e662d43d60b8b77183b3c6e8cb1e", + "0xa89f57a730437fc511e1873830b300df7a417493a468afeed2f837f31641cba04924effe11be92d3bfabbad0bbb7d04c", + "0xa561550cb347fc9178c875ebd8dbf5d14c0afbefa79f7b93b893a25ca8fcdeb0293de5a350ef63413aa70745cbce9a5e", + "0x89fe7dcaa6a10cdbeee9d0d3bc8dfeacd47e1490a6c3b591f66d3a64ed668e6034381e0ea9f5f04fd2a5d9ad5044b8b4", + "0xaac54b334514d41665b80b2cf18285391f47be820446e2272d69edce022f6d7689c8e137e2e9579d0846bf5440d768c8", + "0xa231a04b942d471b32cdd12eac3eba00b8910fca0812c9470802246c479050d6c860f64bcdc6b6e39ed0e9609df9239c", + "0xa6bf6eca52b5f3ffd89b79be6edc4f517fe9c9bc67051179157734689fd63649e321d1fabda916a9c4666b64ed60bb4c", + "0xa7c4f791a1d77cfcdf34c3b73ec7a43aa1c8ec81c39ce81d12c51973ddb0bfacc79e1a128ce17afc5838982f66cede6a", + "0xa1644b337c4398f00e9ebfed20d9b2c900ccb667be036abba0c4d372939f881df2bdb5d40b64354f65c8f2ad9ffcd656", + "0x84f6e86481d3322de791ad01d8c1556e5480534e52970fa601b295a40270882476779301d78bc2ebc323323ad0b62253", + "0xb32eb2beaaeab27e190c9d381b9f3446038391da552db5ded0f5b58d070694f07c737315a465175da29e2a236c539e9b", + "0x857029d97cb9fcbb67e194d9aeadf5b25cf8184b3b704ff5da424fb4b39abdf3f7f317b3f79c762605bd9bdd5823e7aa", + "0x883926170997ba84cf45691c117912f6be5c691abab77fd18fe114577e6dcba18f8c0a6641ef59affcba1b2c92e093cf", + "0x945be3febcff77b4238500054a053c983add7a96ef43cd91921dad908c20d4ae08857fb93a5bb588e9b441aa9a536567", + "0xb9efb8be322722302d1c06640f772596fc362586d8f2e49c41810f4bd2b59e8e9abf3d5369b2421e1ce6949c067f07be", + "0x920ad6d5cacbdb46af424141391817da2fe3d463bab8db760026f98e50bb51aa4f3668520c133ccf9622d66eb8a60e86", + "0xa1a9ca07d8d3a44fe372aceda194f15a2dc3d29267aedcfc3fdbadff0bab1c4397da1049bc0feb9097afdcf1cd1ab603", + "0x935eb5fe97d580c10766bfc2fbff71d8584e00e1a321018540c25f6b04791b63a0d6992257fe110b0d17712f334c9b49", + "0x9530bde6dc33e48e05d98b77844766afc0d5581922e382a2fc1c183adf998c8137df29e56b868c7892b2c1af56edeeac", + "0xa8cd3698276c2bb8d39ebf7fb5fec139580755adbf81bf362e1cc19f4a8be750707bdf4e1fde3064873495cce5cf5171", + "0xac5a83c82004728b34677bc6b1fa507687992b5b78745e5820de08f3fd99e35c905608936ccab62ae39f0408334b3c6c", + "0x927b0077386a5055b499cb5a597ec3c9934767343fd91214fbbb5487faa4339837eab52c75a627d7addc5cda5ee35108", + "0xa8acc2ea4a548d9a2fc2738abcf75cc0efa189b92a99296c0635d53f2c0d7ee40ccc8ae410d2779f95ac6f2027c81d06", + "0xa74c24b8c695920b12a86ed6da6ecff72f8e19fb06fdfee9cd1c1e8e5f1c202d26fbf2fbedc9a5deaeb2d986425477ce", + "0x871251e8d69de5c3117f364bb95d876fb89974428bc167666088d5ff1b83328b675ac2efa2d0e215831e69ee254623fa", + "0x946f7a6d3d6700f65088c817636ed3c1349e4f5122fbc22723d131d8ccd055931dec977cd0cb8dd888c6abc51a5f4194", + "0x82f7c1dc3f133725570c7b64e31b0397fc3a82cb4966948803de210182b9716ccd19e59c0e0382c0c970d05c5e13509e", + "0x8bc45b43102e0df4767156b1e8ec635cc07fd629793d289be1f2470297e8a084bc9af0d76566cc485a8ac898c0493fc5", + "0x85000f8c8130abca642ae94b4feb3448390745decb1f443c34fd06575f1d0de35bbe649b46251df0a4bdc7a8bc133b2b", + "0xad1ef07d34c59afa37fd5147646c24c03622ae4884c163b80d45ebfb5fa994699ad9166ce1ef727c22be3c28e0838cbf", + "0x8d1dd5500229f463f94c611bb2674640d20f2d34dd40b28c4d2a21d3e64ba7355fae55228f1c70095d1b288828a1950e", + "0x834cf56a4f2c2eb04b89383213b84bc6ba554a4715c3c1547278e5501102f6ff2af27cce0f876a2aa2da57b5ac6f3b3f", + "0xa468d06083d770bb4e484718d1c147b49770757b5b296fc6d6035ecb3c2f5c4155176f12ccbe6616184789350403f387", + "0x8abe730d80ea895705bf67ac4f6b6a36fef7403702d8458a383d04e4859b4c8c7a75598721cc75793d29276afea27ccc", + "0xa3890145fa43e6b5c7b8aa0a73a62c39d623c9a75d17c5a05bdddec08d114ab5b0a865c9edb2be6ef31c3dc9544119ea", + "0xb2b7c1cd0aed6b776515a12a0f3a86353fa3d3a3b6027422bf7f2c21e6917dab543e189e860c8fd3aab65484b77efbe5", + "0x95215b7d3d504ff83ae2bff789feb6b5919287d354d567141bae68a0f0d27b3e898edd8a9be5a51c04dd28ce9d4ab937", + "0xa93a3da0e101797c690c38a5bf5bc14e10842e48a18c9888807b2233809ea8a34a76d20a8ece0b682d36c086853cee40", + "0x849a7fee901a9279dcc36fe8f276ea6dfc37c30f75b679ddca2cae9c283de19c4df56790e6ae12c4bde33e837fcbc324", + "0xb5c1587d84b0826e64438d8ee7c103119b164bede8d243a0256b5b798240259dd63281b81bfc613a4874a6732d05e143", + "0x97600c536388c942e0a72ba3bc33b3af48045994a3ad0948fe0741391c1eb99693d072d1efdb644abcb08e10474b7885", + "0x94c2120a5b4743496e7ab9bb2e474580ed27d7cf5b6fb132efcdd7bf934434d2be8d6f0af009c637b31727b3ad5d2280", + "0x8a5ff1e7f552fa8b34b22a220eb1cb018c9c9430f0f14a634121923497cdb4a69fbb8b60eb33e5fdf9b0feb3e9f5afe6", + "0x8b4c9032f25181e6fb9f60eb07e3d6cfa2b14ffdd6a0fc1b309b078f8290901e229a5a6ed96dda74e1a9a894224ff588", + "0xa5e04e164ffc46da1dfe026ffdcd99332874a110cd168c44762c461a5560b5c098ec71673d509fc053f6d9064d4ba255", + "0x97d21cf8327a81385fd3915c7e8efac7662f4b39a9785b4a936fe1b581d630678f42a3e9ea7e02bb4413da7ca9a6f35f", + "0x806d8462bbf148eb4cff812cab11b3d819669ef5f0d76b228fa166b83727c92fdac98ff3afe946855685b050d9d4c6aa", + "0x8a9899b0ddbcf4ba3f16bb006218022efca867a5b32e1de9c7efe1d7039c8e200a406bfd09ebb8921bf1997185e9266c", + "0x8fad2d8629c546c5de443b36927b068cfa333c8c4c1328e1221a1f6af7be5363ab8981fee54307532f239eda7656e6f2", + "0x930146a1f6c3decf40198955059f70c98de7c5bb1b25bdc97fc72de3a84db1b121430cf7a7456a692d8bbb6b325b6001", + "0x82987887016fdb90f79f045c16629c5b2b17b1b4702cd89d06b70086e5922cd10c5763cba6f3d30a2c33bc84be36c6f5", + "0xa6fd7e4834f7f29da41170c13d29acbba86c74d5924cd361588cdda26a3ea7f11ec34c31869537ff7ee0b57a24555e9c", + "0x97b2474cbfb632148869a6b911c2ab91e4af9eff6c181566a1eb34a05d2ef3fa9da4fdf14e8fd8746a7c3123e20d572e", + "0x99ea177bb7d98dce25d300b09bf6ce08a7061360c4ed9a54e30c1aa5a467be6225737b62ae921e91547b5b9d39b800d9", + "0xb9dae836e37d51c9611e6522aa6aa8bccf2644f23113584c74c963d79af0a7ae533af823215fdcbbd8df62f00ec1505a", + "0xb1a7165aa1ac480b4eb1f0b3d4284c69907d1b5056a343a2da84b3863c9a2ec4d757493f5daf9ef252a253bb3b2b6745", + "0xa1322eec41b38b8bf3f4566bd12f9c230dd04d085e0526218489e986d59895d471bd8bb08351edf40021efab1d29b2d7", + "0x96d559df46015e62d8876f4d8679f9a9867dff31eb151238cd75b3a10bbb2ab0f51c804a2f5adec1decbfa355042a6c6", + "0xab55e38cd273bffaa94400bf4913ce0ec1c1c848e8c53be1808d4ce5338ec92b4a4160b8faf0d1d8ee8b71ae751d0ae7", + "0xb61c2987e2b402a52670abe305f8a9976efa9720ad0d7c5c1d0d6d9ec6f1569f51621b6edae84d9bb3fef32bae31a088", + "0xb5234aa19fd9e714c7a9f3ea33d39a5c49f42e7a8edabd8f306083669df4898711d4b50b049dfb91815588ca60052673", + "0x8e98a7b90baa4693c6a1e1c2e556d018c3408bbbb5dcf2c32d120f797fd8ed1373f1f112dbca114863801ec6efc1a5d0", + "0xa7e1e77cbd6274f8c74b37a607cc20596bb7fc35ff1ab4358de15b07952aea397e409b30188c8516676cdd05d4919f3b", + "0xa5f2336ed9338772b71e490b1b3916d33df8b013e4d38dd57185b7314ec9aedaa34eda2733c38e06e656a8cec74080ab", + "0xb5de079ec867af3a3910fe47628c7d793c7d70b79e25a9a436e0a75405e2c58b740c1b86e1b073842d475e0b717d0bd9", + "0xabcadb7a09173f1eda179ab7e3a5722f020402eaeafb9d604641645c21f1e009b758f2a6fd262f115d80e23f8baf7328", + "0x8694ad59d4cc328b064884d147f66095605d9bf339d09e45652d68de765f2b09d45558d45daf9b4b36dcf881df8d4fb8", + "0xa2cc7b2e812041f17b450b5fa7429cf62e2da06a7bb3c08a63d6f802ddf13e8b73d2056bcd6407476dd322fa35b9b065", + "0xa97b0e7e22214f329fc57b6d7ba882ca563f863c06f1afcb60c0bbc81ef08ec866d39c81a80a7843889fc957d532cc0e", + "0xa8a809392dbf35911df8566dc20e2373e2fb3272bd9eaf9f474588a9132f06b5a1433ba9f36a738c6cd3fee403188fca", + "0xa3fb0038f83116eef1d6b023e2e17ba2795f7f90ed7c857d9f04337cb4e0c2e7d691bcea54aa72ac5e4383125b74b755", + "0xa80ada835fede8d121162aabfc8c349f685775406693d599e3c288364097b02d96c10ddc20e72fd308fc882e5b70c064", + "0xb6e6c4b24731a2895b7513ad97c0928efeeb0c645dac9fc8cbb0a6419221807073f6996f2b778e1dcdde63acc3a6b2cd", + "0x880a2e8fc2eb57f44b08cf4db5cf1751bf9f4aa688708039007d2a198f4e7f0f808aa566b36b15b971e804835102400c", + "0x8b3baeb4e1c1d7493bd885dde7873afdc235b58e45b515cf51ebcd02a9b81911c5ca182a9e340575585186c99e71d2bd", + "0xa6248e1bef3c6c6ddc155dfe95631a3f00308fa77b1c1779935e76401e750f151b7377f9376c08e8273680e924382af1", + "0x800133df4ea65de3935d98b0249e335a918c44167a34a16c0a4adaa4654f458c376eaa76ef088672d39aec4c7d951833", + "0x8317a6e0667fb524f35672e070f047db29450b06348604319765e4db09f966ad995098cf38acd30346c7fef5dd62528a", + "0x81fc2ef2ee0e6f21f406c51f02b9b7be8d99d30a054df918cf89c708d64c34d8b0dd060dff4383de858c0dbff25d71d3", + "0xa28611f96138fe6974e3e1925b582cba76166259c32b39e95702fa0c4957ef2ca32d575b1c08cc8dbe96ddc0eb56a9f2", + "0x86c6773f4e0261413d6d3944e0f7e498a6dae518120e3940d2f45054a912e706b3b615fd160e6143a7e54942406f9af5", + "0xae91e3db099d165b198d80b6d9af894203949d87cb980f4db97dd43ee55fbe1a45df156b72e3c3e9306975f9e5e62d77", + "0xad00ceaea52dcef616be9f9815548f8e9b800bc9c1a8832a4d8acca6c8779317d1951e5700e54db070a23db41266c934", + "0x94426f78470aea2d82eded320b45bea09b7cbdf02a3d7c2af4ae4567a3493b352b36f43c3669237879910dcefcc82fe0", + "0x8aad924eb1a30d2844654c9829d82c65fefe964d815572b6c9f902c6a826c247257a7d0d4967e2bae331d52fb3b7c0ed", + "0xac9489ec928e4f43f8d194b8f3ab83382b66b045f18efdfcb05c1d4e67af7b3745ffbb7f52cab4b8895550d10132e2a8", + "0xaf8f390c7cc40a08c0143b467634c10e8046ce40466006a4b4297c76a6c16309b50f41a4a022fc838738c4c72edfb34e", + "0x923b0384e87a2ddfb7a2c47f628172e8dee76fe812c44a756c67cb20527d8e9029a561bd4ef446a013d4be7db7259f6b", + "0x856316b53f09a90af770bafb5c9ea7deb921687fdfcf512840e96fb83df08820c42263c9ccf51465da33f1b03db04d09", + "0x92e8823b523f90ab75ac6e30869dcb257d232b55a3e167769ab5b54cbb83be94cf5d84eed4b1653db17f3f1350ab5e53", + "0x8d0d05fac92079a3df86a72fa399e606fec7e56f81d3443cdf0cd373b3330235b76890197ae61f24d17de39dd1aadd06", + "0x8a801fc71b9b6988a829044060679a7cc3d40630fba81f72bcd15c0e5728867f4bfe938066e68cbb54b042a39600fde2", + "0xb40a6a786ca1a21159b72990b4d3ae8729722cdace4e8124f8cbcc3fa96005563535d28e9d92cda02e91d979d27f8f97", + "0x914f30250d79829919c8ed184c2e471c0d9835f2348e628164dbfe39a51dcdc3f8bf99c945b1f413e65fc5424014e5c2", + "0x8ab8b347b7846fbc7ffe69c89ff67dafd522bec708b7ffea312b3a7eac47fb9d6006cb9038962a07dd89d4688ee6a18b", + "0x8e755f8cde0750700252e41f6d16b825e7f02748a13744c004a52b19e52d58c42d1ac32cd5ed1d6ad14cee5174b4ddf4", + "0x88d6192d72e1fefbbc9ab400e5b0018bd300839cf604cfc1034657f62fe8fcfc52acd86c207dad0fa6383361d338b2bc", + "0x971fa2ab593578b341076d98c49c71dc7d9eb4ca706efe252441499037cc86fea49af681d8a4d324d302526b2a3e5c18", + "0xb2deac648501d7e284a85c19f514f8744c48d2b5516c993c2111128a9fa042aed34dc371a0cc3f00e918531dbf16c0fb", + "0xb63fab8600fa531d7f48f8d207298544d2e03d4da23cfb43d99b0612f1a20441526de63b7609f5969429e763147ee5e2", + "0xa8f30d9b4ac3675d61199e8e624f88b9dc52658a2ba26a2bda5f9cd3780f0b1e32b56c825d9dbc3a059d6c61fd37e261", + "0x8a6f8e963dccbf1db9c839c21a4e832c7a218b00fc31400346b5379fdb8394142bf8f8b981fca3f4d3c43d4e34dd3e31", + "0xb4883e6a4213c799abb2a9b6998ebd4c89aeadfbabbe4c363b22beaff46939dfbe4dd20d113688a293a41daf5cd82c8d", + "0xaedb55058fb467ee9556a3b601af86962f99fc06f7eaf837b4deda030b1899f565da07ddc7108e9f5e7024e11c723ed0", + "0xa8185aafdbd22a2df2ea0f0cf67fc88c4c3f8e64040da08cfa9e8075b792406c20d3155d6ea6fdcbe9f5502c44125545", + "0xb2b27ff20d24cff756e8edbd6f8686d202d687016c561e56dcffebc78f404ff544c4d3ae8802b91bed0487792d6dfd05", + "0xb6fba06a70d8b1000555b8c6d791b1db3fb7f57a0f8b1fa8dd00b2ee14242877e1e836cef89be3f9e0565e61a6b4c275", + "0x92b3dd6e18600ab856c276bc787429d42b8c02abf5243f7919625aa1f4e8cc3eca61cbe106b81d0e4909393a5efc021a", + "0xa508e1a1d4375f5130c95a169fd1d4df51cecd84822dc28b18e464c2189d464e6dc6a5855e0cbb94500d041319749ef7", + "0x84b3e9a6b5d1a7bc7df44ce760b5b686fba006945f6e1f3f67ea2c90dfa6ed70bc1f021828a0461fe158ece87deb1e30", + "0xadd83e686118fc5eb56d79199d33cf0c90fb2a5996c6f453fcd9b9eb3a273a466776adba1cccd6be62a4ea154480fe17", + "0xa1fb58d9a323dcd7862ad4bc6359ab2bae35a608276a3053d40bb3abdaf3e8827027284d964e51ae7b61dbf299f2bea3", + "0xac901ece7cf087c782f75f1c61371f77ba061bb752ad680c9b1012768e5ebb6241b492bafd9e016e989cea1ff51aaf5c", + "0x961b9ef616b7faa3befd807772893c7c66ab6990a9405cf4345ec29cf13d75dbb6da41ec87af5b5c4bddc8787b88b480", + "0xb386f7ba0b94ced118691d883549d70ecd28d1c0d1b718cb82a92a246e61de4ba80b6a76d6039c261e342f9ac136941c", + "0xb6415848092dd93da62b5a5307d356d968bd7c935d3626f40e9446573e5794f37a23ca072fe8af2a9355a4b04ad35e58", + "0x843b3e3221bb08122a1e649e81759297d985c7f393c36cc3bc707a7aaf2f53b9cdd449e7a4384981c5976fb3955871d4", + "0x94083ab99a73dc5cd463b5259a0f4e99847bf32ae03739a440f8f48e12f078602c76b3fe4e7ecd31d52a7aa31168c5ee", + "0xb6f994b5482aabe833e388b24b9445c01e47fd6e354c3684094237189001290aa77a327181e7e7e756682a04b8b3c56a", + "0x8366f418a3fb2dbc9ffb5b798adb968aab991fa689ec24a4c4bde6f046989b1815e1bce5e846f3554028e16799e17281", + "0xb8e5680915eb37153daa9a3a977b47c88b4f30fd358901888a1056e07d2a7070d28a47acac7aa7856ede16bd0c93ff2a", + "0x871cc7a122cd7b9ae2199801e6a0974ba8cea64e5866a5130ee0ec926adda24f91b3ff2785932cb55537030bb5ad811e", + "0x9370ff1ba27d33080efb22836147f766c60f0a8ca250ac6b2a82bb464ffa543da056284b712dc3cac53dfd1680a4cf87", + "0x8614d8029df5058f5a072716489f734131b228972ea9b2b952ab1150bc50b6637543aec1c35763f8dc578275f7c9df3d", + "0xb8efd01dd0016a27a0e2df65b571d405be4dc8e0df5dc0d8354fb187b96589e95847ba0c2856613924125d21193753ca", + "0xa86e524431247115ee497c07ca2a73387eb820d293e8bb74e1ef1ae7ffdb21a9dd8ef1a6e3f391e6f02ee0b51fae2a06", + "0x9151e2dcc0b928573421ffbe43b1761b6ccefa4ecd58be7fbc8ea8e975e18d52c264f682104480d590e6f8c0b8b9f63d", + "0x85ac8cb79fb8916f7eb5431b7e81606b38afba15895909873f85d9577c87ed2c1d0fd489fe058362f20ac05626681346", + "0xa076dd75ed807bb7afcae8bb9821ed46758c1a8d00e7f3d3c91a18e6b95dff3958ed70441a1f4691ac3268d95e243614", + "0x89d8dbe170b9804de3fff5b6512d04643ea0041c3f9bedd7432b171ced1577b0c0a7bb911852c6bafe154ba36cd30320", + "0x809a63ba788e618a281804ef97a75df39c7115900078a6bdb203bd79d3df87e863c631e934dcee62e28a16cb8735acfd", + "0x9727e6720f8b73b6ccad519d8ca1d4f90c2db33ab536f399e2c4ce269be15d99e22504ef153aa26c40d4cfbc450f25f6", + "0x83e77918ba6e28ee01ba6b8dbdd84c53faf65446a90bcef46f262f341dace2e237b1ff8f8d566fdfefc6973deafde716", + "0xb5a4d3fff76905bbb229d579b8433e76f2f070108230f20a30e4f974f12f29ed017aa66e9b298a4de0fd535a0e1a44dd", + "0x876d3a0bb439e7da26539b98abd0f7e0b7e8035eafed08df623a77fdac30ac85ab4d58984396319a88e072dd7a5149a9", + "0x98923e83be5b2877ac18415f9391ea792933db718b29b6970001682cc8434ae9fc640427c0a27f6d62af5f78f3901bcc", + "0x805c675a34443a14c0098613d11b4c015264e038a8d1adf083844f2e3e3f2414689788423dd0ff77c02130331d511068", + "0x8d8cd51d4146bfa48492e9d3f3e4b845d4ad1442ce6bbd95979f9778ffeb108c641c9ffc2ebbba532f922237e5849222", + "0x839862454707a99eef931335e5c5ed80805ba06bab0337c5301fe9fb92fd59c9ff6620e66de7369352b079dc52bf2113", + "0xb3cf3bd867f60b345a0b91314b34ce1c02e64dfbaabd70782614208d32fcb5d4448102bd54728fb05d1ed18a750e88e1", + "0x8207a421d010e1c5854b8e41460c6a13035ee77f7add0df83c5c31bb00d7acdbb676478a7dfc738b9aef5c29d345ab63", + "0xad2b14f87281ad6e1d2b713e6e8303f1a45cefe097820d6a1bdf4652364e70d28ca92193e2bc3d0a1e69da5a51c90ff2", + "0x98025be2d7e59ffd3f6c3c2b28b27ec42206968c0f96d09330598fe17a207baa6574aa22cc26555139766cc284224fe7", + "0x8e80fe898b7fee849f7dc8e5eac668c76f1fe18d159c51eaf4ddd8d4d600c852dbf6c2abcb878c64f37db7fba3d56968", + "0x871c0e2dd929ba4e157ed606741a6301aef759e10a3f919166faab23e599d3409b232240e3afe9c0e1622a11cd453c1a", + "0x919f7e465b399e2819ec17aacc199421d267ff2979ea8dc8962542ddbae51e2bbdf6cac92f8a35e05e4d95a4a8315cd4", + "0xa6e6667e6127ee4f0224a9a94be3c22831a1ab3b16f57462562b11473c425e7112b33bbbb6af860c81bd6e84bdbd3b86", + "0x87eaa9e3515f2d94acf113d77dc085609d06cb038f5e8e90ed29bd04bd4814e95ed0d6db5a1d65572dfaf73ab2e50ba9", + "0x90b30c66ebc16f767f3f0bc1d8bb17ca1951a616292297ca8dd06d54cc53e5fb5fd6321ce158c04cb4c91a04c01f7fbb", + "0xb5fda3715566188630f96207c4253315a9cd166ef96651afa0ae1d6f0aa8856e7642e2f8ef3b1fb1eb2c14a7331f6592", + "0xa54143f662a6946da901ddaa9e514a0e96bd6397020cf5d88084a1e1edc092b94facc150b1c029a508fb3995acee50b7", + "0x8dfdb813296bd105d5813657c98337a24c8bea19bf0d119efca052c018ff5c88f31e05e110fa12f306ae4b0a8498f113", + "0x8b7429599915ffec755060d9cfc2c445df9184ba6bf298bfff5b54c2ec8747a9b65bdc6c73746a94a54b0a62d93b6a28", + "0x8a1d1108174d383465a57ab4b1a6811ab86dc007de4f342d37f4cd311650382e0352d3664ef09cf1626c0b74e2f21ace", + "0x98cb860aee0b7251da2d114b2253daf977badf82027a018c956fd59c6c93b716bfe69a132a4778ee4b7168fbfe390ad2", + "0x94d5a0d33a0aa590fe76c71e80b21246dd9bd8c2f5ecc647e47a423c2dddd743010484cf2fa363ea73bb217247429066", + "0xa082b7a109fad08e2c01dd7322625c18f47497b32269ae4e529b1681aeeb3c4a813cc6088ebb4427b486320fbc4b7872", + "0x86c23e2d3b23244c7763c123ad67a41a2dad8e4556cac23696906d1acf5f4cd7f661281b8ab2027d268405b08eee6771", + "0x801522a5c211e49eb96294a9113022d86c84bb8741e44fa7328122836a39ba7e11e27d0d6773550b234531400ba1e7eb", + "0x9683d154b18ed641867fe67b2dc70e8b8afba79f73fdeafdf9015d85aa0c74d270b290952683c3667c0202a83626687e", + "0x994febc16f8d216a20774955523262966e955cf964950b4b2831a3483f818c20ee6f51cd24f499dda0d3191910a9fd35", + "0xaaa8f12184525e89ce980468fd24e1a9af846246297546655763ecabf0b5b5047394543f1791ba1c70e21637cd815877", + "0x9193a37d5692ff1bacb0265bd7825c479624d2adf33a419b0a71c8a744ca1b0c9828127831302ffea4fcceb1a53ccd54", + "0xb9f3213d5d588ad73b86365cbcf0fabcec5c30cddad418281ff2408dc140e3f6a25afcb6bb569605191665706c675e35", + "0x96aa280b2f0ae5c3ac51edaea4435ecff8ecf8f2536a3400d8c4c9b12c64d16418838dd7ffc1b815656109ca63261050", + "0x8486373d67804e9832bddca04a0084d1976d324d85c22a52ce2bcf7518f014ad00e4795e61c71e0dcad1f23316288dcc", + "0xb4f2e7f7e2ed7917e7c5036681e1ceff18b688c1abbd203c2bda0731ab56701a847cef4f753f68119110680913c2dd4c", + "0x87dc2336d88edd81b94ef78e7bcb6d3876257c326d28b3f4484465d6c65faa6c17aa7a2f85c6b94ddece39f6736751aa", + "0xb4b3502ebe175820f53da8e3fa28160579c4150d79d932923739aab545af537b3301d5b21f5138ab4100e737fb61a084", + "0x88063af42d5845267d979df07be0735cbb42d9b57d3625eb5d0aa7e4ee90ca88fa52aed480a4d60eaf0ab8dbc4f444fe", + "0x85cb81247c09e21de6deec42e668b72f513c7b105f60ed478b08b85fdc8a886a97bb7e39eca0cab09b294e4b1490b0c1", + "0x9920fcfcf836faafd211fa1ca78302aa6feffcda98aadb6302300c250fe8621b60d9c214ea92087c44996ae0999eae78", + "0xa1f91af5b378d61ea277e5dac81cb71d71a4ac35322aaf42b3a8aab1641fd51d8da1783bae0e8ccb66d73db8e1003478", + "0x87507b427d381ce3906e372a12f4e61514ad7a102334826266df14542adcbc8bb7c8450a1fe110069d9dc2e9bf0687c7", + "0xb7581b0cb549d71201583e0987e9e9bc6cd36585c96664f836e1b7326e5375ce8d0a450343fe0b106dcc581b77de88f9", + "0xb26504a6a7a64c44d7f97d0402bf752740934ea4c6e101ec131666deaf574d55fd7f96c8807473722b6629dbda2ca3b5", + "0xb90accb5c6b78322ef88d017fee2ae1cf87194f4b3f6f4ba6510c0adf4c11b20870043cdaf45372844f5e801464bb682", + "0xa904dfa6e1f813b4aa0b242f3eaaf893da7ea854efe514487a237a01fe244721482476b81ed75ef1a951fc54802b29a1", + "0xa00373aa8d98f4dedf9cec4d227b5fab00f3af2a7bb4c8b0dcedecb5a04244321d5f25a81d57ed0ddcf293c701d290f5", + "0x91bedcb316698e73f43e9dbe0229772c856f34901fa4c1e018e96eb898e4ae02b19d900e87d01501099163be56db57ae", + "0xb84dd6b9a61cfc0817da422380b0dcc5221deb600b4b6a6f6c5ad934110a3b66c59f7407ad68bf8642b2bcb5427e8050", + "0x8507c172e499856675ba69fc1b0389a08e58f8e5658c9268172b926dabb4a67b7c836a44d865f736e8fcb14aa2809529", + "0x86609a1d82d90a971786da9ad342035ae4865136e513559069b6dc8ba82ec0bd1ac695fe8afa5f61f85c2310194014ed", + "0x94914f127a645594ed372855550ec0817663224208c127a08bff3d5c4f463b7939cf13a45dee68586b678ae453c6d60d", + "0x80b55565972213814afd6ad9b1884a4d8143ae90c148ba730ca77b0937c2faabb23a6f985dd0bbbe05705fada4cb1a00", + "0x930f5fe58dabae91c26c6fcbb61c3e336678dcc35d028e5c958d2ee7d50b80e1693c0693b82d719dfd9fbe2c03b52c10", + "0xa45053c493da932896d95d5fb158869c1051e1bf99658b183c9cf4415fc8d4fa1b6a8752b8bb26e8b706a03a57fc05d2", + "0xaf7434b48d2ebe639c8082be09060422f662317bdc136d534b76ee3e3aba5ea8f234cd4936aa2b928f6eafdbe5165a6b", + "0xa57a073bbbb3020a92497f0ce854666997a182f2b437e7b06c9888db8acb2fd2128e3959f45c391f0548a3de49e37e76", + "0xa0ea8131b2d8cfb799e806d8cb92cb02d32de37869cf2ac3c82f7c5d9a963d562755b16d25c4b60f4ca214e323790a9c", + "0x82f920aed42eb630281919b9c1fa4acc02b05ef34020cad3583a29375bdaee167a47ca3366ef065cd8e658301942dbfd", + "0x8415ef32a93820618abb91329224bc46d478ee8749ef42e372ae4ea29b6c05a65d5ef515ffc7d720b2f41ccbc040f176", + "0xa0fbbb0113daceaa05478163fa835b070be5898dd9bbfa9abc582409a7b671c0e41a5070de4cb6dd2072888b11825acf", + "0xadfc99221d7f044b57ed40f4ef8a9e47e57265ef8eac654043cf5e777950af6fbdc2c2d5a5b916048fab1c19acd69dbb", + "0xb3d8e85fccf623fb3848e4886d580469bd41ec0533975298bfbedc7a1a9b4e554714991ec4238d8ff976a83cab6383b7", + "0x8b09702f3789ae1f7799ce58a0ffc2327b3ebf2b56cd870f2be66c0d6781cc1f34c2d721d0de63e0fe9db85bee842fbe", + "0xa935864851b73676cb49f509a198caab467e5dfe4358e7088d2a76e9b8c13e5d20b01eb7c0cb9e51ee98c90cfc393c71", + "0xb5035d76a5a8251bcb18f33968b077d43403c69492b809eaa3e202eef174a5649aee30f701ef0be050ba5026957093ab", + "0xb1cedb563cfb09713009b2263975a56abb9932b8cdebf10f7836c5c34785149e9875ff590fe1414ad2d21da977b7ba26", + "0x98a718c23d44b24ac295b328d91ab7a40b23ffbccaa90bc5888efbd32b6a95c530bf5e999ccbd4f1c85263104f336ce9", + "0x8d9d2ee952d5b135eac2f06f0478faaac175f23cb3789144f3a490f2ed34c885ae4d8ad7ed48db85cc6c2bd70b38c6c2", + "0x8155763582ff6c68d7071ba842b6543361cd5f65b7c70d5bb838da2dab2c02f3363e2324307e7d2149b12700d96bde38", + "0xb18b277334ef7f24706b7d48fb764a487bc4e21fcbfb01627b7524e9a5d3253be99d84c417084fea769b550b3ecb4574", + "0xb80db9d83cb1ae861a3f61197a1f14b6c5004a2b3d031fb207adda94d725f3e265535ed7b69b9c801f2e95e1d64c1901", + "0x82cb673ac9c0c124fc546c59505fe4fdbc05a1fece0fa579f6a6df96f74bfa877ad82b6fa768cb678ff04ae4cec58d1e", + "0xb2e190b785a4a882939489b86d0a06cb637b7be8b14204645bdd9d6c37626e8623e35e1e4eab5c8fdec0f8349ede8918", + "0xa82237c64f15d306365be19085e1c725cd148702fb66658c7974b02051b685715fb9e35fd4a596ec24d532df4711f82d", + "0xad6f7e3992518ba04b510b705fa6b28e3733e0000a5480e8a3c30fe71394de2bfa43333c69e750bdc3e7092b9e0f7ffe", + "0x8c0ee358f37c28f3b80cb9ad5487c342fab734886e31e30c667e616f3aba737a3a07bac4da552d8405ad8b00c03e09f0", + "0xb7851e0b88486b0a858a218f4307e0c0c8c314fc69e2b90cce8ba86d3fdb796b572e50eb4e82f83f73c7f048484b45ac", + "0xa7c35abc2e15723a9f395d16d2484b798d098be5414ddef083c8283b0c29823226fbc4727d9cccf96e33b27fc40e032a", + "0x8ec5ff2ba7c3ca8a2d18df81d46e93a3bc94ceca88134ea75cc8ec2ec4b1ba3d0de49dcd4d385083c648a63483377fdd", + "0x80ca7ee722c3253e7b534b42a8947e38741c542dee1d671b603a9a743f5ba2fa95f193ace46c01000ed20ea05ad0639b", + "0xac14edc2d803b28a169154364dac5360cf0926d911a615077a94858fb4cbbe31bae2f30a6a68b248cd8bed015e0f3b29", + "0xa4bdb63e91fa72995316d03cd117347cbefd14eb1b19a0adea1c9d39f49d82ca1ceeb2a4184187e1dade109d10b83090", + "0xac8f528e9e8fafde00e66a75d4bb68c99029456ae9b3b7cc76ea4816e89aca2b8b7d094db214bad1e87dd4e84d1c1a5e", + "0x8a8d090a01aff14383419735840fc5286e71a5feefb98c563b2d7ee593b518c3aef6654f10da8a77f40feb52e1d31fac", + "0xac4259562982b355fe5e57e1cef574a6a40a7144598c13a6bf07cdd8000bfda95b0b0b44f215e9dbc71be114a1857441", + "0xb53741dc30b11fdc6c9778555c1f714fde60890c191a0effe419fe2b6100228d07cd0738d0dd73057cfc7e340c75f0c4", + "0x80ff52fdfae53dd2410ea556ea6504696439919687d2dcce1e952d9d17b6e3699816ee623b0153bb0e0588e36b6f56b1", + "0xa92b34d785a71d10e6796ad07df788c6878717cef4f1f0623898370725006d46fa00a0a22a3934fc5cf323be85fc7767", + "0xac1cc08cd1a8fd6c946bbe14662b18e89725933a79965c663b73ae3cf5f5ab87e794559ed579564884e430e108385e18", + "0x88b8b2264d84106d38c321c3a4927b9b41cac172ae27f6292ea44cd9ce11d185d0061a59148e50474d4dad3c9e940476", + "0xb7ac9f257b4f676d69899a181b45f40358dcaa70fa2dad38870d52838aad9001f3a3145f6550fa2826018952431e4cd4", + "0xade67b3d1602ab0af6a256f25a65b621dded7a0adca65c526ab34c5ca3088a549b7ccf76c586993cef0d2d38af541617", + "0x8fcd8bdc44ab42a70c174682a1e8b929004834d4962a902de460eaf8649883c868cde1cd660d14d7d3ce589fe3aa83ab", + "0xb914f6ec60f1767a12fa34a4b400ce102564dac4c1c42f1497c7bb824bfb9000c9e23ed7cadaa16ad79d5ac906070710", + "0xabb1683b313612b583e87228384eddc3e2e7539e0aa26e825f5c27da222941b6a37ec47127cb0f11b6b8e0d02a6f66e9", + "0xb01efb31962345a2fc71b7c370e7d3117bb1d1e1a9b6984ce11bd83c898dc127fec2e821669deca7c74d406e4678a736", + "0x92439394c6c811d908b05c626f1afeda3a0f8c925747bedf66a4a5895ee76e7445a1982e99d8658117128df5866eb64e", + "0x956bfdcb00837be56d44f159bab9bcc2292295ec1ca7424615e3b163b5d14f7143e214609c0b65ab74a0dbddbed4d782", + "0x880b9a8dc9bf6499f1f71828e6c906e2ae59660c9aaa824a6f36116746406351b4e364b6fa26c45e9d90018555bc7dd4", + "0x83f4a0dcf523d414e023075ce0dde10161d65c0abdba522c811f0e446980cbc21eb0bb42737136bce30fcaae3c673b6a", + "0xabfc5593e02dff15161c4da67a806af3170bb2bbc65e3a0457b4bd994ecf5e001d02bdd417655c2b4433dec270a6273c", + "0x99c6d8bab7d937a4cb5c272c4bc3856a3cb8295cd77ec9e2fcc6a50e0545999cac4c413c3ca8e5408afdb60388c82ae9", + "0xb08f5d230713639ec98a7afcb2a25b9b2d1c48820447d28b6a3ef448aedc4b9a90b6c5ffc6613a70ff1766b51992074f", + "0x99d4b54e35dd3f844088155f114ef93507372ed32a6898b9954d5a6d0743e55d8e7de20d67671454d26561ed5e4fb05c", + "0xb7cad70deba1622c79f1ecfdb2612e380e9048fb6146760ba61cb62e98cef129d3944c5f442b15fc11c102fcc6e2adb4", + "0x95feea870c86525ed214e3e0ecca9f66c5e0babf6da8473e5cc5e2f305c26939f6afda0207bf5855b6a6c928815577ea", + "0xad6e77ec226053ab331f3f871d7fb770ae78227a85096d263bb42915299147a7a7b57a4f8f929765cfb323267b94865d", + "0x82339f53ab7344f8dad554fd0270c2aedb34f7b0c630f0a56ca9217c04f0e4a38781eec769354a44fa90f556b388ad01", + "0x837d4672d73588f19b872d81b7993e5e0628139f5685d0520b1b766d40e71b9d83a8d2bd65a03987eef89b3d5c254683", + "0xb3c27e19f579133f1ded8c066dbc3e4edaf449a1edcb1aaf215939d63a7f2b250b9b7afb62d4cd7cf37c28da81898a67", + "0x91f669f9db8fbc6d7a5ee92cb67c2fc1ccef6dde622efa455dd7535b11f506f4e309a8878b859d6605a3917f6d7d67e8", + "0x8332dc636222829a83501a8312904096c2984cc0c5dc077e067d8962bd87666226e3324a9e5057c1cbc3ba700a3b22f3", + "0x97e81e20bf33baa4412d6b81c5fbd406dccbe70973bd73e956d8ce85c99d2199daee5fa6e99fc6d40071b352b5044865", + "0xb716066fb9e470cca4546a401048c0e6c6408c8c9f4cd80aca6778d3f4121378e11cccf8a005845fcc8dea2e1b9f16df", + "0xa7b340eb603da43f2aa542dfad1ef3d3357f583c46040f2dab234c8246d7c55d6885f9f7a14f319e22355ad498c22a04", + "0x8281ea97a28ade9a0cdc73a077c72a92810b70912006611a00df8e7d2ee1036af73c0f062b367f3d4d75be4b9bf78aa4", + "0xa481ffa0813a4f2110c6ac535fb446282dce73c182eb99baf786ad42b804ef12df078b2f534e3cd8210973880bba6a63", + "0xb71a581ae08eda0437f9e9274c1f9431d6b357e4866e40d4c2470252f0888978497af823dbf464785479e5f35eb89aa8", + "0xa07c9010308bcfb0c97a1059d5213980000841ca0565697d45aa46e82fb36494e4940aa435ede417856d24f73d374757", + "0x8fc353fa8733947ba067ca2bf5e14a6c334e4ff30efdfa67829dc86f49424f4548e879b153e79dc75f1ec00afd6693c6", + "0xa663faca50e1fe5d00f62abb0b7828d6b761fde9f5a54f27c0b726d8d53281f83ac165b3d3db87f970913350a7dd07f2", + "0x970535269744905640d6ab238930dff375ea7efb2f391db324724166f0c436e7a3eab7ef6eb2e5d6724c58d588a4c592", + "0x800f33f5936498e16fd0f58210a5a5c104074039db7d9d5d92dc62cc00d796ea0a3a22e5d368fe269cedcf30bf6149fd", + "0xb4b921cc901a7775df7ae73e97cdd108d98c54534015a1469f0ca6b07989827e0d3f9bea2ec015fabe9d309054aef802", + "0x93295c8a7e5c0bd9decd99ee2d704d814cb6bd0061404fe00984a8afc337e78af11965a8560288529c2a722e8b54b488", + "0xaf43d382ff7951bea94f4540a3a2dbb53ed527e966d0dcd117d5212f36112976e1fa00a47bb9870d3841cb01621c5d7e", + "0xb4d106b21e4676556bedc6e7f5a7eb5c2ad0d5fe8004a1d968bc7806ba871e241d38892b1fa73e9648b23158802ab57b", + "0xa96cbe38f86165288a365efa796b0e2076ae9fa94bb6377cb80c7d5db9d376e9c18164a8a3667dddb3f5b847f52fd319", + "0xa0bde83e1f3e925561c481ceb58c7575027f9641e69f14242b886e7fbc532a2bc54aeeb94ca39bd7da3ac984bfe8cced", + "0x8211c4a70d08fe052246d3ccda60c9e9677910a93d9262d572606d99e273c1ade353eeeadf5b1e3c1ac3c4b9019d5f61", + "0x954ba6744e3f991580b6633e5d184550e44400f20f00149d899d97bc4b51b01d09bb4f82ad975cd55189320523fd60f6", + "0xb7e3f17ae79c2faaf5f3cbe0dc528c6aab0035eb3f38954820556bdf7c3546585fb9814717302c5f45fde7170748ff63", + "0x880446589f33ffe7ff5e105fa1c380d401d6c46e80526948fbf4edcb779753a594f3891461f52eeb3f5f2f6051c361b2", + "0xa26c06cf79c412d49f39e0e27e37c82c4cf0c8648638ee66a97d22d822e064a9a7cbb0b1ede46806ea0430639769cb88", + "0xa968341c5e4a3e6d2a2116222e3c58c2e558f5bb0a2877a27c69fdbd38dc3892f9ed7d7c114f557e52a351c73614fedb", + "0xae9b8bf4774ce3b84185be77723ec62b9a415e21cd60e86513c1500916c96d62519ee8cc061d81ac9db9709d6e191649", + "0x83a30c1ebc046c9a1ba911ecf6f147644f58f54e32357dc395388e6bab66d71fb9b691754b11bf414d43816af8058828", + "0xab5b804fcfb68b6439f311d0420005b083a84da15a8415cc4013898806e67c47698a9d594263fd9be42bf48efdfbe2fd", + "0xa41c18185f8111ddd551ecc8f6dcb87036cebb6eabbce7faba40c6c5c8af2ab59ef027c6fb2dc523eb0159335a1ab189", + "0xb24cd94b7c6e161e651107769d863fe5a3d7a847b9c60c7c803846bd782cec0bd54e6278a318ed23b90cd7ad25933fa2", + "0xa5ba23ead78d1678414d4e986b448e7a24b23a5c0f529ba604a51e4ee0f87baee450fd121b43a954be50bff6c0d7908a", + "0xb89c17de4809e722527832b90b810d9691b437f19db9cb88ca5cdb67bbc6946ec1d454dc0990b66093ebeb6eeb6896a6", + "0x914f436fe0ac7540129c3deb04d51bc61192ab5d0d16eda77ef70ecf8cab5f55a13492f54e8052f2f214186a113d8949", + "0x8e0b3d1dd756a9008894028d0443083c21e99de69b8d8f4e7eb3ca7fc52ad540355d4a1081774a6d51a093110f4bc838", + "0xa9c1730eb5c0a42deda9d9b39390661717479e29007f5f8499d0645b8b85bc0ff12cea2ac4328f6588a12126f56284ee", + "0xa2318a42c99f7613ac78cb110656c6e470cac6903a5bfdc1bb182af21e0f0f409bd39324a13e2790f0facba04459d3c0", + "0xa11ba34521434cb718f1b2015bbf451ba1a7c60e59b1620ea843835c7e75bb42b6ad29263cd3705f7f6f1e40a0ebdfe7", + "0x90705112b625973e1cb35e30f9e15e3c752b2e972231b4caf53518f44b4a40b8a6bd15c4af2adbce5dc194169b860cba", + "0x828035b0e70af8db1294379b4b70e56624e1138ef49f7be81d938e8b25aa5dcc03655e045a95a79e0143c23a77407004", + "0xa7abb1836282917d1eb9886c79b6a36d720612e3b823d9420a4a705e8add6c6bfff2f682e6f992a6af10ae2f71ca8828", + "0x81e97c7f980dbbe93df9efdd9c0a8172ba0f00378e9375c926b9e24758e8b827037ba67e06e994fa9d05942320353d71", + "0xafa640b2a7fb997cffc5db74a91dece901be4a36415786190dfd17a77ac837a2fb2d73e973b8e60582e71824c57104cc", + "0xae860a6850068f2b0e1e5a03afbd08b667f44c4f06e431f1f83269e754f37e18a764b00e100dcdbd1c1d18af9d6304a5", + "0x9443fd7e1263d5ab9baa8b1a3c893765da1dbed0bdf62ac9c886425ea9f05876df1920889b707a2cf248e7a029883588", + "0xacb38feff88de8db3477ea9ae3b33e0c5715cfc91cc71926dce26f4f290dc4f437461a186cf1bdcfcd6d121e087bba33", + "0x942882666a9f49ac24d9099facbf1e65484ee76cfdd2eacef25e0f30260654a7b5c0cb7dc37aa1601980877f945c51dc", + "0xab2c9035b2ee9c5e57d8de70b24329cfbd247324309eb30ac78c404ced268dbe2aaea8d417300c90d87924a48702b793", + "0x80aedcea9c5a9911731ebb444500eb95b519e2d4650c1d465afc61f4997879d60750ae3fe049e54654a06eaa2db7d8c2", + "0xa63e1ba5fac918c8bc0f4364b5fc8d26214deee825aa1bff111e03c0ed43baad47e8bae154ad580b851a0f66be85c88e", + "0xaea7f5f8c387c21cf671246803cd5baac61cd6359848ad4fd685b1350ed6298a129ed74dace279fe7846001bd6577dfb", + "0x906ad36bbec72813b368bd2b79c1c9624966dcbe94ca9dbacc297d0d8af86edbd80cd702ed04f0adebb913a6a7bc1a62", + "0xa46201c20560ef2ded1ed3047fc196bfaef445c4a716890d9235f3a06d6993a8ab29e816eba54c6a2e2590dc8dd61216", + "0xb37eb2c0d765b044ed2fa2923160a19e11509e764025e43a62b4ccbe38e534ab59e68c2cc92cc5aff9d97154b8210c50", + "0x91f93b1404a4bfd3fc8ea019d76230637ceee315da0faf366c712c3ba19088cd3efa2dd30172dcdac11e636f8473a26d", + "0xb6b905abc4a795bf95d055ea09c3f9d0a8a9ba0014e288492a3751d2aef60cd3b7846e1ca8366635a94988b2e197191f", + "0x847529bf842d7623150a3bb91fc4ccbdc66010bf008179a32359f98bd007330bbfabfdc487f4b98691ad65680af67a8e", + "0xb3d37a8098d02b5ee69ed060527f3d924c727016fd92b21d6a52fb1c1ca18c7eaf0caf8144e9e6bb5b6a039ca85cb1e8", + "0x98cef893dbcec865cceae01138613de146d563f13853ae34bed5f142da716673c105ecbf4f2aa7d187bdee20702d8582", + "0x97f60078d18928c4d7dee1ab244b2b7540928e20cf7ccbbf6684148611afdd9cce60dbf412c1fc544ab8c356fda8fe11", + "0x872a6758004e6c87c3788c5c11bcc74db78f076efaeb75127f0baec28febd02528c65b227b7619fb8c29cc92d7c8e799", + "0x8d72cf1191629440d7af8daf3b76b6b1bcdaa8d6ddcde52603dc8b092c2ac78d6e24bec32e1223eeda15dd17ba2c26d5", + "0x89dcc8c10be08277a1e394de336bb1b135bcc5131dee5eece80973ef364a305235936a3b6dc40f2eeec2aaf227a86376", + "0x972c4ee3b4b3b028ab683415bdfecb2454d326a19d274f499e48bb2cfd55165b928bdfa7f97c4fb6d27082cb88b73dd5", + "0xab5438a8af3acf2eb75bea0ae71d8aeae363d6644c54e3b020082c80809ef86faf5811808adc8240c7693515ed8bf199", + "0xb594133dc9f71f72e448796316ff3ce2f8a03c21ef9c54e551d23723d5f197f7fb0bf1c33e9cb3f51188db7dca51bf49", + "0xaee981b45d570a666d0d0b2c7aeaca3cc22d4873812b4424d1f91144142393fd64c49401dfb970c7d5ae91233676cacd", + "0x8f978d21de1e264178f88cad7213463a5efd139c30dfce81a7eecb46942870a3c1971f6e6e6a50e0a8b20c379ac084e6", + "0x9153701c8b82ab43fa4635cf677789c9c9911efcf23250bd393301c0be51f14fd0acc4e467ec9682acc89085b94641d7", + "0x8681989a1be217d77cc8e012c95128557de70b362442e7f1e6162bd52ec6e4ebb0ab28f9ad3f67c1d35ff00216ceeb74", + "0x8e85421256fc71a82d35de9645a6da9cbe4dabb9670758c4eafbcf42b26fb99866bb2b4c374601749738ad34e51dba6a", + "0x976774296281bbe1e8dabaee7453613d0a615cc6abaeffd8e15ca4484b5a743e298522b2dfbdcaa697e1eea2b2bff736", + "0xa585501faf955b6acfb328d801cfec5b59be8ff2fe46ef0bd73b86ba4c19c1dbfcc1df844d61a5acc64bb5e8a68f6cc5", + "0xa776217e5073714b36bd2ff0621246a48799eb5ae3ca438d1efff6f9f9beb13779bc18ae5ddb77c838732e8925018118", + "0x992d726bd4889f4e7565bcdc31c7b4a58ba44da5f361e3b46e0a67a6e4f00c25e3503c94e7b2bece737d7efd47ff9beb", + "0xb277f124d5dd8dd669ef1f6840276c0bb0b60379ca3a0aaf00ca337c40f478d511b1a73e73df6c3b600e6bfaf37a8fa9", + "0xb037e78617c235e6528e535bf13bf5e82c70588d1d0bd08de754d089bd47a4fdcfee79b5666b95698cd98c0e32164afb", + "0xaefef9e398e0edb60615713d7c1334005b21844d3f1401903e09af2db20d7b342b8d80796fccab583c8607c533c9b735", + "0xaad20eec7cf4f0b518007ec1df7dbf4935f6f9ecb36a11d148dbf9e5281aab43feebcc8ce9001374be40776c5ffde825", + "0xa4ebd6018e004ac8b5d022cfbb7c5b3833456faff4f198a3d9dbbd077c8752087bda1ea060466fde4a5f31cb8a50a7b0", + "0xa56ebb8ac9901915400234c1c6c8502905765a7224de56b084f9b0a3468a065e78b4daea27d9887b4f44a72fa61a15fa", + "0xb0269890863c63203dd4da3a08a1bf06621cca212acb49799bfc48be7e41c951d807f85dd4171ed57c372914dbd2ffee", + "0xae11fc0f5fd5ba488104bfc07fed50799f51ceab4768afdab300325e9a913b1f257fea067d357e54950c8d08af5ecf59", + "0xaefce65396c61e835ffa38857df426f64508de6e93f966cc46b54dcbc5e2bfd72df927b00489fc4460414569ce99e610", + "0xa5a1fed75677dc956c000b9135c4b6138e0cff53770399ffbc3b12ff0c1677ace264aef2058aea535ee1a7195afb034d", + "0x8071def0890d01f0d10dab3afb13125f0194e79608b9ff129572b5daffb49cde5bf6d9f24da3f84483612aaac3cb8eb1", + "0xb5e5bb8c0be22349ea51e249cf2159189fb9aee615dd62c5f67cc9f43745676e703abfa6561df4f5f1d79b86c459b11c", + "0x978dfc57cf0d3538ef336a25ca7a2cf373f84b71bc06d1c74907464e3e816d834087ee126bbbbd5090a09ed063f87a46", + "0xa2ff4b59b3e7fef169835e67d47218eff5368aed3e6e2f1cacd29a5efe6c1c2e7e1839d87759bad8ad1871b39c481bf3", + "0x96de49b44bcd2f5ac3d07d6f5270af081776d8631fefbaf9fec6771e13d40a4e5158767067297029bd38e8c6847971b6", + "0x8f2f820e8e3645f2ab9a27b3c23b5f656b681264d08e298ec546c5aaf51119893e0dc8e04d6f64fef48d3cece89692f0", + "0x8de2eeac7dd4b53119d02f0ec99f127cbd8f6a57120d94a9a554c04467fa74ecbdfebbb111d9f15cdc1be2be8c2396db", + "0xb6616f68b00ea0fb78a25ecd51d3018b9ef13664a7da42663d1bfd6fe71fab615624af863f3b41e625b36a607bb42dc4", + "0xabab5be2ab033afd6d110a340c658fb512bb53368886d8a5ea29e3c916a6b1bc46decb2cd0f508b5667f9dd88033ef7d", + "0x8872d0cb09df44c2a75895d46588316a4c9c743080f7a03a384bf4d4be80d341f8dcf0e208383bf3587a3509f3324fe5", + "0xa3f57fda2e8c06fa7ce9de223f5ff56d53ce9fbc48486d88d2845e7011dc038b6f2f270dcfd46ef5222ae9a1557070f8", + "0xa82c4e46f0d1962cb48d6c3d8ed3976c4fd4c174d119470479d9770619a45e6e16e30693b2804a82b516ccdd400508c5", + "0xb53188c6b2907abcfe47fab98f23ac602525e05a5ac6b4421c437025819c80529e9d2d63f8a3c10cb9dced196e572506", + "0x951934cad4c2772aa0ffdfc4f12a55f490824e104f669e4dffc70d9c14239570c87eb998dbb2a6d423bdfe1ab50f4377", + "0xa276bddb27d86e1e70ebb96103a239ae4848ad20c4c5b7de85f480c3f293c934ebe35792361d9767de4333ac6de11643", + "0xb9c8eccc03d7270779a87dd7c52a42c7bd632b9bdf94274b1dc864bc7a59e13eb30870ab740066040aff0beeefe14d2a", + "0x8e0908e4d15aaa582dc028e015c4b2bd97c82b8086737cdd1f2820641e65d88166d1fc763bc483f8fb4643339182473a", + "0x810c6c46945ad5b4f699c51130bf204e47c62066fbe54fd099c3567ca79aa8aa8b04dc5321c09e03df4bb7c9b93857ad", + "0x916d4b23adf202ccfaea7dd124d28573c73b39ebd74bf4dfe32a366f9dd48f4160b8cb0e687e7dca887c4b4f19570cb8", + "0xb1b8fff52dbbd5b9bc6915ba20f3185fa8e23fe52c026a41cdedea5301dfcf6c79c4fe1058f3abf280a00c7b2cbb20a0", + "0x95f9623510e12ddc6f4ae59d06448f496cc911c99a4d5f5c6ff7e434b807fcd4b35ec1ec976a40208ee1a505a892e38d", + "0xac7217596d42d40380fddef22e83db9e6d6b2d0d2e912f868d7fc07bacfb83e8e6f01af544e8f450d31db014fb094c9a", + "0xb10855b8ff1a81ac32d81773ce8a6391169902290af0637038b58ab59fc84e3403d515ba7c99e26b7382c2e2d0edcedc", + "0x89eebe9789a333f5db0aa9e8604798b15a934ff45e19699c2e7fdb46b6863ce02defcef9f6dbd0cb799ffe2b669428c8", + "0xb9cc540b405c5ec78a2d8fc17ee4a08690e347cc1d860885205bc19cba09e62f25b94ffc2cab1f638c87caf217f7b6e3", + "0xb16d06b120906f085cb183a96a2b635334afda4272ac650259f23059407fdcc8b83e91f2521223f79769ba45428c04bb", + "0x83e0a2d9d9f6654d916a822ab1725d58a10efd64e889a17f44860db4d2c77ec1bdde7d0ec8deabc12f8ffa5af879d4e5", + "0x98cef31d7ee167d9c4248e29402ea8d5546288d1b7ca54a5370e80a9ce371bc4aa3f5c7a24c2e4805d8c99af059b4156", + "0x8fd55a0dc38b65c2b0b45c9127c14b9396db4898f14e1559e428a2951cb5076bff9e3f202a83236f15c1d2530539e5ad", + "0xb3252594c3060118acb12eb91d002a74c068c0b8f9bd735a9ecb082f787c7e046dd6e40ddf4b3ba56bf89f223bb5d76b", + "0xa88446262600f605fc4f067dca855ebc56990a9ea050c708961e486fe685707d9e9ca734068b92778a144c0f3c23b4bf", + "0x97beed96ba821515996045a40f17ad46f8f4d927cd9a2c7ce134a60d19ec4a5819a19aab1bb0df886d9cafcff872bcea", + "0x98ce98dc7908161ceefa0ac132b63c860ec2e53f7ba28e66c6c5e45c5945e459797c65668e58c0a5b8a26811f17c3f41", + "0xb0419cef96d4d44fff0338132d53d2c03e7e9b4618dc2c6b9f4475368e21700fc08b844a2f140158fff81f56aef83b7e", + "0xae1eba4a4a715f6d077e90e9efb59852b7025adced47fd9f705c2745e6734f2fd2f2f86f07ce24695a06e24e63f00b03", + "0x86db2fd15dd3cef1e504fb057136f0405758f6fcadc391e6f64b3080f92bfbd4537a0d8f59cd1a0e913b2b188093feb6", + "0xb418cff26800f8793b083a879c8b1823285f7a3cac6fa34cf48ac5355f04f6ba74255eaf436739c4d26d0d80d2607129", + "0x8eda3c25b5699569c03b85bc585acf25bc3f9539e9dc3e8707b34520ae5ac53920f45528f0870d93f84647cae36b6aeb", + "0xa2622af11642fb6cd60cddcd4c242cf13045f4ce20539d11727e8942b4f9a7fd1ea2192e83596a35c096fec3658c0c2a", + "0x80735f92d09dc0af19f593ea118bf52146143c1d2a7343f6e2ab95e00debfbd329d4e887f7421e4a361d815dc1a27973", + "0xa7eff30a31db635e239c8632f7f84263c9a9d82511422f49077823aeb124e6ee3c995ceb846902fcd2cff0f5f219db51", + "0x99129aedaac32b3ec18d689a2589e35fc9715fb3f1a72d28a09ad95e39a68ea939ec5721c501a9e35c60cecb3f4379df", + "0xb9995d65636ce1e70967a8ffdf45e50eb264eb64f15ee887781455c5472459cbb309ab58b1645bd6e8f2bd29e69d81b0", + "0xb8049f4c3ddc22405880bf55b5d5d94a6dbb071485f25a49a6457db0446663f8d4fabcf14106b9cabb1b3222d8786773", + "0xb581027c7d9bf7b97f6eb085934b9caa43a46368cc6740139e33e4cb2c94683411710a52d5933a27c9d12a43e75163ae", + "0xb5dfce672e670158c259f36fa549aaacb0699da2f13702c81f5a93afb00361f9ca22d02dcebeaceaee6813a3c9bf7aa5", + "0xb8184f3eb809be1986530dffd7464d84750df02196274955769a0afa02b65e87686d915ecdc7e75a0a76be8b7ad8d064", + "0xb7ab837f300f4aa2ebd2d770f7a36dedaaa68e1d601eb36a28fada4dc73dbd55e7f31c88ab2835aeb57ff113a14c5f32", + "0xa72013c811ca674c3e909064777df1484190fffb0643b6b1435892f5dd0f1d09579189fe00c862bcd18d03309b958b72", + "0x87fb528e03f1b6a000141f4a6ee24a9738d9d2efa795cc262203fec10d76adcd0f89968a46fdebac99af8d048300b8ee", + "0xb2a1ca5d5d16c7addb73341ebed1f8e832250c2f8e03915a417064750d7deec3289e646c06a09c6a3ae40ea2817636a4", + "0xa90cba4d0928da2a5d8c6935790e1a1f026073632a4c1460fe686d06c3f2933661c2b3c49bb0bbeef386f2bcc4d08485", + "0xa5b684d544500be25136b0b5b95d9f363103a6d08cf49f4934d6c96d43720a79cdffe66698de0ffe5b02bb3c2e30286f", + "0xb246952dcdc38a500e64ccf4f312bc7c690d33a3a951fde5f839f6eec77ac78147f1fcf26ff7b990e8868f5cefe1c4eb", + "0x981ed33458e8ead67d4adeb884153bb0fee0ad98ebd9010ee706ea1da7975c290f82c492cf16fb42d1b739632e66e50e", + "0x88bdec223786c894fbd8f964ab2c92c5ad7fa7ed2b97a6bf31423a6ad5bbb5a946ae3cebccce8cc97af9e788d03f547b", + "0xae852b074e5716e3190593e11fb17f1135d7a5d888986d2be53973fa14c1d4a9887381e648a10a4725291ff062c9d88b", + "0xb87050f914c4f09e2dfef845ace5a06504b6fdb815f685921710c7e82a9fac11f864e3e6023ed5807256d6269271d051", + "0x8cbd11617ab819680cfa68e70e205f3ffecf6e469d88dbdb1d9b0c9c7c38746dd6e64bd526306a8ab59cb7e66841a757", + "0xa1c51cbc1a91618b1ede5cdd77fce26b04971081e5cbf83be20c22b9b30cc9197b9bfd5998fd9ade9b665c8218afe94c", + "0xb5cdb2091d114847dc14a4c922bfe944021549df2d75cfc08ccacc2d740726e90e20a0bc2bb73303e9f0bbb5192fb982", + "0x8e60327955c5de97f56838cdebd24c2ed4021d9e3d74ab9eefd4543a286c1be82a1e8455f8cfc0a17f03358c4648683b", + "0x87f9c1c0987493c631279112fbc79c5f5d7dbf46544119492785f444d063fcb0da4f2d1129735ab77663a9000d9e18ee", + "0xa970df3d50c4ef3d76d53dd2b887e9274fdedced7a83560eb1950fed2075879d9fe1d5af811f04ec92d557a0be0380f7", + "0x95a69bf4092567f5b55a401329d5a08220ae65825f05d56043974fb7b7090372e941a85e2d197c46c9165031b3bd36fd", + "0x8e62c98171e54ff549ccac5d6d381291d0861439dd24e584d356a862d22942e0ff17cdc0d1faab07e496374a547ee812", + "0xab62d0eed8422a3172269de0e325eae9294914fa67f1ed8e5d0609afa2991a26b1e1b9a04ccda8436d04ec085957b110", + "0xa3292bc88e2a9dec7b55ae4c27a3a8ea46a7b2dfe3a817675eb3712f95264c08668703771b65afcdf6d305e396d5f005", + "0xafbaf9cc19adf63a0716cb868a970a372d7a1e24a4c78718a114ced412a12fda6fdf42f701ca1492a8f8c1ef0466f7a3", + "0xb41a5f064f9d900d1534a68c74796927e4018e23f949d86eb76dd5b26e5b686115d63d858a49b545924b3941bcec2341", + "0xb4e1ef520119f9a238fc4988ab2f1266606f53079744b92c1039541aee78b67ac570d7839fc9b2331244d734ad4637ed", + "0xb0ce754a33a506174d5feaff4e9a79295c743b2a122c8a1788c1427482585b398a750b7bd93cc53c38bd3e557caed172", + "0x9842cd13ee9490d9ca7ddc83d1f7d79495afb7301d1f51f4b007dd2b2eaf15abbff18666126adc25df5ae26b98a80f41", + "0xa976af142268d20a248c4b71304a878efec29b5022199cfc88bf82c081f55d06a89f178606d50bd3f8576f0c5c01a6ad", + "0x985ac6f315ab1d2db1b4f2b107eb1652810e63e36b8c14e8852f072d2c8b14922f20d1374a57d75cec62db0d050a0c7c", + "0x8c1be9e8317fdf847a8131ac14cedda922bbfbe15cf95537493c4e7eccc7f2f1a56ddd1a8832e6300734d6019d8b128b", + "0xb55d129c88d252556fe688f84982becce253736ef3b1fb88328e41300ed0713465c8bd15918386844c725fe7a94e8364", + "0xa96384d2d81cf6a79614c7fd6bb68fec6e74064435a1a79dd8b1533e9c7e578da5ecf03e979969d983da893f42adcd84", + "0x8c2b3c06b7249ef5ecedeb4f2c65c0925cda8877bb4b672afb7a15bb5a7b5818748d6b022c6ab8fe9c5a1499e2037c69", + "0x91c8b2b8b204897741124a37f85ddc45c3ef94ceb5dff681b13771e712f2ba5ac95cb1bd2d3e94a84625d384b51b099b", + "0x8bf852945910e9a773120c5ad975f080c07c8fa37c2158e1138162a82983211da70f27e22876741d58c20a6c9dd770da", + "0xb9e907d9176a0fcba87a2797651765c814df756bbd1d0a86a9b7b06d9d886d1908d4e74ab27d618129dcde81e7d969d1", + "0xac4d3b156db2570c349e21f07fd17df935872f9687842035b533c6e4773ad5752f4ba8f9ea4501953f6b8c4232a4562d", + "0xad91c4a7ea0a314d7d1ed7a69a74adf6ad810586c1bf907ae9878ee5f6528437c048c6ae785cc255707ea3e58a4b452b", + "0x8013b76604bda0c429e37006b01750999414100d0ff59ff5ab7b233399adaacb34906ee65054abb94db80fc92ac6d2e8", + "0xb26a2a660af34a4b9b8910463d0dd439a3dc563494f5ec280dd5eec0b14b0e9426a0422f3c75370201299d394c4d90ad", + "0x8e1c7ea11dd513fb8527fa99b899444bf89a1188089d3bb65e3eb87025de9a48e8b4a3068a955fe752f2416de282ca20", + "0xb6cbdbf2b143330db09841aa0e7d22d32772ee62006e7cee13d8c4ac911ff4a59a9dba3d84bc46ace1760353d847bbd3", + "0xb8f5aa3ee213a44c41f63c11f685e754997cac37b27e91d07bcb69947344d94f3b86284b3b1655e168befc01c880d550", + "0x89f93b37bda703494263b10768118ce998ac1f395d422c0ae840e47c6d649a3ec59b404c164a1ad5ed14ccc2408fc662", + "0x97255607a1aaae89530a3bdbb7f2b7ba3fb9d5dc93509991021152dde08a638bb3152503cf0c896c9c19d61f8eea36d7", + "0x909c7ecafb798e6aa45867976f59cdc9d219aca6fd0881f82f296a83a2a3cc5ed47f08794e6e3009f8847f16345f5f4b", + "0x9560fbc2c531571eee5b7389855117644f156ddb00b23a7c2189205d4cc613ec83952b96e941cc1e725c2b574c46ee9c", + "0xaaa69f68b6086bd369fd92355f3a0bc632c1b1b4284529c18a7cd4d71d827291bc997ce74bc92dcd6900419be68efb37", + "0xaf9ab7e6a27e61a99f37b89fc816974ff916b6a24ec3aa31d76579204bdd5ff01a2eea26e76188976c033db4af167db5", + "0xb026dc8850af970d2ffd300dce6ae07db0ca2d21978e4f3a6797b6e3e81f1d9680465080a983c31d473a77ffb62acb5c", + "0x8f82f92ca992ac352ed1e8fe31d24f8090ce6a7f02d6086720422b9bab20f3e3c38a5f63c7fdb193e30d63f08e53c900", + "0x8b896a2ae84c66109c8501cf6070c4da65c43ca8ef9b6b06fc85b6cd92bf2e5397d492796c528c7b2cf29ba93341a87b", + "0x961bf4c0b8068c8406a864595e156004d427138e06b390519cef53af8eb00c748bdfdd480521c6aa0d53a78e8f806217", + "0xa6fa456250d20c6842dde55d3884eaecfe8a39f546cc5e4a77f57907192e849a956a33a81369b0f2633c55bd6608eb63", + "0xb1d1d2f3e3e058ee97c9b6246cf073236438ed5e782bb21c68cd0d77b44f29745dc24d01edbce4437d93071b6fa6e0a4", + "0x81a0bec80ecd1b1e72256ed5be7de8deb11046ead7a96e1d150573f4d896e642b4af095735343f6831bb6b7f4037cfca", + "0xb48d8e15fa8e0b46937637de3c727157f8073eb8a9a04bf127e68977758385a791da2e9c69fedb89b334fc638ece78d3", + "0xafdee0774369653bf371b8820e285e1b48b40745a44d22cf2098b630b8ac95796a74f79337cb97fc60b6d6b903a61321", + "0x8fcd9ff2991902149db29cd4674d60387d4f65397891fbf91b7699a42f579f6b0afdaccec70e5e82d1abd81de859183a", + "0x8af5c73367a8439b2e3e5f1b65e00ebef2eda640bfba2eae48582cdfb244e1b1cc540bc0ef72f9e24399affce1c3e222", + "0xb58cad4da101363bb8d6e8cd0ec7c078f7719462856d7ea573e2bf95e00cc23020031901bd1f2112ffb90d847241e5a1", + "0xa671f7fe2ad81e9e0d5e3260a9dd7808125dcebd970877b000bdaa3207ca45ae1e5458d5ab7bd69b2adfca8b6abd88d0", + "0xa8411cde9eefe73fbceec3e5e3628b159ca4e4c19385ab50b8d7a482f4258f405c47051a89f11dbedb2b15e84d8bfcc9", + "0xb5dd09d5ebb26e341b6df80e836c6de2305ce4941238e3e96da549857ec314b1658f8b03ef069633625b6e4bc13b531c", + "0x81bc9bc924039fcca8892b40aa9fe8f5d6f305343f6054e36647d5f14cad3e4d754dd6ce9ded67ae65825adb4e16df31", + "0x935ec74c2dba94b1c5ef2060c31bb5c1426965f68d9f4125cdd891f20495da9d5dca513f65bf3e8c599f1562e81a0c1b", + "0xb9581e11f361097620130e753d134cce6d40ddc7c516388fe4c881fceadf738f314d241dc14d4f87be8ff0481e898c4b", + "0xb7be50ea49e09d10cbcf21b6f717e0cdca582d57935d72d17e62cdd7bf2071e5d5c91ad7bea79476537e515f0d2fa5af", + "0xab467b7fd32a795411e991417be57af8b62ca199983efc1f744799136ae5339173111465e91083dbce60e77f9f2c0fc6", + "0xb99afb338f747ae89e7cebf069612e22f9704f247d66548d305aacdfae395609a57d4d5405ff0f1eb1045dca4c3827ce", + "0x99a5e52374e1c55f65e44951f68cc3d607157e60d52cd088125a81bc60f2009d1b894eff8e1efb175509aa4b57af7276", + "0x87e3323cf6f11b595ed745a9475a6d99d11333043d512bb61d5f9d8c3f0cb6957aa8c3f041688f63ac13a51df29fa061", + "0x96a5f9ed28056138439eedba186b754f5f7693c09422f42ef82a315b7413b418c4971112f4261e1b9793ec9066c3641c", + "0xb9b5fd36d2d861d40b947c3c879a42fff24b9ee346163e544ce6c3301d0003cdb47218644fd5f1f7f0d6f19bf647ceed", + "0xa8899296b58e5d56d7da438ea48bd76310364ffe666d698c86f20683343663d742a0b3f8c1255e33f1d424cbf61bf1e6", + "0xac4be82ca78df2a367f13c8bd1cb73a28015853f2745e025626c325a10b778cf4bd9942439e35015cb38504bc02993c8", + "0xae5d6b99ef56cebd5e25a9c002e9e80c1d3e8e5fb5dcefc8ea7b7798c7e09b02147da2ba14e42e2b6db2b2a6a738f598", + "0x8c94abefc71d245b0bf04f34085da0a9b8d4d798ee7441596c5166ac353425175dfcab0f76bdabab8f0ef5a2b453255d", + "0x960ab6939b1185806e9f985c9381206c7032ea8a7a99eae5a66f276ad5cf450e654a6f1e956a2a63f33d6f715064d051", + "0xa4c7c7d0fce514db07bae5582f5e4f7a05d79f7605b33fe2a1ae980bc388b31c056438616bc8391ddc7dd5f98810c74e", + "0xad5df00f96ee6e9e1ee65b562d6311c38bc2a0a25aa9ee36f39766a2a03141e95285dd2850a598385f45b9935d63b78c", + "0xb051de656e37ccdf3844a6e095d3b42ea9c5a545e0dc2a5234e2016570375bff6b55ee0dff04ece5713ba8e85629a7da", + "0xac01fad1ac299567a22da6949a011f429bd9775de956dcdc247d5c186ec577fbc12a482ebff3a4ab18a8e35f3e2218c2", + "0x9654db9c6b5e58e0b68fc49718773d44129a0e77bfeee3fb56d27c282de6b75fe9c10f4f3b5d3374443a9fad45c400ce", + "0xa556631390e6cecc2ebe390e605e6fd754f1961e4bbc063c31c08812e0993eff5b5b7449b9732bfd3a22c87f9c528743", + "0xb41b7abb971e253dfec3aaec4443e875d73373c70c33e9ea19c1176f8cf1278c7716a76a4eeb641c142b2c6c1ace5db7", + "0x8bf37cbe29245c5e217a48140d7f0374f46596f2e82c1144ceb41c9801211869b96d7f1d0f7345233abcfead0309cc3e", + "0xa380a799b80f1309ba326f26ee46ba3081b12b5a1143f8289b2fa067aa3ba80c3690fcefded8534a80368799b71ee9c1", + "0x93dce0a2aee4d67efec1b284142d890d1e0d7abdbbfac82f90dcbaea94eef829645675cf17050af7b2e504a46d1bd288", + "0xb8e90f54bc57ff52b84fa3fc3c3047f379c5587ca18d9988c613a3bfe614fd5fc381106729bd62eda298faaf17b10210", + "0x8d8e4f508c284c52a6f907ec39950235c9443c5c6046762911f4818b98293d7d60a2c3f94c5cf60ccfeaeb8f283d8ce1", + "0xa513b66299ba5104ba633cd68121b9ec848e0c8c5252d04a0bdbab5e3bfe6ceac93ebb1ee6f0274920d84eae27df1520", + "0x80e2db8b919dd2ca33e833270738b1f437ae312b1c53a73106b6d12672a395fc3b941292fbb019d40e31b8e96bcb85c5", + "0xa4c28fba416985d47c947b0669cc22153ce887ec54535a18cf457622d03120b6aca71a45fd8704166f6f7a9ea2e9d608", + "0x850b05b9c7e168a83b0e0e77d16181a52d78aa96f4026c4420824cbd44dea9f27f3336b1736bd545bfdf548eb3f4276c", + "0x8efabbd63f3b9ae6111dceb1cffe45dd23f1500f87382816d4192161a77dd0776da2a4463d32da85b802ba7299fa726b", + "0x9426e75c6f7fb77072773a2ee03e1e3f1d90878fdb5d8c294265262f5c1cdd74a7aca339b46af8a5c43823dac7e57edd", + "0xa1c4d2ed335a3c92d867c5cb999b2b807dfb1d45e35b3960dfab19da43e2d1ca9a8748738380cefd137088d8b80d3006", + "0x987a7e22092931f39f05f5a6b38f419750370a71157d4443510b61fe07ac5aa31cd7f88ea04121947b1c0d0419d2a25f", + "0xae73cbce7cda7cd90404302388d41b49ed7d7f505a9a406f0317fccb29e32a5be61a6eb0951657f2d93abbb497be62ad", + "0xa1c7cb4056984c22a57ce76272428a50fd33f0f7a68c29c9438af05a87bec23d8de72062fb4829adafe597a278de0c01", + "0xb72c81a9a747a83a650b58ee01015a8882789983b67ac4f2fbedbbf47dbe30f04f686877d8f118b4634289866aecf9da", + "0x91ba1797d6913270ac1cb9c87d9d8440a651e294c45b2301ff8c40416e58126318f0f2d411b7d9c09c8e19f4da8ca0ef", + "0x864107657717124339cb2ec06cdfa75fb9c4a7ad5155cbdd03d155a7f9e9026e237d7cf5f4cbf07239e7bfbd79900957", + "0x87af853a334b8cdd10bf5f78753b27a0c9aac9f55db7570e2d9d42f13d0e2f8bfc4ca64b77b21e478f23385f17eb4f6d", + "0x8658227bb8733d6c7608d66a748caba761f28da4d95e70506dcfdc18300a559b4a84d11a9a048e82b292eb1b5d88bbf9", + "0xb078413570ead3243b9666c109a17678fe60dd1240caf01d1d344de09e346015cba7a40560b0d68b18df82a0a37ca529", + "0xaf6dd12875a891eea9d846aa660a207a527d08f5959976f6cb7585a98b1133f341f4ae29157f6ea8e0500fb6b49fb9c1", + "0xabc0fb42239fa531cf09f7288fb00f1d1587f2a86503593d481bb19b1159a6a9d6f4794565fe923a545d45b058d3a74b", + "0xb95966d42c59bb12029aef1da7fd50e9e8aa9ea287649ec3ba44247b185b485260af077e0d755f322ee4ecf8e2c8137b", + "0x8b1a2350f9bb0d6de377c00f0897081bfbaac5d47cac852a22dd8a427fd2e3029a1708f452e958a07236c7f35ddeb565", + "0xacaff21e9740b831fee42d80a9a80cffa6673e39f85b815b4f546f538dcd803320f90f4f25436796721c8a11f5a1b25e", + "0xa0dd42f019eedba19f4345553965508aa9d2eb1499a363056d95e27f7083c2343e74a0e7dfb101567250148ee1bec1d7", + "0xa08d1b1863e594bfcfa2e21ef4edee8535c8ee69490a4113787899ad8cf2f2ebbdea54de193ded85af82fde074ccd0fc", + "0x960912b621ff08e27781a4f9b80ef1014a4064fa3c96f534b67e5a094a5c11d9cadb2b69cd2011cdddb463f2936c7ff5", + "0xb3437f1e0872f6b9ec071a951f26120f27425789e00c1a8d3183879ed02e3b017406c051f32580b78b4d0f090474b42a", + "0xa90e6d1b11ebd1f1dec54d7b3fb336b9a53c821f295a592e147d5fd453d66e63295a96ce827c4ad64c37d4bc0df2c7e7", + "0xb357a785f3dc1f9bc1034da77033c0c64b29b78c7381ca59ef81e24ab14448d67dbf84756ea233b9e3539b5ed517d9c3", + "0x9360adb42210abb9d7644bb95532e1f461464446e94cb5047bf8ed5513398414130630866b6980b6afec5401e608f6f5", + "0x9145a7f8b2cf1bdd90b9a860051eacdb937189e8d68793e52bed202fa1e23a87db9c51a18f0bc050dfc3c600780099c3", + "0xae086e289e16608f02281bbde5a6fb2479e3151a2464b86ea737f8a43e15af4fe781312d0e5620a42a096cfbec885b0a", + "0x92b57fb14a0c567a16567f83e72b03b8b564ff6d830a5776014167cea06205579dd10715071097710dbf50b660b9143b", + "0x83e6a3f027163e635c2a1a397d2661a2d6c72c25082df129572082db29b1587c78dc3d2e5999112983a040ca46bc983c", + "0xb1667d022c8099dac5af4ce3b4ed6f524819240275725c7580a2386f067fdc9b3a49b74195cc6f661212fb07ff133463", + "0xaa2eb0c44df0a80047eec28a80440ed5f363e3d42908506bf8418bf04e9c17a5e9f550bec9c8ab8dc9979736ce325780", + "0xa2c1d257de1a55e4c10879eadd49af8950b0cf25121e8d7de30049360470aeecfbef263739262bf1f97020c6b025f9cd", + "0xaf29d1afc9f76417e4396c54300773fd283f1bc2cb00308da5e6b1deac7a48cb117c0e8c87b03076c7a1b8414d25dc97", + "0xa44d4f2186f5d728fdb224f10b496c9b57d96204325c452842423cbd29bbb2d07e98013a3880c7dfd63ede725d15953a", + "0xa30c45d1cdc68a5d5ab65b57d60c8b386be836c5bfda7e2f0347229b7807f6a97b632bf54ba3711066bcbd5e0831e5bb", + "0xa8c3c93d6a3526270ae47bc2628da82bbdb8b2c8e4d6a4cb5e9cf70b49999a963f3e856ff9db12cfd2575187bec668c7", + "0xa03566f1a99f5b82e8243678d0bb033441cb8a2f160c0c66dcebd0b6922a56f895a69b94a9c65f4adc9ed73420fd30dd", + "0xa4e3c839a6f4f4317e7bd06f25c5236e42fb0e54bb975f18f0240bdc214780049f0258dae24fba6301aad508ef9abf69", + "0xb7e0349d89616156679d06d1626f45dbc9683ad73ed91f0d92f8f82cb0ea2ae8d3ba3a752e73a39da70569d41e84015e", + "0x8c9ec5ff6be4b0d9337c5336b467c6d4f552af691bf083a23f1f9856e18b5a13852143dabf03869009febc443b2edbef", + "0xa12ff782575aca7b48844f0402a311bcb3e19514dd4d2ba5b39694c66846b22dc9ba25ea39c3c1bc325eda3afa1f00b1", + "0xb55bb586ebf5c9a3c83a04bae254e22547f37b9090151d96f5d8aa81be17bb38d2763a08cf0519a91878633ced6ce0f4", + "0xb3957203932032fe180ba9cb5347c2c1865a3094d03f6611148af4094fa6a8eae522f2651780d9bc49b41f5c36054eab", + "0xa0c865b498e30180c48fcab93342a50ca1cddd8759d6e0bb54e9f92e7b60c51c373f7ab1432aeb5e5c2d3ffcd79e8180", + "0x9503ffb3529c3415c07247211c2a4f35d8ecef98ce9f921e67438ffd538caa54520fc6d248a081f46221a0f1165011bb", + "0x906deaabf6e8dd0c24a4b22757b7681bf88268d9b4ff97f2844f9de825af511155d0bbc48dc4c03b87007be94f835d92", + "0x96c2a7f48990ecffccbefe128a28cd5b26c664b8dc9bbae16d857f7efc1b7711c734ba7d1476945d09ace569297ea96b", + "0xa37ea083b0a61f400b498ac5ba2360c22e40b688428ff4a02e3cc80206b61061bde037cd52d97eeca175394dc675e216", + "0x89b15c3af439769829ca930fa83c47afe070f6e2d7a7df88e5a4f3a2c0630f9d143bb3cc43ebf9bbc1b91be03d35ffda", + "0x8eca6996ba407886d3b9d2e4b1aae1983023dbb1c9ae47b6637458c73ffb7f422b0a893eb0b07fea2c5172ba335595b4", + "0x81df4d7f576930b2865af5ee1525718a09b65d9a013feafd19cad335e4e425485531807078b9564c8db3bad95d23bb0f", + "0xb6635aa3ca31c851a0283c0c6356235a5d8de9d1db9780e62087be32089c1c081bdc642f067224e88c14252efb960e3d", + "0xa0120e81025ba07848ef24ca9a94699db5274a8c85eb9c2f3b41a81f630d09d100127154ddc3270525961613a41ed81e", + "0xaaa8dd063f9f4f73f5a7c440671e1375ca8c224f8f869af736edcc435329487902249c68ef646fbf71c33a8bd1a04d9d", + "0xa36bfb14bbf3956c317e01fe744bd9c6c6f526a3881f6800592501ca1d9caba7f81b3b54f53b2ee1b13aa6de42ba06ec", + "0x819cd123fd793c0c9aba75aa96293268a4731c68c0a26a52561a695fc4acc409752de84ebd19494bae70849ce538138a", + "0xad4e50ce325477621b6eb4d453b087c3d7df6e3d019ab41239f2ad0615c6030aeaf85e0e020f3e6c89e46b8586b4a347", + "0xa4327072fbcf33be1e57ee4bd5db4c079c5ec11694a25fa2fb30932f8a2a35a63183b24d3ded7f6c8a8d0ad111586dbf", + "0x9454f17aa8fbdd2b15dfa6600ad305936a37b205eb554c915adc43aceb4dff6b0d1414e61584d5b15265f2ec0c85abea", + "0x80eed3725282c83dde575620bc0d86e50412df5dac3b3556d1e3bd9e7ef6f56dab202f4dfe4ce542babd49c1fa7dea5a", + "0xb90d1a07ff760daa23b7408b067c322f126023389beb7bf373f0c68b85ba0ea8a2c03e77e6d3339a01ed3ff8ba51f1f6", + "0x92789ad894995ba07f36a0814fc3289810136f9dbc6c70c57ea80db464772d760b57d5b059d4ed458f256af7603fa2c3", + "0x96a4ae1ca46d3b26029767e02fcf2f623d32c952712badf2a2af721226473f4875c40d5b14e66bf961a5a56aaced3aeb", + "0x8c5073f4846df9a0e057f52fdefe01a9b8c9ace91ef5ac253e823e165ae698e733eb936ad9cb04d2c54cd8570f328c4e", + "0xa9f36450b5ca66a20e52bc196620852a41f1f40262a2e12c278818b6071e6972c3cc6fdf83a9ccf586db6cc177173cae", + "0x8f101df23aa7e353ac1034c38adab8f20b8753aacabd10d70acb41d0fd0b1f34277546b30f64d0a861f448f112e38acf", + "0xb45b0779ef1ffbfa86d7e02e89bba0316c5ce60742b350296eff0d04246f1c8b1bf5bff68bc97792c85f1e5d4dcabacf", + "0xb7e89d015f6c7122a2f35f1c48b43eb0076ac4269158d52e38bf2a11de11cf2928175f717ee5c1bf543ea38945658558", + "0xade2a57ebd7600929dcdacc290168443437bc288371ef40580df515012350f3453b09aad8ae9e64bbc3fe6a3456f2c31", + "0x91c2f8de02bd8dfed1eeebc40a422d444e3459f9c33476b55de3e950d2c38d8463c4edf4d4f95347b0599a48cb2d47e5", + "0x8f6e77d9ceec539e0407a8d75d4e855e376838c0f886b36615a9c7715bce56a8669586f6d7cef75812d84b8be91380bd", + "0x87637da91b051ad92081e682e289bb904c51d95ee1a6ae2b8956982093a7bb4f8a66d91874265dc32229f9db5bd51ba0", + "0x94691811eb74f2970a95e9a2d64435952145f1d0caa76040f9811c9ea1ed7327750d57d6e8dd63c6378f336421d11093", + "0x884cff4ebea1bb48c0d651bcf0a710ebccab9062c96364aa64aa1275e9364a4c261e40a4b9f7e1e135572681a5a7a965", + "0x93f21d4b6b53cdc1dd41cb1b80ff73c0f1620db41c35aeccc059128704e9d1d7da5fd3240e7d075a2503273e7525664c", + "0xb9afe0a9b64dc43fa78f607cdcfe337ac952fccfde41c2e88abe3a8dbb36a51b3445d724908e552ba74bf67ea2cab56d", + "0x910280ba145bcb6a99d89d1526f10632206d2ca9e1a8596e5d181dfa37e5f407e1264b9c71c39530caa59894c10b371b", + "0xa5f583c9fbed59f99cf5e21b9a734de6d5685b9c33931325dd4b581bcf5aa4764c2a250924e7b6f7931dc5278bd17152", + "0xa87267f2ad292572a1cfc89308c96aec0d12e5f0fc2b4135ff8df7cf83bb1e71d619906d415db5841bbbeb173868ca82", + "0x899d7ff8d7f8d0daf62ec8d28adbfe4e7856582a23e62dee175e3bb9461f38bf8e4f73dffe10654a046573896f6de690", + "0xa8f3601e6787e788d46a9d7592dd4bdd8ea8b5136e3c897d79ce560e9511f6236e67a85a35c59295428c1f9c019a0841", + "0xb180a16448f085227a6f3e363b0dbcab285bf419d438a13be2cac1ac9f97973ff6b8aee38294f70a8d72bb4ff474577f", + "0x869038341a2f68ba85f5b2de58d2d794584a3c00a76ad0dda5aec31d4e3ee433be20c197b40618f89f7c8f1692ea3cc9", + "0x8366f825dabdf4f7714c5d089443d0de315198e23fb93c3ed063c4b8fca0727b05665c04beca145dc4c02f333e300c18", + "0x93291da32b501cdfa3624b39f6e38ed982c75c1209cd85630cf83288204032c0a90f013f1dfb4dcedee7aaf0fd95566a", + "0x96c95a1e73016fecc3483fc94dfaceea376ac700fd4804b24e9eda7135048e521daf96f8f63d5a1439950a64296d8124", + "0x866429fba47fb691a4c39460031a7e614096abbca3073e9246babd23075e8e5f6051e424e47d860296ac8ac646f8a283", + "0xb817f3d9985cf9f9657fa800ebd36a9622566697ce68f91c509d9ad7df8146532e24ad85c07f399908f87d1206c7642c", + "0x8761c3755cf5440775fe00081f79dbf59829f8d400adf7448188b97f756ad35658295649294ac9626c2569ab21a5df86", + "0xaad65ace72ef89783507c9feb5555275d70a421a95f306b7613c894bc24e978be809410b519e9314ac56fdae0c71d326", + "0x8ed16ed07d0e989061db5087d50cebfcd6983fd54be5062e333bfb8f6f609bf1b7b840c91ffe4b66fd674eeae2dd1558", + "0xaf3919bbc0df42b1e2e8f62e931701f7c35cfefe3ac3f1985ddb70212476112e8a19d51c673da931777ffa28944306f2", + "0x99a364d8819b5ea0f6d900167b60063f40f9afcf291ded7adaa2d0e46f344751cb312df1c2113bad8d84a028f680b41b", + "0x8d970bad8f95ced0b0323f4b7b087efd0624ce21834b3c9ed435dc0a394cc2c7ce58f1741c1a64265c81654eeb6801ee", + "0xa5f96a4d794f6f844b38f9b82ee15c2441cce293b6b2ba26b25643165236db05ffa918ebbe20aa89ed2a8ffc8df393fa", + "0x8ca69e0006f6a72e5abcc32c3961aeeebb8c0a76d877fdd8a093467485c19662b75f2ad8c750acc9cc12c8fcbfbe9b0c", + "0xb5378b855f6ed3eec19546cc21c947dd12e98783164d95a95d3cac36c89a840bcb9f7c99b191fa7730ec28d57e7326dc", + "0x884e50d5e20bebca96dda539daeb0e15edaac7fc88bca254a7239f30aaec47a64f29b69fb2d90041b82f8ad8e3f13d3c", + "0xabcce1f6149037ac8d27497831acb867cd5e05f637b7579736ba5c384b8145f127c56b82b1876881b782b94a84d32d04", + "0x8747985d53fac369c4a23224d50bdc556c00f406e7ab3e38427aec317ae7c0feee5b48b9386c5764de883cf296ed1daa", + "0xa153c77887f271316d5a7185fe0d2bb7359cad86ba80b03434bee8f21b3a5e52263d28cb9d3d2e6d5b7443196e03cf80", + "0xa77b16b2b7b6e999144af6c919e0a74b9a6ff70de41a133f7f820befc1261bf261142717133dd4a99e168a5cca4791e5", + "0xb89beb83489db9fb62fa32d1a8ecb66fe9ed41d318820d13c3e07e1c97802dfd7b05d34652a478a1deb3b17b4243a499", + "0xa80200902da696d0d3974ab29676f0eb67d15166b173fd63b247a17cc49f56b6ffa28d9690841ed4865229248650601f", + "0x8210103eccfd1f4be55e33991a831c50260bbabc1f311564fc1c52c3b2755d3e4a11ad69cd95e398dffdb9a0f5b77df0", + "0x9958745d00d8f29d05d97875746d863007b1c05d3ae920794e6c65adb47ec208734fdaed1b49982c4f4cdd1d3043c369", + "0x94a4f28dc7a9d2dd01ebc2f3ed11a5bb01a2095e7c772d2753c022d991da7b2e4c80c2170209bcc4771d68ef8cf007c0", + "0xa6b5c5543ae3de57e074fac82221590a8d771e93e22fffc2029b44e8a1c2c8c9cb0362416de54d00fd5420e5b1375eb3", + "0x875e801265871509c71dce38005ad6423fd027206e6ab4c58d2978ab4812d5720401c1310b56ce9ecd95241a17ce0e7a", + "0xb6819bc6497ed57feb41bd82f56216b513085b6d1a560a958adcc06a6da304424ee34ab2580604b0e59f6b0091ffe6ad", + "0x93bef0806f21f8bac88a5d6e2e6d1adda06f9daad5cc3c8de61162495d8fcc3889b767a3e2f3380f162166ce40a0ce80", + "0xa1f699cd7446cdb1321a05f970bc70cc98593aaf0145a0d097e60e5897aa311b00d019e09cd533d0c0b7cc5c00a753e5", + "0x89ae140ad75a83db2903a93a3711be90986d08dcfe962aec5ea4ee69656026dce77821993c1defc4464442bfe7d44734", + "0xa4110c80ba92f545a1a7545cbeef997d6c0242fd4d771977192269d626b35c88c361df53bb36dfa8ea7e40da68e45f81", + "0x906786f38eb7e98c431fa2464048ac3f1f1df8f908a25262978327224bc82168f564b2f3e6da77f49457ce49c1a72c2b", + "0xb28d92b3228547f03a3f489e09070ad9a1e20a73e49f7ada96ce41c19cd6416ad809b3a3a01f141b3698e85c641d795d", + "0xa25b9df9b377baafc8c735a772e0ed9ac007c0b6ebac2cc0f8f2e799e5e6038a616968c9896cea862e99b1750224ffe7", + "0x8085eaabc79a2faf1ed0b9fdd017fba1e46c671c6d8ed78fb089494f792765b0617f790016d8f55697dd0f45d17de4b1", + "0xa0e81b557af74efb95cf94054264d30396121312c643052070ab53eac8e75075f1fd0b384cdf1d96bd39cc98681b2d92", + "0xb8e0ffc7548969ae28beaa9d8bd65872840a03150e2140dd799d9924249f92d962a0089171bf4b311520ab527198668f", + "0xa6188827a500b99af6eb91094a0e464e394c8c0a6d80cfcc5d8be89e8810732a03ca75b2befd00d07d1dfbe7dbe89be5", + "0xa4e5a47c656e74107e6007199b940d8381f706d5bb4226a0b2fb13eda725a556530b8d4876dc49c5f9631dc6bfcc4c9f", + "0x90330a50442db9a9c459e06d42cf7a69e009332976c3950ae7d9981d99066fd2af22f22ac429850b998f1ec929c82bfd", + "0x89dcc51fb717212b2dcbd0fa0da189e194b4ad5bf7f43ab2cc2c96f11c186d0872bd930aeaae01661ce2dd9f94eefce9", + "0xadee914ece15575cc34ab485f2dbdf3979406ce7cd8cd82197f156f373beee6d80e5e3623d79a2fef14b0b4ed1678a51", + "0x87e97e8866002364bbe9b49c5f2b5eb729c7018ec61dff7b8bcee1c1ea349e5e04a3f3781617d46d8fe0e62afe55d62b", + "0xb6b7bd0bc652a0bf79aeeea1767f0f17dd543b9de582531bb3e14ba2bfe1b720a6c6b613cfc295372eab9202f5e2d340", + "0xa6f9cd96d8e422d9897d50bf36288bf4c09d28cb0f5c4e13ef7f76cef6c75bb594d0ca954ff7339590cdece16414fdba", + "0xb9bc319dc5e55630d1ee8cb48978a256b69c96aaabb5269bed8c5366add03a2c38da11cb03a44e150a5c7f34bb49bcd5", + "0x868c36924f0056b3464bff8831543a280ced62be748d60f82ac860c32025c4589e9354984e1cedf24678374c959383a8", + "0xa6244602362c09b382926dabae5793ca4fc50600193c69e645fe229a471f7cf9e58c4a59124d6d2dabaecf50f1e1fd1d", + "0xb42df58ee9e20fce589837d5ed8a938eb83a00c6ffe2f6afc973f6ce26559b8d220976ea1fc18ffbafe739c92dda6618", + "0x90c0b2ed8ed7cd6f6ff812c84ed297b3231f6e2106f2df6d5e4b4bbf5378231025582cf39f35dc9344d9fad3adf04685", + "0xa968386bf1221425cee0d0b926689426fd77e8e8bca5ad3bd07298fbbeef4fc676e0cf7a4f29cf981c682a78a54a2d1e", + "0xa3a46bb7db36e0294b509036a40875850ea5ce4e8853cc0a7d85e8455fc2bd7d5b593879408ef2f3b2b2bfa44aca2276", + "0xaf825963207f046b23534896086a3e56247d752982417047f850bf306d0cce285b537508747afc700dff6472fe3b5569", + "0x8022af88981249b5da08ccc19e4ffbc35feb2cb5308b34064de4d5bfc8ff2b933363988c833ec70723e3b5107f8fbd67", + "0x89687fe6e424c7f0d2751e5f7838e9a3fca4c0bca043806fe511442bbf41cb67d01165ecb662b1ece1b2adede5a9537e", + "0x99c925763420fdac4149a02131831449c1df8be4867a6d2d09e6b14abb821d46bc1fc4fc9aacfa4e9de1a93f9b56fbcc", + "0xb819ee6a0724de9c944ce2ca51ffd3f1d93c77ff25e39de8be2a612abe732dddbf2219e839686a4373609a560041291f", + "0xb5eabf12513e91139025f1236c7ec235368eb8586522dce04d370acd3d854c1e6676d92014b60ea3e4e21e9d6f063f2a", + "0xb82e94f1013db6cc682032c7760aca2a1082826d280801aad9c6564704362e61a61cb52c6f35f769bd8ca191e68e0b0a", + "0x95dcb02a676b17f20b75632c7a9060f990e44b0c1fba84ec8e633554f875ebcf6e54caeb9816267e84a11808d68728af", + "0xb0c7c401dcc019d2108eab7e87d6494e06399f6eb4fd95b8ff9ba4a56e549a3d3a4aff13771229f4c456283fc3cbc53c", + "0xb1a8e3e500e3ed74bacf91a82b39f2b870963dec0b98b7d5ccefa3212fc9f3ef923101887572e14d08145aaafa8da5ba", + "0xb2caf72c47870ce9f0524c4b3df6ab3eb3695765c010a27c0f3cda0ee1c1f5bee64e5392ef8b3f0f11e66bd8c9d4630d", + "0xa8fb4864bce5f1c48d681eb37efe7d9ed1a83ed36bdc1f2627539b92c90e100d4dd64ab664e404b0eb7b645a8f95642e", + "0xa1b6164a4f0467444fd56a1f4668c8d1f295f6e6f5191355dcfd004c34153317202823d72162b621f677c970a3f0bfd0", + "0xb2cc59a2f6f3b7e18064720f93b28801fb684d98ee808ec5c04a5235dc40372aa0e0521410d8f736161470443bd97ed7", + "0xb5d9a823649c09151b214406189d75d7f1ca150cc7431d79b7d60348b6d7405014a44bb7840e35f9c0a634b4c6785561", + "0xaf6b8229fe035cbd6a5da3a3aad93e7ca5ed233dea5fe4477dce46ed17bac9243ebf25a8439ac2896c41baa671c0fdfc", + "0xb42d9023551d999d2be3ee51f6ca82c3b2d41fce51e1dab52095af6d4b59edcad70a1f9b1e71eddff894e3fe35a1f11c", + "0xb868543c09fa9b9b990b276ddc5b68a2415965d3de71b9ac538c26a6333543a7c33d0b432f57756ac0077d0021878944", + "0x846577a8c877461a58a94c5829f2ed9d7ed107fa63a48ee77a1ef1f1d1f940b2605fc742cb5ef849e3cbfc86942488fc", + "0x967ca22cc8c21382b15d73b4dd4f6f0a0bdb2056c21e3c75eb3d9c13dd41336672ceca03065d8cd1062389afa4726974", + "0x8e0b872d766c439f3f868f18ef0c173896eac883783dcc58917f76d5a2e8c291967a032d254450fa7f9a12fa7d7a4cf9", + "0xa0236eb36a4ce3b7d649ff02de9279d364ecd5059932328230314ecdce3278c42cb836f547bb9da9de0fc96cda2fbc7c", + "0x92eac5a5a88648e6d821d3bb51b280fc106f751d85a1742a6a1ceed071eaaa215a0a0238492ddbefbdcdf2e38e4149fc", + "0x88e1036f9b20a2c4b3534175c93d59c1ade3fa6652a4c5c490f21f6c3340769c7f8147d53a92fbfd84c23d7c4295cdd2", + "0x8b094165ad429a339f12696bc8967ca89ec47a4778f387e42e273a1863a38199dd795d120d198d3cbd93203604c6914c", + "0x8f8013229eb6bc6a8f93c17d3b4a1b206c258f14091c6dc39cb1ec492d403cdf5f696070ef5a6c0ab9ed4ec141b08d73", + "0x81c7ad27bd7a48b444b2be3d4b5d4845743d6ac4857b061e659d7ed48ebacdeac29cabd0cd163f3fe6c5cc28753148cc", + "0x91c8a92749183e3e6f3499d3b0e9b080109d5e88ce8acb03b35f3d04591e13b4c489ae323a149def1edaaf62f93bbbe4", + "0xa6a2d69f012d877460c33095924771065fdcdddc30670ea84576b72dd3f7769f90d1735f8914b6841c7d938a2046ff4d", + "0xa8ad4b976a5e4477a97d48a3cfcce16b358fd3dc1ed1df301fad6d6f0e188782c518796faf1465e52312b47bd713e2d4", + "0xafa2bab9363187473a85f7020106b176903bc3a3e3df1f4938feed5145b79b66db8aa608cdda554166ec47e60fb34b95", + "0xaf691bf473160cfb84ea517702f3c01daa6155f31393d807c897b39523448c5af09be581ad713c76aba194f90895cd9e", + "0xb74f3cbc198c9e4b2c7316fffd57fc749e367b7d1cf81b3f5311d266c9a3ab9598075ffb9230dceee230d5f1bbe3f796", + "0x8c28d21c49a15299f7ff3eff7568b8450e6404a168554b8965a291c03fdbbd3dae9ea6b9760869cb1f2e8c7206183195", + "0xa496a0df4e79827cf3bec117b92b5b248dfe129d783841935363362aee4822399974e6c03a92797b3ecde80b207fd7c0", + "0xb39fa07fc8f4be41588ff5560ed68a33c3020bceaf172fd11e0c1288ea885c6dcfb56a151e4773e57d864dce06fdbea0", + "0x990cd050ab056ea447c114217219d9c0c7526803f63952e22ae60a3996608bfa3c6119a56befc597592761e3a90ef448", + "0xb6f02dff3dc330daf82d1edbd4e6964d2e9c38481e74cde8d9d85a9e602ed22c4fe6c9b6f41ec76582f0a4e4414bf300", + "0x84440e4a7146ec2f34e8099e85c09b8d7bf505a15638aa34cd2b42a20f1f335cbc9f0e4fdaf2e53fa0ebb2dcb00519e7", + "0xaf389aed116fe58580810fc474eb15518dcd9746f04a7efd2de44c9774824db79f8ce4c4fa108e7396e1fc016132a402", + "0xb202985e01c62d0de1f6807fe600a3b81fd11f30f5aa033b1e7baf7a62f34fa5342d42ad6a6e309560e3e9ebc662920c", + "0x8a07641140db9701c676b2c094c24cd663a5a34d3534fd4f5f1e38ca0c46772d141679730b5d0cd71d056c257d9a125c", + "0x99dc01e76174370a741e8e9ef5654a3a7769a010da85de41dd315b674ba8786e6a697b74a79ea782a1fcf74a48e51775", + "0x93fc897841609670a1eb88d4e4498c54e286e25238309fc95389b16e4edfb82b8ee8447a436893c7180827a996b9a0f7", + "0x8e2dd561acc8954a53635c0108ff964774fe98d12b28a0c6ea8b5ec5ea3523a45b81ec642c1453e3b2a1c0e0749562be", + "0xa95b0b7f9e53720f4b0394bb6ae8222aa5be00a2050f59ccb595d50e0dd9100e397af9ea77b0335be02d1713c361357c", + "0x8e21dcb67da3eaff5b950f989939237e3735a31e346e1bec8e6ca11edff5223e33c1c6f2f79da975de2fd86dea286e1c", + "0xac02cadeba36143767bdb8cd4e1caf8cb287296b53955f33ed07f771a1fea521fd64b7e153c90d5e270c12ab959cfd24", + "0xaf95bca4016b2ddbca61c9c854cf999ed59ab4b5d619dd55460f20cde5ecc86081a2586a7eb37f15c20280dd06b65809", + "0xb7d7c81261e8c6a8983442e1e801f5072bbada1eb2e49b8e90759dcad653c52c0afdff9cbec41bf21cfe832e49ef8db8", + "0x97fe8c6d071dc80355bf2a74c15ecb16c59bc042eff323e999f4fdc39e1209803d32622c642ad25673c84761f0d357bf", + "0xb37da716119c00a0955a7fee59b93185a6e325bc5cb2a7fb35681fca0688d0ad2d25a0e40dfdbec1a11deadb1cc69d47", + "0xafb8091548179fd2a17d95ca47909d97866e4fe54099736e6414682ad083fce300e0a20dfe3a017c1ee4ee7d271bc470", + "0x9306ba1f3f2f74964dfcbcf9b87bafa44b5e013853c46cb501e10409f3c2af7269aa17c8cab261fe82e52a188ce0d18a", + "0x82430e3c25970411f40aa72ef1cda5b2b51bbc7e243a1b4951e92cb56a2f5b200a039f5554d0d1bb44330d89d1ef8840", + "0xaabfccb8f3dfbd4012b9d196448e83f17bd1ddb8c857dbf98e80ffc60c1af3493ac5c70e3a2f1f26352b1ead143dee87", + "0x832cd6dc83380d068c068d815ad0f4677de0ef602890835b8d32b73223490a6f753092d651968cb3d798cbf2a227960d", + "0x80e3e7f0c46fe5d962322f3fb2535de40dc078db80e7ef57923d46b742a8e4d6dd35ef74234f2b1637a317364d57abbf", + "0x9306bcc29d6f8a478ec085b144161850afa29d282cec756d0d3fcce6f4860f4a4b8c8a5952cce54ea893cf84abd6c4fb", + "0x9234c03bebfe6b47aedc7c5452058ca6a8def3c368bdbc9019ef121ad44171d6b31d9bda9c82300b5b396187324684ec", + "0xabc2ec6016ee252f5693558b694eeeddeabf4579b7e03d37504c26ecc29263e455ce8f0158fbfc54135600b72dc54315", + "0xb46fe7b51df64cf46888a810365f891d43db5b34ac4d3505f0692603adef04b1d08eadb3e31d039817e7b89bf0789802", + "0x988e0dd101bba7d7e4094cde99eeeb6d4411341e684fc06ae78d163d30c4b585375a868eda7ba1e5495ee7f0a7d509e1", + "0x94d3033ee1926aef656b31192653d3da96d5c533ac2436d68fcbaebf827475778689ecf14fc53042a523e4652fb9d713", + "0x993b598555bd2a35e9a03f99950d09f55a48ba63f9e0e65802ecb95602d045001f82f25c3bb60221adcb8ab4e2709ba1", + "0xa0acd921ea7db9870716acb595c65a934a5a06a07c6e54cd26efc86c97eadaae1522a4a26c8f93b7b7cbc4746ecfc21d", + "0x8dbd8f492764bee920e0224dbe39d650be6732b56976a5e1b636b2e7371c1509431175b66c6ca879ba8f915f9df8fa36", + "0xa01b24c1e3aa044cd2598032950755763345534f95f6f71d50565d25cbbbdf9c42e35253e35b683f6c3156f5c998ca4d", + "0xb895522dee1ec9c5289e6fec652093519cbbdca7a2936fd1df3ef956eb404f1a24272c9ae6ce58eceeceff36d76d34d5", + "0xb91cea120e200858457a64a60aa876f167b1b88c1dacd9988700b9f0f0d1bd1dfdd8dab56c2e7197a174b7b8bb8422e0", + "0x8406767e4f7cee2e12431b093ce82f633ffc76b451ac8414716fc74fbadff30c52a22869607d5de465d0f4df8a740343", + "0xa2cf431d18b2fa526291c7027d59b18cbd73a9b48d68cfd6e4b745d27774941af809edba06c8534b1864045d6fc1bc20", + "0xab3fe23aa8c45ab2efb2ca0c593c8644d3f47f748c2f753626289b0b9c761add755e3b52521ef37fd609429b2f8770ff", + "0xaf4530dfc5b3f37888900d9fd08554bef4e47c4c09a8c82bb48c4b9c6c9089465f98762d81ba4272b6861121b65f3c5d", + "0x80f61d086511b9b8b2033921336a68adde99cd25fac71d8f8fd0e476dd30cdfba49363784f0d0578c1f648f93ae23f8f", + "0x82ca682cc254952330d1be8c0e53da24aa943ffe0209b00bbf046e1e4f9425886a01d6582e2853137a9c256316e6f737", + "0xad1d508d2ea2806c351d5bd1098c46ae7ef83f4e49e4e87f83fa2c63f715ec56109996284a541c2005693687b4813623", + "0x9061817ee94bd2895064f4af04777b499a1fedd9688ed64bdba848202c3cf9286b699c92400ed456db926ee23a34f90a", + "0xa8bda55cf6f3f9edb78b43a52b7fe76e5cc2cde21e08487ea597cc266e54700ddcea1a287ec6d8f16b738b67caa27152", + "0xb605576e55d1fa4fd9d7fac2ce549dfe23fd6ade41fa859bf809baa3f1497d078cab06a257ccfd6cd59f67f17eb22f5f", + "0xa92d22ff5b5ec6dbb1d57db1b740521e82b4bef84dec3e130cab63d0641c3a8fec1f6f86141fb1918dc0f3fcfcbd8cb6", + "0xa0165df8dfd7b3cb58883768471cf485b886ece529d5bb78b26acf9ef6c44314cf9f34914233c93b10b1918533dcb8c7", + "0x88b79c9c721c1936fdbe22d68459d1033fdc986d3e52f39341ab06cc85a3f230ecf0965ee8d2dd54496981fd08a02657", + "0x939b77fcd53a523240bee730c2d7b8dae0b32bc3dbbd31428c7b5fdb4c3d34afe7f2a377b2918497574606bc06cac750", + "0xabbf82d0156439761b36a913b661e3d452dfa57e443ddb61613f80e110acf52765139fe3d1dd59c9e7773b262140cb90", + "0xaba28324844cd19b2d5d07a87e6f3180a3c02c7326bca846c1e7a7c131c7ddbefeabbd6787b4e1e910449f3cd1249ed6", + "0xab2f71af8596c10351f7ce9c3a9bec08a5c7837cee92a7400826284752c98531a0199e2a7f9ba7ccccc8fa0a2207aa43", + "0xa71d5a4f8af3a16ec9c3c110ca2135c68103109d4384a299cb7ed09d96231c90b04ce34ce12de02a40924d84947f7f31", + "0xb9dd79bf3286ea08c9b779910c84fdd02a33dbff7adc2d6612cd58e81aaff3f64ba021f875ea9e1201243ce353510350", + "0x9838fce2f70e7c47dca7239883229c1573ea97d469f120e4af659b18bca31cb68d12220fbd6e4e9e952b28eb29c1e5ee", + "0x8dd341e67e4c567a4ea95252854cfff8a7631c228ac852b33b2ea9211b2a6c606e4b0db28afec61a1a55e6b5f0a6604f", + "0xae9b02d60441859e3e6f3866a9bab8895f0cd6168f8e84dda7c9b1cd7917f1c454f10aff9a8de39909e36576bc0b4828", + "0x89fba7834469a06cb0da39c39a288245e577fd956c241707c432c2590e18e956e8ea3f67e4bee5a5562377617af53334", + "0xb7ab26d79ee65eb9612e54f41f75e22abd83db45010e1a94ce5026a24675bdf670e806c71f0964a33d6ed277d464732b", + "0x8a25bae10ef86d7e91a7d686965d17fe16ed635d787d4d6ca337b10ea32082938f4354620a72b5aa43ae62c7a0e751b9", + "0xb18fd9213bf3b2d7d191266c7bc1c31f683fc7da7dc5ddb4c600e1ebf5fa80a399af9e31b4ae747581a07ccb736b4b32", + "0x9968346d8a867eb57f628e2ba00f69e9d6aa8e713377a69413323b1b9b26218f527c0e719dcc1027daf10c3392f59733", + "0x831ee266686776eae4e3de1f2bc37761a5e1b918d4bf0bbeeb20b490902ae97722bcb1c98c485407491f248eecb841fd", + "0xb0e949d7c50b852055f38f3542a974bbfe7a33409d67c557d70c1204f87265bd7478e1751251792435fa22097d1762e4", + "0x8b0bee83715e20f2ef832347c926249b5b168e4ad87b2e5a9149ea4e07513e4790f60b1769ddd1816d7126a0f6fdbac3", + "0x84edc35061dbe8f3de90c2f9ace94be5ab4170b66c42583a0643ff776256217bbc6fa31612e68bfb9ab678f8e8e49457", + "0xafb4ca7a4781dd31a7d81ba8a739eb65c43f3374e76b4ffeb2c7048b055f837e6853b14ed2d3224a40dea35799f0e4a4", + "0x9945fd5ecdda5ac952785310e87917126917fd4f504fc5565c236db9b96f9666934766f46a1989c1aa176e543c6e33af", + "0xa6d4466b53c48d7facb9cc33ced1bec98897e545b10586857e896d35c850f2cdda65e19bb934a8c74f6def805b1df4f2", + "0x81e3fe4330948c279d99a8a1a4e4e141a039b3ccb7287aaba6f9041c3a8a41db1a4763fe04a36bdadd3d3295becb9d41", + "0xb6be2ef16b60a78b17991d27463e401eca731129843021e302830c2fd665726547240ec3a3240586b01a05ca8206dba1", + "0xb9d7fe5671b220a3da83bfccdc16c0b6f5e9e5c87810db14f070dfee582fa190a360c62acff13cd877c818d705a8a872", + "0x86867f22bf6b859e7f0ae7724a1174a65c4902cdcf74bdb22415875d72b67f49c62ea8bf9ed0d6883ab76512ebb951f1", + "0xab728a8167b9e82d608d4939a0712f82843f624d08d4013dfd3de41bc526e9d495cbfd40c443f67ac59dc4b5f30ff217", + "0xa5c4d10a04452c1ad12c18ce8ed7eadea1f3cdb34fa5ce0cbd804f5dd92eae2551b771523e711e8037770cb66d1951e4", + "0x8808f69b975f363bc08f8578729a6e68445138dada78d5818d33fb83a7af6cc6e7030f7b76286829861a4534e0b30248", + "0xa280773d32e1ce3544d3ba5025896d21e358592504737de72ae76d164009fdad05c8a1e5e1f8658ca6374b347d47c29b", + "0xace91a3971be87b1ca8e737802918d86375088e74380c444751c65978afba2b017cbd8fdcd3f9a0c19c0782b0034a589", + "0xb5445d816d65ea36c9bc6a3d5ec44ce6b76dcc18343d7084567dcf2603d2af93fa8469a1c493e19f1853c96f89621fce", + "0xa238867fce5b09e8695240f936a3f3cb12a715511b7516de995543b2e15aed8860a12754ac8d1c5ca2364e4471a9c5ac", + "0x9467528341f5b93b89c7f37c5dac8bafd0af620230a9f7de3e809f01cf73b8ddf70c38c5023a631a1978ac05ca35c318", + "0x8e5f1c3c411f0939ce4b6a5ced42172fc5c3774f596a114e7c5c8ba433c4efd94ca84affc0bfa89a1c5ace5090276a43", + "0xa6351818f7553d446cbe8d3a318841b0607d1f1890ebf9c6220a092bad3ece9ef8acad4d17935e437377af8f9309606e", + "0x86630d0fb2bc104d8cf840b0e545c0c149c1a8e4dd6d460dd15a52a5935c8ea5c934ef099653d783894a6d1f68414a84", + "0xb357b5d9cc645b645fbce2020db583cdb68772751d6d11d635f1e3ecf995a55bc374be7750b6e8bd4968a55600ca9806", + "0xa9b659b8cacb73a81093eeec42dd7f4fc5d955f9fc543037f31bbcf456af6476f303aaf0ef960a2df88365c2704bb61a", + "0x8b6ff5201c15cffe64bdeb818422fa10dc503ef2a6a4d686364afd0f35b6473e4463719173550d234639f6077e19542d", + "0x98efe45bca5ac679cadc25ad0bdb1f8deffba13d2d7eb14c6149d5addfac06b82fbba6d24b323d615eeee1465b3cc30d", + "0x8c2329c976d78f1d5e30ac34a3fab1f96436947d85f0dd190301a1868e5dcbe4ce60f48fdeffc3e6a05ee34a461d7dd9", + "0xaec012ad25d99ce014101d7da512fe032673399526435f6e1faca4b63759e8f6694a46ad01672da9eaaa4634f61ce89b", + "0xb8d52e530c942c3c7a67bbd0366f4cfdc6a1a075471878516b7a2258aa073eba50a113cf433879a0e15462e82087d17b", + "0xb40c5ce16f94837c86e81d98e2130a9e1dd229da5aea52e79cb42217d3b5908a53d76782cbe3934fa8769db58b00dee8", + "0x877300304eb69720f7cfb4f907b4a7e238920fda129a38516dffcbdaae2e46633d31080590d6df05756781224d532fe8", + "0x973632dc791a5214516c3e59b2b48169470678b7dab66d513e35a0fd1df86b992e27ffe6050a5233af20b5d4998d283c", + "0xa8ae0e723a8ea6e95d721337465a388b60b92b1d9b1deb0b9f59ea30842de356184fd55d9b8331d8a29ef473c1ac2315", + "0x92ed6cca30f76135c4b7e7893c3460501e92592f7d2d6409c1e1d80074120243a5b9ec14d801991204f5ec4f94ff1daa", + "0xa9f575b8518dacdbc5cae766389ab2ec01c876038414b7796f640f633367a5281cb49b48b5e80f6416a33b401c21309a", + "0xb9793588283cfdd47cc4547cecfd987f9f8f92c2b408725f39c1d879199d695e87675fa7e5a190ab3bbc97683a0b9587", + "0x8329a844dd67dfd48546791c4330af65501baf9524ecf8ed4fec9ea87067d0afbd33099052c1c2df819ca1afcf25dfc6", + "0xb908eba1b40edc300b63ff6e20e87b17e6dfe975c37ca63c92e8866968070a2c07204264646bbc9318145fcb90c23555", + "0x8123871ed78f46e9eff4fc7af9f490594fd7c20fb814e505481ac5c7bc7588c1706a79b14b85d29bd7b97d7c82b2ae79", + "0x833ed8928f154fe0a88ae98e5d8c74f816e3ad679c1c4ac1322604093e85ed4b9b9c4361ac188f0da5443c72ee4bf3d4", + "0xb9fcbb8a422bd8d996e713d176b7e63edcc6d73b3d1fe3f2c4b59da637a168accb5fb4d227b709f979742cc0af8c0ea8", + "0xad3759a6a6bac3047935443347e3c63819905f6c01f58f0ba76aab422d723cee10c769663be9554473e668bffde1d500", + "0xa60c1909703211a93d7b5e8b8ec1cf4ca06ada653c27696a7dc9a2ff75cb712918888c6b61b8f792ce9b413aac09f48d", + "0x91f05985ff17f9ae20498185f6558f9f38b67966876dcc6981af4d179cd055661adc63155f4afa6167ad61b7038ac49f", + "0x95c5add9bab6b9792517772f9f8b21bf7cc325dfd13a43177b0bd982d0f620185d8596c2cba46a5e10aae597129870ce", + "0xac0b4b6e2b3e417166ad9b17de0b3ba775df6ad3a78ad13a1892c0992735ae54c06b1e6123b0c0bc90544441630c6a1b", + "0xb0135c25f74ae776c241faa6c91a3f7ed6138d19a2100928b7ede64b79e177d92c5cf921dcce3c614e32de34975fa6ca", + "0xb2215b560d5a36f045de7257098e9d75a40122919d4726990b4395eb2bf1ec789cd0c64c46b775f6a8be28f23958e17a", + "0x870dc7f7a513728f2b428a3c08b15a6af88a288824e790f41b1190fbe02b59dce2914a1339f7203cdb7f2f9c98d8d721", + "0x8e3895f03952cdab36f602418cd746bc0b6a07629eab0a20bbd8de6c993030c5287fc146fc45fe97a06c992e0a9ddf02", + "0xa4cea15ebc0dfad9feb3d18168fd33768e8ac69e263263ceffcdfa35e8638711c2971697b7d5b2aaa0fd8c5440f3e164", + "0x8cfaf5369781a59f4117283fd3f290b81816abd3124a9486ab1faf7018d36a73c1630efc4ad648ce462e541827d51975", + "0x82b420eb25736126ef18d91e91ca2ecaea8983b8091df88343e8e54ca5ea7a3da6918c97695cc0cd5c2df95afb1e3cb7", + "0xb3c13923a3d46d990aaa6a1eff3ad32f162ccc5186e16a549dc29ad4d63de6287cd05579452785cab32e2485636d568a", + "0xad8a43ad6195e08a36f755dd536842ec88a7d920bc302451c860444a3fdaf294e5b5dc5a122423474d322af5de8cd8a1", + "0xae40d1a90a77965366b5b5ce87d6fe86eb255cc3d127526930d128ef7763455adb82475ebfb7be31f9c512394f2a22fb", + "0x9763bb9459fd4c0de2534767bd99f98b859030b6af5739a7081d889d6875f5c23f0154c30d00b7240baf6450b4459987", + "0x94aace9e9318d79d3c7ab533baca31724bfec839b01187e326b1fdef846968b1b29882f2520a9e237dc41ada01bc3761", + "0xb6084f9e0051be76244ead401e8d2758717e93c4cdac58443261b3603cfee0eaec7d758b2e4357650d2c1f5391edf798", + "0x8c656a798fea470163e70869a13edd30d138bc148460d122a2275df8cb43f2b45a14e0d8a8a49eeb7c1afd02484b6ffe", + "0x8ec317e63df2881f49401eb2f6a82e261b07474006fc293bbb54e0fb7437697b16ec1d6ea101fcd56543bf4d69374cf4", + "0xb27d9b3b8c3cc59d08159c765d24fd4660bd0a54b2b7fa9fa00b47e6770e6e8d3ca353d305fd772c8171e20765c8a66c", + "0x863ca045abc38ceee09c4a21a3dd18f1c0f70c0289437957aaa39ff764760bc422b748bef8ef133ee28d88c46e6be1c3", + "0xb0de194caa68f5288dc365faf9e9ca3c69b0a8376cdb532cd6f1cc3478671a1e755d0e8afbde4e3a88440fd9cff4e8f6", + "0x8a259f48cf5a45773522f3c5f283a6c01a0febdae09f873e009e4635c57fe5060b01243b2e5e1c9d2ff7490f2dd3b334", + "0x8c4398e1e579778c88976ba12feaeac0c96fc97b4e26a133ae74fca1b9c315c1112ce3977d20fbe9ae5866ca6544fdcf", + "0xb54b25aeebf1917bb4981b43f39491918773bacce37e994b74f877d4a636f1b3f4a2f164b858f95259f285ca0c294f24", + "0xa9db33b15331e852da3693f6328bde30b8cdd79c9b9b63107cf78dedcf14da68446c462720b9ffa5a1bfdaa68f5d931e", + "0x9966b6bea54405df1dc4edfde9f8c3ed7c0733d5a73bcd8b349035744d5eabbad0d19801a678d48cec84c0335346af33", + "0xa3d0c32b5e3036c4a4b222c13f7db23924bc2b2f724bd908a38db3b8f9c95cf5034c4cda0c5083c0967d34061a216b57", + "0x92ca6b883b2b20015fbb56cac4c4b5ef22e555a9b75f4f020822fba9167eebff8f9fe5c729c574cfa5ac27bae1a83fdd", + "0xb72b58d6ddf54c2d37bdc1599ac966c54cb4926c8d2f70d1bd4cdc383c6eec5e4b87efc59466682f8db964d80a4b740a", + "0x89ba63ee57a1e6f13d7c66150a8d6721329b385eed92be3ea784eed89c76a1ea88595725612b109a9e4aae41d3f6c972", + "0x8727bb53bb62fb714e4e5de461c6cb298730641e38a0b49b3b3d4a29fa24167c7c6f4ff47f4f3b91e464a581a4181853", + "0x816699bc7c3ed65747d34786b7fca4e35e79907f459f2df0918669adee54a70c03580c4e7d2e410ceb45c71fcadd44e5", + "0x979688c14ce623dd17344e67373e5852bc1d3ea12d37f7b28095e5d578d8c9c646e4b97a3a69a97764ed0a88f62c99c7", + "0xb4539a9eb6578ed3b8dd54cbf57419e99b69c0ae1ca3ae3b4a21f204813b2a78438d6c72f86c13dfa06a0b9244b98688", + "0xa5d957181c30701fe6eabe3e65a53a33dc43df364c45f0c4d882ab88a069024bf04b71015f1c2fbf03f368e63bd82fe9", + "0xb9ce9a54d9b17d4da41ba3135d077c546cf39dc83230506a4ee88cfe39e76f7e35664ff1b571e231054cf1b764b9267f", + "0xae6bf2eec8046137016ba94442a7a0aaed0924ec1558885135fd339d2996aeff31ac29f1de07e84f7b7391fc5355f429", + "0x85c7c247766a4ca44278be81752f4170dcc069f76992b236b40e71e31e08f30de6a5ecaddc44debe4f94151cdd8d735f", + "0xa19d41fcac394b750248e575c300b9a96dfc5b3dca07ad6e1d68dd3f8ab94d10aaf8edf500e3fc7774e7ee52935f73ea", + "0xb3c959a22fddce5a2e199bc8724e825a6d9776455c033299b5cdc9a9d184be169d807829d5df5e747476d172b5701cca", + "0x916aa7bc58f34bb8f32808858cecd3e90ea26c3ec1f80a40e863ba18fe9af6e67c0b2664a2274eca6d36ed72e59a9341", + "0x864d945b7be551926f747406d72057c7a141110f5d269fb6657cf347cfad7178670dd294f6a98c19dc0943a68d7ed45f", + "0xb3480f8a42ba0e8eb020c2e1c1284a8a9102fa68b43f6eaf28e031621b9f68bc399899e35a1a283fb52530c8574484a3", + "0xa8cd1cb93974d1a6072ed51f356449ac19b04539517cde34bb7b2ba55949d213ee07d387ce7b5534175bd8a044556ff3", + "0x8e81fcc5fa5579f2479011caaa393f47a4e12828e2e82072736d85ba1bf70ffef9fe3b2c22fd11ce8eaeccdfa2579758", + "0x897f935b4542b9ccf8c0660c8fb1a570a8ba108fe8440e17e6c50e01affc2a8597b7f7cde5244c7026013b52c7331b5d", + "0xb9a20f612c74821da05f48d8bcfa7a4a550979e35b49d52031be8bc9cf717fff21db0142b633465c5edafc42b7c73c84", + "0xb88caeb2157d636fe26d3b221143443940427e8722596746bc337679e10ae6e5a9b33c456ac271f8b01db2f5d1b00a62", + "0xb23bbd978725aae647ca2778e801235f605dde17897d4d56914b0d2241eb31f930028904a6555581ad5b2b74ec3c9587", + "0x97a331ffcd02eda1d6e0e15deb110ad6106d3159ea641cfbf424d2e3065bf65c9b14f72a27ff3f576dc51eb068bfb22f", + "0xa9317840cd8f437ea97d80a3f445a99eef463a5e2beba3c986da8fa67def4ae9a0e8d1a675a35e5616ee90986366bb70", + "0x8c26dd7451b12c65351d5ede6a00ac7b9316f9e28be8c692d20709c3b4a5dbc76fb914667a2f1e9a654f8d2850b7dc3a", + "0x8bf4aa18a988f82dfc54668bd4ad5161f276e31567c949b7857cec331c74c6b68849afe852892816c802736cf7c547c4", + "0x836fd166bb9689520cefd6f23905e4c1260f97167b17534930923107fe934d4afb1216e4b89679a564433dc952a77b0c", + "0x94d6a5a4a11f41887eb814acf9b5a031d013d614621642384504eb78e65b6a07c50326632af47b408d8ccf43faf8399a", + "0xa213812713128750bbc5311dc317992bfb5124fa067072891f452880183d64d6fdfac8825552cb809178a3f3a641c9b5", + "0x976d1290308868c5e41dd3766447b29ab8c3b72047a0b7de85d3ee5b1e13d522147a02572cc0d1ed8976d411faff5b9a", + "0x82a4494a95738ebe56578e1e4c0e486eea66d5cc44141f478bfc5a6b3ebbae6f32063725284df81b438603aa564a2b6e", + "0x8a6f4dee79baf71a4a40843437c16b2f304785f3e56b32d9ab2474666fce2c7749c776bd898a65f4a4d542a497cb6d6d", + "0xa04a3484be07c2d60f1a90f9dd8d4170270a808cfdb863864377c2515dd71c152920b65fcd5f47004d27d14d7ee7eaf2", + "0xa984f6633ce3d42c75083ef7732e5d0ea15d91e73cf893be3ebac5e56defb8db97088c5cb3acb661e26bbb354ad91ce8", + "0xa5ab5b4b0dab86706d68c9ad921d4917215c4fbcadc8adacef7309c0c853bc3c2ea34b3868d8f03cda6f504793832594", + "0x88f03e55eb028353b70352dbe91f298ade322951ca115972f1207744254fdd01ccf899aa40ca747da8812dda5bd5f985", + "0xa4bab627f7de273f8085169cf05413bc368c5d9e5f58bf10995a8bbd95e511b1ce15d008405728ae8e8a83621efb56f1", + "0x8ed518d0f225b90fe7f01b0fe4c451589390325044f0d18a8c47bf13e24eae8627feb0c9e9514397536f73f33f67a044", + "0x97c73837e77d965f401b4e4f089ef4de7aed1126bef6be4e9002b2b68014b98997213e492f7aabfd2e47cd0917a11d6a", + "0xa99e8a55ed0385bd279e11a80255b375f2d59bf8b0879bf2337ab5e3be450a2ec05d1bd8867a633e359a02cece4dc1e4", + "0x82a74b5efaf3c217ee2bb56c9b8e76b3eedfc553c73177e59d982f503a5b0572b5cc0d1292820823307eec956c42b28d", + "0x9800ad3e10e8a19d65d5963673c183bd536b65e14ec18dca45e881ff3bc74eac32bef2ef845515ac4fd6caf558a6926b", + "0xa2933c78a67cb40489ffb8096c021ca017b99feda1f9c5d702227d7f0a2ff66a539d68a47ad90ffdfb5c31c774946f87", + "0x947b29715258ca20da5b17a8e3d99665b7e599aa5bcdc5d2d7830a2e3cd78364d51a3d7c0d8bce48a1992b27d1ac4980", + "0x86f2e2d3e160d3ff979ca70c456785b4b2437eb64e58adcb78c4aebc96b470f1b8b999a3ce8ce20e3d3f030d163cd138", + "0x958f4435d35932a91eaad0dc476bfc2761a85f336ad2ca6fe0c6830fe54e8f417434616df9e6f07a9454a4403b00b64d", + "0x8b1755af961e0f9f59651d56b538ea59af489e859a1c93726cee62649da0e304093d62db9a2c5854c8da1be61bde990b", + "0xa5e11042f73f979c8649592f6cd01dafb319344e379a65aa9200d3b636abc569edf822c2bc12b3db5c30b9ee74f2c981", + "0x92ac5584de1adcd38a2ebe361225f224e9b498344521be519faff77f87c1f22fe8e112f9df7cf960b16e358efca0db08", + "0x81db84f05f75a218045d7d5fd4620648bd4a95cf468cbd69787011d615778ba7300b729163e7c8abd1a5b0ea66fffbf7", + "0xac2f522e9f030a7c576fbe19041f5db3913af58da75b87e8ad64b93bb34850a79b852804dc68ad5e7de66d90878544cb", + "0xade9763d1c7e9f68b5f817cdfeebf31bb3ec1391dad04576c55fbe4bb13cf0d45abced3d51b5512c73b2d0f403906340", + "0xa0b431bdd9641595fe1eb8d96ba4fe86a447a31ccf36cd2f7d94c5c86a7d96bbc95b204fcfe7c69c1385997b1daea3b1", + "0xb3b093bd8fbd84414609ec9a108507f97d7f77833b93b15439423d2a2928e40b192247c8471cdbc12891d83c765cc6e2", + "0x8531a5ce8e0c44e887ebf4beac65352c8a9673c51b6a1edc439e08bda1354d359e1ab2e27b82636c6dc0daa3aade931a", + "0xb22c2f3a77ae4813a75004dc2c9593cb2a51c430c559bc7d07d83e95592883b99fbd0f9ad24d2d80d86c871cfaad2721", + "0x8b6dc7d5b8cb6bf36352fb19e42aa37647505436e1442eb1f228b0804916d569643102b2282ef66bc9a4442520521dee", + "0xb29a811ab81dba820242a990dc774cd937cd299495cf721cd11971b9f1dd9441ac687dfff0e91656b9764963a56e4625", + "0x805b280e31664008fdd874bc38e870db271027da70fc2246fa82c499742a9a8de1152275e0be61f307dc8f7a918e270c", + "0x929f690538a500d238208930b55caa9c489bfd3476f6be2d385c36df3159dc3d8bdeb24a1ffd7b028ff4d881551e2888", + "0xa92bbf103ad851a41e5230e1e37ec7802e08f4610c0db9706806afc4a247679b9525f9a534c70d970a1acb47fec9bcdb", + "0xb9f2698a39d6d7aa8aca181fc5d95dec796ed6eec002557d4b63369bd90aa4438c27ab90da4f3ce81168cb42f7400070", + "0xb08703bc97292c56833d8e61105f1431c334f98a7946850c6175f37f703ff790d9a1522c0003f08dd111eeb083235073", + "0x9355141cfadf46f37afb73414c8803f9094b06952c9fccb24a1f8c18a13fa7b1197321b19cb832de3f83ebdf8deee53f", + "0xb7c23f7cd8e212108906b7809df90db58d2c2f3a8e1f775274181bd81c74fd7c2f8d68bc7d4aef639ff4e19f86243f98", + "0x92728e009fc3faa08e81c36c268b3ac18627da7618c96c97598b13242286645789c15c99518a07e658d92eb8d2b89c79", + "0x8fbe36d4f2f08cd6245e8999728884c636a264451e4ed894d2116375f3d9eafcaa72ee59cf7923ed8ddacb53cc478761", + "0xa6b2bffd6bf8f54231fabe46ab2c1d014ddaa797d08e5914f13988140bf804019fff3ad07ac2cb31283fc3e74e28d0fb", + "0x886387540b5a7acc8b2bd107124bd17d6515697e09c85c4e932a6421965c872f014d11d1ddf321651e4b3564eed4f252", + "0x8b81f3ebc962e9ecd13a11e919d86ce14dd89d373cffa158b807fc91555a4ec1d7164504fb67edd9599b10fac5e32aa5", + "0x91e3213ded5f82e34389408e95d4f7fcd0f50ecbdef9726a289238e4159c6d3cd2f401479a1f785865e91ca213d2f8b3", + "0x99154b88ca5462f62031300177e571708821348e1027cad4867eebe42a6fe92a58ee1dc21da9031002f1b051351b3785", + "0xb5c2b7cfd87f2f65df07b39f8a26dccb16946fef6b89268b9300c8529d730a1469ba565a480d7c5ae9df8600ac50e90d", + "0x87df32def37370bf8c4c3a22a670bf5605c78f240eccf8dba13bf19c8a3a9d0560f8899259c4e51c6b0fa64d7d1e4c76", + "0x980a20e5cd352786bffeca1b8a31930d8898eff9f4a6b2570829248410bbe1c78105b6a61cce7e3ed1642e5e2af127e9", + "0xb18b8dbb9eda5cf333ea29fad7734235ac9e7234b49fd04f178136b15d97595d5b415a92455a319ab594b81200cb17d5", + "0xb713a71be9bd22ef6a2747d0bc8f4d008cdf6182e287c1e0274689e915a68150d6083268188c1f4a7fc76d21a219ec85", + "0xb86ff129a981359972bb793a81fd422e0b37f89e76fea70da012fad160b9eb7b029ced81c7e34679f6897a45b4e8da4e", + "0xa74a4cb9707156e21caa20b95a2a4b4eae8f773cf679e2073fca2cd3b1e502ef06de8a3c010833d525a7f8bb6bd24601", + "0xb51f06da38a76c2728cd01f6073f402fc49cf4bc5c60113a2700b5bb0ca500e465e541c467013a2804bd7641604bd2d4", + "0x9855dd73307d8671b6f9ebcf676de3ab7e37e7ac1544447c7ff34a213da46123b57ce23bb0f381da8fdefbcbe6c35645", + "0x8fb382c63f4c935462d013a0d3e2321d72fb4781c10afe6e31ac51766832218a05addc6dbb1f644aa61b5da9bccfd5ae", + "0x855dcff23e0ebbaa3562fd27c43957cfb35d492837aa71f27cfd1bf65a59a12d2beded9d09f3ddb4f801aca8cc34d2af", + "0xb7e7b317f10cdd13bc879c2fb0bfcd137af23e0cb70917e48d53b2bcf8c157ed7e5f58cdb966383ece9d3a4c92012746", + "0x80d2f84c39422afcb449aa68b34fa9d72e9de79a473c3ea5897f6f3576d2bb6fa2d49f0b44aebe5e68b11e85e066e028", + "0xa35b083749f8a5551f0dcf529e845aee189cdcc6ba779f4e88765adc49cc4779cdc2290598908ccedd8dccfdce29d53f", + "0xa30c412f4bbc2de80fe5c577b4f94442255cb3061a40649b0ee5357977503c6fe54821ecc8cc92d5056b6977c4695e70", + "0xa2ed0d90ab612fa3526f7450a43d45a2d9e886f2e5888ccb8405adeb8ca3e41c6a94d18a54b3cb1eab5b8f3851841ebf", + "0x8d4dd3f8f8a3d69bb217d338e757c814eb69e6a776f55cf51fa7c1b2f1ce5f8e9bce8353dd335e793d68eef676cf7c36", + "0x880d1ca33d5d3bb47b788a7ec64b9130752610816facec99af53b6e58a7e414616e9c815b1bad870d426380085f6b5cd", + "0xa287578293da4354f2c3c46d637aa77b91526f9618799dec4bc602305ffd8336d373786eb67eef01dbaab88f07f292c6", + "0xa86d3fad257a64c84954a7530822346da0215ebf4ad9c583f35cdbe16a02fd70d58ab34c93681fbf55d6075db6425cbc", + "0xa7bd884d343a6bde5f6c2512d81ba701fae7afa6389389e4776eacc0698a54c3ab1a0e1652c1a7a23d3a1d2a63cde8c6", + "0x8e0653c8b7279d5c958ab1b53dd77b73fd30d9781630a870d0a75681d38cde4fb7c2183b9c5758596ac556578b43fef3", + "0xb76a00c6f5093e7b28703df85bf968dffb70c455c91e75cc81189598df052244f7549d18e45dc70d98d3d86e0094ab2a", + "0xb270f2ad3dbc8b43ee2603c4e641be76820f07a4757cfa96be2be9c310b7e39b574572103253594a51fa9243298cbd94", + "0x977b8b86841ab8be7d1d50da7369e2bf71f24360aab8448d7748d59e010ce81bfe79530ee6f6644b987fc0d83df3ed15", + "0x8e18bc59841b7d56f8d9eff8818eee06288cd6ca86200eee7b5e6b230070debaf254a2198b4cd7dfbda8a1d55a916c8f", + "0x8e7a328ada969ed6289972b7f43eb5958d23688603ee6d118b6ccd8978378dce2d733ff64c30519b19007a78340fafa9", + "0x98a0fea70a219292584c69546d6d242cebb2f1d84f69c5aa275a257a87de652e721078b983ed67410e3a5eb0cfbb2bdb", + "0xa09fbecfd05772a9989008281a9585accba3850831485802f042413da533b1c7ee45a8cc679804340bd9142b2f9e0069", + "0x99890a6b273a2787fcfdd8e8500134efd60df99410e8432664a3e5325e55e78942f4bb11024c90e4c3618a70729a277b", + "0xa5f3eb1617a77f2d5c76bbd1bc3546ad1628be90fafa9a8b62c605d04e599ab2eb74b25afe0e68fd020daf4868dadcfb", + "0x8b53517d93f42b833f7669c131dc67f14c3b0639c46d3b02bfdb24cc9e642133e0c665236a7ba851c100ca733d673341", + "0x849fd288217bdb154213e79abe1a78672903e15429e37f6846019986e1cc8dd2b3ed28e4cb52dee1762a4dddb9ca95de", + "0x954d839198c3dd2ea1ffddf98050e2c52ee81b89f38d967bd30c6863672e43bfc32e1030bb12f5aa424983bfa31dbf5b", + "0xb52fe86414a98d0896d7a427d57739da35cac4ee24be565956d15a5c1cf5b4b95e5425dd2607fb9f6d6024549b59a4ec", + "0x9586070415a6bf1e11304d2819330eda88e81a88b9347aa866692c163e1af772be9fb747d9281d7aabaf5c9934596934", + "0xa5b78e5bea362df26a89df682df61287763ca1b87ab9618609c99e52e6ba047fba7ec828c0552ee26279aa8a48751334", + "0xaabf36b9dd465ae03551dc82bed9cbf1d22a2236ded28964334f7ad474f317f4fb8515b853354bc06181fc9af82714a4", + "0x910f0b2efc608cae8cdd39df7a5ef9e570592b31df2331baa7721708057188ae96e1b43e2f2f2c8cb360b961d687b60f", + "0xa5c5b131205c21ca68d6103f8499279621da337a743e4a08547c3b4507d52d2d6e5014fa5d920b351a6f53a195687766", + "0xa6898dac2d8748b8bae155a7d8c169e7eded73cace1e382c4dae8633f19463151399c5cf877f8ba344a698a98228864e", + "0x92919d8be671b4f490efb49bae145f419c84a1e81d3ef78761fa326f67d749ff3530f5de04f984a018065f42e852e1e3", + "0x81083de978e025f0b5995550fa17915d02489344cabf8a79248352d78dd6e893d28a5c5204a65a8873756a34ee3c0120", + "0xa6de92ecef84d188cefe29a03b564b1e7bef2a6afd785b58897f7f97a958573a35aa0767bef12a49b352de30b4f0dc18", + "0x985cb3475c7a9f582c11784cf61a1988240d74e49084a4c0f55f3f6068c4da0b08b136f8fa62e9001e0a265bf65fa3d4", + "0x97e6d360b504991d51119a78c5b647f25d5fcc1298631209d82c2ca40ead0380835fe3cbf8b82148b0b01b8157e884e8", + "0xb313df44b2c47126b58064599a0dd6ea49e5ace9ffa663de03ad30c1e95301cc68eed67d37ae6238469e45124c59bd39", + "0x8a58f70545db2242cbdbb12492cc11ec4d2b2ab0ed8450d21ceb573558d7bda91ab03c98736e13d041bcab84fd8248b9", + "0x9077880ac352a5ab0e5e15ac89b14d173cda0b41b6f7fa66bb357195f10cfcf491fad6bdb49d71cc20d99cc6c8e28d04", + "0xa09b2930fb3b1a60af8c5214e8c3f6deecb3fd3d0a5662f3885948f48d1836b5ad3dc74affc54dbeb5b522b90a17dc4d", + "0x9163bd2e5f58fb1d81007422b91147685542fb1c7e2c8421af284c7cbfdcd2d2b399a37123b58a2a349f27b31bfa47ab", + "0x8a3d859f141457f9d63818634f81deb5c858ac48bfbf2e1da21f4f0dcd66b3e1d2d8fe99c4cad38206b1e15dad94934d", + "0x86d3fec476b59782d0477ff333fa79922fb9fe3d6d6b6c5be9da9e88b006b46b2a0f8f86ba4159c5085e66e32fba67a3", + "0x8041cd57335bcdddd37651de2c3e92edc600ac23041d0e383baf55651b1b0960b6a601491608307160f0d7d48ce395f9", + "0x805c284059f8c03b2bf006b1af95ef726874c5548e93ea965b402931f42b189f9f674b6b52ff09df35320085172973c5", + "0x8acf781a0b40cc56b1013cc1fc3bc43036545ce35591f3b905543c09cb1ac1a70a074202b6d5ce3680be913200c58879", + "0xae670c448996156c80d063f1dfb03d7770201a35c71cf8e70b38d52dcb5e2bf73d5286d63ba2f561525d62cd67d43125", + "0xb0fcd0150fc0005ca438d6b0fdd6a70b121d35ecd74e62bc119bb0187cdf6bf674ce9fe01eeac5d46a68ff4d4210ad09", + "0xb752c6850985ab13a057028887bc84674697c012e9da0265dd5ce1e48f0aeddce5e07e3e7cb68ae17a648cd1207eef19", + "0xa6a5c71915a980fd0225847b45e2e9f3731c6b2a627cefb1e2c6a0cd7f1d0555dd32b6b601a7ae9cfc4b9d06a56a578a", + "0xb7d96f59a988a7a810c25018f7f85cd6e81b335a84504ec76c97d7257f9cbfe88215ec89553f0dbf39507d990b3a7f84", + "0xa7cea7b3ba43cf6ecc488c34511b17fc7b97150b2d265785c09c676ad3123b322db32e043c5961384ed6d90d20c63061", + "0x809dc467b304e9bda732cd92b15c0f9b363cc707432788971508b8d60844911ed4edfca96d8cc20b9874f1e38a2d1685", + "0xa5b6a089e022fe460d62c4c5228e1381902c9a796ad92c03211c855541a7fe27c5a39d9123b001b0b892ffdf0a1fa065", + "0x95d67a21154a49bcdc79ed5f2773b651c81fba1ad82bd373239f09a67a50371a147310623fcbc1211ac57aa154e8b300", + "0xa4a4f0ca8073407575dfd5d04ebf76f8bb467598824f2ce7fa74756803d9645d63c9eb3ed39aa202dabafa4ff0a0bf34", + "0x8a77374f6e449d94a443f2d4593a0c3e4925527e0653e873dc20756396a9a4e5696fe44fc1b49e456711259deeb3f037", + "0x82585a825011d6eefa85cd530685b103862aa0777510d22942d8f77a0a7f489f5d10e5b36ee38f66cc96dc57d13f5893", + "0x98e24625c31d5d97c789eacb91c3d51cc6edb38cedcc474deee459f55de557c42e4d0754ca4ce472d0123638eeafb55b", + "0xad4351c76d96c35ee37362f2384ffb809bf6a47213863330aeac1ff9be2c6cc7275f0f974e46bfb716a89ce1bdbd0710", + "0xafc8f5af4f9c38ae672d20e7bc3796aba23a41eb033619b4c0a06e07884e1e0c7a7326f069068dd22e69fa5f672efece", + "0x983d5af05af31f9082f381378fca3526f88309bbe51d0cea5860813bb0fcf6b32a3be110336bd728952dcd6ff8a26361", + "0xad3b55b67b64b188447a1fb10d027bf7f86ce0a0fac966d709e8b6ccdbb7333964045f0c4719c45c36b7f3c9ff73944b", + "0xb410fde230d8dd24b9f1bdbce8338b05110b130591913f23a34c5fd092cdd3f747c383f6967cdb529ade1a264a3ece39", + "0xb3e4f0a046f93c332be07058db00c5182a498987759315bcc3a58d9334e09a59333031c3144b59d03596925703491cd6", + "0xb77e58619c8c471531d9b2e5dce8f82bb8794223bc9459599a911440e64e0b5be1d37e289807733ddbc2858bded1c34c", + "0xb450945bc3e290df96a196083a45aa929ee080bf45112e678eac0a939db2ba67334ef782c855b9b354caccd94b3babb4", + "0x9794d81e968770a6e12add60b32ccbbe80cb2680b157d125461cc3db998691e836d98cb3b3cfff4f156b2800d426b955", + "0x98d1284b4c035e93b4ea0431884d91d5a7855ac6c5b1ea2a994e653cf77f0ac1a771dc75899bd1485066da17e40ee341", + "0xb1da89b14efc14d15b2bc967ffab85c41dc447b6a7922b619b5d5b06dcda725bc4530959b70355ee20eee7c1802601b9", + "0xb8e50ae98515dbd9ccaf27192e58a5c34def86b1d0d181e63e64439107c30254267969f6069e0b863c254440c3480de3", + "0x915f0c7dc95f630bf1114b02e7d9936b0911a69c932950ecb7f800cb1aa1a4e1f1b6bef6ff4a23301cfd904c39025863", + "0x85392fe0edd316031c69d90b106b6685bed56a0d8d814db2cd5d77d07b18fadb632694a214a176ef60aa0f82ea14b00e", + "0xae4cdff23859b7570179586549165c728de4ca254a5da29668cfda259d43a387b3caea8537888d43f713d458da6bd4e8", + "0xaa0b6a3e0555d64a5cd1201fdff7ba7ff3019e9ada1d86c90c626a710df3d97d2ed62d2b63e5632963e09cfbedf83732", + "0xadd726d97dcff922dfd748eb897e540a2b4b8bdbb4eac1feb74717bf086b1760a957f83586a57b5345bf4c73d791ab9e", + "0x9721889b6fd55cf9a914e5aeefdfbfb94d379c6312001ba50ec4bb1dcd03f95fdb45041330da8871cf3dc3c6a6b5e330", + "0x8eb9417573ec6af24a610da5260639efcdfc802a95aba8efa829dd70ff179dec061da9facac95b6af02cba6a8646f7bb", + "0xa477ad7d2885e1f081556a98b3904cd75a4ac7a8c27fb0ccf15d117feca59f891a677fb4ff4fbf38203055a9436ebd1d", + "0x95b3b2ff92e8a0bace130d165984966637a74280d0e056cebdefa6f825b1d55c9bc6e13cc8f263e657dba3dc7fa68627", + "0xb096fc33c038b425a7a922a4274d01eb366a488fc969497a575587ada74b9452a607992aa2d8b9de66705fe20b4abb39", + "0xa813ef1053ea6ae8a37f4da722f16b6ad0213b0ec7829998362292aef68c28357ee27a406b567a629592447db8ea6085", + "0x84248425c3201ed389fa1b64b9e1d151b5a6f5fcb8f5e28ebd665db57156ecf9b2fa77bca857200df9f54383b7c5eae5", + "0x86d0a3c7fa1e64111115469ed0373dc3dbd448e1098250e9e8c5c7e775fd1f267d49b4123c347af07a28e686d5f357fa", + "0x8340b2ef4fc2afab3a3d51b6c0361cef4aec3d5e1d0f779f9fcb258711cb79ba4083508644e2bd182fb25b21523557c1", + "0xb840749c259b5af5874750853b4de6f4d7a274e18fb77f774f5f454c82efc5979a431e28bc8e43bb831715c7fda96db4", + "0xb168d333cf20b053c1b2a915c3485200a7590c3c3661507990390800fb95d3772ec6815d53aec5e2964eaec19833e787", + "0x8f1bb538dd5005384f38f88cd2588228aeb0c6313aede14ccc12affa9715cdb938ed4573c391572f0a7ba6e33a1ace89", + "0xae4a8ec2eb938eec00e6608c087471128b14a773d75a99634671f6fed95f7b24b14f04b3271d1c32faff7f0f2d98547c", + "0xa4ad66552924a6831b657f8b318f303225b2cf29b09790a48285b028bb1420c56dfa2ca0df2e823f694e8e3b27952a01", + "0x8af4eed962eeff534234d7c34f1033c68e8cf798c99880a67eabf38b533570a3776399b883f8658265cd14277b060790", + "0xab2c6406132413cba89a951d919bbe123fe4f220364ec2282d8ee0c140ad8d48ded0df7ab56f8f18ec7526ea2f1cbbd4", + "0x9154df8800e26020155b98f630e640be97a3ac41b182fcdbcf31a3e4f233810e34e224c97df8ef0f39ccca29a9921fb5", + "0x8f306dfc5b8376a88a104cdf67eab54f93e478ca09036eb780050ba2e8112b400bcc09d49665ab37d21b5a2d8440b3c8", + "0xb768260e94bbabaa527b2af8be423577cec3bf4aec3c569a4fb69e1fb997a2157c59f1169065d24a8aa3625d89d988fd", + "0xaf06139ca7d240f2495314d941890c078d504b2bc09d98a6156c373de29781e7581f33adfc738650cad0da3f6e07af88", + "0x849a6e458ab2f4101167cbf75bf47ec1f9e481f556b1b9d297a6b4737584011d7881695bbf3ba31e3e4180696fff6407", + "0xb107e7aff27aa19a4a92d1a65679bf40e85ac6f08d4e5f14859d97c170ceb431858fa4c46d00131527c605164b5f7bfd", + "0xa00666055e18f34ce02e8b67b6f181327ec0a11547c0795bee61802aabef9a3a76ea138b905cebcff9c4c86391763e6c", + "0xa65cd8dec5166949696dcccf031c300895c5fdd53709a1897c61d795dc22bae2f7717e7ae52a9950f9d00471ba6257e7", + "0x8b49aeac3550ef28b5de37576a5d4e2e43bcce82de09f491984171251e26c27fd0a884daa6f3d30dda107dde4544b34f", + "0x91666b88be09799c7de9a5d9a9d4c1bc1b6fbc44c664adb15a2eb27229be910226514c2ce22818fd38b850c89291a7fb", + "0x85abf4084c735b20333b1c2145571b793f96188850bae161160b47dea7c48b0f588adcbe9cf80e05d17851cfe3400f1d", + "0xaedaee73c52d71d7ac3854fa41199615ecf49cb0c35d8203f95175d1ddf565499a8e9cb8d31d89e7cd9cb75a9fb56f9d", + "0x9413589f0746d3b81e2f88b280e354fbd63ac164369dec353e6259a2c4acc6bbcc10f2a851901f39f90da7e523d77848", + "0x826121abbcefe3ad431c713a1a2cef336a0f06f69980a14d0a8adae5640e9aeebf4eb82be4621165ba32ce5e16de4880", + "0xadbff68221279985891e9f3fdb7b1dc71db3e20213b7c8e1931e6f75c6f02e7a1f6f05ec0687885de55ac85440f372ae", + "0x99ce8b064f874cf028e85281bbfa43145893f80a8b12813d047bedbf88699266652de6ae9e4ef9ce575e67065854fdb4", + "0xa809a71a663b0a9719c0327d33215b63c6ebb12da3477da8534d7e8f79fb81e06adfdad79686e40efb2c75abde559a34", + "0xb26c4cd057118f9b12c9b86e77d370b3fdbf2654a5d80a7763ae98c68cc2769a7cb293ea89b3a08250c2f699b8d76e22", + "0x867c56da9a2ed672f47924cce82c9d7e801d6a1fd18cdfdbbe07c82091c70ba0ebc6008b0b9d505632a97aa23c45b8c2", + "0x8cf14633888f2ba0b02fc8ca7536f39fa290678c7e0840c58c53a9d2fe10628be343a86acd74b2fc01b0c03af0996f59", + "0x86696802e4f27928dd6b0287d0188f8067283496d154060383c5ee295a468df32a2e8e24648d93ba868120ac429b68cc", + "0xb15439762d0f7b6c98e6946b3c0a7ea0521845fc68b47fe9c673194d81a6cb375c79b0122e81a027f21a7fa4cd6bbf56", + "0xb1bc19c9a3756098c02bfe36429c0f0d8166a5c9274edc7f80ce65ae7d6c67864a457f19cfde6924d204b81f2a195fe6", + "0x997f1cc78d707f29e3eea0952b5514b34c2cf0720f33a3244cc466df62b13031bea13df2296270eed42b3667c53d6c26", + "0x94f599c9995caffc9b47543b822dd8f84f921fe2a31e82d5d0fc79dd93a4da0b87a0906b82fe7c2a8c23c7829c21dc2d", + "0xa7fc8a6ed802660bcc07d3ca454c415da18d798719dc2688eeafeb8971910377ce909de68721fd97c4d9fe439f37a8d7", + "0xab16f93e6df2464018be01fe040fea08c67e0b032fe1950fa37c7593c8ecbca24dcf0fdb9e1209d5b0def622f3f6e92d", + "0xaeaf19b49843e3fac538075dccbb29a63d55d12f8c4150185b1ae62de778c983632542eb495808ba629cd4cbd629e07e", + "0x85614d537efaee823452d0427ea3a2f7d5a3c988b10cf7adef8715becaa519a9b5174b63e401946362176dc0d65667d4", + "0xaa08d8365e78efc1919cbbe562be7b28c57eb05c36e8da89378cfcad9f21e134eed923559530aa3f62bec758b00c70ff", + "0xb4c2760454170276885d66f03e9fc4e6a4254547b04fea3c233c11dfbf71ab05dd755b9697b442ec419aca000152f2a8", + "0xb814059b189c0ed46f9dab604fca25d881a12fdfaf834a75cc2c0e1d8454ce0ed9f2a79b34bc5e27004903a48c6ace90", + "0x847707b0aeb4fe91c12ea8570cf0d16caece8946951360433c8a375a69fa4c01136172ff2acab6d5164ff6d3b5340858", + "0xa7a9304ecc5ff6fdaaba6e774556bcd7c5dfe8ee7580a677301dece55c6a8564e7c64b60fc4efe89ff73954f3c3f5b0f", + "0xa1a86fc5648edd58cc7eb61cc30c62edb5314caca5551ffedf088fc9c1b92ec5b487f670c5bcd2127067e8fd5faff03c", + "0x9086a31715283fd525034d59d4ba3465d6c30059b967b1eeb7d537f3bf8caf6879481ada2849167e997212f3300f8ff3", + "0x99c11903cebf722e1cfd63a46b0ae93312439ff2f014b6653fc61927ba430c432b4955b30b7f078c340f5aad4ae24313", + "0x934b7a8b7bcf0108ed31d35a645d73f661c064a6fc6a5d1ad417ccf1b8864623b0cfb54707f10baa86643afb5c5ec980", + "0x89d5a69ae8cc18ad77995ae92d30236d5a5ef00cc63274e318d18abcf9d936453d18a8e6392b52d2d66b51c18d904d6f", + "0xad2448cea1948f0a4915ab054273bdae33a08c494203d11f46888f852d0abefa310b50367c80cacfb602cbc249b31a71", + "0x807274fbe6f08c332a5d2e2ae12cfabccfb53511b8d83bdc875856cf15ab52c2d01cf706c9be428307ea62fbfd67f87a", + "0xb2f4fee9f32c0ea7fae306605b62d983b130e4d423e2de286bf9f4343b79e5c4545214250cd1348402d8278140c61c00", + "0x8a36f79ab3ee0063098a39382061ec3e1234e67087b9519d0b762aa9cad54a7e0bd5d24e2b0a57a690993e3182f3e83c", + "0x86668e6743a7b6d1ee62e70e6031fc8639ecffed38afdb1afb41d64ec402a308fe0438a22387d9b0c130ed301c39acb4", + "0xb816309d1730cb39b1ab00c5333c6962fd5f5d8b22f3c3ba987b1e0a0065334d206141dcf0e68eba717a4eea533aa6f0", + "0x8754e190b8f751aaf9f8e7076d21bd31db8d9ebbee6b26517b190f624b3a892050312cee9d73cf3d7245446c6a376437", + "0x87826589ac28f442c608faeaf3d63ff057af7724f9d412d1f2cce8c58fad0adde325aa496c6e4e8441775c02d8a74c2c", + "0xaf30e5e32fcb17226edc54030f1eff8af619c207cd9e42a2ded7f15cd29fe52f140901f0925ebe4e997b56f34d3f406a", + "0xa62a4e5b6591d336744481a0797eb23ccd0f580d04cfacbb3e415ae3f273761042b8901b0312f93a6eafc42a50f81cc6", + "0x968a9ccc95e8c124f4475c348a33ad2a52a42e191a93bab3d7f0d211df999aa081efa935391a8289cdc4a5a8f7433822", + "0x93350cd99ab7d3e51756eb01c89172cb406c1debd3f0001d2fa8a01018be5609d73df671e1ff43e612ddbfe7076d9ecb", + "0x8df26dbc565ea7e758ce4c2656b65c1f0396761c9360d7092d12c121d3bc1c293ed28d82f1057f4eb5375b15443e9258", + "0x80a0dc22fb4a12b06cf05ce39f76537eb3db9691ca466ca89b2585237c03d13fe3fcd311ce2b3dbd1b7382044b803782", + "0x818b79cab08e11dff3d55bb0f55333f6340c5b462609d43334c14fd878b0f310b77c542c74d3674a94c692de704e88a9", + "0xad1bda19b1bc3f6d757fe4d189ca82bdcd0a9c1ef509c43e3f49700f84be33bb9b8b8e70f7a09bc6bc00a78cad0cf9e0", + "0xa22ab44c676ba2b3889341fb137dfa14cfc5491ce4c3c1fbe2cb7103fdf720ff2b77806a40109dea9a68d8f072e1c167", + "0x8eba6af1659b6145676d3663b04ebe58c199a1c24837ac4969793f07ed97165d20bb0410421e561cb9283faafd9eb51c", + "0x81b216cf08a29dfc3e16b2865e712e15f494b914cb24526a96799a3078f200a3fd403767119732ca4de07203b479ce8c", + "0xa023ac601c8e0c22553068ce4a7b8361b0b37bef5705fa68a71c3cfa80510041cef3640bec2cdb4f317904521e99443e", + "0xaaaab84c8aea75303fec31694114b3ee10fc1a67357cdd675ac9d0e33c3279e3117d389e9ab017882d517131b14e6088", + "0x8bf9a44b3df3d7e0c776e7ea5eb76f16f1870960f32e7c5b63aee9b432a0adeebbd378c574ed60e15a3abadb409376f4", + "0xa93faee621d930f336f4fd952954ffcbdb261c9dcc4e60cb848362223374010c555a73c0563e7933d1596b0526bf75cb", + "0x88753d0e35e87f7572f2012a40bb757364af5cf6e5dc0dfd16d082e698d3fedfab3c671bd58edbf11cedca247e9fa55a", + "0xb7de5f03681634991d2aa8a0ffdafd223b1a0d1ff70fbd9c00d03f228c6772d93c388c02045461d51326483af97bca37", + "0x81f96d4fbef3cf00da423a1c48ab8acc222016c21f6be3df778342c1d1aa1a420faa8ce906bfcdf955be045efa4b447e", + "0x8dc75ec37122afaf0aafdbea333291ebb735792b4d5934fd16bf28b536fa759dd851e1de448c3efac3d2b0097e0b349c", + "0x9186f66655fc1c551d0233b761c6982a3b8539085ca9a2baebb826091e179026b90f7ba6a825f38c6a09b190a31bace1", + "0xa1cf319c9ed31ffdb2108b684bc21cb495e77c853e6c502e03f2ea08e88a0c2b4e31958004d9879242df420b628acd8f", + "0xb3d3e5a75c34640bb2fbc7b62f8aced8dcb4b9b165992717fdffdf765bfc81fb4e67f3e737e6f70f24d3c24812ec0ed2", + "0x86ee6ce0480f73cc89ce7959b4af52351317cb6406cc368e889472ee5567e8a98560dc1f13b87442c9a8c5d6b31fc446", + "0x9478256948d960e3148acec3487da232fc2ae6818ac2c6eba491adf130c55badfe83f9a519379fc5ed0b63366de86a02", + "0x898a8130718ac6f98ef673fa8b725af6012ef28be3f2320359a5c2c40e479969e5926f1864624ebec10f27594b24f618", + "0x906f45d4ec3f647d0c49deb95884629a04fa65cf91a075bcde67940634cdc98f76fea8717fc1e714ecebb337e9fd6998", + "0x874c5a55bca05fe52a5d1743b8254b642431b720eaa74f73b0faacff2225f448ef94e12585b2d3bcf12c140ee3e81510", + "0x96f76cf34b14263a30df2135131dea00074f2ee853677b94fc32e04cd9872424dd93b32c55026b89c18bdb4e58bfd19d", + "0xb62e2ebd543f3e9a11b72f45275cadf77b1033713625c7374c4d2284d63acaeb64977fd2fdc90145066146c311a68737", + "0xb1759d3b667af9f15da8d4e77440fba4193d0db159a0bf73df32215b2d292bfed7cbaf41c07c7a94ae1f04bab23cefb6", + "0x88423607f005af97b5f8131bdb1fd6d7cdfc4c2da4a4a14bb818b3ecf50c2ae6d3b8cf55e23632354537f5c0dcb0f48a", + "0x8ba63acf22ffc1576935467af19f555a0c27a4b56e5bf752163038f0010fbdbff8a2131124f4cf36a326dfc188740e77", + "0x8b1996a0cdac9c6d896111671ac4dfa84a3a3738c43db6d6788f1a7b8ccd6df16a31606db00cf0107eedab28af05cd7c", + "0x912a604a97457a6b46d48731fb44dbaca26e7cc70a4628dcf553b43a9efddc4e5fb040a1b89e31902888a7cbbf709333", + "0x86eaf5b2fa873bb56b94eb7fc823527ae50364c1bce87e36fc13de149f1fc937af858a25cc477277dc6eddbf9efd5480", + "0xa0169e6e915e7216b83b00b31eeda207a02c9db6825b5ea44134368eae5bd009b7c95005c621e0d258c33c59085cb66c", + "0x8c8ac664946b5e69b4e34ffaa486b745ac8afc8ac702e4a4cc36c59f420a81b31ebf8b875b1f572dad8e4ef1f547a1af", + "0xaa6fd75ca832fe60eda078fc81a1a529364cfa8a4b4fac071d89e33cdbafa7d88ff3df611720b48e6fcdca2e3eeea0da", + "0x8d30857ada34991ce6faa82b4326bc353691ca32aa25511cf3d52cebefb262d6db8d93521020a2d11b3ea085287ad54d", + "0xb78bd8ea8bd6a2fd5741228502b9777177039ac8f033071c82ae11fed7f0a51d8bc64fa9aee44df25eb4b3822d571144", + "0x90904aeb1a99c4818ef21498a583848f4d1ee9253d70c10b03ed7d669b587f8712fd26d4409f00fafc3e26b5d72b4c5e", + "0x87cc8ebf78ff2ad752843792e11aeddbfdc628e03e13e0db598e08b496313f463f481f3a17ec889a3acfd128fb89aa81", + "0xb4fd122c4830f339fc019da6372286d3a0565ac04d4f5ac4f28b2c066ed507316e1b7beb7b552f60060825977a2db9c5", + "0x86e709d48d03738ca97d6140f13effa03137570c43ef00469eb0310909f66061d9fb933fbcf30bf04f13839e36d45a4d", + "0xb4a595cdd219aff5b8d0f80b679e58d9a7ab9cc389b47784484704e7d2c5249981b2b86be4c37ccb11b9afbcc8070214", + "0x97c6bf26c8b28b982b7a56ff867b2f5785b37260b90e0ae680920f368478a3c88f4a47bc394c07bbe88fa1aa1776f255", + "0xaa48418728684c9a10992d1851b69e54529dbc3548fe46721758ac6b33f82254d56738b351d146268fcc56a9b7f05df5", + "0x962a282caf6f08a63aaaf7ed2146dd61d527144f3fdacf1beef36b34356df50302330598b8602f1447f6beb4439a1048", + "0xb55d325499ce03c9b1c35e6aea30622841aff2a2c225276d677338579ce83177c0d64d78e7d11eac657a30648ef702c3", + "0x8a91b9296e5633b3b9144f61e5436654cffaf04623a864ccbcdd21c8f981618a908e890f61c74df19ce5b6995bc358c2", + "0xa7b6b32333377df24c0b0194393a1487a72a8783e06b1cd00ce6bc39337b34ff58ace57c8dee5b7f0ea2c9a54048a61f", + "0x97db4494e4208c9f297b484cb8159e8f600c61a44e1d878b07d29f0406fd32a0c12ebccd42ee7ac4c0bf33ff54a582e8", + "0x8697bc039265f7b6e73c133823dcac9041d18634c68fe16412b4af41286a4164dc86f7e71ab7a493223a84e185cb6f1b", + "0xb18a66cf37f93ca0189201811e7de02ee029445132f0fd4209e5efbcef46ba6a28aaaee42b30cc7e97a25b08f4bbb43d", + "0x8b69f189f3cfc34cc3968a07e13d1cab0f5c7e093027a9fac38504acdf12e2defced4261a686a2fc850336187e017957", + "0x96afba402124d9ff7048200acf329ccb4e35dabcd609e62d04d25140729e110a674849037e4b8aedfc99c889b132cfab", + "0xb75a809fa3b1c17139962bc22ddfce47d38d017d585a4e76ae1eb8f02849551ff7bdae178cb4546067bbab45b7041ddd", + "0x89196f1fe0869f2fd18f5c01118853503d71c4073aed8bd9cfaf694ca4a9e87974a9ad6e37449bafd391a2045ef5cd2b", + "0xae52921b5d8eb5df7d4923aed1afb125cb98aa6606f8cbc2129cfee56ba3cdb7225a30d98ca9271cca67fe39c763d508", + "0x99f1cfd27833fb64905f8678a532aa984329b2369ade3860025ad334131a9550214297bb2f7d3569eed7a9cc558a5922", + "0xa77fabcb76e8c6ac2a5196666e0c75c7f6c73fd8a0a5fca32a454a9457870689c83f5821f90f28dfd91abc3bc62ee761", + "0x92a4b97b7c14ec14c74e06363b0ab2e263d0d7d84125e2cfbf659bbee996a4d8561992e19789e507f4c24e5afbb91b2d", + "0xa2387e7857600a93de57faa0484650289c7553b9ae5fb001d011f43e5bf31c010c9c8b5bb82e7000465b546236e79066", + "0x8641b6f2dbe9f0b83e0a7ad8098b0836af158fa2ee6ff1bcdf3e2ac8b3d25d2e5a24d515e9d549feab4e82b49e468fa3", + "0x937306770a47ab2d5d2eec4bd6d9b3a8ffbb8c8067504571609a7e7a85c665b34ad2662701b67858e01530907172768f", + "0xb6b1b89f261e56b0cee15e2f5284c76789db26a6ca4762500745e260bda40b00b65add4826be6131775202c8c6c4247d", + "0xb1caac20a1b2aeaf287d38d42987e2c381e74495d9e880eda3ff59821d5974d01c7e3c611f4773a13ff41bef0f2ad44c", + "0x81ef049b849d7b0a732579299a86f1cfeb85f27ecee4280066dedf6024159fd47f311f1ebc46b58f63f71735a05480c9", + "0xb3b6b657e64fc154eb33b6056b8279ef736839b56f2c8f8ca438cdaceeb5398b8d3625676cd393c196f664d7baa3a615", + "0xa450678001e8db1ebd8fbd5c808c99945bb3549e834a346cdff316ef8d3b49b818cf9642e5b8097181cf40583ce901b0", + "0xaf3edcbfae3c8f368958cd11c95df4682ed10f894f770783e967fac1eed533ac427c1d4eee51f968ffdef080593ca262", + "0x8348eee6ec1102884929736d6768477029961c3d6d09e9ebf84d2fbe55c0501165f274fc1c0549ab831388d431e051ef", + "0x8d799492659dc44aa38262f8a4ae37b6ba6eb10dd20481f652a1c77ee9a4529efe042ea873c13bb2ba3ec4792b167c14", + "0xb4d3962f574c3298ffb0958ac999367db8207dacf2ca9d563cc1efb42fc889e19b7f00db15ffa91d145ff05eed97c3bf", + "0xa3a7c0e45dc8ae816d8765bbf097502b56651c0c11a03f476e362b64ddaee223128defbcec5629f4d7f1f9c3e4cb9f2f", + "0x951036c2878582d84d90dff79ecaca673df4760fbf9e09e63d35facf3e3257be6e1bd504f3c3daf8ac1e91d306e80d6a", + "0x8ae85094b13d349e60c8f303550cf4b01e96e24fa3a9f12d44c9822c004f1b3e9cbd772a2b4699e54023176074778993", + "0xa7292b61d2667d74cf62a47aeb559499f19dfab2a9f41f16e7b8d6e77909457eb2aeefadd9d3d3f6db18a438ae53ea0d", + "0x804310f5d2ce8bcf9095945f931eecff79f999ffdd24abb9e91d92f6e405decccffe4a8d9e731c4553de79baf7a5dd98", + "0xa77d3af0fb79b6f5b6cb640d04f4e13a28f8aaad1f60e732b88f86de547b33117386636d1afc7bfb7bd1d4e527812365", + "0xa431f239ffc68f6b1ea13bbd45675f0323cacb279e11a14f664acbb15d1673b99cf3603b335a100a0e297c305d743383", + "0xa64f4c28cc36b86dca65359cfdb50ed3dcc06fdb22ad567c7e0f833c880e76a53c330720fc2b96235cb0638394bae41e", + "0xb6fcd2c047de58003e9af3a416a2cdb143899441d82c691fa46d89045a12d3b087ee4603b401287a0f2629154bfc9bdc", + "0xa06e3b863bd183d8f91dea6d0211913663b3924f1e3476cfe0f328ff7c388aeb8e5c97757bcb56992c104ce0ab6ff27c", + "0xaea78204081cf5d24162686a824ff8e72fc0f88388525d646af7739265f60695b7d80b53cd1ddfd046bfcf59aa25f5cb", + "0xa89f556d42541a655864adcc1d5d67459ab488143e1b4eb48c67af30a8e753541fbcb479558ac26e1fa498f74a59025e", + "0xafc385b6b08c355a05fdc75e9360f4ffb384fcd74e8c9db34bbae9e0c67e0d1fa7efbff4160b387428ed58e129fcc027", + "0x9428d05e17e5525fae515e1ba3f04742fad1a43baa2ee166d2f9431dabb46895b7345ad833d495c99939f0c57cbaf1c3", + "0xb7a62d36ae55e681d48c911e1a433b568871c65a97916f939bfd638a054d6f1136a78c96640779ce1e3afcf90e3bb23f", + "0xa45b6d24930d91fc610e57ee78c6dc7557cb2ad976cb92e2157769447cd7c9a6a040f1008be9eb5dda2a7b8c9e524774", + "0x8b24eddad804790df3ed82db7c0ba05082c61a81763c44c98ad436dcc7e1e89a2800ff9c2deaf350f6222cf4278fdf9b", + "0x895409dc0aba4d29ff322d2414b33c1458126c023a3d53b25b9038bb90372b7c20d3e9f6b791fcf8f76449fa0aafa758", + "0xb22767ed218b575f397ad8306ec48fe07e8dc3a9f2f090fbaee411b6ba673a1258785d61adcba007d748cb019c458fd3", + "0xad4b9e4164010c4ba05a23f9a46957c8625fd4281a4e76f76ef7b4d6040d2228dbd2e6faf22b4a966ab42f32467a4655", + "0x92340f1051f88c25a915d0504c1413146f37f709ab060e3859b14aff9be7f8c91352dcc3fc866910a84192d301029cc1", + "0xb4e19bae926db3e1e295ba856984b32b796d86cbc81e81c6978e989f5331f27ce9004f90536a741ca996d19f998541c8", + "0x91502e2a69aeac8e709553501311b4392dea3d5b6f14e7523bf780b8af246e1f2bdc4b29fc4ec3ceb725fafa31bf51e0", + "0xb20607db1bdd6136130ba9683d581f5f45d8623ec4a2d35946723e0d8768654bdd9aeed55ba38303d8d1e312bc4f2442", + "0x8fec23ac3b4cde8c18346dda1afb2b72d4af1a6c013dcea36cd8cbf7223626690ce933b920bd9137f673d0985b64d54f", + "0x996bba551ae3b76c5aafadfadfcf80fcb554ff26e6a9e14e60440b3864239129734115d11a89ba79c19e452525cb5a39", + "0xa632f25ec68f02f7758103caf613511a1fa2e529e0861f286b4e490e8fca6874af2c13e3aa6ca97c63f3c621c197ae24", + "0xb332292c6213c7216bb78612457de615da878619024626383914f9c28f835f1289818514038c30eb2bc3566d2da470b4", + "0xb5bd5ed7e990ed8abf7de268aa1ef7ccf5562cf9c92486c2472051c1b5506bc9e72594380e7bd00c91771ed4e9707851", + "0x8781393278ffd5c522ec450220698328e60294ae1e35f60b25baa290a125cc47fbf7435eaf9b22ea819d431de0656f38", + "0x80a308c1acc4363f9bc54e6831c5aebca2b2af47d699a17ae2fba24495984acd4a25c7c95b96aeae3027f0fef9549284", + "0x94a55b36389e05b848c6d0e6426a400d1596195c2cfb4a972b6bf8abde2cf86a932b769a90b62a65d0aaf388e66d516f", + "0x8d29a5db4ab3a1199946a79ebaee9de225284f0523637f90e4ac16fc609dd3dd5a71072c30e869fdf6f057b7806ec254", + "0x99caa565547b13953b91f0468b78551784d947b5a3fe1b7278e4a45b294f074a93281e9ee084647d1b24c83b39a0cc90", + "0xaeee1c88769e7bae12f163a056d19b0090c7fd866d451963bc855bda2736c41500bb97a8d72a1a077357419ca94bc3a5", + "0xa94bd8b793a57b4fd79a84daf1f7fed5820bfeb44cfec0248f6aef130fb3219e1bbce68a6a55d332b124e1cc55224c51", + "0x8528607774d780b31417bf85fa3e54a94e4ef6e8cc233ad2a1dc795c68c299abae209c46ba77c33ba74c6ae75ee004a1", + "0x930f2c302a87d6bd159bd6b4db43212e7c806e17f572277ab14dd9715a435bd67b3624a9e72d9a2777f9b2080ef5cc36", + "0xb50d97fd2fbe60105dd1dd44cd12d8ad62b8a3127329f969be917fbf10132f1c6c6fda8029deb990fa1ed26e8c220c39", + "0xb685aea07aa1a45941f5eb2a593c0d97ecb5a803fd2977783488fb00fe6580c41ab83ab6cdd678704311c5542129c510", + "0x8cec65b68f4b3b10d032d39ec4c448e6d76e7615560bb754a53c4c6929c2470a884e7d39d9f3e58a2a9f121ad4175a34", + "0x96279388cc3e91dba49763ef50faa7550c3b4c277b2a0b0ae3541a2f990f9352748db75755a7b13efaffc9b8df40c74e", + "0xa7599c33614456b1b02b57921cb76b01109811a82f230f9e7e82675d57757f06021ac3f514d557ed9f2dec025364284c", + "0x869684197084f42dfd95350f8a54b0c7d940ceae2bbe49ec18fcfd178b6b0d21903447509e0ef356aa3d2aee83701bb3", + "0x85e9ab73165878b93e0229e3384f048e9651ae29980f9c5e26492c45e180e09a3af9058fada434d1c398b43d99d13056", + "0xa453a46ae96e6330c1b315d1b5f37d160731309d49d13d6c38c5d7f0b4f23ff1d18c985c471564afb54e4477c5d28d19", + "0xa5999c704320d4468f94d647d83c9e8720c19782d2a03677143c7216dc434b3160d193389b0115dc638f6e2e12f2d441", + "0xabc7a466cd848304616b2eca049c4b7509c5260c9236dc1432044ebe3e912afcc3a6ffe3e27d5d79d3ad4636ecda09a4", + "0x89ca07faeef1118c6b840a2c328fd32a5709b31850057302a7e607891e11f3f9f62e4fafd420564ff10a35b9a44c0f06", + "0xb0002f9d2a8aa850b9f22dd8d3b7881e8656cfc53e6c2ae6a913d88f6934e0062f30da2702dcebfbfafe36785203cefd", + "0xb8527c70bc791c87f5fbc67e2856e45b7254c5a0b673d4a5d3e9b79fe0715b608a2f35d88a61eb1d8d7cb615fea650bc", + "0xb9be558dbe778ba11fac7080789522fc004510f7b740c42023d850946933362a173267106aea046f338533e4cb29aea6", + "0xb021f9e635e64d3c9b4ecc8075fb74cf0e5727ecbacad15f822c8608f0d981ad2c300fe6e47c6148a6b1a13cf920d85d", + "0xae59f2a83a1384ef0b5613e8843cc9a934f7126430df7cd7f5a8508e3d83aba83bf3d18be7380570b24ba0e00e05e0e8", + "0xb403e4d0495a0137a710c43393798593bf131cb8d49beb0f3b3d344554dfc3355ebee14e884f543bb94bf9aae40aac59", + "0xa73b722287df7558c503f89d113fe0c017765c73181eeaa9ebe6de5c8a15ffe76fdb85ab93051a6f565653046624216a", + "0xa7d1a28fe1d36b17e37cf5eac7e27549ce9f6eddcb36203b58797d3372371f3b195cd3432db54aae4bf99768969f5b60", + "0xa3447ece13c415c457b899d4a8b8ff388ba25bc920b5711f8687cc86e9c1b3f3af42c490ec6352fa8609b044e642e3f3", + "0xb12f2ac1e033b6a627e7f7822317f629c896c8f8dd94ad91512855882dbb10b8e80a1e29c3e39138402f1f7e0de673bc", + "0xa7c65988996741bf59888415fc2264495050cb13500b6597d9d0e034898121b605784f681962cfdc80b0af291c316e7e", + "0x8c40cfc07dd7a4bcf514f2e87a1830c911e8168b0b8531a2838d2a14e790922b76c4642ae237b7547d8a3625decc7f0a", + "0xb480d70b57434467a40d6dd066f51b9e637abd2f49dcfa6450460aeec2bc895347e21aa82baa1bec7589b6a5a694fa73", + "0xa919a033c24e96af1eb0cb1ede3684e9a3bc338c7ef37b67cc9e9982586f74072cc540981e2d1a2524e99144bb21a64c", + "0x921e0b350907e9993a596b80f827b2d40aad60e9c62f4b65a67d3fa4c0acfa924c93352dad6eb3e868264bb24904e3a9", + "0x8d5419cea0bfebaa9c1509cd748c8af3869aedc3ae27fdbca3a0f08b3751a3b870e8dd3640f4abd4b46a2a1e745758bc", + "0x8b25e6eb600de81fdd03584fb9db9a7bf4c154ef1482553d7bef880bdc5baa7b64abac6db96fcfc4408329adf8fa351b", + "0x88cdb72bee7a6768b7c24d124dd5e8b29f0c866a0624e5a7c4759962ce1d71de7faa97f7baa56d5f51e35bca43862bee", + "0xaf1d59add7df3b3ba234b0b4f758349225b9cee65691c102294eb7e6fb683d7588fca33ed97eda361060253acfdc36af", + "0xb19370b8fe123f1dd2ea6d5bc75e151b0d1514224f5824437166fce77ac41ac5ecc1e7c1e75b75e948acf04c420efea3", + "0xa1ebfe84f1c012524cb475e68ae6c7cec79fb3372f1380321a0e306d15828613589567efe8bb5784360aed568e26db49", + "0xa0f964e3cb594c359e2308defd3eaec476a638b6e1c216157009e11f7c7d0c33fb9e62c4243057cbca49ba315d4b508f", + "0x9391e5087374e45f03d36f6919463c473938a653adf3880571850374ef0a0e521b25ef84b6012a19a02ec88f0ca3891c", + "0xaeb86d4426d2836e6e10c3277583a37b6684ba35f4f30d2d073043f0a0148f763b99fc42c3935026b56c32e5cd0cecfe", + "0xaa98c07dcfb1b0a708486d83763511c7004896856e851bd83d25a9551efc28f059c3fb8752ece0296964e8c13ec829b0", + "0xa466fd8dc1aea7022a86e12a119b16de35412a1b461680f6a1cec408e9b9c1418a8e406fd4a5656c73488adddf17dfba", + "0x8c9b0e18a033c27731fb3d22b7c83ba7a86fdc2234e8f2a19d7659aa67bad7a85ef25264e8eb81af529feb3fa9340ef3", + "0xa371feccc2f1a1b96ad8a9a7d8db0c06fefb1f2800933134299027459b0eb8cd101b9a37c76c22dcbded01a74b13d465", + "0xaeb34fc2758d8b68d17f15ab3c299344ed630f7351c498a5fe7986f7e14d62e74ac9a8f5d2de7c6289771210539383d2", + "0xaff9e961d0acc71a077e3af52ced373bc694f9154302abc908710e500e908f33bdd10b3c41bb8fa8066758a18d64c667", + "0x98bd5a8751e598896e9aec90649294934f81c36d2d0fb60070e9b96eb47d0988f71d9b68f4c475477eb4c996a9265c13", + "0xb25a92c6260f389f6443a572960e0a52ab9c9250d8760ed148082584b2347ec7d103358c033266bec02374e69d0102fd", + "0xb876968bedba7f4712f5e5eea605c1e5fc40bc5773c61f08c32e0c0f3ec575eed3e13e48809983153beccdbca2123edb", + "0x8c4091ef8946c9b27490099d5c0b47c404b5a1113500592515deab1c3f2778bbe933b09c9824a3a7ccad2141f9b5dcc4", + "0xab85f95d318ce235929531e2e397d09b9906c58958fdff1209a514624a099d3b8c103a51b2fcfa0b17a8f008744b5d71", + "0x9016714cbe49fac5e7b3e493574078c462e18f6363f413270c23da6327731f71e2dba5dbf1da6bbe0e29f57f0c33f869", + "0x8c90df700c0e2d104ce7b76be7899209136498999f78195cd888aec6f069778d657e5032ad7db56381470dd1f519dcf9", + "0x83dea8472e8418aa069a0837a5c44835aa1e00979a217f6295aa35548f509fbafc7db5b31b8767621e4f89957892e8f4", + "0x80a1d673220144973ab70d977b94cd3d6b8fff7f82f23bd4b30ea393952951d2f07c24e6d411b2ec19f3bec13583d9fe", + "0x804864b58f9747bb3ae54c588dff46eb6e16b6d98e0f711828e97d9f019297b743aa2202f823e3153ef5bc4b95da3501", + "0xb08eaae2eca2c64001e1da7d0e345f96dbd3e09888f9ab86f178718ea5a04321a8b8633e72dea68cc05687042808e3b3", + "0xb962f91819dc570c2cf131b89882fb2a44a999b94fd1ea8b83f400e9b66075a35c89f0fe0e8dbc3a597cdd1aa3135888", + "0xa5f33e8f04a2d7aab44e832f8ab4640519aa4ef88b58e0a398e45347492b040043e494de4b355f07cb4bc728b67f1ac9", + "0x8ed80bfb4cd15bb87175cff427c6a1bfc3e6292bc5c2d04dd42b497bc068baac5602d41366448ee7f37d85a5d8437750", + "0x83441e746afadf64583571a9918ba5122ca987e76a6e37f98514b1a8a178380366d10ded5c70d4feb08be6fa6d4bc25a", + "0x8807fb8adb2aaa6833960f435ace162c01a9cd0692a4cf038c89ef7405600868efe7bdb3e8a3db48901367ebafb0a1c0", + "0x82c64b1f77fb78dec00cab089cb7a88ae16c72c94d0870bc92df11587feb62277eb941d2f7d3d2fb033d7bfee12013bb", + "0xab2f1e3f1fcde3b8b2c07135acf3a492ae7675d9bc971ba57e06c99fdfb39e1f68d1c826cd9bba872749cab375e44009", + "0xb4a25f1f5a2aeabc29870ab9a815721f3cc031ab1a55417b457ca6504e5e96e4fd0d2d364ae17738726c8f40cae9c36b", + "0x9519efa4774cb4de4ea834376d6213d946fe6882e2b36342f683762fe50d754765dc301569a836febb2c7c9dbcf44f64", + "0xa75de0d0320e8cee962d6ed4b07db718615e75543fb25f0d28ec5e76f56d72b18d648ae42d7bd3da18f54ec1e4497a08", + "0xa2a17aac11e732097b25c0b9f7b97d807dd78ecd33d88aea5ee0a46a42198d379a241e888ddba940b3307e9c560ec45e", + "0x936ebfc2234d46282ec4de88958553759d766f682d6f9669d2b77a2cb0cf9cea9b1ac02014ac3f5cd47dc5d8af2da314", + "0xb33def3135e7ad61a660ef1266d61216220c7e0bdd867b727ff3deea904072e33a195e4febe64ee1e263349fc9096cdc", + "0x94337e4f14752676a703fab8544ea0ab7acea0ef924b85b05ffb84e4476f1087acc9a6d6250893a32b82f02651a179e2", + "0x8f22942bbeca0118747a22d0aa13438e40bd6a383e310eafacbffa1490f5758504da4a11e6320e1c55b3daabc72c63f9", + "0x86e3ed934fc613d0b3269cf368e32e67f4add59e4dc1ecb1f016fbdc6c53101c2435f95fc36625aa8c69c596acd9b0bc", + "0x86f04807460e1d93f8eea2a284119d889659b5a6b124d41dfb2825b31685361e8163fc3a253a49cf878e316463c9ace8", + "0xb043b2a99b94661ef8b270842fe4d3c51891ec23ba749d9c999982553ecade6f658242b373982c9a3669a886889e4f33", + "0x8b6a33a68ba7b5932ce11b3f0e23c3da580510fa37668f2154c59c3bf788dd2276a2a8c66a6bba1a68084e8b9bbf378e", + "0xb54581c88d4880fa4a0ec6d3c17b6f0ba339e8f7100242efd3b820ac942d75d1f898259d6f1e64a3870fc301d9dea2b5", + "0x9449dc9bce23c7e3b41eb34789dc7765c2f7855f9670c1d145bbd1b2d1b47a9318862ef3738511b4f89cb16669c0af18", + "0x926245ae9d4eb213ebcb88ab2d7e2a7d198557721051fef4cc966cd11be3490a3f83d4ff48f5fb60cbad9c5de4b98d1c", + "0x8518dab07ab15887c68d0de9fe3c0c09ea6bfddb99c145b3f6ff84659e7799da93e97bdd17884b228772398caa8c2ed3", + "0x9969575cbd7953b6308391e9ce2cf4da466b3e730c9cec0e88522258639be35fd31abdedd94b445d7075919482513103", + "0x8b1f28002c19b17d6ac1a6f50afc3448f390b3209b1a76a9a024ceaa274de4588ce82a891a03e878ea08747ae5d98211", + "0xa611963d1bc45b60ffe6756a743ab379e4022bb3fb263f5f305a615c92432199c7e1060a79aa42f7662fa89a0812a4d3", + "0xa3c7706ab74e976464fc341e5a9f7284264c1610fbff02fc36b88e15d6859fbf40fd8c5e93c8237b97acaa0900a03764", + "0xaa623fb8892dbbf4fc02004a44e07c21a422e5553e4b02fcca24dc1f416a54eed36f2f7376dc1e66218e850772676e99", + "0x8133cccf10b1686bf53143bd3520515ec72e7295f6945c43bcef7304de597b767265a3a9f7b281fa353acbc3cf6997f1", + "0x852e4aaf4da9dafc988d0da13a7f31fe8403f6bdab88dec363eb8cb8d3e64c48ff34102f6660642749d11d69b613f8de", + "0xa616028c6cd54a6514fd9f7aa9ff13000eaaf39f582441f73a3ed8208a513b580eb7874b5cd0b1e9a542c40c5887bdef", + "0xa48ec58bc3bd4b512c21d3d55618e9c51836efa97cad42bf79e748542804114714db23d79ad03e410e0989055c9bd46b", + "0xab480f3750420119ccfcf8d32c4a18ca580ce88bffe81433c1d6999c221c8aac482de5c0e41a5531806bd17897698d6c", + "0x8522bf3b7157cd29e948afc8f479d6192364a11f85dd5c58d4ea0443aa6b655f55a80e6a3152fc02a8eea4c0815fcf19", + "0x86c91a6021e738103031c1ece906ff43227eb23088e5ce1b6a1cd58664d4a80d7bbcb0d56c3b0e02cba1e1c2ca22e058", + "0x8ee51a59ce6becf098256e19c9aae5ef0c2c9e66c587d9a32cb4ba1ee0b64c13e2e008908e35f43314316508956654ce", + "0xb94766a0fb91c8de2338a68c4ab08ce5bcf62f6efa221067807dc647b595fe5a342d7122111540a1ca6ea7743b6ee772", + "0x83f917b8f6aaeb9eb2eb742546e3f2dfc9cfe00cfec60051010113d55dba2421974098c157dc2601902d8f40bc84693b", + "0x996e489890dad3c4dc35faf53d870bf1cd76f1dc24e0cc8a1f899bdb44e89dbfc77fb11f7b33c270a1394c909f7a27f5", + "0xa89936283190b2d1ce8d166b36694afddb4c3df01bfb1fa7bae69c55d1acb4e68e5e29867ea33eee8031029b3c6409b1", + "0xb08e5a5d6797ca252d12428b2086e528a6e5c3965d2e5ff2bf83bc71ae9c0346a4ceb3bb2f2e3f8a1685fc343f36997e", + "0xa05bd12a7a6d52d234a1b3e9ddea7b18d6d41026a0d18251b1761f1cc863064dacf821707cfeef2dd1c02536f584ed94", + "0x87c638feef9c88a9f89d10b56fe4bef6406c1d734cd1f01006e2f2b331196a49c7184c10786e855b3de8978927df42bb", + "0xaa194f3e4d0fc1d3107f9564b13e6274bbbfc7b8c1e73ce6677cc66d9319dc34b5a0e790d6d44c614c11feb50530a252", + "0xb2ab7be7ee9d72d1015e94d006020e758b73f200dde81e89e52cd33f25aced0cd84b8c300413d32565c253edbcd2fb1f", + "0x8ec08b22265aaaf27a84a6cca5f0875a3ebc70fb36c4f5e59d60c55bdf2a4fe11ab7ba4b387f5d668e67682a0978fa46", + "0x93643b9541db11b48e0c84caccc8da9ff7696717aa176ce6d863446ef8d887f3159b0ab6fe1f79fac883a371f6736e93", + "0x8325654fd8388ac96935149165fa3238d0848151a04be57f2386c3304056013efb49febee0a871cfc2ee3c11bb029042", + "0xa2c15cbe5d5167f55f2a454390b61d99601614037fd67fd198968531ca2f84f3c214b971ef300a20a114fabc6c67db0f", + "0xb40ed63b0367174b5b4b08396afe2385b0f75ec2569fa3cf60f87e1b17fdee888dd66057be2cfb185e9f32df59b7a8eb", + "0xa466d2c8052a115f121177979620385bb07148e202631979f4ffb01e7e0f6fbce28747df9bf70b2168653096aa704fbc", + "0x99395136290cd020cfba0ca896642c245182e2020ca2299be8ebb2f62e2fc62fe0be593838f62681f6632fbdffd640c9", + "0x8e4f081d9a724bb54fafb66297a32f84687493464550c09259cc6f8abf770d076a514ae1d6726cb29349e27ef69a74b8", + "0xa8d5c941e7c03dba0232c763590e93e3d99fa519b0a65996d20dd20deed1d0192738f3b339edac68ad42016223733582", + "0x877baee9ee979be8ce3bef02422e57799dcadc34fefd8bf2baaf945f267883f67211ac5c06246f7b49f1ea5c99550a63", + "0xb6fcc2a73dbbba54760d244bc13e1564a3c61097e9b525b247cc8687ca08625a7330fc6b15e45a3ee508b4d34853d852", + "0xadf720dde6e9b5c63e361d69a2ab46ed73e0deb82f8e30f27ca2b19c2d8fc43e18ac04b4fa029f553f8d7dd79457ecda", + "0x8956c9038f3338f541bae9ef1f5bfad039d532dbbbe7814e3a3d5442d393ea6114aa666559d8a7e3a026c758a17c79d6", + "0x8d6de7f95f30a5a4b3d441781c7f819a0265852ab78b8416227089b489787c8ae9dffbb0bf88acf1b4c4d6b8a29c1a53", + "0x81d4efd71c9d08e9f6d7f7d7a2fa5089e80cc3f8dcc685686aabf3b4c8bd531b4aa07e328c0fde32b638f23eb78de588", + "0xa30053b681ed8328b5d64587b0d38edef0e366a2762cf5068dae177e4f4084c4333f9a5fa5fede93db80f7a8fd5fbf57", + "0xb340ddfaab2dcded58930e5dc2b72cbedd0e79ef652f34356fcf72054a87fc2373bd3aaf8a88af8d4633f73dfa7d9a28", + "0xb9f3a7809be0bf834bd7affa2059d9371b848dd5e5fa93e83e90d9e078a2fd3aea64410a72457c32d33ff1ca11dc9300", + "0xa9a8ce26a38dcf277ed66d75e111b07348101e93d03f446ea72bd903198122f8a08569f7125f6d4ecaeda8c093a00ec4", + "0x81e78b705b44533e2e997f549f46723a5e6b88241d7a86ca20448ae3ab140e967347abaeb8700594a0cddf1e82285abe", + "0x84724094dae5b7ece30cc01b5f2acc8787de57dc0c37a437c3e8e26fc03069b6e8562302a0f1c95de85937f07fe63d3e", + "0x97a715861e5bb715a17a948d6b6a389b89744e8ccd3699fdea9ac3d890fad027b78d436f8012b0abeedd078a20ba91e1", + "0xb710b2e7d87771416aa34ba2d93a044bb118f279fff62c1224c150ebc30f21abff212019f0f38c334daa5a96598ab900", + "0x853034af5ad08c563ed096ab2d0590ea644d372cb400bfb03867092768d90b7432d35c5506378d001f986c59769d6d56", + "0xb340ab52f751e9d516348faddb45f0115ba0619ec9db820f870007e3a4d305ba2bd0b2a58a7576296531fb78886b16f8", + "0xb8ed8feff520009743ca3313899a118df025a61e6e03bd5fd27898a23beab472746ca3636c22ea3835e9526e17c06dc9", + "0x87af435e3e4ef611d6da74c8d98e8d3f3de64ac8748105dc20287a7dc866f57d10a2b854f7e0e09235eee647dae1ab86", + "0x84108b1f0f0ff73a179cb1be1b2ecb4268e7fd2fac3dfc7f6f99889c90a33b4310946909b9eef31b256b8d0e3ba56bf8", + "0xa6b9fe966293e60bd384a1e4d472b0a72544aba41b31172ac8bfc3e19beaf51da54a66625d73a9ae22c7c4d1b0840a30", + "0x92e82e92aa615e198ba3c83c039b0adcf4393b3fbf9721b2e47ab17a84bded2bc8bc2bfe257d2d76162a87e8bc7ce759", + "0xb9286dd48800606b7ff9c3fe2abf5c49ef0a6b981711b5ba1f62952d6fc4a9999bfdf061c4664a019120f15e341925d0", + "0xb5da5dbceaa7e82f30fa5fde88b03ea88e7003a50eeb53e3f3aeaa63aa586900525b42fe1b699451b5d915d1b83c3705", + "0xb06072869fb8526d3077cc61a3c55d54a7a1197bbbcc875aeaf617d7d1eff3dd3ac243e2c76caf57dcdfe306edcab4d7", + "0xb132db9ee3ed16e6d76db9e6e3dcdc2b142cd70b9582518bbdf5415b3bb476ad900d50004dc0ab6b87ba697c6314b4c9", + "0xadca92336f3546ea50b034525fdf548a36049ca82d9d3cec10073e7cca186227cd662d4d66673e7214a6ed58cf75da6f", + "0x81bbb3fa241f9514575fb3f6cba8e34301187681354c94e7976a4205c0bb238dab52b29a76a5f0e0d4cb1bc82f8857c7", + "0x91008dda2bb7dfffd6746e3544ef540d9a1ac7ee9c68ca9984a1d81041a18fa9f35b8c4bdb44ef3a860c37481d5e9a14", + "0x8224195cf18ca0d8f01521a0ea92c9c598c556746c825a4dda49ecbe324d570a96775eb81dde1d3a14aa3660d50e27a4", + "0x8b355eeadef5fc7cececee71aec3ed30349df8f43f25da1d75d62ab00fc73702b405fab6d422053c2b0fbc7469ace9a3", + "0xa4d657dbf2bb30c1e57e0b63960663bd86ce17204979a9ab82624943ea370119f040b58b067a05ff6d1867a22a58698a", + "0x9379a367c918b2be61a9a42a495ec03f0168a4ec36f753dd37eac6e9f58a26c8510ae7b579a89afdee1d192edefb4bb3", + "0x85b37bddc80754f0432573204a1a4b86a550bfe9689f6c710a61810aa94dedeb28763ece40f28fb3a6f3791ca4c86b8b", + "0xb41c3269b96e190e40cc16e6c7cc8054cd0b7902a43c69b79d8ce471a417d3096b2271badfcdc59deb6271ad3e5a35b4", + "0x941185020a227b7a995f59805c8900f7f6ecff1e7b948a8b714f85a54449a0d41e28db5e17874e018eab72ade20eede0", + "0x8a0795ce082f74e4633acb1649b52b46ea2b4360860fef6ec107910e245b30466bfee8ce59a6854f866f55ec5cc7bbd1", + "0x931fa63550530af5a7ee24964b8b4d0c66c2bd59108131f375c7de86bce59cf52890191ec8540666c895e832dc312360", + "0x8fb86918190a3455014a5cbd15c7b490d68c10cb7b505e9233b3eacdf52e63299d49ded75fd74f8c2bcb3632a9c29d14", + "0x92c896826c9d871a83c4609f9988cec0db6fc980c8b88a7baeea2856ec2a0a56c3d5a846a87d03393dea966b534aa8c4", + "0xa9d4c780c94384f5a13cab61c734836f5729482cde62f2888648a44317b749135b511668834d49296ed47c0a3b9fa8b8", + "0xb7c26da09c3998367063fad19340f53217e8545535d376815773e201ef49e9e1b6bf1423b0b6bb363586f5f05307fc89", + "0x8c445b3655f1f554c2a7f6f7d035121939a8987837dcb1a1663586614dcf2cf47f73633950d8803e2781baaac52c12c8", + "0x8764f924f41d8c5c91fcd77de26ee3bbb86d5a5bfbcc45188be453c8dbe4b875fbc5ef5b01ea3a26b889d7b45417f173", + "0x8605a8186d5716dd5f955a7125619bc72ff385cdecb187a9a646a4bdf6595d67f00e777836261f3a69c19d2e2cae27d6", + "0xa97dca2185e4fcd7583b1e695333d55f54edd751da436b8982de8c344b5f57e35ddb61ad4a611dcde08e287c78c757c9", + "0xb11c576a049f93e0731652f1a1ade62b0124cb7b4e2b13f6505206c27ebf7998ebdb3d887bed01e43ce5c24714903aff", + "0xa46dc516b8ab4aabe35f38af1236052564b01d66c558e7107175064a5226713e8550912867eafe4da133f56950df57c8", + "0xa13e75bca5bd3b08030205cef4faa56a49e5d7da94bc41c708deb2f65343c1687aff26368915a490b89006185f18fda4", + "0x8ef5135a6f1f635a4966aa540cb877dc98c6a88fe462be3226c1a270c82cad8e091aa49ad39862f012edb3c93d15fb4c", + "0x99158ace79ceed67b6d8e884050c6fb7c7a1509e41f0d2b9069ce8dea392f17f88303d0942cf3c0af3ea52d3194123a3", + "0x8805c76ada9dc7e57545a5e1a874e6105592601213e22c1601b0b157b622e51f004a1da754a8fccc8f2a2241c14e21a6", + "0xac3dfe87e17ccda6196f621008716a14be4b983d187265eabb8f5eba7268cf770a70ffa19d1c7e77fab0373eca7a4045", + "0xad78a31ad6f2c84f6e5348f33631d876daa3d5978f6d1a77db80aa219e12c9ea656e9c18e6316f899bbf6c2469cdee37", + "0x8c8726f8f6fdc40516bb64b6c624a6eb4caa931e3a9ca8ce2c31c282ad59f0624ea290b804ba84e339e83422070df419", + "0x9303d1906cf416a184e15f13cf7dbdca5fb296b078079782c9044b9cbfdf06b0c965305a8d88678b53f0a10220e56f4f", + "0x99b9735a77cdc1c675988e613b3e8843e2b0469030a33f5c14383803a1b20e328d45d2fde6ff0d15f6bc2eb8da4f4d88", + "0x892a18f4ceae3fe7cde8f32b84c6bd3d9ca867143a30fab4f939281cec12587929faf07225725bf33ddf154b90972214", + "0xa100a35a2865bb465830ce2f68406d8a92bdeb21056bcba28c0ce8ce5ddfec6e293e926d764499e53facbbacd3f72994", + "0xb797ab22a57520a0584edff499cd1aa1663d8b3f411faa542022c5f1a645a3f952f9164f61d200e4500673a8d95a938c", + "0xb1a457d100def2e26b2b30617ee866264a3ea649bcd9edc7be132f5cad02f3209f5dccb02b95a462b5af9a71fb88a341", + "0x84c1f6d4f29869a359cf89118b1a80224cb574393fb557d1c61730a1fb1884895c4cb07f23c52165975b89fe9d6f5a77", + "0xb6d53e49025bcd1d7960ce46d4f64ff8f29e4239fde1b19e5167d506b086152da3bc3b86fec8ea531a20afe1c785fa59", + "0x9635b053c03d1be0bdf81e9876c63e8541b793ddeeb2a8f3ab0e44fb78f81a9e61f8c68ce393c7c959b62b67f9724409", + "0xa19ca9ac5a345c96a607f979a958d83eef4350ebc9cea0e0aa11469dc554fcc39d9b22f8a3c92de599ca08ff4152ec23", + "0x8e7d45d35f6fb95799846fab51b0ff2415857bb54b049694c1ebf93f45167b8497c3341b656f194edd5804195a7c96bd", + "0x87c05c7d5834394507ad3d363dd0ca5132a7763644e354c3b7a803fa594d951084d37942f59211660f10098cf49adcdd", + "0xb276246af578557aad38190878111e804db0f29846185d7033c913a31e7657d035114448ddfed2f3d75c04c79ee01e79", + "0x868bbcf14f96547192053823e4f85b50fb988da5c4cf73f5cbf23953252b665ef7aea4421c8baec90522f58f027a2b19", + "0xac2be3dcb8082b64a3745ce0d2b97cf341483713e1bcbb37369123d6723968d3bad1410467aac7fcd3b623bfb1d90d9b", + "0xb1e5cf361e0857373814e8db7fc275ccc1dbac8559e8487cc892bf82d4c6be00d1b2ffe40289692a70072c5f80dbacf6", + "0x98e16a5854635c72bce6e263bb57c071194df076e1ddd81e645884367b730d4d557ebb8c74b3c582e09046d2b9ad8078", + "0xa0016bfaa348d44a3ef814b348f7d56fa83b78baeed4a7b58617b6f4772dfa990e912ebf91c2321307884be85dbf81fa", + "0x85690a2c5cec392b6f98cd2d03e4204cc51868612543c7a3112066ebeefd4304c5c8b21da44534224398648b413634f8", + "0xa3a1d00d0fdd8c8cfee153347d590ed78cce48eeeb7ad42032a95baa73cc458d46882d0e9707f3dd519b1844f236bcdb", + "0xaaf2774fb26da59c115a28d86f0c6320368fc6d2c0bc2b7e4516cdfce3058cb423b0026b6c75030ddace9ccb7f058227", + "0xaf507cef7320bd003526fdf43c04af46beaaca5b6ddcad835ae14da60a2ce732b453d8164553e95f2b776df55ddb5efa", + "0xb2656c07a8ba2a2248d0313a7795b99f5acc120648c08e3a77fff5cb9b861827c94d4f2f99a2f2dec1d1667ca3ab26af", + "0xb426b97a51f0439f2da2d0d934693aaf52482bbb48893de12fbdbed1b2155e30791e7098baa18f93ecc45f8dea4f22aa", + "0xa71a7e08426518ef7307c2a1be7aaacd843794601c0d49f4f0e474098ea0faff74fb5ae2bee416aab849afe04be434cb", + "0xb6d510022dd3b9ca35e93ddd2ae77877967dd6966706f339b2197d2891bf523b5d55b7cdc80274368333f9249b62a7fb", + "0x95d2f6cec1b4038f56c571ee0f5aa14fe5fe7b9a2efab89eab4c51a696d2ada549a42095245bea14d7f7ffc69ade417b", + "0x89147eec9de685483d0a5e21b877cb550518a1bbcba0ee65e9519c294fb0c422a729bb0f5a8c8e3fe77070e1a89fcdb2", + "0xa66e7116eb277ba900c06fa48baf274e2a6865977698a504dcc1d0c20f90a7030bb2a841fdbfaa5c8ef6d81aac4fced7", + "0x815053a8483ce2a84a34f81909bc3eabefdce59140f0fda6da77ec005e5dcfdbc6f289d0f0513efbbeef0358daf94025", + "0xb480d2b6320ebf29f3781f04dd88e835ad81d2c63b716f6f244fd2b113ba3781001a34189df586cd629e70c2baa0e5cb", + "0xa74281bddc3a93503a695f0375121b3bdf98db4b2b053eb2cf0773647f6f69d1d98a61efcf82e2a823035ce803b82001", + "0xb84fb99a6943447cad21bfe2b34dd8da43d349e53e85b73fba8a5fd0fe3f41e7dc629960b3325d08af1544e5dc66de28", + "0xa8d11ccfb0dec31b39efeee74c58536f29abb02d06dfa11acb7134cac626a17ff4e204d1d138a472c63c629b6f8406c4", + "0xb5017d42a2388d90bcf4d0b6e015c63612a0864b2b379e9cebcf2e869e5fd45d2713bc549ea472d77e82fa8750f364b7", + "0x83c8e090de4ab6ed169a033aa4ab84f7f3e2b54186106790b30741e9d87d9a5d61bd6a285447e0d1a8e1865ee618a91d", + "0x8db64f3a1680cf461f9afaed4e714709d37559071bcee52e13feb5627c1fa7c093fc8923ede3e70db07563d2d1eae69f", + "0xb6d20dce2f50b78b094949e64edc2ce1b077a3258692ecc2cdaa01ec19add246d0832a319bb0d4153198e3a35091d86e", + "0xa61e585ed55dedfad57352d2abbf8ab336a999a5abbaefeb5d0da9fb0d5bb791119e52034844ffeecca9655675d17228", + "0x8ff58b27196f589ce0d3461e0c00d695da47a79809719b4bd4a229ea7bc9319469744f2254be4469092b1a27532439e8", + "0xb5edaf7c3f9dad7a54908da0e7a153d69a6bdb99fde07fc42928a0dd38031e32dec81c864147066412a8ca240e7dfd0d", + "0xade064bb3f87431a32b361074a89dd280cc1160a57fb3cf21eea5066e886c7bfc3655fe39099a1913b8b53242b23b2ff", + "0x9169621f97887db46384b43ca24b1447e23fcf5abf141e70fcd1834e9d691b9bfc6e8059d060bebdf9922608593bb972", + "0x8727bb06fadf0633fb8137a54d6912cedda0bbeb0f93af97deef3490b1b47e58fdb37a972dbab1534a5172ff0c840114", + "0x91991b98243bd7c138bcb60cf703a9d0828f6791eff5c2c1c5cc7e8edda258d3cf72680bff2c563c8e964f87450a3037", + "0xa1bddb74f5892597ac687451b932449305d6deba20e97e10989bae311d532a7b72a3fab08dd832589e6a22c0fcb548dc", + "0xafc52ed64208e4beb029d1428697fea6add02210f613551d1e5ba6011c5d13f66ce26b3dd2a39b30186c566b1af66c06", + "0x929bb88a9e30862be5f45c002c11537780d151f9836edeadcaa4a617b0bf958046ce331e15bee646f9eeb4d9ff854661", + "0xb3376241793ab9f1732997cdf515b9114f88bb2c25c0bd3f3b22e5b665e1ae94fa3f6a9f88de37b7792c3aafddc682a2", + "0x88fef7680a7fb665043264c9733dcbd23e20628909278711aad2e54f2eb8fa3d07011f593069b6ba7ed312d9ddc3a950", + "0xb031434d514d0878b7011ce2840e23e94a4386034dce422f37fde539aa35cedad1511f9eec39fc23c7396f43ec22cf92", + "0xa4a32f1e58c4ccb2cb4ac6c2dd8acafa292810c77126844f33287c8d522bb8c32dd89ce8f7c1dc9a273165b0879a45ba", + "0x82e5b11b9fad7c7d5e2a8abf03943aef271ffa43ed8127dfd85c7957b59d7cea56039116edd0b0b992262751c347f75f", + "0xa650327144db1806cefedd1daec1de3164b77c02a0aa652371ca0401b50ec3b7a392ef6a80de6d4724892d71cf48eb07", + "0xa88d8370d88379b52bcaaf596c32faba155db4857bbc7eccf89b5d67a97ae481e53e81de6c9461a6719d179f3ffbaf16", + "0xaae8b3d1b1bb0d71f19e37867885a1fd550f7805fd1306881515d77e5f6a990e0bb40c685e350ed09eb4a55298f3a393", + "0xac024fdd79688628ee188a7a9d39cd1306883c260dbda9e79eaf2d2f57051b5379834dccfc641302cd12a8a24fa2224b", + "0x90cda91b9e71b7bbc091b9e8e28d79f0fce42255e24a7a3bbf3348651405c46d3b6e2e33c5fb5e99fb4d0fbc326f77a7", + "0x91325730bf7d71855ce0462a2fd0840f3753964b296f7901e1ad761f48fd133371fcb805c315c4d8cb2ffe34e98ab9cb", + "0xb9e1a298ce9efdc004903b21e573c113c771b1bb5b25e2e88baac6dd7bded130016b2f09e50a4346c59adee607a71760", + "0xa703a60c430e365bdf9023c923a04fd9db427ca0da2da8dad6b0f0d5d352524943839d859c15dca64b590ace6cb1ca89", + "0x995a5ef468a38caf66d58880245064a7c0ab520ebf3c9e9f956110a9dd68658baae22ae274a48d59464c8d37d2f8b643", + "0x889c6e4516ece0e0fdb8c99aa482f367f2cef0ae2ce0987b6b602f6c856b02fab27114a6f4b82050738bc98a48ef5837", + "0xb432ce5f638aa48ba952b9c2e06ce822d531c9a24011d14650cac0722a4c5ad1bf22109a2f429cbdd22a567ce6f03094", + "0x86fe41234d309118d1256a9ac79b7bf01da1fdfcfd579b655f31b7c4cdab6f687d46855d56bb11bedd4b0be17e892b2d", + "0x905ec536f23dfdcc4f8128fc1c00daa877eb3caded7637dc911aff0e6279eab12f1748949e4bf015e4f8e30626d3177a", + "0xb6b9f47cb82244d7b1102b37cb52f5c9336e4c05e4c90f5e448fa92444bef12d2fbcfc39af9e1fd05811f5f864f12047", + "0xab56e7c534ee1f921351dfed3f3eaa127869849b44540b39b0dc021b3dc4dc94027e4161f7f3ed40bf42a1d08315264e", + "0xb9c62b4e679dbb3405733bbe0740450e72ccf39bf953142cce65fe014f132d5af5864ad96167027012c98dc8b8889e8f", + "0x82b8036a3fb6f648c6fb0492334fb3dc8f57c32779d4eef78ac2becb0b93f046dd68c2fea3b5039c21ce8e1efefcc685", + "0x8525738182748d6f901650cc328ae498cc3c712300441042441f66c683e06dd741b644e8e98732552e55839b66f86b82", + "0xb625cca7bf4ce510f21e8197b223dc49e7ce245c5a5d1e901438eecf7160a0bd37d0196191b1d934779f4b6a387b6db4", + "0xb63d753d728670f3b63d4c24acc4a3d4859e5f15ad775e502fc50d7ca42b0d2484a8649eaaef9eb22cef28a23e10d5e3", + "0x8e951028c0b4c5a691a219a6dbf348ef66edef60796094d5f6abaff1ad5802b53a5abec9b8b3b3b98f8b5858672847ee", + "0xb6b71004d898a3bddbcf7f730b8d5c0d8bba0f3b508155412446732ed9abbc1d03a90864f4689e6ab207aed495830e1b", + "0x98f33a74e36c035d9476b198dbf3a75573856264d45313e5bdd89db291dceaf4084917a2242b0a30d3b1ba4ee3016c42", + "0x912fdb4358fe617d7981bf9a9986dade7fe279a0445d7b14951ed77eb88c77c4aff4162467e40fdaa9dafe78da0ab4f1", + "0xb17bdf7a896480ae70b3696cffefbca468b57493d5db59362dd85a3da296e1162356358080c8b0a7f3fde798a3ad1d15", + "0xb47ebba84e62bf453ab223496a892fea2244ba6c37615c3db31c2ecc16a5f9519dd79aa710ec1220a2cebd254f7690f2", + "0xb3361190434ab75e46a40e0ce21ccc251fd0139bce90664bd33d9eb6400317c3210509e4ffeef604c7b05b260544e19f", + "0x966916b3966d7d33be49fa4eba925aa2f92adc2d0228d1144ef633dc5d67fd8231087c488b492688fa142a8cdb45ca70", + "0x8ffb1491d4448af82b7cab5409ad26d99ef6ef08158c73a9ee9626c5a84d2fc6d852e2c786c94b47b5931c7194d5b82a", + "0xa2d4a5bb458688b8f593f39cce2b27fc05f8ee3985f4c5be453706e8f174d5a6585c2070c0bdbb54aa1d8e79b5ab40e9", + "0xac180389d0432699bafff42a4c3da59bd32ab1bd1c4b4a4829580577fb3c5eaf8aed4dc61a93262f23ac44255e6c2b11", + "0x87f8fe99acc93080e2a2ae51eba24f0b146c1355855a202dedb7deb8e1cb5c6ad8664ba0e93ded5ce253597fe015fdc1", + "0xa554d88dcef521dbf5e4823bcc9145c8ea98c598cab56c85f101ca7be82297dd7f361d457966bc69584adda6d40ecab5", + "0x86ee126cc839d869c7e91f0f8d919929f66c1f67675ae8c5eaf6bc35866580c49d45ec8edf0891b546ec2fe7bebbd304", + "0x970d74575be6cabcd2e33a8dacf25b378ce750478bb44086e1821c97b6b27055b7f00cc8ca189954f0150de7381c80c6", + "0x963badd0cac713d8a23dabb8ac7da5e9a83ca7d580ec81dbbe3e5d53c5c9370b86222ca685215eb282c8f67a977b4b66", + "0x8d2735c85136625b3f8c4196a8f892e276845ca7c876648498143f1897637807a9a5162bb90773099a7b0cdfaa292263", + "0xa1a8507bb8a300e1df882651b0155e46a0f58399375f4e5f993251663b5935a76a02e60999a4851fa082a89d5cec2e63", + "0xb712dd139d791a95486d8fe48e35bb8bbddf890435dbf8dbb670699dcfb143fc582d4bdc8a6751f6bf58a13dd8c2871c", + "0x8f108fcadbaa43dff904a23c89d809746a9f732be817c2c882ac3493624aa5e49af7dd9b46de7d9d01ae982bb78761cf", + "0x80e270c6620756d3d127457fa2e51592604f85479a1004d63c184d7d2ffe2eea4ff75faa436f24bd1494f4eaf90543be", + "0x81f039fce432a5d3bf9649ad0fc2d93de831f5b9c0d0e5fa92d35b5bf4a52c739d478289c2386efc964026134f91ac0a", + "0x89401011d51b6106855487a37459351f18c39f08ce90b15e52a876cf36e969a9c9fa6cad94a55b844ad45fcf1807f705", + "0xad66c149ad105ce8b53d38c410d73a3cb3ec910a9f0ae798f3aa5207501c7ee39b85f10e91b4cd91e6b280f3912c492d", + "0xb709445e56d02a558a1496bd2b9115d2635855b18984cfb908cbd54cd279d29ecab21cce704cd9ebcf34456dd1195d79", + "0x851059069d9fef4eadf6ba508ca330ecb7436ccb91d09f5d0416874f9fbcdc56472d2adbaebc63a63f190b6abe7650d9", + "0xa933c1b614e6d5a58c599b7189d06bfa3683995f449d636805c8307195d8e98b62ced873997898d6b1b01f6e6a52b743", + "0xa692ba436613db22bc30c3f36a516971158d5489bf2c50c39d0627a74048a6d0b229606823f37a0832913425ddc30d06", + "0x830999596d203b96329185c100bb7360189a50f7930286c36544d20e57b8418c71d8db331e4352a98f380c68a49b2005", + "0xa56d7c262bb3d443fc0cacb2b61f24554ce35b8984fa3418bb4e271d5fe4f5378ef7b12c6cd02f537820040bcee95f98", + "0x844a4e9a8c9eea0b6f929a80da9f4e4e273e999fbe182d3855b0a40577afaced6f8ea285595573e99e13b6a71b985c03", + "0xb34df6205fc429c9b7cec189b2634d49a4877f22bb8060b9f7baf8c2eac4e1d476ed1f30fff1f4c019c65fce96abc554", + "0xb3a97648b3b79cc513246d3d1722afdf7645e7216af233645fca6a2756686592635facec913d19acf99ee586436cb58f", + "0xb9cac906123f2a4aa13d5d7eaac84e84eeb0a1b7919526de5198b5475fb815ce556f8451c953bb0bc910c93c6fb3fab7", + "0xa5e441019d492897de73d31a44a0055fd04e8cac894d626d0457ffe9de5394d0bf851dc5941790cba388b403b86864ab", + "0x8e3081cc7999d91d787e4c0937c9e22c959d2ba4be6fa04eb97471997ef150836a910ef28455f117dd54fa9ec655148d", + "0x98eb793d88faa691ecac3a7c78b25eb3a833ccfd0275186a63b1b1517bd2b984d9908c84e55f044b31c2dc5e251d0414", + "0xb38b5454c2debaf1a4e9e467c6205cfe26d52d1c1dde5356c089abfd6a90dbae89525442419f108c7c8e82e34ec3d5a8", + "0x942545089077b9f27304d2d6ceb3d549e983f100417e88332bf05bebfe8d42b75a96171ab3bcd049acc859f3cc9ad1fc", + "0xb9d444777403590be63076b5dbd9325ad58c1eb244dde2c9628234b62ba74f6b0e956642af2d08cc65f82a1b2e24bfbd", + "0xaee8deefc7ac67882ed7ee6c01c08d7739b6642deb2614064c69ea38c5c65e06cf609bcaf7db74545199cfa6122f23eb", + "0xb3e476268770abfe0cd64a4f878c58c027ff352569d8cf571bb067368e777eba6c003d344746fd006c8bbd474fc3360d", + "0x858137d63f90f66b9ef2a38d7ebfdae1bb89e5bc1d9032c96d699ef276aa2d7461366c00de8c47de9231d9ec436572b6", + "0xa3dc8fe541c9cdf89d83753347d8c573c49e8471dc07b5d41bc48ad1b10a3fdc218adaeb72bda0f362c8af8e1194df45", + "0xac75940ae476a6ff07cacf70a379096786d10a5a5244fa5c466bdd8af69b1f98e97a3a27877739dd4b223627e0ce6d55", + "0x8c6809f893c5fd03ca80d845147a82d8d54bb7dc6a688733b1404dafc360c45d5ea742f98f6a70ac2decfcead05d876e", + "0xb0818eee75f08ab207832c591aa783193aee5742147eebf75cf7f1eee6a6d8855b309db4f7ab51a16ab77bf619e14fef", + "0xb339ac167debc92cc9132dce076bce281e7f1b9c88978d36e1b5b9bdeabc974af318ff142f746319681764bc4db191e3", + "0xa51dc040c75a8a8bc3b0ecef47ca313ae13d9560c782ee014257ee728a09432c4486a3f87b5ebab690231735fceadf80", + "0x802500a52dc271c52f893b620952604b79d25ad243489dca7cd679b22907fa85947c88dc04463268d25dcccc8a6c34fd", + "0x97b136a881f500b07e5b0b79fccb84b93dd108074f92a1cd76e441239041ff389dbf03483fe76cf7c22a5f40b73b51f3", + "0x9155dfb5d7f7915e50da7a715d1a5ac5b43d7093546d6d342ec8b69d47a86cfcb9dc11d8079f123854033b8d3e1ec928", + "0x9423ac1e11f70b5d0cbbae48b7a5be8350387460631126ebda095b3b33a7ee2845776aa20ad60e2bfaf975722d43064d", + "0xafa907dc76e03d10cfbcc226e50e3bcee56baa4acd8db2cef8e484ee7b7bc536e1765e764180663710c4396e22fb4dc0", + "0x8b6fb4bc641fe2147d3394322418e2e8e091718e3b54dab8d0d6bba687bc300d73cf1b17f81e2812f0943a8bbc1de538", + "0xa8bb533bf42f56edf112b03d34eb64f6dccd57251244f39daeb6531af650d0368f6e4a0f9171aaf4f5a5b4a17debeb56", + "0x8d763490dbc9a9b73bd571833afce20654348cd553a69678ec89454c4cdac044ed3ef0458cabdb60ff35af5e63405961", + "0x8d3ebac80c55b7ce726f4cdac41c7e2f6a5ff4ffcd5f1803c463ae524243f136dcd15f9bc74f8b271ce90a4776c94868", + "0xab63cd85311fb9889041e692bc9d5c1153b26a805b511721154d28f11dc8ab84733387fd20cfa30c566ab2f8e066af4c", + "0xa506ba11063b14f25c26c92667dbd9eb67c8585d05d3980284aa19a09ae97599a1cf8d7cf45b70a32063f1fa3174d3bc", + "0xb834434632307602d9e046de6f625af5de673996108911c6b05d6bd3e2aee17246b2d860f01dc2d6415fa61c73110e13", + "0x8248b69f51196ce1e15fcdc25d487153896d1f74818a5617500cf0bedd5180028e6567533536919156860e34ba275f1e", + "0x86a5ed8b6a1e9d8d17b69640220bb80c9065198c8f7610d4ee6a60d2d808508771a84d6bc679ee4db34f43f94315e0ff", + "0x8fde55abc106b2afdac3b8796f83c8ce1b90405532fd586d349340c4d7a4f4c46e2a56fe2663fba770a8004dc7b9d523", + "0x82489db9dccdd13293499194068bb4ee8fff51f74f1b504d203c5deb5216287a6d614a2e0a769d4c929bc103582c92b8", + "0x82b2d71281cf886e80e09ff907c1f9213dc444c058e965f964bd17fd36dc0382da2449fdbc3aa7b6d07004d6722a5848", + "0xb0729dd38dd64c441e81a94fac0c8b5b3588081e43a5b0298bb576b16a9713acbdf09b9bc2499c677064619cb3a172c8", + "0x97c4bd5c97182e80f55e82648e387c4a3362c6088381e96b67cf0f04bcdac3dc670890904180a5388b97002c70481235", + "0x98d99f80ae9c59c921c6ff71ef01c2ba283f531ec32666cca1fe7dfd9bbfb09f197e9112af1761068cba8d6319af5d74", + "0xb0569d892ce82d87a3d809f4c86a88ce627ed420dd106ae49b88b8c470ddb081a3dbdbd92d7fc032a7082650e4197ed2", + "0x8ff68d42ec2dc5b13ff5c7ef506c619c4bbb0f62fd4c08e320953e5cddded2aa34624c6c5768b546cc2f00add0dda58f", + "0x8b53131206c80638dcff21d7f2dabdbc6faec545f19ab1f4f2bb858d6b01d87adf886072c3a744d58124b8a7a0c87573", + "0x8b9c9aa127ddb950cad4fc21cd7c8eb802cef6db7290664b1773b9744836450e48af503009d4bb266ceac83d765b3b9c", + "0xac61e051add512e749588e2549ff55f3e6fee5378443cbf64c80cfd7b260cfa63f16fc3e242aa140ea243435be28179b", + "0x9240700fdcde974f319a90ec4a9b92a0323424fe39e513c7412c621cb33072d193476118636bd2655867ed2816e03034", + "0xb6b05975d0653079034f9792d5d8cf5743e1737e1b3860e431a1e159199efa5a55b2d3283f6d270c9ed3156a233e858c", + "0xa2ea8fc31294943a3a6d02509cf8b75a7b5d94de917ced468fa64a6c24ead4edef11c34782eed848792b0570219fb77b", + "0xad0b54dc5dceb242c05a7f7c529289c8caed93ebe743f6609df653aedffbd7eaffceb53a18dfd109f28d14c80e1f7935", + "0x81e4d4667900eb5a8434e2153503b2318f63708499534a8d58382931791eb0ad0522b41cecc7eb0e6ddf99002bd0127c", + "0xa4c5c329fe159bdeeaecbaf479c60c8f43a58ce613e135e9e9eed4af6bf5b6116bdbfea31c82bf0ba87c3f651e1464f8", + "0xb95eaf48a9128df7f970754af926f9865c2078cabb4da4918d8b45e95d72748750ffd12f1d8d3f76cac0936ad0097d16", + "0x8567385d52e6f6dceeee52f6b690781f7c05c26f0d20912bacc38c23afe8f64925ba18f8b6464d4a0557670ed0cea232", + "0x8f7483cacd15fb7e49b2f8deb7ab05e64bac18ac9dba475666649c2cdbc5d6df0d5e789fdaaaa997a3b524521f0470ae", + "0x9252efa0698c0cb30dd431a72a0f5f2f14429f6ba50bb60f7039df45777557afe3ae732b9283b4a814d2146a8cd8b7b9", + "0xa54da5287928a02cd5eedabe70cff80e56db252e2811842545beb14f25ab67788460a71ab8ee47cf0c1a5f8d01635256", + "0x991a80279c622565a03929c94590f33cf0621a79b70a2168a41a4376bb3f0dd12a9ed9b16c0b6a4a59c50b5802449874", + "0x924ff5d3a6f0ff4ee58c3674319971257543d2e19f0ce3fd0b0edb214faee920f8d6199ca794a173363a9fa06c96d7b4", + "0x96b136b8df76ba24e4dcd68065c650fdc224fdfc9c1ab6410e008fa5b9580680c3c85801fa217917c620c86dcb5ce3eb", + "0x95934e64af642e7d45ada1bbe8b9fe972877a674252005afc34ec2e857f755ea0d77e7759ddb24255f21252d6c739305", + "0xab14c6bdd6d1ccaf69e0dfc6c832751afb70f89e4800c6fafd22db2e7e5d6f2addab8b1267c8f3fb85cee51c761e69f0", + "0x87e2edb8dec1253547cece2a7e6934b0299715e634d599316af0f076c61726c7f2aec83eaddcc9add1c397cbc9fed0ca", + "0x91170baea88ba00fe00db375e8d948f58061f9e7b36a4573031b9996757afcc2c7e9c2d9642bc51402aa586569f0a398", + "0x89d99b120e4565b0538b2ef4f8d8c05997cdbdf61840e068054e7f21677cdc1dc2f63adab1b6814225d14275c737b0e0", + "0x880c2b79bff714665e9b3a0a647773a212ec5f0dea37ee6b29ed6850692055013e108a86affbe44d1abd0ae80a748950", + "0xb564181f9ea65ca25b1ae7f25eee84b73f9db109ad1939e6b9351663ac0b083fc13e6518ad8eaafa3caba9ab959bf7c5", + "0x93cd91391deaa726320574bb46706fd8e30ffc2308290c79abfe2d234d0f0f59ee4c38791e3bbd8c3f840a920489ebaf", + "0x8e846d48e7b120b59c6556a0394d25f744dfda0cd58d4e70029837753a82afb63a015e79157fe8c810cc68bb481d19d6", + "0xb36904e7dd71bada7c9b9172e4a6748287cfa0cb6960ccfb7202a36c57bc28d351e1f5371c2b449437cd266f2d22e7f7", + "0x8947c11af34a42f314983ba9c673e62fcf44c6c1f733a697351e1b8422a75338a85bb19149fc130d01492ee18b3c9492", + "0x905afc0103e34fa9787102fbb80967b8c917bd03abb02731fe49ba1acff1e96059227616cd21080563e92dd021117a84", + "0x88c7acdc65e6373e4c8ac6a13d1bce1d534aeef2965a4d9f887b2e823c7ee7921db1397df5cb5e7f12030e310172d6e7", + "0xb028c19082411efe8a46c8abfb9936c005e766e2ad3120be774172f16419e2b04ba3f31132ed2bc209e7214c2d7b2b61", + "0xb6b3a561d583870193226391ebf51ef47185ab6efb3556ae59106b6f266776064e5cdb66f0c93748e60d557db64e8f84", + "0x93732aa1473dc2e50610eab2c8152f2d96992fea840ac2d82c6e2c5760d8c1c05e8ecbd69e14d03713f43e77ced9d3bd", + "0x9734c433ad41a8fd91e161de033a2a55189ae31e2af406d1fae443a182bf1977dddff93f6fe2ac7d9c4fb955c26ed59e", + "0xa1f305d17c36c06c515d30fdfb560f899e80a2e2461d0bd947032e5ec764116c7ccbd528ea42a3b9351e3c9b45904431", + "0xb517f46b582655e551f766930637e8dc2a762dd7a2c54fce429fdc4cd503e9fe4bfbf323f50860be2c18b3a17d528654", + "0xb395b5c48b1cb0daa8c156188b390a78441c8f16ecc8650520f9f2914bd1d992b83849bb11ec17a47f9f2d40d138e3d1", + "0x9147b715b62fd50e59bc96d210e10f1062c87a90263b5586746325deeea89e759464be55a09b0548766e13bc910c4d3f", + "0xa7dfe5e7a39767d14d531d371b92fc4979d326ed0f966eeb7b4b4252d78117bf5295b3c17d1fd636dc2c0097cac901c2", + "0xaa3f9fb858b30675e9e57170a1835717521eafe4bd0a0690b10020c7a753951576b4c7dc80cf9f042894fd5741b41b1a", + "0xa1f11dec034733e862cdd4aefaf0252a9e8175b6d4c834b7a7d30ab884bb6ed6a1d92bb0e958f0082085cd80157a0e40", + "0xa1751d7452b7c5596fb801466d8d07a70831e568b8ca66fdd75e5898739709795a5768726ebe13c469b1d51092d86a60", + "0x80acf49051b7caa6efe78318792d05401f5246c5b3bef25170b2a49adfeec8048ad5a5e6d50cc498b23896176a9d9669", + "0x94156df9959c678578ec6e12ac068f3a28d69a981443fc35161d14b1f0327b8424746d62869ea9377a86ca6fd2c95b5e", + "0x95dd91b1e9b457de913a65f198dcdceb1fca75692853bd5ed44eda6343f32126e6aa2a309411e019dbdb9519c865b96d", + "0xb2516bc36a726cf2dd5553e319c64fc508682c7446a2a5ae696e43f1a8c129ca9602f5a41bfbb57865a9dad1d56728d3", + "0x90cd63b4f9216fb70635e4dcbc9a6c5874cabeabe4f9ea83bb923146d03366d9befa48b20a64f3a2cfdb0c3a84007ab2", + "0xa55bfe9b33781501f10d5632e8f5330841eba2d0a64b0aaaa92db56f014b5e44dbeda3b1f5b2e4c17eb6a243977b2a82", + "0xb9e84b3c617708971f5e174fb8718906f9bd353f8b0fec8fa03d1a6e4bec20430212396a5406595343cd15777c5a3f8b", + "0x97deb79dd82185555442f91fb9a70cbd30a564751528fa0df0a681315b8a71bab5073716908ee0546d70dc41efa3b53c", + "0xac77c2fe555584b9cba7438a4e3904958f671c49536f185cf1f3b25c5a57ea65e15554de22def94c5c623e8c99e47a9a", + "0xa27c62d39508552d79d2899bac6138783f308e3befab65a96a1ae4ab108b799628cf37db1ec72859a0ce1ac68f68b106", + "0xa2aa287741f03e31f2c87fc37e228279b1acb886f32c6438b3e9807b8126da875fca7f194295c45531e939a13048a882", + "0x84df8999c4c5ecc807819248957d68909d16ef64d94a820dd0d266cddb6775c9c7464f0b2385b7bdde8fc0f2169a4177", + "0x8388e1a1babb941e03806b392fdc1bbe1a01438292ea1db4087b010de0805be78cfa56d20e9ef7c8b6be5a04bab1b1e0", + "0x8cb6ec409cec27e7c4537ee2e5bcf82a33e7cd4761d19059e902b6068a9744e897a6010e2ab42ce72625cbc433892ec5", + "0xb6e71cf74455b0f506e03eecc0976831ec9a56eb8fd0e39e5e12ae199180a4c6e5123174ddea6ce6cfd7a414cf0afc5f", + "0x815dd267d9f67b4d229a798a499b70ea2a611f3bf2a9d3698d1105890a2b6462fcc7c6ebff0d5d709707ee4ffa981689", + "0xb4e5b7fbab4d8a66d1b167a5acaa4d53949e1fbdb00107e62b727b4b4b2cc70e2685cd4a16266e8d13ab176f9be09c10", + "0x8d1bae7566ff551f06baacd8c640d0d04accdd49fbfedda0841914aa1bceaf9f3f27344b80bdf5f9b93ada438a4e6d68", + "0xadb054123e27afd4a691d2cd808a3232ab58f56fbd514935caf47b8193b4c64aaafed4d08a7a10ec4deb66be8c292e64", + "0x8ab5255246e01478ba7dc6807c84850308a719f8f8433eb049d5b11cbc361c08930722e7e5878ad99fe1586b3d11cb1f", + "0x90e862be1e3d0824106da33aec437a87dbd2599aeb58d46b4a39a5f651097d49943c3248a154e09e309eaa7abff3d500", + "0xabf16f35e3b2b29a72cd96802c900fbc54100484299198b2d40cc6071945781cc9bb3eb43f6ebe433a14c1aeb172929c", + "0x867a0f396374cca7303845d8a1e4bcebaa53cc0fc2e790dd58cdd0b5ff2b9a99e18ad4e57aa2b061826545935a5607b5", + "0xa6b6a2e22932d7c9ba8f27b1e1de8559631a81effc77ed2cd7c45c48e49ea7d2f68c59d07a155757493ad82f733d93ee", + "0x885e4c3904c545c0eecc9cd02e16d359ce69a78e3a355e7fbe6485762d4523f2604f2f663a4521152a8bdb6fd4a9d4be", + "0xa668f417391b07a35c5d40ee5212cb7bdaffcf040a4f20a3d7e70e9d715bd908d4f8fca87a7dbf7b676e088ac8651ee8", + "0xa70d67f3379e1ee0708c34c4c7a7f552267ff679460b9d8891549077c724becb99ff79b35bd80420a4290f293ed4133f", + "0xa523cca782ced0d8a3f7e19707f9c64ff38495f739e035bcfb5483f202b209c07c50c764eb28d3bd8cf68ae093c46f19", + "0x8ce98e5f96889ebada090449ae198208cae5c247cc5f6fe7800b4c2254b0e7f2475b632cbd5021a0871b466c5b943dc8", + "0xa69cfdeb27ce1163ae6b6b4b5d46b49507c7e62789f2f90f7f5a0fdce79de988c755cc9afd8397b1c02976e03589f985", + "0xacbffc94dc0445f7797a0d83e5107ad3ec8bf61620fa83e73a999ce4f9b6bbabb00245a619aa6f9b082a2711bad5ce8a", + "0xb64162794503c86e478c23f060228105bab4f3f5d46582bd455a94526aa6d71f4c9630d8d63854c8c67aff3904681e0c", + "0xb1288073c012a0b2b7e31708e874106031a8cc98b2c94ad0ef1d7b9df42f429f58caef5494f6d581baf12970cded2a17", + "0x8d7ad217c3c1cb74cc301540a0e43be6d74d5a3c0383ab7c9dae57e25f8725781735b58301ebc014476171725299782a", + "0x924a33c759249af270617767101385910494724a51fc63600836ca00d06f0ca86a4a0a85e5e87cc29e404ff8e04d036c", + "0xa7b21ad39bcacc96cd857328a83e5d26cddd0a5bb2326da9a8f593927ae7b5927704acda9ee217176618c964d0452d54", + "0xa5c3616c308bef98807a852e16f146859b0b1f31ea8a721941d90abcbe37eeacb4403c6568480b6d6e773bbb94a89307", + "0xaefaa1033e47673ca2b68e4c945e6ed892e223146d4fd24219304c2667777c1b18a19488b73053cf7b0e6e09ba1278e3", + "0xb308c690176bc43051f51839d3ae1636f6de5a57c626e8def464820ce2f96ca09ff26294a3dbc9b4573cfc42dd03bbb0", + "0x8f7b1253ea9e257195ee92c54de41f2e7a310c90602a628ba3180e059e5bba79d6bb8110d1964c59daf4b65cd9735704", + "0xa387f003f7731b81bace54c8501a3a2a25d8a910cbb28dd603ed16ce61ef1df34e233dc8579071856d7198a071efedf6", + "0x955ad5523828c0fbe8ad6a77a191661ee9c8005b741b7b0439b76711b6992795758d76133399d266df5e494e4f86cd67", + "0xa44441964f5cad7b54d0105f162ed3ec40d12870fe8c5c30bf16238440143b330ba986d6adb00c9626747e99449f765c", + "0xa52df726de07cccbc77e81abf4f1712657c9261f65feee8815ef0e8a4ca61b8e470503801f1da8a23fe6d52f3306807c", + "0xb5d239222c3d852f2c49997e76d97b70bcfe73d85e81258d9781f5f7de87f9c81648bcf58cfffd554e4685b2f860e6d8", + "0x96f0193aecbeb1540678f1a3369401e916ee75d2a85f7124c555466a3def91a5d8b5f774e3156a163e1010690d457c5d", + "0x886b9f4965120d942b076d053571837780232e139c3efcc6bd6c64eabddbed2d55c3a9a06001bd7a2ccebb36135edf4b", + "0x897a1e4e9f4eaf755807bed984ef0bfea251740386a168061f4386819acaa337fa6d3f038b4cff9a11926e68f7888f90", + "0x989d9706f8396ba422a34b55897b9e261ac1ba0c7a7a11a30562ebfab92473b9e9b604ea8baa6067137a4ded070fda10", + "0x96376812651020f68c6a1f0aecd04591fdb628051f01daae179f7008ae33af5abb42e8f304662c9b6e2584e8b02ba6a6", + "0x9344e6f3ce42ada6281d0fff654f408e61f0acce81e23ce47466bf1145a99cf60dfba9a22304efbb1f428c92357d644e", + "0xb90c5463445156c8de69d8c35db656a76f3e195c325808396a829c11c06a7503f3c092816b3f23a263d56d3f2c075ff7", + "0xb4dc6d948f4b67b513ce27fd12bc8efe43813c119d01b2da391d01c1cb0abb7d51350a5446e0a72a6f8bbbde2ee4b0c4", + "0x84d208ab983941bde208fd71d58c7f9335e14db237cec42df453155a3a8dcb21dec8696a1334cfe5d035c192fc44e88f", + "0x9577996c78372d2d6c9de27d497afb29c918bd894bfefad9059bd85cf2ab520ce1d517994724e1567f12e385c126f26a", + "0xb778b9054776a2b8ee81be356050b977bc8aca0d0a202be91d56ba89d8a384bd29c5c652ea084709d4fb365b107962b9", + "0xb7ea99f8c841678dc854527ad0c8ffc700b43b5b36b3d18303e51175b3901b144c53e22eea6ce7cd500f6879a80a8c21", + "0xb466aa7d1a5ae3d9aea240c8114b3dc3af38f7d8f1e323800a6382de5766f19626d07cd6ca6eddfc4d71a43d2d49a07a", + "0x8a72b1ee7993f16400396982b6a5198f0de08821431bc66489189d5b364b0e36daff5077b48aff1d55c9a88580cd1dc2", + "0xa7c4dd6095f8cf61f42c5901ab67e9d1ad21a42d1eae9ca5e147a9396507c7a21747c2794f71ac66002840f4fa4e1dd0", + "0xabe40e33cca787e7c521e2e97fb5f95cd4ca7ad6148a505afdc94e0c003e4903b1524164a1df2b2a1330fd800ac33b7d", + "0xab8e1930b1e592aa2379cff636e7fda9fd7f05b358f47d9cbadcfe35fbdee5bf06469fefc052f62159c10942ea2bc5af", + "0xb28edfbfdcc27c3892d64e7e05a2aebb173808c020186c225590b03d91dacb866108370f2c14ac97a6d20d95a8e32f8a", + "0x97d4841704bacb06bce2778104e4437c930fdd9320d85cac383d11ce9246525ad5167cbd63ef04a8ea39c8fbe3d88169", + "0xb4b178a1c3ccd3344831936b784203919cffb611cd18def1a52ffa2a8e4286f9f9681bd48dff9b2abfe62da5fd619fa7", + "0xafb01a4777a128b02fc22e282e0c4ab1d86246d8e0813a7e85c51907bce079766ae40c31d3c440d5f99c92e89d3a683e", + "0x91cd070a607c20140c1f35b25057bfa20290b1435e99c5b33068c4e5755ff8f1aa2be61fba28dcfc131cf881aa1c39ec", + "0xaaac82ccda92c6090970f60a56668c011ac20dcab26347ad40585a60b5a9b5a9af883307c55526d4eca1b110a079fd3d", + "0xa7480de83b4cbb2eedece3d3b27b8d934e9183f448d56d5f49e0b63e24575014a94e09d406d7ca5afda08da9f4eafbc1", + "0x8e568ae356775b06d963b440f75bad9b5977b7bcfb8fbd1dbb4daad5192521bd189674654d4ab86ded4a6be5fee27ef7", + "0xa501a84cd0b4138383572fdd09242e3a748e593f55400fa7600698d4f916a2fc1feb96557a34f4ef0f13eee580fe9f54", + "0x8be0f6b98d52b83e9deccf09d05fc4a7b4ae1cb11972f01baee4fabdb804cee2b0e9b44a1385238f755d2c1ce395cfa5", + "0xafd01e3658ed9204d39fcdda2d79239b8c45dcf80fda8a680a8797b6be294e7e8bf56ce345896c3f08446e9a2a053a61", + "0x851f0def025a50910bfb6c2fbe5ca62a31426747d9cf4634c8faa714a014fa22586c3eabde84e23ca77371ae25d720d9", + "0x90a1aa7bbe7842cd361d0ab2e16203a56318885d2d32409370ffb64ef0ffd3c8c57658573a0714b04dd1595aabfc8f21", + "0xaf56f30bbd796de5cbf6f3d041c2f649d0f36e0a1335ba923eb1487e0b29d0ab307a1143e6cabb79674ddc01dd9a5cd9", + "0x8429afa5476d0f3a4eed4104fdeafb79f80e94e709b59aa44b4caf0a94bf75fb3efadf76e96389179eafc389fe896efa", + "0x91d8399bcc3b82f0044b9a697b2bc402285f6d2e7b76eec25ffecab769f3fbdd45d20897d28a8676f090edf847eb3c70", + "0xa06f8d37404ae58c35732db58c4c6270e4311c691ecaa7d89b3e9b2bb1421ee3c3cde555d066340c0f2479faea1ae162", + "0x8011fcbb711ba6511960245c69a73fa99167eeb4d238426bc31ce359a90a2339d5936042b281f3ff3eb976357db96885", + "0x8dff2bc19830b4a58d2cc3c1598d060da34c8fde11635062dd4222c96dcbf2bef79b339c63fefdb1653153ef9af79c48", + "0x84ae7869e2405e326bd167249f89c2e018817d3edf59f3db8adc25f64836ea4606c78158cb30020a54551283bcd9f39e", + "0xb7be6cfbb7cbb7788fd60fbfcae3504d441b0af3b46317944e00a23079c605c08fd116311432be5b378ed8a11da219e7", + "0xa3656ce4a79484e365b6b7f81a9dd72a09746da16175a61794bc5fcc0c3dd608751ea2cfcf7bb0c14421e0b05d94df75", + "0x929d5603a936bedc69ede2d1277692012d0c820a23915ac6e776b832b9f4e0e6276fb3b257c7abbca32ea166d4482149", + "0x82d47138de8b6ed4bdaf69526ace4f6fdc50fe5abee63f1c6d4447fe4948a84a63b7963c8a65858442856e282fabaf26", + "0x8f8b2d05e77e9e4e2cc5229ea98c5c02ef9d9b6939ce6663d98d8e2dbed73af3d41628662c354972c1b48157f8d3c459", + "0x9353ee31f477b51558f4ba5ca437d801f59d01ed995a8801552f8c578d1937997bd76c31aedab99fb5532789e72469b0", + "0x941f777fc9115fe948f3a979e1ab87f133238935acdc19d33e1d86a1a64924eb9008e91bdff8d650f5e3ad06db931234", + "0x8ee79ecb7d07e3a5fb80ec15c085898e97876448685891e09ebee9aacd5cd0147715dc60b6f75b601fbe83598f1a939b", + "0xa96a50de4fa25367706c99abe9dba95ce1717483f50692bde7c8c3a6b427d02d59ef6e8bee82762fe774f5afa528f0d0", + "0xa451ff58246340157fd94d028ce1ebe5ce49e5ed87d9b61884c8ad903ef9b697c4ab9e5acf66180a89a17749046c99fe", + "0xb12739d77fb96e9e93065fe279307eafb11c795da2b9efba4cb239425faf687b9762235700d9f2cd5df9cd9fb2b36e3f", + "0xa665e34895d02e68f1dee7ad8090558514720ff3e809cf46cc06d1e1274d219fd08781fd430367a3f09e2c591dfd7cf4", + "0xa262410cb60409720ce68935e91c743aed5eccb4a0427449f32a4acca103f9d65413290ffe2cbc895e2e1cef96ba7c6e", + "0x9597cf4d49db896796132aed4bdfbec71ebba08a617a611d1fece75bbfcce902e8ba228b662d0ec5fb927429f082eb38", + "0x80a045d2bd30aff2267a5385be12c646b65b24a586c4f5cb1bdb81387e3ff8edd2358cc8e3c4c5c60cab88d4dce61d90", + "0x80323f4a9fc78bc89aaa172f739bbd4f57f9321a7b8e9eddb74ee5c99d6c7b8dfe847f7103110f0a44d4e7c20ed29114", + "0x943b749ab77112be7593bb2ac11094c66c94bb89d5ee2cc05316ad623a3997a38aec741ec93c24770adc670b6ad12e91", + "0xa8e1b4935aad8a84112a99fd5a4d3786ccf1c985aca0b256c46d52a8801a132024391431cc2cfee760c25eb18289041e", + "0x8abbe403bf13bad914a4d5bb0c8709f5b264a7a81ba0542850cb89c3c45bc294f62b22a36d7f829ca80830a3be5832aa", + "0x9084defe85d170967c08d1f5e74ad1dd592c2b013b01b84b5fe3f2ceb260bde2e52ca22e4006b07f01e3dc7a36774e94", + "0xa34cf1cfca622dda528589b5e5e36a4a68cee7e18cc621736e3e165b06a5df9a8e9f3ddc406838c1fe94ebdc44bfaa18", + "0x8c5f5d7e98828d0a063d90d5f78bc493c46316fec3245d47ef8900241fffd5316e0d6d6f1653cb3b22bbf05286736c06", + "0xae7f2beef46b6645a6d0b3ca664c826be205ca6de35bd2809a4871f19368bd2c009ad7de0cb4c269c2934357e87c7f64", + "0xabae2cd1ff7320d0803b6b5345ef9dd364fcc001d91fa456199dde24f474ff3d0ce94d460be9659caffe7ae0a6814217", + "0xb86710fd69a6eeca8a813c7c1d643b487a32cadd70013a4aff4b7331ec08d1469fb17a06d06926e68f546e7f5238e1f5", + "0xb42e9dd8d0f12f95a16112ef7ea60e6f4c76a39cb64e7f6bb4fde6ed1fc54fe8317e93160d736d97d87ff7af69ac2a41", + "0x86e5561a7b621e68afda9d63945dc69bcd615cc099c84ac51ebf6350b25c9c07ab371ed5b160a86488e8213d143335fe", + "0x831c730524214b8368bdc619e5c7e55a0731b6c5ddd035e9d7cd90577a472a429e779efb0ce47320c8d3b62997eec0de", + "0xa3bcbb6c321b329ea2bb944f48ac984f8bb6cbcd38a5f80e8780257765756cd902d252a51804879104527bc7b251c1b5", + "0x8b1a0ee0219a010653f816de88b05116269325c42811d717544468b3bf477953900394a71d56b6dea13e4e6ef9c9c5cf", + "0xa5d06e2a43d965e47d400343c093d64bd5d4adcbe3928093c80439f815938b9e952bf59da7fb26f459a5439fe60fd49c", + "0xb92df54cd0515bb9868a8dadb2a808d3e62fec12be3c708fa6c845c833c3321017e2f8d71f10b064fdde02b098e22962", + "0xafd8fb1d8ced274650ecb6c370c5bbe8f09d263391af7c2f2290b5c99196ddeaeedc8b9b6173b6fa349872f58c83149e", + "0xb359418883d3425b1bb896a9a9e2a3068c19abbb18ebaccadb85dee713b14bca5b83992cf239cfbb73adbe2f07c63f04", + "0xb8cb045dcb0735b02d6e81d9aa9906ab2f19df2e2adb5bff0533022c03a9a530bb27fcd45173faac63a8d13bf0f41565", + "0xb8b8ed443891d3ecd807d3f92d8c2afe714a423b97019cec3690c24002cd0444548ba6b454e1f9934f01a419206896b8", + "0xa3c28de7e71c54dfba701b7e1053a1719032bf48d0e520bf8d513d155d588d08d14af3cf1e9ba3083f8e59dc947ef99b", + "0xa94d1569107e659db2ca58864eb8feb03c83ca083c75a6d949805faaf7095a4f981cbd1f89a464aa46107a891ba758f7", + "0xa9c98b0501a8c5102ec0daffddce83ab40bd097c4ccce66a8f8a61a3fc28564ce5dec37940092640b36a0ef6efbea4a2", + "0xa473b784935b52ce73755894177ead52cd9f2a10521e9c034298fc0461aa6cfb03d499812189eddbce4b3cfb58774a3f", + "0x8c7a7984739a3db7b28b7ef10f081e2cbec93e1da39738d082898fc73e83db206fb52cbec476c9809c7de61ff5871b71", + "0x88b87148a573e576d0a8fa912858b7a9876001d8364bdaa7dd2759dd908555119f6f580c0d3a663ff5c2a2bcb05fef99", + "0xb169b58fa10256b2753221aa33dc4f0f3308a294b98300528347ea4e89128a1a1da502990c9f2d266fcc10031b3c5a07", + "0x85b1f0e49528ec8e51112771686b5b9f18e4cab091f6f97dc9a327221fde48be87f59cb46e6caac6e1af1a8c70135e66", + "0x954021598c24f5889a642b9d20488a04e3c78c5b04bafcd0a01f377cf24b49f64b1d820ee8a73f8cc193e1de9a106a6f", + "0x8954b280ae11638d6e9c27f826fe66c0ec584fccefda8665f75e0699ed640e8e74fb1945753f84baf606d2fcc804b1a4", + "0x899303d3bfcf48d28aa49e915ddfe263117ab87384f611bf7d555ed141dd728a39b97eca74b6b623a20d44458f35a157", + "0x8d792116aaba18c94069cbaf0da373c4e61662189e8bd0f24dd675531ee6f99d574f91844ace86e3d018c4603ff0e2c6", + "0x876c457846f27161c796f2d063aac7f73c2197ce707872c828af81ffabe91a6f353c6e887464c921718425d046c0a722", + "0xa0382a36d4f8007d444643bd5d85d0b6c3c892c7ef8158f51c878b13af6a5b7c8b098ac7a6e3241a6e13b4ae987addc9", + "0x81d668e292ae20a5a39b55e6798255c39368d9b83ca46e986c343ff9cf4f3140e3f07115995b8fc2554dc0372e4acfdf", + "0x85e58c950d8089ebd5d0a9d852c9e78d1e066c4cf1f1e64b4e76356745d3eddc13f1abf177dd32f0aede2f190053f8c9", + "0x9420d1c470588085057549b7e6544aca2ca329ac9b232187d8ac894b7a878d6d3ea351357174089943b43a83f057ab8e", + "0xb6ea12644c6ae73b8b9752f8eb8bf06312ca14d93fddeb5f79b92167ed78338964d620379387ffc9e12ac0e323f3500e", + "0x82767d1ca19c7672d38216bf17a8ca0a52aed5dca77684da56419430f9129ed25b6c547fce50c834746cab666ddd43cc", + "0xb1864c611fdb1b641708a5be8140ca0ac52d59d7c3fa3eaa10bd815f7f5e34413751f829f5fc0faa259064b73d43f4c8", + "0x92f67f02d17a1ead3b01478687cf26b40fb32f055f3b34feff21de083852460e02afb834f61c37fb91100709891379ac", + "0xb640a52bf00e4b29623c9b150635391b4dd42f0016e827daaad7aeff6e6a64fae4d67193664bc5bb368c72b138c76efe", + "0x941c8aed9a85a005059b83d35f6a70dae2e2b5f645719b567de0da3bbf1d2b85704ac977970a7206bd98609182090160", + "0xaa976af6c9809550721103fc8bb8359cc4313f672421a4ddd760bc4ddd86a036c1b4145049d9c8165335309fb608d6e4", + "0xafb11dfe01bb6a9d2cc2c040e18152645b4aa972fa01b6cb4285312bcb11a317107e743efb53aeb4bb6f8a7fb7741f50", + "0x95f8f780fae2878792aa3f60eab8954ecb107942bf07f0e2854173595eb2d4b914f4aa208f98a63b0ebcfbca46840123", + "0xb1dbec7871209fea98676e68d7a02dd82179a74e389bb9dc0eaeb2ac2d446d26810146586b637869ddec4caac8281bcb", + "0x931c9d571e50dfd2e1bee0c36f42085e4aa4e7d80a1c3bf99573d9d09ff710f6fa27f30712daba107d43d263b226d130", + "0xb080bc730ed34724851d00be3bba84093a296d6320fe7671a83364ab1faf922189ffe997eca0e1ce4ac2c4435d7b7f10", + "0x8dbbdb4f82398c891d16dbd4169716e078de5d677d3d550fd3853ff6ac8d15d278f17a2950333545bab823fad09a4922", + "0xa71bb5b71699082cc45037805fcd95e410c29575d229a556a7c5f2969fb6f957f0c63861048c65d5b73fc4680a5c3c70", + "0xb5bc06a742016a20c60d61cf55006cd7c2c7b8f367968f279815087b2bda7009c1773b9c91b8a4b78717b2bdf6a5e96e", + "0x91aa31c68634a81c9784d0d6adf4dc85c981e122635d4e1f25604c8184da860b1292d65324d4bb9bd8a002572cc96bff", + "0x85484fa47e235410e2ebc49f4dbbea9847ea064f6f6776dceb0d868280fe88bf6c5bb72e24c0ed3cb0a3f1d96ef8c9ce", + "0x88ab35f32986f0bbd8502dc81506cb18638298e856934fa374480dc455463482ca780385537e7ea73c4c863107b74f7a", + "0xb3022847a668b6d5d52d0af14d594c3e842afaab5416e3ffef21224bede0e1bbecb0799ddb7e095623a3a6f28b6d5f43", + "0x8802d0e6e5203d0018d243301c57934ca85a002f91e5763b2f7372816c7b3ddf719c3b743f2530d9b7330f4f35d69d83", + "0x85709fddeaaddead7a27d3f75e5ac568b0c9691c797f1505f5b33678158f5dff96ab98b921bfbc83368c6763420bf949", + "0xa45ddf8ed1c273d61578bf6830fabd4927f82e3efe7732d64a1c82887b9693dcabdad1e7a65f09bde459fef89c0eef82", + "0x970fb837063e059b1c2b4ec88011131e8cdc459daa1e704095bd327b7c94115c57cc1d9e8b4a29d6cc4f20895e309c61", + "0xb789aabda019356bc5c5dcb015f8e7c5da25150988af0d44cfb11d8702da22fbb43f69c4af889dddc0647745d162d91e", + "0x8ccd44696d8c52454c833b0b256ed0073527616ce49ef25a113cb9f16d41f39d27e3bf169ef0d3b2fe78f2a5910ec83a", + "0x9846a3ae6a2c339b09f53b6cb1262114d1ce2fa3ea43d77b04816eea6451e8620f0030ba428eff80d72d8e907c8f9e3d", + "0x80c18de89a31e2c8309353be974e42ca97dcebefc1a914e76b57609b9cb7c1c6298e2ee1bb35ab9d587f195010d24337", + "0xa43ac7ac3798af0923ef5bcf2342550aef8551c198a31b0bc9015ecb24fd2633bdcffd84a2c84f9eb72b4e67084caed4", + "0x8cc1551213a33114c8e6b3e00c68dd26b9cb3728376b498c95aeec60e7506a3346641ed5297fd4ead33c0e42b85079be", + "0xafb54536b43e311eef9f584b8f1074866f6d33cfc75a3294aad5aea870cdbc3c97ab6e849ef719e2e1e4386a8a360fe2", + "0xa2c5a2240256c64673372b63359b646dcadb108d785b4fb16a165f4b3b0ab3dc3dd5058582b25ed7b728d56d5aa45649", + "0xb35e3e4407b63edf3eb567fdbe03eef00dadddcf41b799c80a9c9e26ddcf0c6b0b9dc4df0a0c5d54bf31ac8273740a32", + "0xa3ce737baa7e1c1c69931a5b2fe1493a06fa0dcfc0b819ef8242b4fdae8d63bec8d15561d4fa24ef6d6c3a326d0abafa", + "0x910a67b377fb17d3f9cd1f994db52eb5f35a4aa002bc1b7208b259b12c64c095e4dd65ffe54772f8e2773923a890bc97", + "0x908c5ee131dea3f444a9ee2052c93a657d28f2f58e604bf08e51500a306decb2db964f68e87d5ac2f8207cc4e92adb09", + "0x8f3de5e756409b575ac2786590fc85de506f0adb51450f5c24669bb3a688f080c1cc37cb8e7a3c8db8e25c49a4bd76cc", + "0xaa62ceaef91fdf09d2ac2edbc07fcc651584a7e7d7d93e7bd4bb4c42105144c2da32326b3ae320b36a2df8aed07e5610", + "0x959fc29ce63dcac2b4dbe8180577cecf9bfbb6db6505d76aada43ddfde5f48ec8f6fed14fac19389f6c9ed3555ef7882", + "0x984cbe54156763d6ae078d6a8205cb6f9d63eee390dc5990f5d8e85b9a19fef563653d3dcc190c9b18c2232a916b1409", + "0x923b448808d9ac04488e8345d3fbf9aa57cc3b3f375af138b674daa0e5a864faaeabed08f94010478543f3e1248c699c", + "0x8c0823bf2706d9aa4c074673e9d221eb021de2baffe8b703e64e676b6801da73440b7793254fe4c8c48d2ff395e44bfd", + "0x93c9cb050494824aba0d57320e2d1dfc95c988bec46dc8d73f7036be9ce0d7de02e56ad1ea3dd8fc129100800aa639bd", + "0x9339fa01caba0f4837efca7a3d983fda1f6a479f63890db7f7beb837e3f6535b1f1d0788884dbeb73fa657410a4ad308", + "0x953f213ec904d4540b356d53eb88f646a98581a6deeebdf99a6646cf612e5b07110839d46c57b76545f6879f12371b10", + "0x99a4576f12de20fbecd3906e48dcc784cdbdf7fa0843c570c6f59f13cf3a559cc1f4882fc1d31015304090f83306280b", + "0xb07fb8b73793a236e58b7181df5a0a2e8d50c1d3069c475c6e178e32d14b6e75c45af60a8b54823c23ffbb316bd4a98e", + "0x98781507866499ce396730ee91a08e91d3be337690f7195750bd43a601a8f78e9475d5ebb43e347934429a4ff3db58b3", + "0x972a5a21354beadf80d8a6e449cc4f072d6b747de293f075b8e0925c89660db9195a30188dfc8b73dba02467ae02913f", + "0x827dd2e21ca88891b9b37e10f0d6b6304438cd6aaf9cb125ea7ed822078a233f3e1b49a8bc65f843e9551691b46cf91f", + "0xad3a4ebaccc157a7b880db6990a937e2d230875f509ce864fb0b7ba5febc7f4668191bf3aa55b85f3c17ce8b7d75b349", + "0x976672c981d106fe1835188e202adf6ce77314f8d7c8f797aacf25f00d57f8cfea31b057f6afcb40b9f97df6ea387979", + "0x8c77ba87e3e8fd5de85802a764b719d67f4edbdace75433af7fe966d3d18a94778c4414572b84f98bc6b5993a3225212", + "0x84ca9b0435001c246143e50487a55349bf38300cde86219d29199e2e9137e262a1619ee7d6f6c44b9551319f1ea8526f", + "0xab06e3313800a7dbb970145c1e89b7849db8a1e3169560fe2c64956a1f9d1d3157d531713a8d7c2213356b22fd3014ed", + "0xa0d04163ae987227aaba1ae82f74fd1b44387501fa47fa61b66728a0697155f48bb44b9eb5e87050a5bdb7605038db12", + "0x8e76d3e50853ba5945610251dd18736b8541bf72bd643f6b561cab1c028dd044c820fcf79a5b45882e7dde0ba6db164d", + "0x967ec8fdee2e6d61f0ca2cc255f4e72c41a9c1a62150318be0fa508b424487d9254ad135fbe8dcda55caa51b9901eda1", + "0xae25c496f872f7380d9c64fc9bee0dfdc0f05cc1d2d6ea7747e166cae7e67c17a72a24a9e351de15f52baad355625d7c", + "0xb8a95f3bc67ad2a2d3cfbbf2de2003b7bc894b3f99f0364fd181eb11d154a7193b1df9b671a3a8eb8bbabafeee2d1a86", + "0xb79996f818d94842175b06650a1e7819cb12c96b6ba37e61fa14b67684c2879e7d3884fa6bae06faba009329db2b0d1c", + "0x856e1478ef99338f144757fe4be68d935f0069a05b0a6209be2fac9ebc5cc669c6a80825d3c74801a54ff8b1a3777da8", + "0x8024798b150aa722dc599f288cdf455479763a9bf776da74d5f9cf76026500e5a0282d840e5ae5451a0e28d507b397a5", + "0x97cb767ebfc0a6cfe25666089f85e5a3705c108096a38151baa22308276ebf7cb3c04079ecd130cb8cae1689508d4bcb", + "0x874ff07def0f8d32f2ffce7cf31a43e8bc5e633b279acd7138ae938e46889e486c092ac34924aed9a4e1f93a91994211", + "0xab5b6bec8c81133b6edddcd048fbd526d59fc8a1f5acd7aa72d07852696faf5e8d305e85077450188cddd43d6c1aad27", + "0x8402f5173327a95438797cee3b107407e8b277759c942bf1b1f975dc63ab89b8c43f0f4ce2a11de6e5727e9952b8923b", + "0xa5179a16297f7a0913ba61d69879014b9adb5e41813ac33acb8973e2b43cbc17a2f9a7d98210b39471a47b534f0eea23", + "0x8f7cf3928b51b0b1bce18a34da935e7e2558595e4ebc50cc1cb698f0bf3c1ea0050aadbcec33786118d791218e1734b1", + "0x81552a8927942591572429892e5a1572c8bc4fa7901395a5a2de3ce9f1ead122e4e5ffef6cc8434b3b18af1aa62e45b3", + "0x8999a1bf4f22fdc884f9310e7a3f5baa0d32c04e887c51a20736cff3216f3dac5bbede43632d29704536d7f275b0be9b", + "0x85d9952816412a890a3e479025d1c0c8858337498ae28731ae23332c16a788cfe51fa9836bee73d03b253803096100a9", + "0xb6a736447acaa6f4d83998973cd2bc3e12d34c6c076880e6765513c04087eeee5b5dfe9394c120a85bec8fbe127f1f54", + "0x89302db4ea39662024c748ff5b22108c0f34850f0fda476051a89a3eba0e02a2294a4511666987d89f3b3bbcc334fdf3", + "0x88ef018d32e6b379cea9ce35d1c12af698d8241c4c7468a5d558099f5101f04ac8e49d09b6bf031a811970faf02ed0ac", + "0xb33afb11f73195a7132430dc3961252251aef42150e9aa63a8c7cae724f467543a4afec289bf27e10ccabcad2f7f812a", + "0xb706315deef0529725fa6c4520e5d320a028b4607d47fa6c4c8ca3558afd68ed65dc072a354d263d20405bb13ca119f0", + "0x8ba035d75939c1a3cfc72a9ad3aa4ade105880345eaad9286a182950368e688a182f6175357a2e62d977ff7ae08959cf", + "0xb47ca04b80107eefd3a596be2e990f5f021cafc6b7fb64cbb78802f9bb7bd2cec4f37755c451bb1fc8786a076e90bad9", + "0xb6fb1676fbdf6cf95add7173c264b820042511e34dbcafa76273ef5e4500ad1208b274855985f0eff5196e7200e5a8b5", + "0x8c7493894853f4e9fef5a0143dc134f03eeeaa10c80c5a72afb12f10ca5207df1c7bcefba6728d61f3f89d3978902629", + "0x97d14d9debd4228be04f2352e57d9c8138d4e40228c269100930e2a3f6eb6e66f2f99807be0c9857082ff8b9a089049e", + "0x86e327360a19f6ddc8d0362cf92fa84677737064a94d9d0c1031bae92b85abed36193428199b0f66720be0d6edb0d28c", + "0xac79bf758fe91d47d1ddfba62bba87f5e64d93f82309d4d07b62d78ad6ae95908e1989299db99ec52c5ad8c8f3d7132f", + "0x804712afd93328864a52a9f9ca1ae148de26fdec7d9f51d1bf8c0385959ddfb639ae0904c855180dd418ac21f9a8a7d0", + "0xa789e15cf3c1e911fca7f6759a2c5d0a281c6ab744f29709b8d0623c1fc197ed9bf56b89fb0953baf261ffc4bd8d1552", + "0xb738474bd1788f326c5145ca2a468d914ead6dbc338680f62ee21b1e5fed49fa501236d70dce5363a72147b0a8974c8c", + "0xa34019db5e8d5cb680a78c1692978ce0f3f8b21c1615ff65f3d103ed5a1e32884680c90d1dc18f0edcd8a506b1003806", + "0xb1b1f26ed57a7bf77257e2ab1bf314b22e47f8a4f4c5cd154beaafdc34b257e9b976b26c8d9f1508498b6e8c9e9fd2ff", + "0xa5f645d7a75741f536e5218d4a38ac75f5f2d759e62bde2c9b628a4cac299b477a833bca98010b6c2a8f30b85f407250", + "0xb3947ca7df831d68107713bbd52fa300411bc14362c37c2617780f5d621e211b8bcf5fb7099d903748420818d840234a", + "0xad16157ac24899485e7eae71eabf9e4262d01b8f8bde30d7c79fd00ffb4c347d765bf2b4a30c260c9fe2e5153a3e1c69", + "0xb1bcde4588570576872430e704a64d7130f921667c13101c3fb771efc1e0bd72c4ad4b8e35cbb98d709062257f0ef59f", + "0xab45dce0e29201e79cb1da61cc4353840eb8b47db99319ff7802d2e18f00e3fa8d5e70aa6a797684b4a6741277ae033e", + "0xb6977424f2f5b968a4eaa9dc1ac1018ca51e6158a6a4c189f0adc94ea1c2f30bb33c57960a5c972a1800cca2650e2f6e", + "0x899f48fedeee4badd5b69632f78a244756458529f27c75d05e9c54cb29579abcbe4ff7567445ccef96274c8cf5b7d31e", + "0xa8225095071acb2610d28d9ce2645280a84c702f5f5040df7a4134de1144fe1a1b07d3e28d4ff5e2517b4b2bbae674f9", + "0xb48316873f8245854568a37ad9c5fe9d5e6d9ebd60c9cbbf9e6f63c512bd8568e3a736039422d21d383378c77d8f10b7", + "0x8b40afa65e47ba365e723b9e24bd4a13335455e059346187356ff9abe99cf71eae383ee33bc184a9ec17b32d0800f158", + "0x96c3b7ad1e31b8d4ac0e14358655e21e687beac6f6b7b48dd3750641315ac7088352976e9804b9c625a712f9d4fcfc4e", + "0x914dcb36d621753286340077d16b36bdaa1414eac7a8e7ee84404a37f8fadda837bf4c5a932e8b0f3e8e673832e9b3f6", + "0xb20a438985a4bdaea41b98e831537027f4bf19ea9c1ac5fd37546eef117cd3d41b9c1b125d2302ae3d41176ab5d9e9dd", + "0x94a4cf3cc42d7055b55cf58959a7715232a273e66ec6f83fbcdb79d01769f7e6b1e328f6b0a910d1f8cf7a5ba4934779", + "0xa62b07dc466c2f83dcac7fa98215ce5bece548164e32b4bb3aac055b3c0aa68ef5cad58bf7d392e3b1d54ea6f0d9f0d7", + "0x9870784890da6cb0223daa367163cdd41ead23c300d246d62debe980fc3e7de0b42576309ae35da914474b8ed2c5acdf", + "0xb0f28a74169391fbb179ffe8647f3e6228e75b409c49ba81d34ce780b12d408d2db5968e9664b9de6a7416d2f6d1c1cc", + "0x857697b0222cce1458ff591e1add39f5632cb3aa2e589a64166738d8c00855e354c2ed44c4cee8dd707188790fffe6b1", + "0xb3566bb224742d0871ec5d15ee890755d7e6727aa7e2f374abe965ef8380b49422897545e2cf8fd3f58bc81f05abf173", + "0x88271995f9c647da82820b042e59011121ac723b4d0a2e461cfc1351d89cc10eb7d18830adf1c7b9fca55ed3e910aedf", + "0x863a43548db29c9cf35f24c1d5f7aa984ba21bb924dd9e09210a1feadb1e0ddca98df47e970c230879faa5e7434b118b", + "0xaf5c71b27157a2391247622a5029ba11d17ab4329001b01b3236f38d67ddd6b8902aebb48ee9c963983c16f6d8c53d26", + "0x97abbcd4fff0d1ee2ea777788cc146c1b32601fd93a5ff9908fdc2de225b954d8fc0c9874c258dcb90ecc7fd169823c3", + "0x94129bc418ff5d00ba3a3389b62986fcda5714ad25d25091db12a66e138a35a9e38999c4cf38fe7cdb1340c099c467ab", + "0x8a785f303473e763578a5bff75a069764e346224fa2dd8ee3105ca779cccd5939ed8c21f7369bab9947a4ca92d3b605e", + "0xb37d1644a00401b213f29191a238f4c9c32ba550db2ab3b4c9d1f02021a8f6972ab0fc76d0bc5b9c6291d5edb9632658", + "0x8e42a2c87d7feadf1a2dad9dc822b40029eeb8afb785ce574a340929c4c6ddfe4d750bd3a482e62bfef1bdfdc36f5bd9", + "0x8837b0408f48c8b975ae777b0516c569dad0daf607da51f187bc2c67d3f67315340848fabf7ca78dfa46b05e3fe33005", + "0x96d53e8e9b14e602dec666fcbff8ac2a7ca0474605b294365bab5f5228d8cf0a17a772cf2f37f7de3607f7ea6127d0e0", + "0xb286888ab9afd161a714fcb1954f6046754c1e3e398cf639bc215327057ae68ed69113481da88627839b551cb9660be3", + "0xae5747c882d3ad685e481b0b42907f0934a717ef5b0bcf110fe3125d40628959b879186464f95bc4a69d90754034c141", + "0xb1ca38e7b1f87e4c878d4b878afbca750fdc2509f625a06871da830c1f68a6cb20dde7d51ec73a78454ffdf54451ed47", + "0x82225700e9b32f416618b074479302629114761fc721ff492d792d4d1a4d6fec887185aa81395703fc8d07a67fa4d87d", + "0xa132ead3cac6087bc7bf5153f29ea858a115249d779419e5c52f4d1f2180f4631caf45ab7cf90129af68bf67665b8dd6", + "0xafd4778ab2921b6c9c3d3e2d8ab7e33882f7fde3c8f66d6704f0859f3bec468178eb25a103b78ab092de5b694f2d2ff6", + "0xaa0123ab3e8af146e974c9fc72dce94554cbab212336c8aebe618ea082c15ef02c6b47b6c575d262d1cc6b0cf2d11f47", + "0xa5e35113393e82c0ff3a39afc99a60f90993d5e4995e5d21a9a395ae31074ed5e2244214d4dd877c3d89e52fac6c4252", + "0xb2f476cd5d9df15e624713f22716ff01790f2fe16957b526677bdd3d203fa8af98ae58daaffca10f84a7c61e29ba1d79", + "0x82d6d062828337677ae19ce13d27ef45ee55270a27e674946c7c1c762bf43af6391d77454dda4dc613b519f4cde43636", + "0x8e86b1803d4ee07791269ec9175dc3d3b595197c089551e5bec3edc55c77532235e64848aba62e43936d3e9438635f5a", + "0x845b7233e40eab725c241853013d1884d782457ec188ff7ea535926c36da0893882fea2c9609f96b6d85392471b71d2c", + "0xa2090ef73e125c0809f2bddcdd7b74b4f4eae452d76afebdf47691d2afacd1db7c6a3032e9a4c4ca744bb496258b8ead", + "0x98e759616bf468bb4feedbebaa8df381d01cb4b0009a5ca5fc980426e160698abd6fcd2095cf964eca6f8d92fe1bfc42", + "0x8a29df48ccec0ecb8b3d904078897d996ecea1d2db6b40b79fe51bc5dad04358d7f7edb6543d7d1cf0c1f54544c3d85e", + "0x9422e88414d88e5d84b17f9d2f1c50fb48e9c5b8de215dcd7c52bb26a6ea71cf92c90f3004c4fcb34040eacf5b60b06b", + "0xa643123915445bf0e528d36dd7f2da9a3b993f93a7fc9f6148049fe14eb5a0063575d971ec955aeffbdce069d0bc2937", + "0x81741f92a157bfe12aaabf0d81121e5a8c7df2dae86f5fdba826167c4558103363c653a928babf4ad7e3e80634d26375", + "0x904fe8e258be2500bc5566c3890a9372c9404935ba19396e8cd30289cf02bda13ff3d776bef56dd87ce57aba0a8539bf", + "0x811997c1d70feed33ae3684eee512a46ea91400b39638d405a8bd6f1d0169706f48d1c04beb1c5afc5b10879390a1a0f", + "0xa4fff30378dcf1f04eb97951b85abc0f5257b9e53b7bee814a5acf060919d73504db14d55edaf54e4030b4c1d7278c57", + "0xac84f2568084ee7a715b2387e3fa3b15e6940a27ea99b4fc9889c828179c55f29992b68d719323c2ede8ded3a4e16553", + "0x8fa542c15bd29bcf72a34b3c56eac1e7d4e4f3b15b82672cd956d23a9b9863233816ffbcc6738a225c86d9dd13d1c3d8", + "0x90d94517e7f1236e49ed6903db72c0de3098b42fbc76afae7abc1b09a903cf92cb1bb6a6ec8c29331e05b8946c2e9e2b", + "0x916c0d6b1fb7c74c0001599211ca37812f30c309cb6cae529c876221c5e7187876d37268776451df2aa44f91a3a17a11", + "0xb9ae0c4f0c00e8b07b489e015711346caedfc7cbbcb36acf3a2ffadf2a8f11118f93cb70181c27443d42634b2f2f6d90", + "0x97a51eb35da8b67e82d55fed968ac9aa42cf2d1348ac146d534344c4c7535c29ce25dacf9901abcd7e8c43a83e34e25f", + "0xb2f035822c552cfe3325da99f28aa31b847477a644402d43379947ee219fed751497cfffd3536c91f2474a94bf758203", + "0xaa2fc0777c208a2efb2884dff33c459f2f6c9dd4cba360a65918c8604cb02fd493c8e5d26069953bba56039f8bb694ea", + "0x84c63bbbea15e06775bd39f39995afc613586fcbaf32c9ada1410dfdeff09b8e7f3dd0c99b23c678ee72e44543ee6443", + "0x8259332662ff222d4d2f817bb94033d458e650e5f6e2c31ca84c6f3a4b3d2e8d1f40593083337a17193cddd960ea86c7", + "0x899fc292aafc17d01c06cac50a78edf1f11c8c3253f4b32116625537351a1e82ee3cac67725973e3563fdd73781985b1", + "0x92d3b9aab29854556666588d94c3b49d159c9ba9046487583469ace7a6b8ffa61164839dee24d28dc2fd36b9387b6225", + "0xb54f62077e1e42e18586a03b3d3fbe3fd680dda6988bee8aadc95dcde46c215167b261433d6cfaad8e2b3b6207662af8", + "0xa6c021aa10019319f944f8a77455ad5b153a502dc9eabd9d306be3830a4fa2539e3cb380355953c3581f12348b919214", + "0x8cdbc2c995699cc83768dd23383fe492a1bebcdfa55fc4b9d1113e510a6f4432ae55fd57db732eb56265dba6ad452c46", + "0xaa474f1710bf6556538fe389694b4fb737713dbbc9c93d8a879dd3aee8e004c2441dd14b5f4cdd4a98e804d031ce00ca", + "0x95448d62b1503e71d47ef4f5a01c60c938fc3cfd9280d7b6d3490ef331131130630425adcc53c9c96f262a80c3251e4e", + "0xa4535757aedbf6d7b9bbea99f4bb7bdfd1c99d5d976bd8d4f8c69ee09c9902ea81884d8b6f4fc084e12702fcbb9e4b3d", + "0x87796bbc38d5c2d9a56a65ca91a40530b57fc2a768e9e08a2081734bde163f39e069edc99e87a84b539606164993f30b", + "0x8cb7647e60f023066c4835c956186b9e997a7425cc38465e95be568ab448b7303977c7ddaca73b78f6bc137f25e5e020", + "0x90584dbd8f672a349682effe2f775f2bccb1911b06d20cd02f3a6e30311c6678e5082ab87ee47af72e0c064a43592bea", + "0x8886147e87a552c74767faa64516438d6473ae275e72b4cdc174825696a4d7878297b1ecd0fe1a62fa4559ed232e9e26", + "0xb739745959c324a62943a225140daa51faa8e41c8e20ebd68d6f000351101a89341641933dcb2ac5b3a45ebbbf7fb26c", + "0x814f858b4c709694472eae1c82cfb7370191ad6d0cc5aad69084fb8e9d81e90ac2fae52b4051af25f1b806c273f61e0c", + "0xa00426131acb84ee08684f2fc2a3ef01290e48e6b5f96bcb0459adb62f4190a4b2616eff2a2712991c48adc551ddaf64", + "0xb37a1e92b72e3ba42b79dd997bbeb031a392e42606254965597ea4b8a2ca51f8c324619fc2b9f886e17b632ea3bee629", + "0x90817db93eed264f49445d1d3a14ddc0d5ca93191b6baae278b4c48231a56b25725ba6f7ac0e9c7326755f0082b79587", + "0x95b7f470ef1630dee768698a31398e8cb407df3b651a15493c38f6be6c7eb387148124a2cb1fe1237117617017c12203", + "0xac49be639391aa5dc08e8678cc690ff617e9a0ab40166285f90c2d889c87ac70c455a972e61cfc339db59be4394a0ad1", + "0xa6f5a698508f8047edc45bd605ad4e88245de20013e7a4e51994e99fc60d81dc945504b24f23f7241f28059f4b5d6756", + "0xa4d30a6db06153074871c6adb0ef4e562c1491c1f9841c110359dc41a3bc0bfcba3b49fa53c29b8258a814b8ba1ba328", + "0xb25a500efa7d38f797395cbec660250f4a00d104459cdf7a15b541db3917e26bb7568526444d469d363040fd094680ab", + "0x8444d11f8a0c686e2b22642ba1b28cc556ab7311686028e3fb4040fcce22959b7b6cf244b77c711ba86e350e17411823", + "0x8ce90bfdfa93cbe58421be78e30e471b2c6e6beb1f9b3f85031cbe269305e18d25a2170819f2699346bdd735b6f5d664", + "0xb73970a3dc993e28b71bc236b3391acbd85a8cc622b79e669109f9d3ad7ce7a01a8686e75d85408c54bb70ff9771ca80", + "0xa64cebe05fd027069a18f152a18be155ed65b6b563696e395e045c8b2f0455fa75c2ff41c1247e596451b36ddf258460", + "0xafec84a7a480b09cecdeafd025ee3ee02e3b3338b02d26cb3b7575ecb895057650f0955978d1d732ca2e6b391ed97728", + "0x8caaf53038bfad6e0651e61e9a44a39027d456ff3ea46ee9d8e190698d5a66938d5c5723dd7bc75f0ddab660e178383f", + "0xa91607e39108d2540b4b5c9d33d96328f56ce9574ac9d1d4a81ab5c938443c3d7014e19f77cd55ef7be0a408e44efa43", + "0xa3f4c6629a3c0f34ea060a8b976096e6fd3a91c24d2b056e9b6b60088bb0c706e25dfb31079f42e0ec031aa840f46afa", + "0x96b9c7d3f47ec35ab0270cc57841e9f3b3f5bce3d26faf6abf6cf657b6e949ce0bd1ccdcf9d490beebce722aea48caef", + "0xabd2433b4003b7d861b35e99b51e2eedaea4831776e7c289beae2b561ad69a771233e3d6bc4a7f869d0744c5be61b5a9", + "0xa989e5080d39d4031aea86c03b77abe069ea9b7fbc515c6a79c825eedd6a9bf6a0ced1891eed20edc605f9e25a691f74", + "0x93ca5b311d28e4dfbf4de84a1e1530a9153599e0853c9abd3671a1ce04995e00f7d3092895461137fd78c72d24a99494", + "0x8acebb0309595f4eeb990b7a1543f0633690b7469ce89884d5654a7bd2d2543f09232693a04e1e1b445e6e0041c8b242", + "0xabe3858cea5a873a7576d641571965736d55d46f9040fec219803740dc2a5b43c72689e94c9b61d3c3c44dd3a821b694", + "0x947cd395aef4faeca9b78b6cfcc8b2f8f361de884b29181266fd95b21ca6176e7944058e20cc77c7757fbca4fe445394", + "0x8c2e50234c75d645f3c887693e2439ef42433eff328111b9c37aa3ad5a3b21678ee44ee2959a91610006b27a0f5363b2", + "0x967253e02e34069ac676063aae9a493bc6d52b8bcbf1da6243bfeaa9fe05f8c840ada0a282df9c0180d05eb866402441", + "0xa16a4c9a11686a5294d8329983c8a4aa0e6e5ad0003ab319b493842e8d072aaef45c3335d9a64bfde6bba120a48a72a3", + "0x85187b866fbc72e5b42b91d76e7ec2647b93bedecb060b7475236d7d152d17f901c778b704f7c2c1d3d269341890c233", + "0x83b192d925e3f4a1fafcf22cb48083b2f88632ba93c1d498539bbc4997f61f74a0a3b8d4947253a0daaca8999c407b87", + "0x8338eb3e7f549988435f4f618f4ae1942c6756bdc28a80dba7ccc530bef161c0bbd20f77c8c4d63c94e60bc12f7cd387", + "0xadc869c5acec5e58459eb804c2141e03e3582ce1fef7d40fc1dffa3ca0f923919e291a2ca4a60129e2a470cdb395be31", + "0x9279068c28840f2c34e48e9a7e7e9406907ac14bdf4eec7b8c28ebcfe16a18fcb047015e4309f19e6fd73d6e6c454157", + "0x98c4fb637a868f161f2f4222f93f3bdf13a61ec1f4e4c20435c150fca1bc0c01c790da91afb6227ed2a6aa540d70366c", + "0x9209fc7b307f40294bd9cce166277a7ade9c64277c600b3ff09579fbfffa471a887061e9cb5fac97c423eada30a8a52c", + "0xb1d63569d5d47d052f3a6e8b2c390bfac1e92098291a2adb209f20af875ebb2a8669533155b1d15b232690e26d399ab2", + "0xa2c975c004e69e7b0f22636141d34adfb2dd1396c7355e95fcd0493e931eb7eb99b4df0f0f202945d7bf837809a29ed2", + "0x818f48e65e337913c52e9256af134f4311be84dc332e3ac4cb5ef659b9c6e9cb34f04b0bcc0e2a3a574c9c3cc51d7368", + "0xb92b63d0b363a368a348a4abb10661c38ced99a3132afa6cf002b81e6cac26f862c9d0a6886aede555d7bc453753cd37", + "0xb4051275cef361cdebd254115275b0b86692d3802241cae5e2c75accee7df98d3165cd1de86226f382e736b12d9dbac3", + "0xad89d85749c23e045bcb95c3433eb8038139a51c8edaf06b5cb235549a2f9ad17589097ff8a350e934c8662a8879a3d4", + "0x802010e6dbf4265cdb5b5362c0b197317f2435253237561a3a7bc6766f98b129ee06d370382998ae70080624fd65831e", + "0x8ed6a5b601a5ee11e983035f3109075444b063aff693b3601f87c0d76d2ac253459de48d0fee32330c3785d38eab5cc2", + "0xa6c8bee787c4b87137f70c2c54ad3ad0955269c7ea57ddabb1a215e613e250944cada7f241430c0ef09f8eee29fadaa7", + "0xa3fc6a643e1ce110b08344f8913ea7f8c9e44bdf1a02978df8dcd3671d9b357397df9857fb11ba220521d1ce40064ee5", + "0x94089626bd9c81247f45e25e573bd6bf727a0e1a7dcd630dd5e661f65d4b6f35bdc16b64da648dfda404b5eab39d9152", + "0x88362a160a95f01026a2e52aee3521e8496340f96a35351892034198740d8b6159175c60b910a4ee05af488dfa578c8b", + "0xb55a5b875f5594bf41949c212543517bb1ce34db3a896f93d0216813261aa95f73663c789ea0ceb2bf8815255bd328ca", + "0x8f9acdca0158df5ecea4d574e0ef0c256ab271d9d3d3bb4100761f5062f0a1a5d2b8a23685097a1a2b2a08287a2e2c94", + "0xb6d4e3bd49a17fe7d929b41fb223eaf93141453f7dc233eaa74424290014a63ca6a099174b687048d59cefd41fc720db", + "0xac0fa8aeca20a0b4189e96c57c85a2174338550855f9d0ff0c553e773a1a1c32fe3f8db7c8362bddf601e41380c9177a", + "0x82f05710f08f12b206b2ad6a2d06161c884b2511ad90b43fbfcdf54933c2360b7c85dfa4f598b5bdce8809a803d483a0", + "0xa2ca711642fd498cfeb897e4072d13e43b5cdb2480449975188fdfbd4b471070cad941af03a2dd8938d3c376366fd199", + "0x90c27a1df934339bd0821cacaac41fa70496900044aadfccf6e5fe28ceaebae5cbc500fd6f2f88c5552b7fafea79d06e", + "0x818651b7c7a6f691fc47a61ae4960bba7239007e14930f3a8cc9c95dcc0b03643047671f819e30d89c2d1891640fc13e", + "0xa88f01062ded714e7f2f1523644222cd8e8cb8e535eda88738f4b4b19079f4f7be664abedcdb618ad1de3e74689042df", + "0x8174282a183f3f393667352fdd60460d2199de16752c372a44465f8b71ca134c410d1d81f15afac839748447875f8643", + "0xa358c3e53dd70e1a608f36a1fdbe225e28c13b5817dba890ed8e82adcb7ae86fa68ff6cbda7e02e8116c11587ae1ded1", + "0x8aa0bc208a84d5a58b0206a8fe5ee3c8d224ccb86b11b7c9d924e16b2853a6c3623502dd60b94f8d720810e0079078b8", + "0x8bca870eb6cc5f7b5f6b84f88b49d9a3994e61ca3f2ad963f28f925e58430887f5362ed4bdc2a2a38b5fb9e774a75cbb", + "0xab86840fe84b1eab81675eeee17f85a500dfcc95dc4872e57b39919ccc71b702585ab9ac66146d264d2bc8fa39338a72", + "0x87c46966a4bbf2523dde607852a40b26cf3431d0bde9b2c609997c0f29c5932d28014026862abb7d4107b28ab8e2ba70", + "0xa91666a8c846a9944ee7ab243ab535e4124ca8bbb756777609aad848527b354060c484acc19c333459c09012670f03f7", + "0xb7145784894c6df87d2ce6a06cbaa713e46097b5f83db60e5449e62ed5bf382a7fc3136e5599226a2fe7951847527c4c", + "0x951bdbaaa06ba8b427fc4ec6bb44e93e70692bcef6369fa06c7a6882227d27f09465f37f0a5868ce43ade188a5f37f8c", + "0xb69662dd5dcc9ce7bf24be8a0e85e80c8e5af9b030e740796f91de548569bafa2fbcb19d98e13900c76cae3fb601a8ca", + "0x9630a7eb15718a2324518f78f26a71e3c801a8e2eab3236be7623807321c128ccd79c74ab657ea8e115d6ff3078a6887", + "0xa2f98c2084f8cd556cc1bab19398e98921ef56f6445f63444384efe5d7c895690c57d0d94cfd24e99f63f5e31859e34c", + "0x8c3994d3cb76fc6ac22ba2049ea4547db92ef78f009d24f08695b282c95e395f2c1477bd52d3f569d64551aa5e259b5b", + "0xb58571076faaaa547df9522b48c684b310500850339d79d2349dd8211bc2c8307d13cd5bb7571e0b5baaa013b502e410", + "0x93e07feb14f691e66be756b37467f290da9a6677b8ff565964f010fc20ed9c58d8c712c4abaf012c787bbb22cd1473d9", + "0xb4bc6159db1578111190b19aa678281eb2fcf7a82c7f699da7473720493e66e0ab54429da7af24315ed9f7399863c954", + "0x93cfc98563f25b45c15a07780ae0a38c4ada52ffc1350233a3b45417c16cef92e7926354b761d0e0de55aea4c1314406", + "0x820c37c923807790d77d2cec39f0eca63fa3ac6eaf0a1978522f0b1d293a5c46af3a0b4ca542cf39e796afc1fb3d7195", + "0xb87fec722faec6a739355fd30a2757e5d184c07b5bbab8581b74eabc2da413faa6d11ccd65cc93f886c788239b1eefb7", + "0xa183bac7f647a0c15b14089879a8aadb712f079bcf2078d3c65851137a00dd3ed7e47263c064feb19362f98180aa425b", + "0x996233b2010c20e0246295735b6d5b3e932f2aeaf0b35aa3dee66b6296f39e2e7ee95a7e1a15838ff3389ecc8052e315", + "0x85c943e09a6c77e15d49ef4fe57d89744fcdb705ca370cdf70b3d84aeeccbf2155868f6790333f88fe36e08042ce195d", + "0xb88f82b35ae14a3e6fb972c47123236bb7db08b9f9f3828033fbf5a895b09b9b0de423f1caa04b3e8e754409b21f3a52", + "0xa12c957409b6dd335964532ce3c045aabd280188b4d6ee809cef479e51dba030cbecc86b0ea8777cc8828c087006c5ec", + "0x87227fb4299efa535240793cf0079e952e971a18ee62cd71a62d6a5db921da669c5d8eb1bbda318ed5f3b03b38798a73", + "0x84b5c7585fb1c98d031a0bf6fa8ad5484c7766025af552cdd72e7ae59247deb845f8678862c44ebe640a7333cef8391b", + "0xa94cdb0f42ae3afb4b1878f960669bd99008c7ddc24f2fed45ca521c60472e5587fa9bf97b315efee1f74619a4d9b762", + "0x969a9bd21a6a90aa30fea44e397cc88118fd5abeb68839556194f9ab0076806aa320928a8ec94a47c4eade15498f5175", + "0xb2fb215bbe7acc3baa04b0aa9be654afdc450faabe2702a0c9fa760c9e9389a58aa5e3a4c6af4f6f5c934640d90b59d0", + "0x8be6a43071464e6c7dfb0e9a791a658214c1a95adc88f144d8349ecaa0e76b8ea5f88cfe95e82694bc170e49a43ec4cd", + "0xb75d56cfa1f3b61428d24784d51dd65b78b977bbb52cd71401ac7d3c2643f3dc097d6e7668104af402cf7e7e6ddfbaaf", + "0x811005c49d1be377ebd2fd3bea9771089a0f5675c55e9da5f31fe13cfc9d1ff8520f085918279ccbdb0363eda16f8056", + "0xa487f7000c16429f2b7bd7e8bf4990bf26f666f8aeb11a99114d33e24f946cb0e3e025ec8c0b0721f9be101504c8a1ca", + "0x99b72e711ba7b97083976b2db7b97346000a78bff9b20ed910eaad02f6c03b45fb3f0f1217b328c3e2d87b481eaab52b", + "0x828429d387a0b83ac8e377b32db1c893a4555ca253b8e3159399cd053c5de726655a2ad39348c8e7ef11b37b0bca78e6", + "0x835de10c73da7f0c07295a3306ffb18991334c86e5fa4c6df2d8091e8989f6454c8b43721b13696e1f665480a64284de", + "0xa4ea48f0cc5915993c83309df99247dcd7df4c15c723d168759175010fbe8d84adab8393707cb338fb90a6a77b69745e", + "0x9976bc842b06ffbc5afb309eef8964908802e9a5c733de4a8292d5d5773ecafb6daeecc63a8dc8847d76b77d4c3915ef", + "0xaae89156b013e4adb4bd8e7b6007937f0ece09af077fd407798e4155dc09a129d44fe8f8b5f6cf6b3c84746181d7f4a3", + "0x81891cf2d70a8c326c6870a8158edb79babf302b4f9d51229bbafdf038cee39b97f01694eb719df99a62478bbf909a85", + "0x97bdcb526108ef3cc2205aac074ef3001d528f56b4889573e0f4a3a2504232adf23880f7fa2f57bb787ff30b89599da9", + "0x9778949a95fc663c742e70596faf91ccaf8b5b93b78bc2d4993480722ffe10bab3c8df3ae50535d258b6e749a0abb86e", + "0x88bffdb927dd88c1ba3eefe7da3fd6a42ae494bf282e094893e144330cf08e3f518f47aa1dd76d6f249cf83e6bb9d4a7", + "0xb53effa345fe59917f4f1ae754e9f6b8fec9bd34cee85872b3fc47e52fee29c418b9406aa50c8d5a2e853d6f2056a49c", + "0xa616775e7e77e846066fcea413f0023dd491d8176dc450b0941368680571cdd236f0f83883d268842fa61dcbf3e4864a", + "0x8b5ae13dbbd07ad19bd2c7bdb48eb3c760244fe0caa73d28df3f0c31f5418f8b06862526f5a84bb16b2a92eb2c7ebc28", + "0xa62294830750dbf43ea497155b185d611d75e767aafa8c2c30256f8a4875b6fdadaac429e8363848b39e964cab2aaabb", + "0x94b6973fb87c2efef5efc0e7dd7ecff5ffbe76320fed8a20d730f9e3751efe9e5db39981f45477ddfe037e18cb971930", + "0xb931b6f789947b5298c258c8f0b221ca927c447f190f0d8afe2f18ce9b90979eb3247e77e128a1d6c57d3bf5523e787c", + "0x968259d9d001a08c0329bc19b2438b48dceb5942bc6ff9892d78fc36014f1b60a5ce7deecc7a808e41aeb4e26143aa41", + "0xa52c1906f103e3fbee8c12fecd93f7b7d6f37eb733147bed841b32caabc880fd6e72884380a3cf93129d9800ee7877a7", + "0x969dd12f0f6ef0b868e21539dcba5dc7327033eb546570f5bbf91b13f9c2ba6070da430538c40bc53a2ace4794514038", + "0xa853a74380d78710c212bcfa92d3f9c433b8ccc6936356f3bdf923b8e420e1017bc530ce73bb8d04bf7a25b20594c753", + "0xa84dfbbd3d9f409badc8ac2da5a0db98124df9d01bd71b1cf5b2b9c32866309304848a4bc1fcad1130bddfb9636c1b56", + "0xa9599f55173e77dad54cfce6ddc77bc48588f36b79a98c156963a2f5397262ae07634a98ab9bfe1aa6357f78aaf89d89", + "0x91e429b5ad0bafc09b5eefe600e179ef56f1ee045765ab3d5ecbd73eb201305a6de4382038b1350abc70bd1435151a0d", + "0x8785056b83a726622c565985e815847b63745fb66b138d24c985d6f42d5762c61ccd5172d4a3237222c881e5f036b98d", + "0x85869796ef180f500dae84f669b76a9b245e2ff4614a58d74820c22e439837b7d9866f480b72d88f44682be54c6dafb8", + "0xa118baf9c17d85e22ac3315f5ba9aa4e230ca2a031906f99bc43fc750a0f96aaa5e6774d1cf16b492726a37db7b51327", + "0xac8e33f32c1cd14c6de14e75f83b8518bf1bf6f0a70e23ea0e5a29f096e2992f1259a121bbccc5252b9668c605240435", + "0x97babe93e2016d29af74f776e167d82f1cf2242202bdcbaac4a1eba2b3fbd9e7ce57cdfbfe799a0f6a06a0e6838c4e99", + "0xa70acd7e1f159adf7381d3f3ec2cc42b56232601f18ee62fb650e13a80954cd06d39a57217ebf4d8927e28c910671ae0", + "0xb33ef5c10d0588df0b9d2d963912b294a2375a26bd25225f002cdc206a1cc058465c64180d348cccc899baf3d677033f", + "0x93086926eb1be21ab929b0098767611bdf1a853b6b67045c14f00714f806f8655be37150be1da05c5d2e6d9c66057bf9", + "0x8890aad532a6c9b818ddb9f1ea12d627010b4120fd4969bd239a9654a05116272d4cf783ff8256de337bc01f9b4154d5", + "0xb878977630f647a5ed7c99f59ca5eb653cd647277b899b918e5f667eb17b6dc433b56c2f3a2a18a785a4b5a9ae95f372", + "0x975582fadbc276c9afc4d8ef767a66684df5f56e898d2a8749cbc2763982c013e5fd0ad0ca7ebc67758124a609b59663", + "0xac45e154a651857f0464db38afb2fb25853e8bb1eb476df31908b13b4fc86491d4f831c0a15ed6bed0c873b3dcff55e3", + "0xa778d373e361753964a7fe4e1d28702c62a919e5203b941b04b0e74cdd3b4e838cd9b6dac3c39dd523f3227f1b5e6766", + "0xb1bab7994941f8de4235e2e188b302bba847c1618ebdec7fb782241e9eca8d32dd506d254d865e0319c66396535cc484", + "0x8c4ae5b346325f1d1609328e41d20108c4388bbe021361a86a1f9681caf1e6fd64896d72641ba8c984e153537317420a", + "0x8cd312c6a23e56657624d21f230a2c22d102badbfb2e38a8c067186abc5a459d0c78433ae7b54334591862c18864d7fd", + "0x8739d71181c5a657c6fcfee1df71756c3b6b8c48e8d97460fb64eb891abfd23433ccd08574a677fff600ffa5519a2363", + "0xad3c8d1e9eaa6f9122fb14d323318bb0338c5f9f29c719715cbeb15a2738493930542769b596098a5f505359c0314381", + "0xa6d78b78227f8c1203e502caab1213092f320e77a6e9729e1659cf81e981cf905170e99b56c4eed1326320acc6aa60fe", + "0x8e5ba0e69e0f08a49ea4fa28ce0792f7ff6c032844ceef11be90b2215940d4b0f3e4acd5e4b189b189b0a0ef8045aa26", + "0xb7b31957e7a85a640b851d4241c7b2f6af64f59ac221783b88c1b51cc4185f5ae6446a3c7137ee072c2eeb97c929d7ce", + "0xb066bb41c5818d6008349dc6015ab780633cd961b5d947062e14618c1ee1abfe42139c86b77e7f5be0c275fc3f5b8909", + "0xa6597158957e1a0af153183151fbc4c73bbf8156c77f7b409d0f97470b5e127beee6d9246bde770127d3e3ad400cddd4", + "0x82a6de6344e5bd0c5ca95f3be1ccd42fc974403269874603944c08ae1cd3ca887e66fc51ed61da8b7af3cce02f152e6a", + "0x89fd363aea11ddb2dc71288bb534a4a6e32feb5b9e4b88d132f4181f2579f8f8f39d19fcdb3d3d7ea118b9f4431520ba", + "0xb70c945986c8227d239201857e12cc7cebc932c3bda8913c82b62c872b18f866313738788e11bddd630bb5953492fec4", + "0xb4e3a1e8f82d988c85cbb58d9cec69bc63fadb4c1c9a09f36b5a61f1ee96baac1a9458bfd0f3250e1734ab3fc6c0a0d6", + "0x8d01d1eff496e8bdad1e6fb4b60e4bef0ada39a378c8b57cce2c115e611e0c4fa54f9b599e4c34dac925bc06e940eceb", + "0x90857123505746f7bff08e03b1a90f67051a71ba47b49e7bc63f1a8ec30e02a98aecf56465d3b4746aae166081099da8", + "0x98b9d3b7fe1d5449bf6498c30036e3f60c8b90962fe04ede9ebf605d07497f617d99d51f0f0c0c14381377de765ecfd4", + "0x891e7867e70582ade85730a21c19f6fc239760f76f8bbd8c6dafeddfaabd6fa4845f62d649b454fd3af8ae7028ee5f9c", + "0x945136f71f290d8cc6bf282b554cdf8ff92200feb7901987a1348f2d2edd3bd7b7bff6f57ec25fa302a27121a1a959af", + "0xb574d8379842467c5f3cdabc2da9a45e5a6083efd7298b077ccef2c4c3bab03abf1dc11507f4c896d745ffd41e4dd319", + "0x946fea5c1b1d840c10a5a732c7dc23c2bc5eeeedba6956f85ad78fc1ee4a95b309c0d4a4919d1f7155814e3f36fe322e", + "0x98befb2f7d0a860de662f28968fb6200cee5a33cd7a6c376405a9cc6f0718b90fcc5cd5b9142e84e95223a3dfbd10f29", + "0x8c5f208ca23aeae44a056bc21e04b570c13bfd49b14681cc085d5b318e62e4c088f0bea9dde52376967649919b59829b", + "0xb14478442f8e985618272d4c56d43a28e10112ea200b52fbb32b19a4d1eae965fd5ee1e9772416d52dc0e2db57d3ecd6", + "0xaa308b19a57159ff702bceeb69a385f91339db7e683db991b1414bf3af9916d8e52dec4c492d7e8b5a5a011680defc1b", + "0xa8ac18a1adeeaadc192e15b7e92b611c936ba9cc9aee01f03c2a236827ba527039c719f16149d7aa5fb297cd63878766", + "0xaa09af54f9a5fab6a61552421c13ca62f99fae212a9606f8a5a050997271ab6dbc763390bb98d90b1af3bbe9e8d9513f", + "0x96b8ce26b346a0d3fc99b6e463f0c619196cd85340b795fe1c1c0cd4f1b3a9f2bef5454e0bc7d51d75ce26f217460602", + "0xa3efa46273c392704ba0718a44f306edfea03b1a6be0bc1e5c67c62c89671c650eb8ac9bacc35372ade6bed12321f1ff", + "0xb484881108a43a1dbc16a6e7369a04286f896aaa1dae847b4019fa287c18e9d82c8ba4ad22cea2837bc220524a9a7a17", + "0x827b63d83e15ef61d54dfc365ed8a4f9e200d526884ec4b1d35032227245410ad7e1b1dd3c1d0ad48ddc4720f0fb5e1c", + "0xb513c3ddafb01b6189590b74d20348db74e400c106202dacd9ea9552ee2c642909a7a73ed7ab45a986eda3a0701be79d", + "0x831f4030463c84cc6cced28dfce0b3e6b6ead01afa200ddffd807f31ddd4ab93a8699ccc9d26970407628d521118ba6c", + "0x86312e006a800720329b82f6feb2934e2cc156958ba394278caa6766ee10800d2fb8907aa92346dcf6d389c4f66f5e1f", + "0xab6841da372a286fde1dbbc57cfe967cb4bebd6fe2ab9e317cb9f9eda04a4db0d5844ffa8db72eb9cc6bf311667ff6e5", + "0xb8238dca3f2be29bfc4aa65a9f59bd4e2c17fae78114a69bba1170782b993afacee3755e768317a923fd32d860f6a74f", + "0x923c1b60c052a3ed4736da7e84e52b0e9e154627cd90cae335dbdf05af109ceeaa016954d6e47fbfc40d9d5649c198d9", + "0x96a69d18c838512d95d97735263a8cde752b2bc790b3827ce048e177a063dd11e2a69b86b3184873503a68170b2ec255", + "0xaed7c3af469a93c22afb47a904bc70b7d88262ecdad48ea6a6c07eba7398410bf5a97a786beb11843cf40ddea9a37098", + "0xa6b50f6369ae558dda3ceb8cc9d99382a1e62d0d9804b903086845479b9381fadf8d4595c2f342307c94d09e02e0ba2c", + "0x89fd703d457580a76544bbaecf65f93d3335d7a22e93d14afbaa61e5236d9c8d8b005e403e9f5e7a103b0386971a5e65", + "0x8e909a3638208c8f885820af8bca6ae839128ce0d902a2b7b6f9713d21da8c943a7984d9aeee7fb104df4cbd1092967d", + "0xb41e2d7a1a0082eef43e886eab5e781bd961a83155d6a14d62756ab7144a208f4e4574d47d2ea094a7fb50d0ddd7a241", + "0xacc6c63450d124014a1db846bf578c44e910436c83190fae428fc3125ff2065d4c6a1165aea799b46093a86126d4c483", + "0x8dc63127435cf2f269a83024b562b3f4da18aee3399ed5255c295e6b80c357cd8f1887de94bcea29f84db3193570c417", + "0x8c4cc72a98d42b9c5807322f596ac0b48b08b16ec956ea4a70c641a16a70895644e5b14aee85a4046673849249115abf", + "0x992afaccf05d79a3147d2985970c1793459130ddfb18a9d31f3036c260790109c9ee6a19a812f5d55779c2facf87785c", + "0x91394d3e84649cbfe018d9c709604f6aeed53e91cd57e2b29d0e84aca3c413f1e0135c6bcbc70784dc8985a30b9f3fb5", + "0xa33fc126a8f9652c6905b1f522bee45848ce42d7f4c3a4cb3f6ce0e6e64c82de74e175c2ab6b5a867a8d42322d257ea8", + "0x962d5fb816010a14140767c2486cd629f7793b304a96cb82ab85a867bd9a407bc8ed44131f87238c34a1e4ba41adb1f4", + "0xb09048879ce26a34f56e1d4b2cbd6eb2a55d4ddcf3738c462329ba6726fc0a21b8c1bb55169cb8338b2debf20dc0927f", + "0xa9f9ddcb86b7427e268973bc7f3239212716df394394fa535b9fa5225b6191d234a44a126766eb470ade18c469a2d166", + "0x87cba6afb115c0b3a515b08cc842e7cc2c705880c82184174837c0a06e1687ef668609c2ca080840fff80282caec7390", + "0xada109548c449990dd8f1bd42c9cbf194a62625d165416ca469c334222446fad7a743b1f584ec3f20526c3c44d870696", + "0xa69a0c58fdfac715311dbd37c4464f0475120362234f5366ffc65227e8178e037ae91efa5a52cda5fe28243f47390175", + "0x98e726cf884c6f706fa25fe25be154afaecc0c3bcfe682a85afed225bb44ea07cd1767b4d9f2201358ef19770330f0bb", + "0x988ad5bc57f0621e3ce1256720f1161e785371fd478c467c39e554e2de27df5ab8176508658aa90ed7179bc212ed0dac", + "0xad0ff6dbfb397da51fa4d9d959ba5819adbf1a1ee31f68fbd62ae07a9cbce0641588cb1008dcd0056c17d74e83c7114b", + "0x94c703cd32b9f52c41b07aee3e3c19b8c2b4182da80487ed7991d568ea8827f0cdbd1e977d482dbc102c4de2058903c9", + "0x906fc2a06cda5d82445e50bf475dc4ff2c17e64c982539c26545798f9e4dce0bd4daa8d55b027cc0a8e1b26c3e45cb08", + "0xb09a51f22a9a24cde25f805cb18754e27d3d168e64db4ff13a202839a81c69dee8372b5872faa0d23fea283609cf4391", + "0x93c908f514e97502d170310bc495d02948d99eca51e71f9a4779ebabae1431e1f7ba465af485546a9fc97c025877df50", + "0x8337859db710ed7e276a47e90cb3912c829151cc2bd3dbbd4dd04acc90c9cb4870c44f4233b407db8240a93aaaf7302a", + "0xb13b16ea0943e235f8cb064d6dfaba9bd8dac67e9b6275a4c3f54a1770b9c905d8855517415ef6489843848108dc85ff", + "0xb28489f0de1a76839a898b8d2f302c95610f17e893a6e7f2e824fec773cde6f2b219038a3f1fa212bed98c97daa66d5d", + "0xaf13afb48d56caffa32f941ac5542ec2b7fc0d6dbc3b16e51bd2a8b633f0a041ba1e098d9a68c470da00e630f08f24bc", + "0x81465afadc45ec24825cba7c9edbb36858bd2ca8f8b0b9d7240152b58a411b08503b530932e7b6ec3b0f8612869cb244", + "0xb2e6b7438fb6f70b52b8726aa870f18191920bcb213a375817d100297b507908d79567d0c1780b3f25be807a8ddcb853", + "0xaa7ed2b0b2bb2070b5f001578efb3d1085950c19f9d06584a2d31e1c235e6d6d1d7f081ca6fa2b0b0616b01b9a467005", + "0x91a245f1aa8c8ffe03f7db1412e5466f0345196727eb8e6f98b80c01672e4260e90724a538d26b094e678a3d85f2dda6", + "0xb9ecde963c8176d6a726b129f229d803d1a6259533e432eecd7404703c972ec7296ba35015acb1f4b5ab2653a3991902", + "0x8cf535bff6e98f75d98c5d2a691a5d1aa645c7ea18d677d07d3a11a9cfa222a7b8edd048529d163120a5aca411161314", + "0xad2e51afe96dd0e942a7da5a37587ca1359fc17cf66ab70cf37ab70ea34f90054fa52503d6527e89e464f8058f5cde79", + "0x97337d62f83ecbaa1f402c3964dabfaeb279b916ca08430a61fad6c31d60087c7e3a9decd541651a2b6e68fb2816bf45", + "0x898b7581288bc7f97987138b7481d29e2cfd5255ebef133177d9060790a0973ba07de62cdf38568c336c237cb084b7c5", + "0xab53c0759663bd976de62f9f98fc82fa4f58c146b8a6a3053d4dad836c762063ad69a54d51b5499e9def86f8d4bd7ce5", + "0xb35ba58109d44c14be159333b999c1e471fb61f5ed48f9d2a6bc689eb045864f3fe88a6ecae12315183703e2b1fc1ae3", + "0x858a20e233f2860c24c5a3f4a820cac7544eb3ce91a2d8284f12013b13120121fea3c4f25427c3524a1e883aead429e6", + "0x965be1a56adffa51f5d80761327cf69656e6c37577225b36a34afc2f8a959d8799ad0ecc3eff4470d49eb22ebf8f198b", + "0x8e575ee39077bd865d70fca2d93473f51dbc99ef4f715f4a3b1d9eb21deb2afcd0873b4dc53035b77e05f52029f069e0", + "0xa5c670a73da241f5888c5cb44c27eff2b8ad3f491e0b128e5f1d498aa6d76640c9e625f3c5399ad8e99b666e4b2a9759", + "0x920e1524255b03cbe500edb230696c55b7774963535c063121c9e9987ab74d504f2f1cfa14ba7ca82a6f66745fb0b392", + "0x8a0bb7cb267b8e1e0cddee208734632b28313b3ad89f9c2168f341be5390bea3f09eaa51f8923b87697799a53201dc26", + "0x859ab9b3cd602e78dbee8d8d5c3a9eb4270f130ea4a1b417ca5612be753d20106cb2724097840ca8919a9a96e73f96b9", + "0xa76126d9a997fb0e7e2b27ac682dda1c6b99067313371387084be1f6e7a9a59bfac395e91f089e14cecafd151674a446", + "0x8aeb466c58e2829790975fa08dd31f18a51a63777070d2e24605adb1a77b5e0e5c5e0bcb483076d23a6fddee5f402f8d", + "0xa8959f312f2ce0d7d974a4998bb709bb98ff6456413ef4ae9bcaa8d687b8b5ecad91414bce8f704aa44a83d8a0c86462", + "0xb9545c8567827fb28d070624579702ab96af4f06fce515ad880893b97ad9a374c4c91d6288e2a584ef14b1ce4930a6bc", + "0xace41f9c2756ced611da16e21704a367b122ee1c2feb83145103203ace1a5cce0ebd3bf295caaeff05281672c92574cf", + "0x93b90e75f56601191e3b568368bf1d24f97512cd42cac1da8b42f0019e07fa04cd5f835b7e9503fe4702632df27ddc19", + "0x973c8feba289eb473448c32b141ab4a6f861222626b3f2fa265a431a54675dfe5eb479100a33c172ff935464d6e85f90", + "0xa6b0798ce89512644490d65ce3d0441ad950f9a25f6fe2c9a766a58b9c8222fa6cba753f314cc7ad6b6e3da881c67abf", + "0xa79c560dfa179075e0d1506adf5082318915c15048328b15ddca5748ebc6ed8b10fc5d7a50bfaf8942cf9ddc6912be0b", + "0x8841b34df170519d07edffc4d33a0e70c518dcf53ea8d0a9f13563822312a65d16f99cf596bb95eb0daf85435d4bc0a9", + "0x88527539258323edc2c296dc742cc26b9a4a984ca299a81705c702a425ebc7345a79b4df84b2d440a1e73a09fa18b5d4", + "0x88026753926a068e1cbf49a9a0fa545846cc7ca9abc0778e44f5b7510c1b6b73e9a9b1aff754199379522b2a985c0881", + "0xaa2c306ccf91f967b5cdcb50808771ede36acb9a6cd84fa15c6de4c873cc2d0a64e79778a2822a109b41f5205fccc30f", + "0x9751fd8bc2a07ffe0566e5587e652d3d8d5250517278bcf8754e14717b8941c07c194f14fa757f9a2f3461ca6376bdee", + "0x919746e5eaa18b734ef59c0de09ee8ec65e348efa659219d9eb6a3a77b8edd9449a6dab727e9860ca0d3837b161c0352", + "0xa271c146794d6a65c6fb87797262c22b1d938ecb2624e03809233469296d33ac0de6909183c8efa438b5f3971c8c3eed", + "0x82fbadd9049248914a15755dff692bf689eb2650fdc6e44e8f3ae003b8f15a0f2858c7a2a8dd137b3448420c5f434229", + "0xb90992cad6df98d2fd1c75bf90978205280d993d439c44d6721cb95d52eb042e01b418e45c3c48ed667aad577f3fd1c1", + "0xa0c3d1e8b80ed4a979a22d6a9647bd57f22ac8d73c37ec3d56d06dc178a5c9d5ad3ffd6dba9eb7844c1f40b8c89d3d33", + "0xb513aaf2f0a07fff3543d8687426d07773677ca4d23554ca517e50bcb891164d1f5651944a2f6e0a634475f6d33bf0dc", + "0xa0b179aa2ecf572ac4a3ed898aa34679be3cf3d8d9bc74e33609345cf1743e915124a59ffcff41bec012ed2a99447e6a", + "0x8e991c5549126d64e0b515a03d266e19097eee38d08121d942973d568f8ae23a15b037337cead0686f7c944b9fda3e39", + "0x93cab29e1bb116a39ce1a82897776da1bcac06ea131a7dd141a688ecd4089c5a0b8616d6721b1c6d92309ae0820a367a", + "0x8d4e0159fd3534172b2481764cae7746b1a47e9b7b9465fcec0824ef234674fc567c16ca7116dc90ba9b2ac3eef28d60", + "0x88cbd9ff6ca551a7efca30b5f59fedaca8f9efaacd4e9bdd17ef0dcfe4f3449b52c7d3066716f3e7fd478f264d10714e", + "0x873c71b2feef5230c31f13d8425f8b0eb0171eacb9225f484a36da3cc796d62594fa4771af9ce1e7ba951f5377e5db76", + "0x939eb99d7fefc9fd5b3dabaaa5b331365121374a4ced862b8cbe0cb3c574fb1f0cf4932106088a1d87522acc31ba7f77", + "0xb283f1d54bcc72e31ef572498821ded40485f38d2ffc67f70bac68a100612b020a538b36001d94228a4dc97da8fdaf17", + "0xb2e4c2be605c8ab3038b4e91bca7e77e127c5c3106913ec1341102e138bc8aa1d218c3d3c2ec1d36fb8e044b4bc211a5", + "0x82e73cb5b2cfd78c17131e871e92026643bb56916ae64f009a009555903df878fa3a2019b82f7e71a3ef7eb503c792d1", + "0xa6d828a5b7de0e7818975b65244f6efeefc712c29f2f17b27f3264e19856d869c350ab39750ba63d6d46afa3aeb369fd", + "0x865b17027e9d5bdf2de0afa2f524f67b6defed87b14e0af5f4b6b1966c2de45550fd2b6b39b1be88ee9cb06e755f917d", + "0xac8b47f9b7e675b556445d103271e6bd3b39b94d15ee1f3108fd1b777d439c75437c78ec3b281f7104af6d0efbf0ecbd", + "0x85c2f71ae18105fe499aa4da0a835de3e92ce05d0f28ccbcffdd2860898ae9909e1c05831ca4fed96545133bb3170302", + "0x8bdb4a72b06562591ee44799bd7400ebe71f6737290420dd4ba2bffe0050d8ea4d586b7e329541a52611e945ff1b16b8", + "0xaee4843c9ab02026ae723531112170bc7464f51460bd4ba5166fed54ecda0f53342cdf94f4354a5bc1b941e8ab085a80", + "0x84de368006db07c89a7a43b7de54a63637ed72379a41d029430f6b4ebe404866896d2e84996998f7b2c20324143649f8", + "0xa8375f69c01289cebbc97843f417d0146f68c6416981032bc1f42d3e09845d5131eb9b4d68fd0ba7f5b1223b83e51bab", + "0xb1ae126dda1a88fee9265ed8e5bccb810014044d83c70e01e7f80059a685067f4204cd15809b230caf5dd77738a64e38", + "0x8177544c7b1f77181735c660102da20fbf9a2ca4efa79b21c92f1cd2b912630aa6c830b7513980656bd275097be59d1b", + "0x874fe8038905065ff3b77f1e53904854fa4fcbdc4c8959fd2df2e3967b3b84100c6f63fc44338c01fb26c042c454991a", + "0xb19324d737364cabef3d2ee4785e8f19cae399afc06fedff8fdc120e0ce525b3755161183a1f5ad11ee758104081a49b", + "0x8e7525bffe35c1f5c2db63ee911e7e0197951ebd25868660e6672a3e7d4fb309738268b36677921be3be2f323ca718cd", + "0x846c51c7d22e7d43f6e2addb7fb25113c25ddaa51252a898fc1d7d5b510f772534c4f5d37ed3074d124cb259e2bf8110", + "0xaafe2a16cbc901730178841c39803ed84d3a78f92f42f84a1c01be4aa3b63ed7ad9d054ceaa8a2d56eadddecb287e8b2", + "0x8781c9810ffe3d93fbee3b576a15b8786c3efd6b5a96b75819b1f93daf413d4fd0f56d1ec277e8f5adcb784b17f08371", + "0xad66011f0e2927ee1924725bcf8a296069f74df78ec66ef6aa8792f68425e48e9d7f717d022f68a079501770ce192fce", + "0xacd0ef46fafb06f336565d86e0b22f9e5500d2f73d047c827d6a207af40b706440afdaceb32e6571deaa1a79f5e6fe27", + "0x8f65bb98baaae22e84a3ff375e7598b5c61ebec676fbb5a4f79c8463c427eaa96ebc51b1fb504840b7b0206ca6c2c72c", + "0xa4078341325d7debf766e43679b8b68331dc13651455a73912afe062525d2ea909d8829ac08771d9b32f2eea28b64022", + "0x88eb29841b022f2ec9029ecd1a137173cfb79addde1c7cd4be425e5806ea6ee295b11a0459a940ba79f789689a8fdb81", + "0xb762b9923a40a1965847bc7d046723c3b8f0d63323303aa3b25e93b4af8e527f1afb3dafda831f50baaf79926d1b1e78", + "0xa21551dffcdb069cb8f30b625c8404dfe5efec83227e3a1a67ef0c9c9b49c658bbb31240c3ff6f8c68e02f67974c732c", + "0xb4735a6610c371754001425772aa5314b759c24da50b38a9390969c27e215ad9d463a76762323b7954756a8d5ee7936f", + "0x81bd78e545938f8a3e53ecc2e88dc26bfbc30941cbfd009572d9b38f8eee47a85209a318cafe8cbe055eccd5e62d50e4", + "0x82ea5495db9dd48da97723bcfce02788549c6006773eb9f4aa4f0f3ae13414430edfecb5cd095259179ec2014b6ee1d9", + "0x8493147b8f0818c2d5e75acda498139f95fa6f904b47f87a8c07e258c60f39bb1faa1d29cf0834c8a1ef1d6015d37b42", + "0xa491233ab353f9daad86e60fd48b6f70dce60dbe36775958d8e270725cbbda96578b17a0c4925ba1298e630c6b9ca9a3", + "0xa8c148b9e1373afa54778b6d4f76cb12f40eb6e07404a7f27b271fbce0d18d621675f1dfcb30e3908d7df1d962de2e5f", + "0x9826a45c29ee22cc26ae399be25cabd16180a291669fc822a44d14cfac81aa7ce85112d7f2c30effc7e83d131c9937cf", + "0xa793c75e716aed4048a2893f11eeba78ec565ac250bdae16594d056f06f4aa7d2a156e1617fc26def4e39984fb28936d", + "0xb6c454d822343cd1b1ef7161cd2ddc28145134d4e59e6d69634c010ad1bd44120aa8458eafc28f6103ece7e34b368e1f", + "0xa3340a0edc3fa82fe4f31ca2d19d295aa09c74cda3bfc3534c66eb71bbb7903843bafa92f7120de4505c7ec819a89664", + "0xa18e5218cd4349985f412ffc7741b5db21bb14c6e00431daba194771300e740f75fd46aef1876543967e8719bc6517de", + "0x885ce63a88617bee05144bc67d08f1c7072d8c4e09b23b7359f020995aa8cc9654378d382de6340ddf0803717687eddf", + "0x8d8a0b614be7df01a12e534bac102b1881905a9d084146b3d0cf2086dc7d400129e0de8e48fc966adf9d8ec8c1336429", + "0x8baad19f604bad656398a4010b20ffb6ec6131681d120220dbf2cc5779de1ee146d0b773bdbdf4e8e30aa0f464f2b18b", + "0xa39ae3d204491871c2e88d7772055b35af341ba66531ce3575f47c749eb8e380d63a7939d3408cd51356cca29c76d4b3", + "0x813afd593876667ebf0fff2b8a8a5bfd0f42a4fe2e4a0b7c78b6183605706c97dfc40b627340e1d9527f618719d60e88", + "0xa013e458d678fb302bcb6f002a52e3e0ace443009eecc9113ab5b78f4663acadb8ca9cd757a7cab1e850aa23f09ed698", + "0xb6e14f351fc47b9e46a83984756812cfac795cac5ebbc6f00d673ee23209d0d91a6bd7d576c7d35ec3c7e7cafb758a46", + "0xb94246a346966caf6fc1e0081a211f27b38f058dbb9dff915e3e65391dd36d66c51324667e3d7469a865c0cc064589ab", + "0xa1bf4bcc7420bd17acba90ee67af96e73502777e1723255a73b1ae3e92fc77e80a287ce7c3d4088040e0edd64577c8c7", + "0x8b6f5eb9b6bc7320349b19876864baa6cd8e07da4f70653d7369740184ad416c40b4395c04750f5d8b54b3b3ba68295f", + "0x83250b957d920b1b738f4d0f44f9eefc01b5b0582128f5ddb5a282a11ee207ba1ea7867f00588f8b891bbde2e56b4c43", + "0x8eab312cac9de78c9fece9d67a6b26d58c4e15d5e0668ca2cca2d9c51636eea5210a893f9321c2fb232e09f9d0b40fa6", + "0xb4d1e5f284d50360dffd2a0d21c4b31d81f521158aa21bf333a525cc68e690ce8ce4f0eff8e71a0c2d5853e2fed18231", + "0xb1f194c28bbe217a2c98ca8212fdca744f0806d60e51f9da81548155cfb97a39e2a98e753be8b2196c83f7db8caad2e9", + "0xa7905cbb59722d9463c6317ae59adc10d5bcd6e9788f2a54f4ff4a4de03df3f830d6b8faebcda541d429a7e42d158c9b", + "0x8a3b31d0d0b33e7011dafe25ba5c3b7629cdb5dd5b31385d786fd80888fb8409812b96d28fedf6a401a93310b045c620", + "0x86e4990bf50b27bac76926dbc65a1ca34a759d005e56eca56fd0e00ce82635dffed6f3052740cac2f1f37204699bba9d", + "0x8f0b6a0b66f1f5fa3d12af444963c6a45785a36dbd9e1a5f42830b5534ca8773a05fb618292e718cfe8a066b8fea7980", + "0xb7f206827d715b33989de5c02f0886d3a457d0ae34931ddfdfe2dbab121b69ccb560a71fdafcc3ff204217611674f5d3", + "0xa6e2ffb0c5f29043984c54f5fe6449ac4b7a86f2982c909606b88316ef1f0a54638d565f44d2fe8cf00279e0eee435a9", + "0x8cdde76212e73f9430cac210b52507583e81aae0bea491f6cbe27e5e2c8fdda373ce8c7a5f16bcf8c6238b282d06639d", + "0x8030955eecc9b8e2161d40f1f514d58024d25e07c6710916824ed8982b8bcf7ebebc5643f0260e1ef6150b6901dc2dbc", + "0x8938fc90e836d7bdf1cfefb2716cc25aff34e7c4dcf66b349d1fc6681580de7f58665faac29494b30bfa0c743d6f33e3", + "0xb182f9b4a5d838e9d534e41ecbf06330c56a8a64800eee561de1fc2dd9486565ae6099f40d0f1901066f45047641bd65", + "0x81f98b85de7b6c581613f4a42e0cb0dd9e6336399b39d38a4751c2a9f195b65c9e5592fa1728b91d83cac0ebfec7d675", + "0x94681572da95137ce41d913360cd567b570a87c9a439f2b67b90d623561b75bd3dd0486a90a63d49eaeb412cb97768da", + "0x8e64922606ce05375556901b8c042d4f41a18fafeca24c1d56998e0bc9054bcee7ab079c3729a67d908d0d7967a85edb", + "0x8e10e8952b24125321d0cd9ba922affc93908b3abdce47eed22fb2d44cd556842c31c36de6d4c28b4a1b5dd84e07df81", + "0xb6d464020a51bbb53670c81d5f1474ef439e006851d5d5a3fcf74219614a2a9c983737f20b254d38a2fc7333b35fb3a6", + "0x91801712ba264cc2eb65e8a3d5a032674a89f4c2dff95ef9d80d3a9285f3c2cc108e775dc326881484756814c2a03637", + "0x986e5a00f13326735bfc6b41b086623101f01dd55f2a88bf995a3b81054da86bb2f97fcf647d58e90428e8e9555eb020", + "0xb2875b4ebbab678fcafd270a0238a208b19803012fdb3c23f06c74bfd45929a9856b7a0f9881b75c7e97fa9d35e49d1a", + "0xb3d1acb9c844d8d2232834a81862c59548cfa849e8e5408ee66b4c8b86ddac0fc231b2538a752eb6c1ceee92ca443d1f", + "0xad0b1b5d6bb50c43f5f3b692c5d3569d2117b01caa7f0ffff502d5ab727f7702a2d458b89d77d218d3f92351b4c2b92c", + "0x95b1b99dc260ae6ac7c387bedd43fba793274b15768d93df13c88ff6cf637732cb6b1719467919b444c3b5166f4f0107", + "0xa0c3c8b59016056742145e7f4ca6568d4393124efac6540645152bf71173dea3d0058bb11b3093228ca4729cdd5b3033", + "0x9278afba60643257d9f21a4033df3b57743c3b43d66d96ccf413154a63db054fbc3a36f2ef378169f4f19987964c0bce", + "0xb558754c97f9824a72644de1725127dd36e284fc07ce89006b990f09db77c48ad6728e5c1891a691460bd5416ad65faa", + "0x833a02af76172f868a25e850d35f4d164889bab8381fa9c8d9880ab0564a3769ce3961cde72bc94ed73a1723daa35cef", + "0xaca496f3e528a2e3eceee138291107ddddd68bb088b2e49ea76d0c4136c6924b3251d7661ff467a36dff29f07ed09102", + "0xa9367961ae88a19038c446df3eadb280da005d120c16f48ffeabbe4cb8e5e2784902cfa1192876ab934bc90606baf2cf", + "0xb43feb49373dc36cb46e050e3cea43e636a64289efa3af790dd3fe960446492b858f51b3be62c6b75b510d8e2b985573", + "0x8cf24955965468125fba2c5a5799672845ea6ce97cd307b09236ef1a3cfe55c88958ffa311e8bc8335bf261a84275d93", + "0x88ceac98b512e5bb915554af92318a5d07a494e0b8734c4415e192e7405d6b06d170fbbe254e3bf387759f6d4961c34c", + "0x8a9044ddde945daf3e0cb3f897ca00d0d4e6a5f7c99aaa3929f0beb9a44d2ed23c191e37c57140ebf3ec759f50f84d57", + "0x8b2a2c0fb51e7c5fa51e8c593bcf118696b8411bc93e35cfe5de6c5465c6e80bba64398d7c6b71badda616b918bcc7d0", + "0xad8bba2b7d5577f971a1a561b17a9d8f6b7c35fba55e3e421a0d8d77b520eccd52122f02afaf3899218b652980986a92", + "0xa8d743b56896d44bec838e10ac1ba5a43f58c26655c71be0a5417d936260453a8e91752c87334676c5dd1dcdeef4fbd7", + "0xb0b0540f8d2d1ebdcd74d6e4007324de8f8bdea0531880520d79773c0b8eda65ed49e672c5a294fca6b4560442085829", + "0x96da830d1c1625d002008e9a364005b2ef16cf56f5aa4a758ee963388493cbf90aa75c25dd67d496af17212537ad44ab", + "0x89e819577a95195056b872f8f790d001fde3253a23120e2c41b3ced7fe8e9bae0df74907b7d65ddf9bbd6d2efa18eba3", + "0x90a139ffc7dc0992c023651517db4c195aa2f618dc3002f4a0a43013b6c6022d8d9844a49cfbaca543c9cf5d9b2210f3", + "0xa2061f543b216fc9c801d885ed681f9253f67cac40528b23aa8a709f24e0992fa42a10f1bddc7f10af2c22209343ca26", + "0xb5f53715b9146966f386f214477743e2fd2b771bcf90b192a5863c06d7225be34edb6bf71389085edf344e60afd88561", + "0x9634ce27272f3c687035789fa4eaea2aaa71db5b5531b21b8e029645827b40561a5901b33afd80a3aeb5777aa89850f8", + "0x9674736cdb4a823bf982d54876794e99c7672eaea7455be90e815abd03ac06ce1fd9e73bb987a515863c6cb4ae597835", + "0x90379303e285b19fd7816a6d02c0b8f94e6291b56c196d76aa389cbf813dee7ebf64e45555ebe8a281daeecfd7aa5b00", + "0x8a1f759f6cd6e5134f67b96e0edce7170e4be1b39afaa7af1c2de989116a6ec9d38a2c077c8e6e65ce0bdf729f20f1c7", + "0xb416f9937a51a298548e91cbe8fff71585335c00e69602423adc9cd72d18821987b8fb5ede32fd8bd2166e2ba9aaa792", + "0xa423073148046c81f840a481d57909f7ef621a51827e44706da9e1f0e27fccb8f88652097a9880ca64c41f6386aa9069", + "0xa173305a5aa2a17349eca704fee25593f5c2fdc5cd8cb932a1bbc0ef34bf54ec2f867ca93d8e6aa33679cbb71fe11083", + "0x87c6756d14d815ac8237ed4a75fb11206f615585ed527ad582841526371366ab19f602c7448a21722adbf2d987d89b81", + "0x8a1a6f06d6375d2bfbdc7531e9177a45330458da2581f65ad129367c400cd77f548aa748bb470bc560c0b02ee5b802ab", + "0xa24a05c30d0fcc8334f6974c30d13a5593bd3b388e2146ba006f232bcd6886edffaf7e48ed6126efd3e651997dcceb12", + "0xb35c5f8a5842d97cbe19105305cae1f971da5662c52eb979975efa0753bb60a050206fc0babac5b5083799e9ce8a68e0", + "0x939ca5532c922d00d08ec5914e6c58f8a1302a1214a1cbd5c844b334ddc84e694768edaf1a2af02289ad74970800198a", + "0x911d6104a240f84e0f6502597405b47a7faf5e68717f6d389baca62bf82fbb7207ce8d0c584fd9d57d3afe1f957b7cc6", + "0x88777ba7a4bdaecee78d42687cb4fd6dcf04402b43524e2ae67506d93acfdc29d9dae640c05d01c90caee1d04cf3d35a", + "0x9226e684606f8169e38dc21a14911d0306b1c9ce5244500e4b108eb1a0c0783486acaafd2e0b3b60c413bb003448ff21", + "0xb2f527adbb9feef9553bf508f192b5ca211d0e491925a2331bb294fcde7d8e0fd72b441e9f07c838640dd35fba03e1a7", + "0xb474e6d6ce22ea272a93a3c078197f40c01b9121c6f3083a8e587c367200b8c97ad94e156883475603f0a66d0340fa52", + "0x95c4d9896df11d2b5a8205a19d6331ea02a2de038aded8e6fea6d79bf5a6648d5d986bd29430e4cb5a6afde8b07a9a48", + "0xa12bc53ba6b6f8350b400fde04518a741a1d755123a6ad1d435c7642492c7df28f7091f17b254e793561923de781eae8", + "0x8a0578ac03070bc920a3b5a7a33d976b3133501309af5339b0cc70536965465b4f7288af70db3d5be16bc2a1e5c26a86", + "0xa66e27284ce6114e48ab56d7f623dc37a6e79cc5f487cb2bdf0acee099cae744cf3a9de53b111492b5ef99b0deaae0a7", + "0x832a338951022c80444ad8c6d0285e86db54254d2689defecac2ed87f5eb4d876373af6d76e3d613523e32c3966142f2", + "0x81e83f01bac3ac3fb67e780b28de30b32247a774aaaae118db3d45c8e74d1d4f1defbf9c2a7ffdf176f5c1cf4ae4167e", + "0xa1b214ba7265f692b4637352c6139bae8bcaf3e7db5806fad0014ded93048fa4a36ac9c9e0b7cca0a86cd45bbbba2fe1", + "0xa7ab6f470a421e72fb703a9d153362056ce80c40264a3ee5698168130cab8e827df5ce3e6321ce9a669c87a2e5c67499", + "0xaefafd219f2d062a378474c48d2650b51901b6bce00e4ba0b509395a6fb39699037577da353cbde187e65de87ad01575", + "0x93db16a0a77d1b181f33ef10300112fd8db5b2eea26732bffa3b1fbebb792c6ecdf2899cf6f26b505dfb46deb81b217d", + "0xa63b6d9d1cc2f31ac5f836133ae66bc9de3e07ced5026f5bc90116599461dbdc03cd7680c1bb43dade9218ebfe1bc1fc", + "0x984b49ca86d38a486f6315f4f9e6ad521901a06f8862ce1fc095d9c66bb2164e334718c71d7472ed765367db5fede105", + "0xab49ae93955a38f45f756afc4248a37773ba8d0a19779253fca3b744854715b9c9b10c09a37d3426614ffd3a8ced7bcb", + "0xb22166dd64c83fe16feecc09d4b1df2d967ce7f4ab526ae39799dd5a5a4a9ebb1d4a432c5efb90e0875a4eb6b079e2fd", + "0xaabad619d887b69b9562066fba2179c69c684b8cc9318c9e39646f4a5381535c024ab277a0f0be46abc95283b337212a", + "0x99f5d484db149e9f8dc9c6758647c4e3702d88986600a3226874d612bb4b5e92a76b1dfbdb0909b8f21afc773ec67c7b", + "0xadc8bb04eb8c56dc4ce97c3fc1670da10db134cff2edc214ee3221079251b968e2dbc087c56c01c9260b49506958a6ac", + "0xad625ddf5cd211102543e0943a7770a9b45cf3550d12dbb484cb5522b70cb626f9ac795b07a305be3e6949d7ad475f66", + "0x8f9f5b2b43624e89e8535dc73fc54b744f247572b2920679bdf6a3ef346e654ec40fe8f81a0f7c7ce7cd5b48f3975359", + "0xb70b1642f28bad56bb24b342eeddf5c3782e0cf6e0d5007c252413bb44b32586da1e3b4d8b45a72c91e44e07334da68b", + "0x81b0311e557c47ec22c5f5d1f757c6193cfffae357dd2460019247178b13733484dc8630fe2e13037a1a3d681c69066d", + "0x951c9f1504b19acdac1c04aaf535d3cd3e39c431b2b5d9def9b374468e93d378ecc3f5aa02c91ddb93eea431b327ca4b", + "0xa85e1f4c292723d18a49cc9323dc7af12bb5a8d0c95d71881ae235ce123c50018907f46bfc846dda1a01b14ec45dce14", + "0x8a46c8b86bf9890df60de4c210cd7865892d0c11fdf2747620289d73bad597e6b482c208dc310c25955dae8392d8f278", + "0xab65408622c63b67842a80c4ed665258ab617ccd07871fa3f0fde2e5ddfeec49f01d7501790a60b3a05d7579b087b787", + "0x8706913d42b557d9ea4d7b70697069281504b3c4e1172a2291e3b3e0a0305c8d0bff6b7721356d971d2fe58e32d4556f", + "0x8d9b8f3c113ca1215dcd15d4c37913d023c8c5d04f617319af76bb7bab72fb756c5bd992db6b9e765cd7695c316360f3", + "0x942d4d3351b2a9bfaab2500b27d24fc2d7237e791993a7d0335f36fe6456c5a1a8bd28dde9228fb139e95288d6de5bbb", + "0xab014e9cc7d3ca08f1d3d24473ddbd693331f4bf21ebdee0fc997aa2faadb43db6a1195644c459b52a969f3d98a85b8b", + "0x8b679da80561955990c91da9093837953f4ff7fdc658b51639c462b578a2b31443421712c6b7742fddbe0ced48c21cb9", + "0xa9132ac18b1bce93e815f6d2f8a0d2f433ae4d6fa04269eb0f5f25864a8009b01531c7c3ebe87f07454927a010ab6dbc", + "0x8ab02c113149efc877967c92621a8ef618bf423017e78b9cd30cbb13c51200c6ce27c46be75e19ba843d64a3050d4467", + "0xa881043298341efc28c60d850d90d90279fa6d8428953337ba57b74eefd858e362c6118a82ebb025c9c102c91b4aeafc", + "0x92e4a587479c64b8df955c6bf1abf1d7979a978e45d96f05bc1b9648f10428d77890be9ee03bc1b1982f5ae7b926f0a3", + "0x90c21a22826e2e9978dd7522f51353fb33224cb65603779de41db3ba41e01d664e131233bf873e28d6c71294b565c533", + "0x88e8ccbdc54ff06380c2243203d3f8c8a75fcfe638d6e6a010c0b3a39d5cda31f8d2cc416ee5264267aad2b457c94e50", + "0xa256198394b458f6468dc91c35f579da0ef02a55fd93e98b25e43b1bcb650ff889df4899236765c1a6b35cf49da940bb", + "0xb5c7d9c03c36cbca068abc6778053727e77d9b58c5dc33b11629f1ade1c228b1c964f5a7d8dea16057e76662c4d79f18", + "0x9588e133517f0d49622222b4de5c124b1aa4260971e43e4aa767fba8055540f2848954886b7f245583ea527fe2fd1de7", + "0xb66025d75169bfc7ea366cd32419e24fbff829709e3e9587d7d59620b3a7b72034d3303106f965f5f7a71d66b7f314f8", + "0x891357bbe44e60627b975c10c872a34b78d6b264380e351f3a86dbf99abf8e2dd8d20c52dd6073086e48e1ca782e2ac1", + "0x8a066a3482526a92476bb8c3e5caf07575c725d72203d67ce98f654f5ee8b7f979187416fe3d7ae0128800b253d7209d", + "0x80a9e3d8900046b71fcd5b7034d1e0f57d95d2756da8307a11aec0553e5715518a125a653d356f399409545256a1984c", + "0x924a13fb2da7a899cebf2ac09c8c0a183491777100de1aa056a6c2bceffd5a63e255f16a9066e4ed89ef28096a1230bd", + "0x866cfc8116d2e0216d8049d5ae2ef0e3fffd377028850716a4bc2cfe16c5a6be023334bd6ddafa0c77913dd4ff0a34ff", + "0x95eb74bebbbc59d793e3fbae8e98c258451bf9bc5097df4edd832e9f1c30a1446a59e1f75a44832d0658d5ecc13dfc86", + "0x972517b2d72ab53193db5d682db2de7790a418ce4952c29d64e1f9107d51a782f4084591b7c775648f103445b797e8e5", + "0xa14ad2cb69da568f2f958ef4253d7a6daf574c6976f4f5d771ae7673853ca22eca81e20400092bac84453b6eedf5aea2", + "0xad95bfcec6c06cdc11d316b7ad33fe65555e985bb33b15c9f481a09caba1e5990601ed6a88038c0ae2e04b1607e2da48", + "0xb7e3bf3a585af1029d83f12cf75acda894fc4441cd7b3d56efb6991ea91b07512bcd7d6d68738557a48f0446b2cb21af", + "0xa57efb1e2d2e10e41f356768385375a21d9f78bdb34d618117581bf7a15024eba43570c3956ddb85a025d39476f831d2", + "0xa66d3622b1cdd472a2a4491881de035c2eb4f1c94927902a3bb9f10739f900130907c6b002982e03785c43ac30b8109d", + "0xa79f2417d32fd772e46f3bca61ac788af8fab174e1e1e48a84ac557f7e80a9cb4e2d7b467365ad18f9777f4cb5bb2b8f", + "0xb952b976e3b6660326c0ed357ff25ee1291b74891f3eb7bcea39dec2ebb11e287d6e26ae0506425a20e5e445273cc63b", + "0x8c23929e9740ab51d9b82c6b7840067e7163e6c7b9b9441e1bf867ca2e532926981c98641e6c798ef12d35108abc1dd6", + "0xa519578772c9ed2d691a8c423d360e4bad76afa422f1a5218a7a08ed52c9a5935ce2ae4c0be182eac0712259a43f849d", + "0xb1529dd189cbf3bcca50e97199bfb85b42f2b26edd95b35758d988d1d3740f5d0d2e249763874fdfadcefad9ea1b3d02", + "0xaa3fed8d14a4f38df75b9eed7f187a31cbb7a748bd3225dacd8325a71dfb680729fcc91ad8cf0b67ce314e1fa8ba02c4", + "0xb77c28abce17732a08e682491182f63fb55640e60384932f6a9c6d3d7886508c9e67a841cb93e59448d2d59fceec4620", + "0xb7a24c58e3b85d60d654ed14d78993a9cc78c130442c8cca42921ade8ec94bbd0653c9fe5c69ad1fb2aa46ffba04da39", + "0xb7d08f3ce97901261514a5dbae582848e75515c5f9f41f5e70ec17a8d0db3067ddb19aa1c86803bdbb757230b148bb21", + "0xa5b8a6818be4d59079d88f72d7aa4957c48ff5898f3fd01def48ff6bc7aaf9840aa91f2f05617d340092dd9299115c2e", + "0x8e548db6b871fb23ca1cb8538d44b77ad02f4cae4d33c8c43228b820abee1aa913ff9acf2483725b195b4e65e2e92063", + "0x9509189e063812fa04f4e26f87b33a2289a05c229ed1038fde0dacecd87aa55ae0fdc678a1c86bf13b81f4b3a872426a", + "0xb355f24a5dfb7a8f3ea717111a038487632bf00d67cc2cfa2ab61e1cace7bc7f5bc9e04b190aa6be0652627ee219bf76", + "0xa9b335f235df51b92f40f44f19150e182a938b9abb3bdd8e8c447b2b128050d228e0115a268af4c1bc2ca49552b4e0a6", + "0xb306d3e6cd7ab56f5f7572fe51175ac6b29b189220fe2d380b959d131a35804da5ce95adcfa51d799f18e27d8d5eee0c", + "0xaa49cd2bd34c37ce1f05e192fa6837f964c068170ab97989e1cb22ea7e13c2400417a51282519e74d8fb6983ba89a549", + "0xb1d4fff41d95613e30427ae2ae1d3df8c9d06389e1e0f404f8cd40199d6c4277b7a898d06f1579be107fc5744247c36f", + "0x99d220454889f476931b0cba3570eb1a8eae30b4c3617513833a551aab0a2630125f72dafc64a766b1a322dd42dc385a", + "0x8267ae38c9c8532c7d4ec4455279a5ed4f2e48746cb0f2619937157534b0e5466c5f4b99b7c342c095f71f3b77fd5882", + "0x8bba0794cc4ca00eac50309a92878084a6a22e4c23206c68b8d7268f9e7f615da4b9d0f3e006d9dd84bc3dcf32261e27", + "0xadc965bd7c7bb2a52cd3f4d2cd3fbd72a196876a678863c6a67a25b4a2330d1d3be603220de22c8c3f60c1411df57b7d", + "0xa7d5f38a3c4ca0541d5ab101af9c27b04c5bfaa42a1715e882c5e7715e460c4666aac4b6272b9fc54514346fc49d0560", + "0xaf94b91ad9b0f01df1d41a459f16ffbe30710325617651cf1da000eec43876161957f079a27b70018ba34d1d5d68cf6f", + "0xa0e2a492da4614f41741157d3a1d19a2370ecc8e178d813e22b902cf7454b8237f1ce3c16270eb6f3ead1f92797e36f2", + "0x8dfcd39155d7b8073b0a1a9a617fa75218f569520d4817f3ead375850ea8a3e3dca64c44e83f54afc37173d927070601", + "0x98302358e5b740b73e1a6c568b99affc6de3c7245ae96d9c712d377fd363d8b8f49dbb714aa8d39b5b947b6de341ece7", + "0xa2fe0f9fad663cbbf4bb05f61edfc90716564d5ee5a9529ac3cb8f06f96329248cda85c43f24a2382a9056e9a53520ac", + "0xac50b0727ca2ba80692c0b7f564417916695ea3760ce9fd71593050912bb97366d29ae5ed05ce52984e52218854b8e3e", + "0x86f56bea946a4516336a90328fb4b24cc7f82d8710d0d1e34c2e27b6af73c4f4a9d6a848dcc56a87d6259a99ac444557", + "0xb33d0244948c430a58b210943e41aa3cfecc9a823dd3e160634ccc45ea2680987db2912ab2a173ab6cb9cc2b7e16f7d5", + "0x8808f8c2c2377cf52e7314820d88234d7819a6108fe9e1c6a675dc47cd59f81f95594ba2f5fa10e3719580f53edda641", + "0xad34a814be6019931972a76b3300a4fc9ce763d6f4fa1ea131a67d575c00c827b9ae7260d88577b4b3689e90a845137e", + "0x9370abc67ad0fedf30b929d1613e336c6e99e4bf83ce969e61e5d77061b48a1a493f28fe2eff436d4a979af700a83b5d", + "0xb0db136c8f4ba2fb7148b1451b18f694769f5e53650d68342f15817b04734ef8ae59681a5754df617d755a687b6ee45e", + "0x9149909d24382054a05fc0b057613d059721f132a19017a92198b30e48fbbc5f8f0b5f5db55347dbd9d190ca88f9a28e", + "0x883d1d170fb0fa95b55b10b32ebed24b1232dbfb5c783148a63a765fda200e796aaec52747441704967914433a01a323", + "0x8f55fd5ea11c4fac277112d72489ac1de28fe163a756b125f27acb78aa6651c70d1cd8c45e0daae417bf894149ed2d57", + "0x8d08685f99aa8525b008b868f5486e24a08568a5afba9b729f7d26370fb1b162937db28b935d67e4d22f7fda69a3a6a4", + "0xb1882e23d784ab48b2f9e58114c5920bc9d0c4c01d2d7fa5111561df0cf2d738e31a32963cfa58939af87e79428659da", + "0xa3eba902d376063e48634c9436802cdc6b89d3a7c7cd03b26a3fccc7218dca85a3ed939eb53956d2e001805aa5c2d63c", + "0xb97330c40d51a4b71f91f56292b628379ba735509a66c7df054112578b9df40d3aa32598bc64c03c78a3311a17997bd1", + "0xb84f3d2af2aae2aefdfec9a0693f6bd71eaf4d477cd72d80f4919235a471607c5483b354c9d46628a76d6b6fe7c586af", + "0x8a1c39bea7fa580de967d8ced7e3860a9031b07842d71f8c5941b8877cd55ba15ef7aec6116ba38ba290b887b4530685", + "0xb120fccf939e7d7959c2c1e70d7a7aa3b84684dd1ca8e5cfa9d281fd06d23eb67a629b1a27052614c3ba639ff9c90dde", + "0x827a8e0dc841af0e2c4a9ca36c84a0ea60099aecfa40294344f82878b6909f5581f7b34fa9510883113795bd09b5e4bb", + "0x88c24cc54dac5a2982be5ac49684d99f95574bb8cc44afae4f6e18231ebea0f2ab65b49870840bd3e8f2c9247f62c7c0", + "0xb91fc3f2cf743f4ed42e49007514d43dea1d7bab388a18de6f71367fb8f2e9b8e88ed9f7492b647e548396ef3e3d7765", + "0xa175000c4765a57c57b219b21f8302cfd85aedbc3340fa1690119bbe7cd93dac4fd0ba676b1784ebac83efe3e78d4bf6", + "0x881a373630ebc24dfe17e27b3f176de6651347ae741d55675675e9e6904ebf157e787d86eec42ecebfe4eb8f28de6fc7", + "0xa47c8b155c8ce8e16f38deb345a051fe0c9b217cb7a266fce78d7694134247887789645a82c0ac24341f51da8ee6ef00", + "0xadfa5bcc682d4449adcc436649b444dc61157154e24d68615b0ceab50eced1ab55e15b45562dd8e00785806e9ef2b7e7", + "0xb7d2ecddf47e9fd25dcb283eb80e323300bf5c3ee3344abbc3a1f2a3296c631577a1fadfbf685abb336d5d7059d17166", + "0x8833f6b388e46e1f8fef1086777466277cd418051ac0323e2cdac5902d7ae45eefef93ce90b088bbd618e0381c1ada78", + "0xb6abf44c5aee5d0fbfdbcbf1e77354d5a2ccc239b894e1e06d7ffa76584683f707384319ab0e0d17afd93a854d7d26b2", + "0xa8c61859a9553a83bac398c14c987b20c8dc27d63112115b8aad26bca275cf98913783c802ebe3b7c3d878c130407b34", + "0xa5de7a519f8de4daad9137f2c2838544219834cd70457ef09467d869f4dc32098b7a8d4fa85e1eb283632f6d09971318", + "0x98c33a315a66cd8ab9ca8a58c87e5ec588107a6416c4ea498d0b91bf7597f53a405e437ca0a9d9c6acea27ad0ddbf4cf", + "0xb2909b1f8752f4eec25180a17163ab215fc20c4a931d4471d3be0ab64207a65c7e462fc0707791286a92ff2f2b7dcb0f", + "0x8b96c2fec34cda02e98510a3ed80a980b0cbf4ec03e3c4260f84027cc7453acfedb5f708c401d26db137032c6cb4a31b", + "0xaff645dd6ffe8b5076c83a823daca4149f0769bea3293b61330ebd97a17fe16758e4fbbcb5bea7449595c6e261127b34", + "0xa45f8b3b7196449f9952cadc8d87a787a28b4ed89f8c7599e7db361cd0f0aac6bfa464024ded5c0ffc660e417594fd41", + "0x85016b5f7ea9863557eccb0e742cfbf0b09630f0bad3de55aec92b95d4645055cac60d03602586b34f774bd356dd5554", + "0x94fd89dff2fc6099e5ab90149458a4c794eb1857f1dd9a2c84b88099412477dccfc2996cca2abee68d23a05265dcf271", + "0x945a52621ec19d26f7c8abb5d01e4f5630924b75a349ce74219377a137f4a0d386172da523edaa522d27902444023cd9", + "0xafbd452dcc57f5db6b3fdd55368807320459c16559d944ee8ecd1af6acfe9d58c13f37961f78030883f8ad7dbfac66e7", + "0x8ce96b3be871a1f33d559a6e55e4d86a0b92ec3954417f8d98676264596c3296296532097b9b20c83c341527a0c929b6", + "0xac6a4dcd58486d25a4db1751a60ca4d02b80c939b39ca165a37d9a0a52d8675b3753719f136a59ac400bde3efd036c8c", + "0xac87a37a14a5d48842d30432935929a0e9dce5642142a8c5b95e377ad1bf52120dc64697f0508b7c258af24a0ef484ae", + "0x859f0ba02d496861455d9c39c269a1ae5bd224319918fdc3648311c93303c0e13301ae7f3f77eab4ae43f1184a912b64", + "0x96d9b1d2d2fe70b8fcac136a65b62a4ded85aad9d350c19bb955750a0b24f93174e9cd00c0e0a1987793e1180dfdf66c", + "0xa7f5135873a1c08c7c8d46adfed19d0ed0e33168d463ca74f75116168355318ad588ebcca1946d7669c5106bc9f5a8f1", + "0x830b0587587b80df078ecfe0857a4b4cfc05b722c0f4f3e1217048ee18749e9940cd0200c1f7a0f60de832a5a44e9f1a", + "0xb6625ed0199097acc9aae20611f02d2fb837e4695762cdeeb4dd722517ba5a344e5011f14d5076783f3c32bb5c4a027f", + "0xa17be2e528c463aa4ce4bba2df5b005f88e363b87be7324239413ecd5bd68e350d290370e1080ab9911a0d54856536da", + "0x834064460f0e5f38950cf5ec197818712f01950ee1f32b1987dcf7f4098d20e1d91fae6d48e8a054390693a2e572f888", + "0x86217b9bd269408ac92b5cffda5716bb3bf8674b7e222668d72939a626f4ab64f30efddf85108c0764127cdbcbad7d69", + "0x8d7cf47b0648be0bcbd3ad1062d90010e5ee84e397895ce98160d5a568d60a19582c985944ec27bb284459789ad8f6eb", + "0xac056e3ed3487427142b3a4e4f9db53f1a752e1994f178577c46dad71be5fad4d03d24ae7019804c41232705a4bffaa1", + "0x94b83d67af6735e81b2e392e6af8ee4dbafb0071d84486389f36f222dfd015da718c621acdc4360630403762dffcbe3f", + "0x8ad27bb51c6cb860c21954f5d09dfefcbe3a9a0bff3e24fd1f74850edcbcc76b5b389a616ea0c0796b239b0c22357a44", + "0xaf9990dc4c9f536385811528f207a8352b083a4abe6dc016eb5eece0ad74da65b2c6c475a78cd0ecce0b2b550e4412cc", + "0x816dcb8ff8556540b54dcc1efbd2242dada0acc1e3d3da13ae581d905a9106bdfb8c138eee93992a23e7740593e8ad80", + "0xb8fcf8e11e5924d3d38643b2a4bed4b54e69f816f40d4020e76655eba8ffee758c16cdc2d970d3c8c1163cf501044c03", + "0xa50e0ef4ddfba6d969e7dd864a20cafc7fa6aa232fa7a806c3d53c3e029cf110828c5a9c354ea42aca5688896f27e6fb", + "0xa560435900c48879ff3f89067daa8e512482f061c68474d951c608ebb5a69c7863a28fd1e216eb4b140e32124e50fc73", + "0xb9202d152b7b708ee61c4fde6cf423b481854538d2580bc43462610f12141b89ce779c7398a35c27ea6ed0afa5332bb2", + "0xa9b3f8be28f9546bc70f680dfb9b08c1eea6fc381cb6f3ebfbe33bcab48294347d4e64004c11dde5eb409ecb19941ad1", + "0x8cb3086d265060f8e52a96fcecddfd261886002c1821a8f59a1ddde19a6bb1354b17cd19a9cbec19149dc219a4c394c5", + "0x906e8dea406ba0f0ef43ff623f8521039a9455a2290cae4ca9bb6494ee0aa812528267d1349bd5d339113dc9d1616b28", + "0xb9b5212b76d5824d66b8df7cdd5effcb05ccab5df6ce67558872c99d1e484ab8d21037bc0e22f5c4082b192972b80acc", + "0xa1fe817596bbb5bed93a5dc4c03e14eab627484cdc7ab7e4fba569ad0aaa93b34c4fc8680c4f8180d8190113218d26fc", + "0x82fe7a20fe93564cfaf7eade8d4d1394d1b4e36048cb8632bf366d3d8084ee52c74d65c4c69d9d24208f7916278aa592", + "0x81f42f9a3b8007e5f02c26770947f884c715bce1e600f38f164a390f159e2e5b6f8522ef566bf36422b14340bb6d3556", + "0xb53d3c89bf2a4b29bdd8f1bfc001c2533f86d869fbdb383fe9cd93ef0c49da0692361baa9f537094e1af662a3461f8af", + "0x8fbeee613823ebfd514e991d81babc05176d5c115907ec36dbf83a69eaaacd622f1f36be2e47b984cd6ac66a6b35816d", + "0xa9068ba463ac13d4dba25f9bbe3c93baa35828563f357c53a7009cf0c809a23502e023a32f651e29f14424c5daab2884", + "0x87468aa4c942476b3ac3000e740c4dc72d320884357dd99eb25e81d7b52a859b9ebeb55f3070022bcea3855a9a198e9a", + "0xa5f1219eb902234ffe8ba809df590080ce8329ee574eb346f6b4372892d66b0725f048465221655b70b3d4c2deba9fa0", + "0x8d9663d4b48cb86201d343b20a8e7a6ec47a4bce0e85a905be31121a01fbef95d9f29d83530faf79dda163c6c76ec514", + "0x9921ea9176744e15f64b20ac6e95ec132052eb853ef47e9334108778fee60d9d9b53fa0b8011c6a4aaae472eb11cc61f", + "0xa04c2c5e2c5a7673652919aecbc5fe09a636fcae2d06003ca6775018112b606e50bd2d6ae6ec6131d2a9999837186bd0", + "0xa00ddb29776d2747e3a6e68eb51a7cb00ca0066a9aac5a2da632f355db515b32e2c441fde870c9731a9dcc8d9834557b", + "0x85afeeae8bfd92c51522320cded430c2fef57b1950f9f966f47ce6354e492e9c40f950a7ef6d5202fc79fc020f7a6260", + "0xb047d214201744cf7e675af5fbd29579c3b26020c5e0a53e2ce078778b3d3a673f0fd87eae8af8f0fba3bf0f8341b63c", + "0xb8aa5364d914020158d11fe82c2b77197ed2b1a12492435200204e20a9209d3c0b4fdb6fd3f0b1db71ee3b986400ff46", + "0xa59a903fcafaa8b5876a3eb1d79a7db17c37457dca018e393324d8db3be7c2aa3ed2303eb3530d6fe1612fd75dd92e08", + "0xb1929c1711ce44465daada15808099234c0c5c8f43b050b2792b6ef9b77825996a74abdcd84d6ef08d648e77cf804357", + "0x85bdc33f8dda0d853074e0657688899befb6356c38f0ec2ac27c46c39fff06617edbb1c5cd220314335bd1b792f1e240", + "0x862047e51f9119f5a0a607469496c0574b0087d566bc58cb5b61a9a841a3cb693b89837a7c927c542ca03d0106055438", + "0x84ba54c002150e5989f59064b68989413abb5f289f3ccba215b923f86f76c19718be51d503ce3bcec68322a7c7d5446d", + "0xadc9ea06c11bf3f0d704b321005020917e731e6706f18a5aeb1b56dab3de39a94fe8aca3c248a47565ca5ce82face9f8", + "0x868324c4ef80bae55510316f3a8b13aa40e60c8a3d55f4994439d1dca6f5928c4cb202769d78c21597d8737e391536d2", + "0xa6e3b57e9909b5fbea2114c352b34235a4d4147417e480580c291308b4b9cd696b36278480893667e8ba01fe3bce571f", + "0xb92e1d6ba0a2a244ac5ae2e7b20e152591c1c466c9b4c658c72cc5985ded0392b04ec00e32291f1652d21dcb633919a6", + "0xa3e2bb4dc07ffb1e8dc9055ab45bf22864980f64b612548ca7feac85ecdc426f773d6d48bb7e6c7a578025bfe99307e8", + "0xaf764cdb70d5afdbb49dddd519451218db4e97ef3ee622585880425c3d85a8df88613f4b51ad40a1f6635e45b2efa5f5", + "0xa426230b8ed77eca3d1ef7f4735fcfe0e51ae37efea5b96ea3bf313c241bd703b91a592f035e98056315c9822ffe8c26", + "0x96a3ae7f1b80690f97372d086d2d13ea2b40802bd053980f73cddfd37045364ebe38064a8cf3531e9bcbfed421040f20", + "0x8cdfbf0663bde624b703d7e6c36c5753282487147e10e5a24fdec75836f7034e4c38f3fa3df373476af969a4f835cec9", + "0xb7f7a549cdfcca30b78349b831ea5173bf5b91d56dbb999b2dbf6b85d8c22ca8a9a62b38e37dcad7ee5136a32edd5743", + "0x82ca90321c43d616670a7d85447afaa9034459b796b51792c970fd5b8f124e47a13ef661291a4ea58a495e68aa36dd87", + "0xa824a36e4e2db2bbc513d39e4e2a841fa81106437eeb4fca9ebd78050667d0b284b7217a35ee3eac67d8be58c0af317a", + "0x9370dd0c0f9c7585761eb5f06e7899d75eac07e13c140c64d4c506b90495fb8ea914f222608c478708d4b47163dc9907", + "0x88c07e19252e905faf129e3e877dff8dfe93e81b3903b150aa33a93a7eda2820a8471be935825d709dc662d06c9f99b7", + "0x81e936c00425f7db8f0dd88b16c3c5208e8d95a5072e69524f3b5de45f4e2dd25f0aba8ef17016bd914bc8f5a42fcb6b", + "0xb23227dceec18d6dda92a15b7dc8623d9928d545db93b3547fb068c99cacb3fcf3d7f88e4357801de8a652b919dd907a", + "0xb23f1627219587773c17070bbb190e1280ab27c5d7e98b43adea0e1f5017790149b71f90c3691301bd514d20238c5e6c", + "0x821b7bff6349c204ce50e00e296982536baff68031165ae4c639122195e7295ea0c82ce66fe32a1b762f6a311aec384c", + "0xa26c15bf1ef4d5543c4a006e4ad2a450d44c93c62c0f0b035698530cbbf925f6705d375e1dc8b2c6fd9a2c69f4126b77", + "0xb5c5bfff4697fe13a5177fd87a8e293fd1c6782cfb3d1f95c5ddcb13c309dd1ddbeb14cd359c9f3029b57ba52996c9a1", + "0x87a0d37f04155bc22ade44f567dd8a81445facff15d643886cbe6534aa44505e331bb75c9ea2f27624154a5890aaa2cf", + "0xad85c0e6345e2333a0ff76b769592f2b24fd0661984498dec6fbd2d9b0cec5f139bd71331a28b13aa490baa7fe27b635", + "0xa9e6298b90aa8d3f4385858e08f393b3bd61376ac3dc44a0907ccfb372813bbfab1388d544c1a4907aac38a87dab2abc", + "0xb5cfc8bbe4cd3ac1a66b1c8138c5c68e643f7f4c310cbf1483f6e48d4f7e2d1cf24b2704fc687032eb03978f18239072", + "0x9493895ce0c815b60b0ab3a989f63c6ba4c752976160f3e52290a724ddaac9075e07dfa913e113807e0e57725b1cd593", + "0xb1e800c2aa32d34d34b24dcf890f6ccde7da60b98c4646a5471fea7cc6df8862b7a9c4c40f38d0554e33e2984fd564ae", + "0x90a18f877f149a314767f5dc15c8726efe5d20a8e15ad4922c6042420a2cd82018be813debf02c6d69b96e8a27c0c5dc", + "0x8fe35142442c103e7bca602445b87cb017c76befc83d66894d4f810e343b3a571f3fba14d94521340ee7c5ccb13338dc", + "0xb43547cfaaae899fc6295f496f213916e5adf9b0d75805c32df0f969fbc1b4f8584759b2a06b81546b48004d72f2e8d9", + "0x9410d55865098325c7b559eb4e84fef8a3ae890e1d6053b3f173ce22e60ec6563041ad8cedaa2dedbb59f3dd645dd1b1", + "0xb127d9e4b8280e10434d53207a7191782464ae83b4463cd8a32026e5d8a7a8c5306ba43ed9b7ea637d65f64d6a08bcec", + "0x87de8fe67524c7d107d7033d4107659206c347c47cbbdf85e3441b53c933417feedcfb049465c67f4c4156219a4f63ac", + "0xa582f976e77b861731595ea8450c6b525e371c6548cbf7911f05560d4c7a4b62a425d5c785190628d1aa1f8f27c43b51", + "0xa195e358742d924fe2a7f955eb21ced7b211cfcd5dc3e598e0d2713c3639b72f986aa586b7a22a75f8547bfb46cd52a4", + "0x97c249b70ca2f9da728a256d18d600bb923005ebad3e1d541ebd580af3fe07123fdf87f4e8f98fdf9dc8ddd826ab7344", + "0x8fc7891e2f540d8f20464a36056f227ac2ef3bcf2b6edd4cd2d9024a48fce19480fba36afc7f5c4bd7234787b8d17f31", + "0x9047512fa27e2d8d901516b5714133c1845494b6f2aeb2a0570dd8533852f00a8d9a8ca64979310e83ac73fbeccc33ef", + "0xa1be9cba454617af0dd38865ec29e7d0777d7c68968c856f90b5bd63a7cc4274fd8b179be54143bed972b921864424df", + "0xb086ccc8a705999184f51e9b45c76975ca8b108b32a3955e122711fc1ee007d8417a85c9cef217f28d6c7799b60aae4a", + "0xab0938a72118ee2980b28dbea9f7100c6f54fa82d93fba8bfa81b6bc34f9d2033a987e5d6d3816fe0bad53cb88bb8c2b", + "0x90fca0bddc14f70282f11998fb4c289fad5c0e78c8e8f9e7a811f20413459a05c9d107ae771e9da501854022d827f2b8", + "0x84cc69b7200f63c2214375a7a0a5ccc14bc02ae45bb6f3b27f67ac538d01e628c66b40e5c40cee38bc8634f1a3c3cc6d", + "0x8a07a1cc0a96e6c6da0d27a540e235c2ab6a95d087e624c90cdccd781a9bea6abc0456d896574950a9e21e7d87fdc582", + "0x87f2084a2f2218d7f9eb7725617ea37db0a19fb0bcfd7c95501f62fec0bb6bde3950690420a40d93e26f426fc622c825", + "0x8c9fc9b470dcf8e576af943edaad28c29f53ac7e24657618c21d910eeba6d7b16f16c418bdd5cea3d639c3919e93b7dc", + "0x8f026883d9d8c7c2a5c04e4c7220ba7061a48392a8a7794a3e290a94967d14caf040a3da3513fd9b4e695376e706006b", + "0x83bef852b9f387a2aed0d3537e77c895799c639310cac98e7b699e9f5d74b2b21cbca58ef910c6583e0b849d665ad379", + "0xb08a03accdc64474490706edce9df7853b78b719ee731c195f70871b7586ed274778d99b84ec3cb8cc0b5e38c102bce0", + "0x99fada688669b2ea8d9b7cd730b057292ec3fabd30cb733ea3f7cb76f756b244cfb26df03b9c087b6d9c58f5233dd1b1", + "0x8eb0fc7ab6b4238f2317620191dbe835d4ebaad0882e22e8f0857053d25d6d9077754251202472d875303669dbb806ef", + "0x8fac2cb38c3a1e361aae5313ebdc1c7e0b7d1a440482fbbe24389a7fcd381169fb325c79e430be170452326cd4931732", + "0x92bacde1472436209032f0592973a5a40d505a9b2c9de648eed1ce392d0c18e23aed9114a9634ad3a7e6afc4ea80ff21", + "0xa28b394018434be07323a2356fcfd6c70b3a4b1c6b6ea44da1da66c389a659235e0dc941019bc5053ca41f10d9b6db2e", + "0xa6d23d7fe7ef475bfe6486ad4a99ea376c6a6db3e70a0a7af421ef6e6c4d6b9cff68d03a7239a56eac784769f63b2bf0", + "0xa1232e6747573e19df98a088fdba57116745612cfdd4ff21f8df82a66c7d5df7e0a6c0cd73117121a516dfaabd0f5016", + "0x8dc574376016b73f6730103cc45c952c5df5d047d0b4ab3da0303f66f43f7d147b5eba5300750e885c621e72b4a64b43", + "0xa66e9eaec79c958e624655fc2adb7b89ff3da0393898e028bb07cbd6511ca8d9318e1d60dc11cf0265a498290e756ecb", + "0x8e5299b661dc0e088527904d2c2fc0256613a1fc2b92bb92c633acf145edbeeb053e82b468a3877f6f14f0878fab57b6", + "0x969943ce7b54f6e728724b26cfdf4df90faf9f9796bafb910ba66d96cf34062fee6ed9121abd193c9e322950c8eadbcb", + "0xad29ce021d7fc875d1e61ad3a99e112ff092ffd7900a608bad30517e50e2270e0f8dc7fb5cd42f1bb995c17d86268f48", + "0xa55fd82520f4d35434066bf93a9601c96549cb4714d9ac05c32e16803daf8763e23c3125d2005eb229bf5d7e2a91ec3e", + "0xa95eccc21af531c5e1a36ce88eda6b87732f5fa680e851bdeaef73421c1c87c8e66bc314b07ab472ecb67a08ec53cd4c", + "0x8f48b5a0636bd89a1ee259223065449523984cf3bd9be78c9242276c848d2140bd94d1a6670e446b51b178ff694b5c7f", + "0x8a58b340e30f0cbabcba1c565b68eae66405fa2242b43a7f7d3bdce279af42fcb4ef58c85fe89cc2dc56a41a51f058b9", + "0x99103a659e26c9a4d19404db4220dcc5defbfacfdd969eb7d70b4fbf9b2c91c92112c0097e8f0c32ddcfc35741da21ee", + "0xa088cc15a45094cffac52c38df427b7144d621cd1d12ae87d74c00a039d757e36fe3cc2fb35fda9b33b375553585497c", + "0xa0f1d15bc388f6602c975b4b9cb23ab83fe31124acd946195b999620c3c20c6610157a891114a43e3af551d7b8c3e4be", + "0xa571057592f3a9008bdf726254c364975705a71bce4e084a37915c5317f635528088a2f50afdbe7240c14d813e8e979e", + "0xa31e425feee58f8372e2bd4c21c48c299850df34044f27db3e4df55fc5e7c042cd19be59500acb375fd3478379f06053", + "0x94645ca6400f80d9a90f5b1c5b515816d6049ab04a552109c9c16b41366a7f3931d49338d944ee8eaf2ef5c77062c362", + "0xa61fba865027b7ccb03a4ea966081325eb64db5a64c5d765d2893f6a19411d40dd957d8a0b34733aeb3f002a4e0279bf", + "0x8199b89ea13ef8eb2f54d27bdcc781a5a7fe5bfef4ba4444bd651ac6021f4d90250b2f2cd8c63fa3ef237ac6eb1bab36", + "0xb39e1e98d07c95a4fc19ab175147547e5a20e66c044f29e4855818db4a7d0e7e2c24192aa8c89fe378f8d8ab3e9f0e1b", + "0xb807bb0069474e190b40bb2b34165351e73a392ffb0de83879ddb181989a22bccaebfdc90748f54de81c41ea244e7ebd", + "0x8b058266df90032a1a9befc7abb759b64a23ab628edd051da8b81db4211c72fd63093dbd94796b0690ff2b0c0fe16cd9", + "0x865decd95200fe45947a4249d2d8551ca5d7b3d7955adf10f94ada3e69d684e5c5b8939fee9a4457f22d21bbd3ce9670", + "0x95fb5ce7af13976320b36422b5cd9dd46379d13110fce619969308ed6a250cf3eb84c73e8ba1d32edc01aa2f6e367707", + "0xa1a176350aed82d5ac01a072ac7f3cc1535e20fb597ebc7e417921537f9bfc4cfc0d490d4df831f0f8ecedb6be970a15", + "0x974ddd091c1aaab7ed356b65c244748a713e98b133c5606436e531c31b31f6ccdcad2037b12c68fb54af4b19bd1d82ab", + "0x8ae9b7a8cd856087300ca90799ec3265b92f84da8ee9e98c6ede1be378dc040d0fe68b8ffc94b146f2521b9fe3d19e54", + "0xae17df60b83e4530af584991b545bf4b3cc1045416dc15250a6b75a9a04defae4c0f60b8bfbeb54c8a21fa84fee58e69", + "0xaca1e75d4a05282b0cbe6256925c0f269a4a8323888bece4a48aa0b5e7bde7fbf1d3e4f5cc38fe6a38aaa091ccbba4f6", + "0xac19171d3ee2f2e5021418c37a0eb25c083de6a6396290ed35b4771abcd07fda745fd082e3c32c117bbab7d9fec2b67c", + "0xad8a35eebd3bb28e08b9ef64bf2d8b75ead69db29c96544d71686ccc0819ebc6823e49b3b879ce0e5ee3131153900632", + "0x9479f12dab191269b020b70132996cb32059ac087e2a3f3e559d297494189e1d6849c340ace032946e12bd4923a3908e", + "0x8885e680de6c158cd67d66c142b2b4ac42b96e97eab8e2dcb90c3b454dd214bc530fbab6b5d5746064b9813775b6d5a0", + "0xa16d8d27d9b2fa04c7eb8436062a53ee0a4d679bb205d7d7cfc24e5f28e3752a9959847e9e31496bb0cb1c11caadc30d", + "0x951b00c69dfd9fc80b17733b843c440c58095989bb8744fc9db63a4a6116f24d5f224a279478fba8cf57753261bde217", + "0x8a693564994a1dd298f0b279e618b46bed349c53236fed9d8e05ad9383ce55fed02b8a361fb8c09ec5ffa8a271cee015", + "0xa09fbd62995a33904b4a34ac55c80f6d4cbd39a902f5db1038d909f1a2d385c3f5eab04b157b5662558bf35ed29cabc4", + "0x8662373988373409a4b31d45c5110afc32aa008bccbeab39d5b09a0e10370dd879684e722a8856b0da278e2bb91d67a2", + "0x8980d3cb8a82b3a827ba65f44e50efed0a6f37d6c150d70e4dafb67b1db173b46ca29d487ef9db92d37ca8312d246008", + "0xa279558faa11850aa4f0dd9ca8bddf69cb98bcd4edfbb0c19f22d1bff85d808e8f2cc026d95afd09fec2d15c116bcf73", + "0xa3fadf9c3066c93aa6a31d2346ad0a1d012c12ca7a24630aee46a087eafe5fa518d20647856d44ac03576bb3a9f81a76", + "0x8a8a19b09417e1b1607aeb54841fa69f58e094b46971c6a5cd0fbeb2aaa98c56599ac242272e6973ca0a9d2c09ff8d77", + "0x858a636f510b494edc76e86b1718228f076b8a21306b02abd086dc2a96c7a034704d743ca5d89b17903fe7b2e43e6fe7", + "0xb031b789e4073b82bb8c78f9d3fc2b901d75278733a4fa0a5aaf985a298269a735217e85eacc0dd554375d610a425359", + "0xb8603ce7cff755f5e07eaeb4d74dff179cde405234bbd7b3f62fd903054aaa34a9b868b04617d7d407c2b8e377227f07", + "0xaa41829c941acb3f9f0e2008e852fe855e153960cd3c85c4b8ab9f97ca91b7a5aa18f997cd023ba9e03a653f238a4f46", + "0xa35639f920619dff592176aad2b4b071d5c960f149c3a75311b16841d1872f29aeeb7c155cc9bff41ea7ee56f799de78", + "0xb252195aaa52e9a34936ccd1aeb40d28fc262cc4570d4f9685da8c591080e97438edf64d4d4d074491344bb5e86b6b23", + "0xabe2e52d10620b503dd1aa584e005d857294565ad90dd89217a77fcce4bea7b0c72d54dca7a1c31b5a9042a9602557cb", + "0x818085f2f1b525d9b2322c8785bf27a6759af9aeb231b0977cdcc7d7e77cab5de056e522dc791e72b8d9b93a9c41e833", + "0x930f64d40ab26be006e91deb854c5b22bf6951308dc406b2c7c7791d5dcec470529957fbcfd6a3c9655d544d974de7ad", + "0x92b28bdbea8c7588ad3a27992c19d73bd3a478b276f0e11c4e82ee2482e4e167cbcfddd17a1ac6bebdd862be65f54098", + "0xafa6a85fb906f5ffe52b6e9715435dcdf9f7892a396d740d67560fc42248d23bef470989663a73190ac9da442cfe6a82", + "0x82d3338e58fb316d66694ff4674a5d99bf0b13204dd251fdec95d48382f2d2ac60176a19e5ecbaab5e00af2a39a338b9", + "0xb30cd35eb15b3910b8b8f91cf04c223d79d587a7ef713030f0ab93f446caeef52c60ada365f8d3d645b477e7fca61d94", + "0x89554d2a9a11dd7e56f0b568f2a50c72d86362d95eab5d94a2386397012e18bef7c9e01a2d71fd325c0692e4d316dd16", + "0xad58326fea1c00e0f8aa92923661be4b3ecc79164d68e91c4d1366c9894b6d049a4f31c9bef6e5f21466ec014ba6b94a", + "0x8915a16afb0e68a84fd12a9203f8f348954920126d88136ec027a81f541b67c421b84ebb3d6e8f085c38c2499c28ea61", + "0x8e246e1acf655572863481367da007e94bc1bdc1f28aeaa1fb163dc05a51c3526a2bb9bda0a14fc6d658d85a9322e44d", + "0xaf83f9ad3c7c1504fcf60084e0948624fccfe3a9892dbcba8f166d0d67b475ce57ba008f286069da20a0da0cffe3b4ae", + "0xaec86d2d803612e8d27a01e3382e0a876164baaf2f3b8c4e9455ea00bc2e525378018e6a41ed9686c6408148e852bec7", + "0x871bdd8c84abeb1456ef73595360de6cf9f92ca9e6a8b6b816ec7497be60a9f509ef2c91332d17cb5fbd347bb0113d2d", + "0x9503ce513df28b61d721fd5e8667272a28f210ef787bee58538f786acd16f04a412387c6f5e6313c43f426a70aab65b3", + "0xb2cb0526e7e524ca9fe918e951c19460aca911d2b5ebf97c2bc74aeb69778a28316dec8916a4e3628b46bc51586c1bd9", + "0x98f52ee1896b632dff5153e3d1fe389c6200b14cdda6b27e12d4a4182763b63e0f587386aed78c97a32114dc286b975b", + "0xabbea974929c9ba70551231e3833d5cecc71c60988826771f792f190ca77c80efee7607dc1d6bf01a53796d8d9b73017", + "0xa4cfea1d06cf840bd599b14c011b6b204b2cf6f57fc7d7f310052062a4fe8870f02504e6c837c2b556c925921e543556", + "0xb957529d7e5d1fc45c5a822a6e0e480e46af2f5cc3801c31996b9b1acacfdd8d142265148b3e1453a0df0c5e6cffc5e6", + "0xb7411aaebb1b6a6a75568f81d052e60fa7752a64c20dd7cd5457f999f0185807987de8fb72ed94ca9d1148c19ecbe1d6", + "0x84be67a5ca80a1fd0f43cce4c00a465f167445e42232c2d2cad5e1097a62d3ad564041a55f0c76a340387503f15e0ac4", + "0x98803688f8e7b445c7ad14277b9f5f12acfba4f9a4ba6df9e2b7dadb726f1bee5098fd15e0b5308b6686a38864f84912", + "0xb085eaa421e566276bcd45d8b9fb71475c4530d63e90914eb2a33c17333d5628c1ec8a45691cbae82ccad97d4addcc94", + "0xa08ff7dc59dadb183dd0b5d336b6174464604bb2b49315e0c42f34ea08a8bca9dc9207750638bb7ebb6387257411956a", + "0x94d72607cd8a75b2fe2e9333959bb9d5b54d74ec36fb8c123c157b19a17f01f310b3311116b34bcfac305e9deabc79db", + "0x85fa61a796226ce555f8195c792ff6f3d483f62dac41c17b7e8295bd49ae6039574896548728fad4ce966be84a62a6ca", + "0x829ab1087ebb61db05c59e3c9d03e7010f8c546db117a6409bb813f6fa04061833771c8aa4c5e2981bd1ee551df0ea59", + "0x97f5c5261db0b130bb8352fbcf65002327bd6d8a7d4fee2a9bc293173c8c54be37ae229c5488c1983bc1f7857c66188c", + "0x8756439e5978ba19e2cef95dc55f706d53a05d1fa964c64d89b0e95470b5344b2f8d44680080626c37c77a00ff0e6b00", + "0x915d33f90980089c33f403ba4fc5c689ea7f1656f5c4e1110db987c59eb981b6a46dd9fe82c8efe7d1e3504f1d2c4d2b", + "0xab5bbb84884ef036c9b00a84f7d5ffa2931854e2afa5a63121fe64d548531af4203495b977bfb9301bb1e4679d42665a", + "0x9830b846a9041e4539eb858a179b4db6da89b507424e6d858ca4334d973ddae255bbfb04ae25c3276ccbe97c46f5816d", + "0x8e35f4563b8a5c9a76cc1da87ab21cd894de393dd61bc977cf22d3de454de350836e032ccf7d6ea55e2e6b83c4424146", + "0xb6338ced0f05806c625905cc51b7e772c5db3bac144e897339f67b6949f4d648d41b7d23bd3f299f4879507951ec031a", + "0xb3afa470fc71b92f415b879a814feb0702b6adfa08e395cee4f7d8b0e3537288f16c83b28ad4e2db02c1fd6d39e6afad", + "0xb4fcf7af3196bec84fe1f6e3bbebb8abadbcd46de02a37966d0ebe20972fd890803d570e4a201f2a89f479e09f19191d", + "0xa21fe1f8f57691165d0c7d8436765562cc935288f24fe765351be335f906c6c4dd1d0714b134c51255b14511c957319e", + "0x880a3a8f6b4ba410be06628a011e6bfd38d86919cf8014b4b4e1c930f8e3035749579389690f21bddc4d4699de8a4b1c", + "0x907d93a7666d847a140367c0a0ff80a96d6a8295b07cc4ee52d3be987f431d8dcb95d3717dfd248a5643c5395ec2891a", + "0xb8f38c78b8a2c487874c1a6a92d15cf0dcfd26319d4cf65c2f4fa9432203ba5ffefb02b7324022c34bfe0da369d96d65", + "0x8bd4ebb6d720fe52d626a621670a06c8a304faefca3846df1f619f4d456e14f8bdc547fa7210b8639b89c6584ea5c5d3", + "0x8ebdaa288a71a2d3188d6294ad0948a4f72c1eb6a2e921ec82cecda4d315a86e3e6233b5ffdc7219f34a99e9b4555317", + "0x83320fb9dc62119655bb0055192471ae06b7641dd4af64670a4d9475155733555ad06a93ad2fae72e029049601780654", + "0x80b3d022738318238dd32f122bd88cf2f734a61e315ece521e9e038f4a9bd7b54b5e67784f5949fbcc5fa911dd4b048a", + "0x891a23b4bf5cb8558b4540b66fb6b9fa54e9d0b2c084f660c8bc77af5ddb97cb5d8042b538f61330d9fa8ccbee6c8a41", + "0x8e5651d9c95aee23835bb1a06eea76efc9d5c881cf87ee847ee5149fdbf3d67dcd8ad0675dec8fca6cef25368348abaa", + "0x86bf1d094bc4fc7c21b21cfc7adbc750db0b27c35bb160d306b26fefb2699cbbb1fe624df1b9e7f6f895f1b81a829361", + "0xaebc3cb2623344315875029378c71ab7ed3cdc9d3d42d4b835b373c8420adefd177a44e532f3f06f74f0a40d53713e5a", + "0x9527f659e93a740b4c50d0d3d9aaf1a85936f04866ffde1aed30ab2fa1c1d565b46bec5fdfa510fc3ea934137bbd46df", + "0x8488673a4bc29c3ce9133cbf41c546fab4ff28c5d46048a21e710a8df4f2bd1c77d0ee242dfd962a30d646e5ebee8c01", + "0x8cf29773c0e0fdb75bf6f52d7066e7d6e9a3ef056bbb70a98026464b32316189addb5766822f57df63bb68b78c85e1de", + "0x810c6c1aa53f9c3fd0018651b1bf25215fe24687b568f21a121e0bebee576a75e5f0d08ac9c6c21085e52228b314c6f8", + "0xb529a87fe47402aa9ddaceac63a060a6640418891f931036c6e4098a1b308821a6f1a244fd5c1c22a6ed5f72f6bcf825", + "0xace9284ce89b5c81049d329db2376a85feeacdd9f735cf00038adc51865bb78bd9bd5d060efd0b727c509ec19988f99b", + "0xa2e7a949c951bddc99e68d80b3f3fc4ab960b682229fdd794f9eadc80bee91dfd5eda0052149d05c74fa33bb40d75ecb", + "0x86bac22daefca9143e0b1d25534900b1f7711ade4437642043c4a8c65f0d963cd1f0f958c7391e5a663dd3c59ed9de60", + "0xb7d2a6e2d44edcaad19498ab3368bfb87f9ab039cf2249d6e76091dc3db0c3bf45012779c02811cc818e95796e6ad9c3", + "0xab474f74e1ebb3dc696e7a6bfd8845ef15fb6411fa28426c486f7b0f789a6af3016ed5f7da2a36215729f5cca0b36b4d", + "0x86616a1a9dcb50d1896f3eb937bde67f213558feb401aae9898e41cf1fe33b443170c7c2dbd1648c9e3cdd0c24289286", + "0xa466169a2d95a5fadb6a69c7061cd2911c3eabc0b1a2488e216f8cdbd2c5bd87e80908b002b9efa51a67f02d7af2155b", + "0x8368af8b7c0f55f3c4f7036fbefc9d6a0ee9ff61197cea8ce48546753bdbc0b61eab604b8fe2c1aa91ced7a879e5899c", + "0x996c91779ff9767232ae603c5b1da5bbe0e303c4c2c72ad2d5944ee1297af3535f6bb3548fd1fe8a92cf4b281e1d83ab", + "0xad4a93d1ceecedd27389c658b38dd71cb13c729b27e490381d8c3ed4815b11ecbc37b1f82c0656e0ebf77e5bc35196b1", + "0xa3538c7ea3dddfbae80d67caa9fc547938bf77114559f9fc5180d9d0ab837d7fb1b27bc37405686f212f2e98b0028e59", + "0x8abc9fe135fbd48414f2ba28344d9f49ec2d5ce94fcb314ab8dc31c754f3ab7e6ab268184a67dafe8b1fb811a762c112", + "0x99ace100d8db88a83f1727b7b48baa1cf45b971d08112e452f5003566815ccba0ac3f8b1df6504f55a392efac8e3e70a", + "0x91ff50978ce629651f1501708908d75b490c18615e933191cd37613a83d4b605b0b48d024d27807637e662056d76276e", + "0x8e4104331ff1a40cbee9f489a814cf5bbd6fe4eaa1cbe1e13625fc3e6697b27d933265e5ef8728cfa8fc4ba5b19a614d", + "0xa442360d49bc9ce3e75eb40bf2ba05e9437fa594e8b8de34bbc822cc7b706dfa0dd10bd6bccb702d8556cd1320924821", + "0xb6ed6cb0aa34d5793e929e0d9b9651e41da3457a0b20c1bfa93a8f65bbb65bc07c7507482d71c1c285f5f663ae60019e", + "0x86d64df2dcd36d0c7348c77480c8af33dfd889bae7bb045888eecbd317cf3e4731b96ac18f410a99ed33a3f22d448f77", + "0xb8dd25415275d5ef8260bf5195ddb9b15b78a8799e4d15cca7d6317a18eab7bcb8fc759be61360915a28a8fcb5d6ddfe", + "0xa325a334c84dc1d9acc0a9315b399d4be93351c7049f474702ab58b4cccfd69aa50b8731ffd598ef0144ca96477c273a", + "0x9012a2dfedda5147cb9ceac681fa9e75e2901eeb3c94d87465a44d11250de4bc66d1e00ff674f2da1d800b43f686df9e", + "0xa1049d59da2a942d4d2aabfc0d972ebf3babef9c5d8fc5598ea23a048c2e58f7f17b4d860e437276bdae221d9e41e3b5", + "0x8c9d9a8826c812943d74c4d4f0fd2f1c8087135c37bcd9647b722b59801b01775a644e38c24b43e8e70f83bccc4afa27", + "0xb9cebd7bc7b041c18bd35b970f87e9b5183e4ace034e21117001fff8a05b2a7f9ab65cf6ab8b818b8192d1db5649312c", + "0x826710d6432ef97625db25104fc8dc3225bea594a10cdd4473d5ab72be57b74928ff356d210032a61ca590bc68509880", + "0xa18422ceb8c61af305277628e154d3a9c49f47e230a44c6216128d73db7c3ca9eca9f87e29cb2126f1c312f423c61463", + "0x919d357886de9eaddcfc46cd43e2b3dda3f82e926a3aedf02ebda9159faa00736bd2cd7aa044c76ae238a3a95a5bef38", + "0xa822d5a726f5c38e9d4a750ddec80bb965a6e5374a3d87757e2e48a18421f3142c3985450d1833f3ff4ca36e3b838c89", + "0x86bfb86eece6f6ea8f51985e312171b9bc821e0c3ab4cace556da28dd7bf89cfd5be3fbdadcacc19f2371c6a11c564d5", + "0x91b42643b297d8eb2c1bb3f16b57ab2964de99dd22bcfa07db1d0010715ebde94d11851df575f4f1ae602644e454fe0b", + "0xa5e444ed3d5fb3c5afd2c9c24d676adbf396f5d1d47bd532edbc72c83845970582ec49ed026b3b982c9c1ea725192cfd", + "0x8448387a14d84aac6afef682a27be67e5b05d31b59346748d2940072eec771adb53339f335daf4463f555da2d8543f18", + "0xa5034b66a26bad0f753be56dec722fc98a072bcdaeab0bb9cf35a56a573d9424cfbadbbaa8ae30690f7c6c6495331fc8", + "0x9317ac32da1772099f41564ddd8247e3532528b240db753a1fa6fb35cc039c6a4ac4546597bb2fb28721684bdfebdb88", + "0x8b4b0001a6234335502c8b17c4de274b83b0610960b5c46b9075c6e41f357ef0d8c94e9b14bff8be7849435512626ce7", + "0xb1aa903511fe4219acabf8761a8e4316cc4f8955ac8640c68a7b547cfc65365a8fe0843a4098f9f17a4c9beb75624393", + "0x8384f4953395aba4939b24b0669853df78f2fcc01b2145c08d3fc333ee2a7d4adc12f2d81c37d0cc187ef45b5f69f59d", + "0x92beb5a3c14637f84ee7a3c9b4d9b305b10af8963c087b86047e9fa959f41ff362d56eaccfe887bad1ccbedc488abe2e", + "0x8c60e16dbdfed2d1c8cf3f1bb0b0f462489293892f9d2e0221b1691321a771b163fbb599daec4cbd917da75f5f662de7", + "0xa8a6e3041a0c2a12c76f51139b221b03ccd1afaea3b72ba2c3533b797d5f67d8b90d3474b4f6f8e19a77894fb90842e4", + "0x966aaf74560bd4d164ee46c7d393b2c628e307019ca4289dbfb6a9a991608ad80efc1ee6e9847a19382ff8f3004aac8e", + "0xadeaec475d4bfb6075be90cc37d61d45ce14da77f8a9a508b9f829ddf2abf91683aa2fd0372d3025a660c94b0f612685", + "0xb3392bd1ad0c202d4a95912e0e06d8c64d7e2a8818dba8f895abcd0f6932efa9a0bff8a2aac107046d3478782fe42d33", + "0xab38804443da16d32f11c0e364449ed351dd36b7c82b5c7ababcc33a930acefe09fdb5261da04f6dfab29421fb1cc017", + "0xa34e0df9e953841bc44c09e16d69235a26ff390a6d128339ac97aaae5616865f86153d8d7466519dec6c52ad592dd3ad", + "0x99581db106391e6816403b1e9d13747aa05bfbfa5b46696cdfdedd1627b60e1ddb92215d138e007770512e93bc6184f7", + "0xae60c3b1ae3594aa4e3f08eeba3951157921aa6511148c6d32003d42157654d4a3a39efb1bb317135620f09729d134d0", + "0xadab0bc35ca3fefb14729259b16907a34e10ddb6d78a23f28596d3d9b244709651be7719537df33bcf003c0e43bb1a66", + "0xa31b7b2f3411f986b3415870ae42f90bb678a9fc44c942f6613cc4f90f3dbffa4b5fb8bf3abfa4361dd8e396d9a3c5ab", + "0xa69b188a8662eee48fc98201fde6f0d14f6b54db83ab79c2ec2f4b6be809773231704fae2cb281fed8b05107c63f2fda", + "0xb79e1e7a9045af6537981f54dfeed0a1335606301b73eff001880798f01ae9c0fef6e427e171afbb1d0a78135ba912cc", + "0xb1b883fbe379995b3741836a849516a0f21b18f42a34db2c8cba01f86711a2baa5d14910a110f1058e36431dec163cbf", + "0x87bc463b90123cd9e177f2284d72a7f4a1d4151659e1e4e8900bc21986f641af2f9a3386aba56601e6fb64da630b84a1", + "0x97a51bb7d717495f943db162837d3bf700ee0653da9a94b36153443584602156e168fde97d77407d0861641d8d373094", + "0x8b02561709564d0721b5247775dc66c6c09cf68a8ea62fd7dd361905ebcd98bdbb2c554fa272de71c6d22b04d33e6902", + "0xa914b9406e71c09deae875bbd628af3f54de5ccf811365cf229dfc69541d996689d05679eb02d42a0adda02be6e32d2d", + "0x85dcc5f3f77f72cf0818bd04c037cef560f0b0eece3191e06fcbb54228d11f7afbb8d9f8675b404bb39ffd04a3b65bae", + "0xb15bcb96a98bc6cc7b802dc29b79a903223b1712a10a22e776f45c530a4f767665dab1a3c6d1b52157f4b79055d5ac81", + "0x965e353e665b3734042b61951e105c1800718eb3c46759952755321ff5c639327d045c58fe90befa896e96b826910298", + "0x96776a5cd26b69f08a68af0201b2f739cdfb9553b466271063a6c8b8307f2a3f51294ea12c7e8118c0e6b884886e1bd9", + "0xa369453bfbe7ef0b2445231704abba25527b073bf735a968758975fad789c74110a573bc7ec50001368209a0ff385500", + "0x8e54dc4f2a557703b2d8bdb74ff107bbb239034ed363818197b2569c03572c14cff21273e94802159563d50205edd651", + "0xa1c66a1a82c60dcbd139b8ef4de62be423e7641a6b94ce0d0468e60bb1b000d268755946a028d3961d8b4d3722016ad1", + "0xb14b3c26dd9d17d6fd8eeefc7f706c177ebbee9b8d05f9b01174deb37649f77f97ef1a1abc0cd4ca7a13618a4036067d", + "0x8fe8f9754c5ee102bf96ba6b6f29a14fbf83cfe3c5f81b5358ccd4db87fd8c5d88760172373bdfaba7eaac98ab1fa863", + "0xa8c308c15242bd9c7b28e110715315a1f9818ebe03662027a6f1feac13a5dc9bb111d29444d13546d8e441e49960b0a6", + "0x85d87035d74a1f4662f42a8c6d26782daceded0aecee9232b78139b1b50fb764e87cdc5d1ca9d6905735dd9c3dd00dbb", + "0x986c31370f594d4c8a9096c091cb1484c1c0755804819a9462ad1b67937c6b378d97f1e4c27900405b21de2646be70ca", + "0x832b4b427f3347b0073c24f54e17ac16d5a80d04261c1d464f89dce89f42750d69dc8a83ee0481e410f94cf1d108c0ab", + "0xb13e54d91d5d414223caf43a7fad36930300594b8cb3ba97c0c873cfefedc165d05f05deec8d74a0412d5f0932813088", + "0x89c931d595849c8e54f50d550ae4a5d71c4bc74af436965bc32adbfe829a48ab15c856a69070b4a4602e0113131ce4cf", + "0xb03731793db466b74112a1b9dec3344fa952e81bfcc7fb2bef3cb20f566c3b2bf60c16a93f84f77f4c83d8f2a535a2d2", + "0x92e8fc80d49001139363e3201c93db8326c41322db51937ab641ee7f1b2f7d03089e20eab19afd27abc23de039ab4b0f", + "0xb27d95c90dfa91886aa91c9c8c85ce09fc875279028bef49abfeaf44437a0528ade620c8c2b3d712ab594e73c5c032f5", + "0xa42e2598731a792975feb5b24bf00b1e7cba1620922f8c2319dd5878419ce6099663b448299c0623ce400875c48e12a1", + "0xb062840f63b555a254e3bc36e9075d57c816ed2e9cb0e262f9de0f3692456d94eef702489e5b11c9746b949b5e84c06b", + "0x886226745d906664c476615dd41deef6c338ee10380657fdb75cf9ef28b4d9f56e69c8d0ef01e9cb80eeb42f3e5773ba", + "0x854a3649dd5b22def4f246eb0d1f1a206d3dfe42b5e44b5fa963a7c5b8bdaaf7f35b542b3e9cc53187e66a2315ed9f9e", + "0xb5a48cef68a056955ef4c080c85e4044e9f8a562f2beac9fbb5e19f8d618718c86794338c6dae8f94b6f5e9f8e98404b", + "0x8f8bea7304cab80d0009b417c198bfffd166eed6f6db19f28b7616e8b0733cf0a4d54d204361d7f8f179985c8c3a16ad", + "0x8af81f10339e2f75f6b6fe22a641298bf90c8676260abeeef90bcd52f46ef013f5aa4bd9d0b5ec15be61b7c3e0f32350", + "0xb0397c64034598c825f9ef653ff16f680325546695ee6e9c2957d3c87593161a063c5219304ce6a16b7db75f1a2c5f7f", + "0x8d2e7677ab6fbe2b0f5ab6dc356190bb3ecd7fc468c698d512a6c69f22ea97b71fa961c88635897a5b539ea51b70b4a0", + "0xb4e91a693cca1007fdaeb7e679c6837bb8eae0bf61aae447560ca6eb5ba918cbd9952b41769657978413106b359e169d", + "0xa8331a907ba7d95a5e4090a7680d1bce3cd803db49fb84a48996e96514701de1602c4eeb4b5e0b1c2a106c4f678a72a7", + "0xb54dd28a97a5f934a34c2817af91a41e57f88d7eb5fb584d3b6692f2d1c4b2a4e273c4de5fa33a0fd1fa02c9d7cd1fb1", + "0xb8b780e0f6059ea27aec9f3693ac9adf0b93f75fe7fac5230deee1e7471df0bce9b5b2f260a6a0a346afa723860471b2", + "0x980e9847ec83d61442a86cf8c7464b357694dbe67aa5de3a8c88ccd1a038256453101366dcdfe11a565065d78ce89807", + "0x9350a17e397bdc3d2bfbb84ddc79a48bdc6ef5c3d8c1ea39251e762fddf9962b69cdd42c563d03f64615b72c9dab07bd", + "0xa34d24b69089cb5ffc5f06eb2acfeba13c96a1096d1af9620aea28753baf3d0aad0bcb30037ef3a5ac36b178816e878d", + "0xa7c8b9108fceb4e0377eed48af9846530114df986cbdd35f6d54026104fe6bfb3b58e57fa2b3a750225528f8dcb8bb9b", + "0xb0f71f6a04cc7119db96033f89530853d58a445565de2efd269b1e3956397c35a49c328102325b780fa5d0cf5adc2a4a", + "0x92be082f04722fdf3abca7ebfd162b7062939c3410ec204d5478dc8de2bae2b25e2654441d29fe2c350895512d333ab0", + "0x95e7afbcac22dc2d04c5635d7a8c6293f6ce29bc6c932850d24ab5216b449251bdf7aaea838ef40e0e4eee1de8f63bfe", + "0xae0a877b488865f21194470677e12ea7e357c5d63f6bc454f608e33df9a3b20e9aaea5b6aa42e8999779b8b445831c39", + "0x98df977479667e23b897b91f2db8f4cdee7ece7fc3ecf8a07d752efae090d8bd34d781353ec1394550d8a207bffe582c", + "0xaaa0f1bfece62a63f3bc76862b8789e2593b4bb40b3c413956e9e5c4eec604e39d722cbe1db210396eca7c2293489099", + "0xb362703d2b72909d06407d139531fc144e68ba94e55643cc3cbb9ed24145223aff460b1627b41eb9a3b709978aee5a58", + "0xb020025128804bd642fdb1d2b70b07d181e5ba30a5ee16f6bd00d7e2d0c6af782e454cec107304823be61647e65221fd", + "0xa409894c0030081a2c7f8fba27bd0ac53997a31b35a33498d78bbcfa0b7ec0a89b9efa99dc1b8770ba889060f39d56e2", + "0x862f9eace3f54288749ca8402c22ddd7829f0454d17ff4891727c86eace899cbf72d302065f5f581169f00186c23b4dc", + "0x91432f2a823c3ce95bdeb5854e8dc7faea5031fd65c82dc69e4adbc5ead2e5a5b58a9cd1428d3f526cf94a217f37d7de", + "0x9543a9038fdecaffecc4d3023fd67f7976dcdbc7014e82edb4573479b1789b4c610c3964643e031f69ac7a3e3dfbe241", + "0xb4f31d580987f47c550eabd2d276678a294a612ac26806a06634b8812a571391151d84c29b6b82218cd84dac85bdcc88", + "0x8d922ae4eecb45ebc23eb1a8404aa1524b281d0f0ceda58ea93a0cfd4184efb894c047f0a46e2d007704f5506544907e", + "0x98973979672d1d52e561cae7331b730a577c422258c22720edc344aae35ce071be1b017816d58bb29b9cf5c433fd64b4", + "0xa46be974ea72c5e5bd16de591bf27087d97b9030fb4a74743bde5e480052a0de58bd962dbbf0e0fbb0559566c3d9780b", + "0xb2b4464973322d865207949afa4dadbd888c9b0230737561c3b76a1953a85ea9439fbb1db9d0d42083c62419db512450", + "0xae811a9eac5f4ee6cb3a4dab456a3e5d95cb1ab303c19e76fc4b36ef6b4c83ec0b2803ab8680ad1663bdec0ea2f19aaf", + "0x95a426f3d2ae6c6069f888010bb20c392bcbb65d0986125e0f0066d4206f4f443f70dcba8a789da042b57a36980e75be", + "0xa9ec01a5777d10275153ba7441f2e27ba3d6f1a875f204469220ad999bb8a0372369278bf5a11640ac0709771b814a31", + "0xadf1091e24bdf10d848f1a0920eabca0a2087220fa0c3f8e5b4c72ca0424ff3e0c77ad4c259c12c3cd1c0eb0cf32c67f", + "0xb9a57eb8642729541088164b9974775934d7a4c56a3a3ff2a190d549b294fa87002810f31251170b0407c7e9695cfba2", + "0x8625501e5c56948812b72b3495747412e03ede90096be089cb8040069e49cddfe697766ee72505bf715802fc77c08fa3", + "0x8a745aeeddd1be100474d96aedc737208ef19a93a8ad72c10bdc0218073fde6209510048eb46e271553b04d8e6529f46", + "0x8b8d9ac3b91ac0333094c85e81fe2b8cd5c2207073a33f66bb1939e8f1c84ef064a8b2ee984a9f450f0a6e54bb56ccc4", + "0x8cace31444da99fa5dadc7c46f689fa427949d8c089af3d90c604fbdbe0dab052392fbad4b5aeab707e4caa9e739f366", + "0x8750c8bd1f1abe5acfb29ecab0923008cb4455ae8a1db01bf3317df05e1e02f9df3c74e879d9c57b8f59877591939ab4", + "0x8904a39ad86cb42c06692d4801b3718bb63a07a2dc5ef13de16f668b08968db34966457ff2e4cb770dc61a216f4abc5e", + "0x967d1750b0db53e977bb9ba65aa820d7970f8c75d5355cf12a3f4c509dee7e9b6c0f7a828474b167c25b15d74f0e9cb3", + "0xb37297bb6c2d9175e0a7654c5bc6d248f47f7183c3b10375f07e21e9f3e66f6581caebfcf468dc0f8c04132a2a0ede55", + "0x803862e6fbca945cb6c0ba202257df5c7e1e1fadd78b842970206575f70c9757d4a54e9b1a0a269dd37c4f830a40d2d6", + "0xa7a27f2fc7a1e6d276522177f0ae6630dcf5205d08c19319c315bacb165b687d125832d97ed689960885bb7cf42fdf36", + "0x87fbc08506fdf980cdd534d4ecc4dcfbd381f3937dafa09db402e07a67e1cde579e680d3f77865b5669f35fc00901530", + "0x8fab8bd57f76d187f1cc22e40b51736b1b0234e70813ca02559ded9c7835cb3dc71a24c8f679081510c32f330d6ca45b", + "0x8fb917b7dd71e1728bbf32fcb55343890aa6fc890740f41f42e9620b5bc3ef8b1ec67d9c047e4a9de0863a5eec18e5f9", + "0xb7429e758850bb7f69db000d49763df43d18af11460ee0f158b741dd6b7575527c5c8068cf54f7f78098f9ddb92a82db", + "0x8bd3c73c1b6f88ed2696d53d2a0617f74bfada964d2eef2afb5e1cf00bfb646f552643c55d5453cc622c9ecfb23ad492", + "0x8e025e91b30b0f328cd6b79df9603698f1715eb6209e64ef8705cdde5ee1c4ec737a61d9b8a4e72e83b2157c621e1590", + "0xac0b91bbb5ce5bbc8e8d6c0d9d4e51b3960169c608b6220a352aeb13072133aa9d934b4e69d7c5c39fde68d467fa8069", + "0x88255d08bde3b967dfb1dd338dfbdec12a2079851aa796be070a1d70204048c34f2739b7461840136b03429a8b83b1f8", + "0x97a83477e765f3f17eef0d3243ba9bbdcc50fc581f904e92a853a076adeba917279fc0e01aeca42de1aed8af9579bca1", + "0xb0d9f1afb807e0e6f839632393edef25731ab2141cfa1cd965e986940a4916c8788733a39def0cf67afedc516dcc6ce4", + "0xb563e9ed9ba2134011d7bea6314af5d71f63caa1bcbf878c26d7162dfc76343c38308955215252962fd0c9c87200f1f7", + "0x838d4e97bd67822c22cda558f0d35f971a0ab7debd3da3f15c27f7d4b3301b2c17b60cdbca0da8e067f23fc97d136ae7", + "0xa7bccea326cccbbc4773de402fdf2cbc21a028197be98cebf6e691a7679fc948e6bc4981a14fbf493a254eedc444dd7a", + "0x8b2687732f7aebb153bd6030dfca0b6d257b8f2945eb8221ffd36ede50d463172cfc4bb17dc30bd21d8572aae2540d6f", + "0xa4a3e87ec5984c3a755cb39fb04472583a0d2c771552b0701788f03b4618c87690a13a905420358701777e8b5ff2d190", + "0x904c4dee5dfff129de3fb8cd0a6e0576c18ed3d77f49b8f0601997013cdd4ecadb86690389555ebe8a436d8084024f2f", + "0xad1d9c7a6236b22474fe8d45fde2e1f072101b5cb7018ac73c0541c0f9ebec4d5c4469e0570cc188cb5f5ba1d8958be1", + "0x87fc8ca6f737cfdedee973f1586b94d971564a1fada0e4d65894222edcca6552764f1ca0b02782066f19f871ba5842d8", + "0x851829a8b39eb6b91523548ad600bb876408cabed98d30958056367c686bdedbc876e1903b8af8ffa3d3618e3580e3db", + "0xb99270859bfe7d8a4c1a22e2d88a644dfd2f100c54070ffd9c4e1044140fc0d21d62c61214a2b81a9cfadf944327ef8e", + "0xb89a2ddc91c59dc2ed9b8d11e4838002e731b0bcc576e0e18106238cd3282264b14cebebd8a64f004521cbdc690c4182", + "0x8be96bb11a025d265b7b3ff3151e9e227a8416e6118595ac29bf836ef751504eaa3a9cc05bbdcdeabde11f2dc3d20c3d", + "0x87185ed410be571fb532e32d0ff4ef68e98ba2d3d5fbe92180cf1fe8ddfbcc89fd1e03694a9fde1a12ab905db89323d6", + "0x97ef023f71850ddb282f244b3f39579eab69ce5bf3fe5dd2159329b7def4982cdbdb4e71476471acfea0f7ba5a7fd061", + "0x9944324d804fd3978e7e137e6e65348d7473ea23c591136d55779b5a31f45f9e4d866d8a18c76a3a0e8cf2ee61cdd041", + "0xb9930c9aff260105d4d15fb749aa33436f6fb52cf9d50e39dca19d9cc7938d752773f06756af86369e1f5fd5aa71d5ea", + "0xa85ac6bc027ade2a9bbbab2b231241cbbe56e562fe621ea19208a8ea36e1baced89ec9ab8e2f83b602539e5c053f5764", + "0x9917d40d37549caae646848e18ffcb49f5c6c4e396ebe7e74129a41b0cfe2726b4dad34d51f4bc706063e654da898824", + "0xa25f8a4d8ab34724a732dacd2b316c80a6544d4b8c1f45115c4f55c3efae6129b83623ffb31da80e2601f70ca51ead16", + "0x932b54b2bd26670936843a92346d231f2f3e3659542f4d4def73fb36ac0350733853130a5e5e9d8e386d34f817f5a91d", + "0x871bf29d7263bce62a02690681d4e1c3c2f9c2751de4e35810ece13c9480eab93b80a00230ef0ffb858a829ee6bd96e2", + "0xab9643bb1c32dc2e8c05ef49bbde9937072af214c19c3932be137b7b75268edbcdd81d1370089be44462b8032bba3c57", + "0xb67d510c460a2f14b7cebaf9a15642a14b2542c13ebb1d1690596447ddfce6a86327ffa377c28891f6bbd8febc2c17ca", + "0x93a5ad5019a8e680bd053a524e0ffaf8cb18adfcdb22ccb6cbed67012316bcebed65294bcc0cf4f4e2915dbf19ff0948", + "0xac7a7fc1140b1197f2aa424b053e8ceaf48abf41819efaff87a2e63cd6e962c278942c2b97742ffbbedc5cd426a8df50", + "0xaf0115d9c2f887ff97ee15a1116ab06af1920f2f42700b75cc010d4c8038eea941c9bcc8e7cf4a41036813143ab3e8eb", + "0x90c768d880b6ac17ed7ff9bcf76cbd5c1c4879247a757d8cc8b31c4c7bb0ec763d746e6e06e361afa8ee158e36ccaffc", + "0xb3f10561432a97c95d02c1a6f317bb1ab5b98cc88cf5d56e1492ca84eb2ae1db92e9e31fa454de562e719b71442e69f0", + "0x8d94729b5fb0afc196064991f9b3c8e04c0858199aa951f49421ab890079804179fe00707978f15637b8d16246794001", + "0x968515d07a0f0eb52adf439d8f70ecd1f6655072abbeea45431dad26c8937f4aaeda552a22a420598d2136f576a966d9", + "0x91f50e6f292e2bbbe226b221cedb9db36bcd459bfd74fd6356b0620766d96869266315e8503435af1719d8ff765467ea", + "0x968b328d79e183ec560e8f0de113298755cb23a893a631406defdd26ecd52e4b6f28934ad2e219382837fbb8f87f4360", + "0x94c126a9035059d2d817c4fb16cb13fe6047c356fc495aeb369acb1c45e89306554631f50d313707e82624b6107d2fa0", + "0x90ee85deb494043a1cb280d687e3f55345085e576484308755df1bdb6f734e7dd25fd2489cea746be5d2c6384e7986e0", + "0x92a4f64d98e7e633271bdafb1eb88474013b5ed2c65137c243729df0d79ccdc6b210118ed3587ad00d3f0f757400e47b", + "0xaf31031fcc867a53760216cc1f467901aeaa3b28438fb3ec90d6a1c8a46590062c40fac939bc3c7e7a7deff8f83c262f", + "0x94306afe09f20d5de9ea26f37f5fc8df1e29b3a6963caa94df031efd428545493d53e0d8d7af12ee525e2e21cba23324", + "0xab6285371b981d5443ecea699af9da916f9320b3ed0a11c15503f3b10eada3ff5dc95d24a54f5aaab97d3312de5b985b", + "0x8e9735364ae128f790dfcbedcfe0e11b991602dce0c90ab3cfd4aac74526c30a798fcb51a8ebcc5528d88c724e9c2b02", + "0x89a3c12bcc68129b14fdc1d9b5db8d26d11c6c9467f5bff7c40abb8ec23b193746697421ea4400d5ebe53bb3fbfe59d9", + "0x8368e44144947f9ecfa5d126f4a57bb1d3728fe3c5d3bf83310174d638a10cea02ae79fca91d5489ecc9fa679feab49c", + "0xa0474ff532e1a6a3dc8f16ae27e77d6ab72b62535ba0d3ed09da5c692c6fd34424141cd68470922e1e147fb7f7479d5e", + "0xb9ae0e47fa8d999135f78c733cdcad786b96087a340f86e4cc2bdf019b07fd4a76f9b4b041eb397f61bda20c31d27838", + "0xa7262ca18a7179924d28161d64e6b6cec5da35b7eaf695642dbc127a7bf4a52bffad82b8d3fcd010b308dd72eb567f26", + "0xa23ecfac8a3f978f9ca8810458973f528846de6bb92fa6422b9547d55d29d7db7d8bdc5181e9ee2257a458466f714449", + "0xb04c32403400f82677d831314956acd3cb507520ff14d856cf8ec4fab37a4428a5d24ecfabfd2c6086e4ea6d26b005e5", + "0x9669b2725cd5965305c6ea48331e693086f4c1c4ca7dec26bc6290e9a8e70f9f0bedca6e36985c39ea35b412abc7f4b5", + "0xa6f68cecace45317a758658463c5fc1f005283d8c3d3de9364e7dea453007d8d4bc849a21205d61ef81019e0d25858fa", + "0x8ee19ccc1c83b2c4d7c7b712bb370c129201bfb340c5b49d991207c995f870de2d0efaa88e05bc9eac567c4c36e20175", + "0x8a530ece1992d1de92c4e845e71a1ab24e53a8a0679aa5bdeefc60fd890ca3cee2121f66c6f4b29c437440e7644e65d0", + "0x924338d7f356da9b8477b3aeaad6f754a8d8f6a791d70c3ff23c2a6d4488efde9b9fc351319f3ea1f545dd11cd23ab76", + "0x8eb76f86e057cfe9f655ba29bac89cc97db07f0487c86e7b41555b5549897bd3d042cd2ede35e312cbea357df622c6c2", + "0xa2c0da965489d15ced574f5e27cd4781a1dce8fa4f17762a25fef1320096b9eddd92a007d58a194ef57def3aaf4e925b", + "0xa3fc89753e8896d796859c9e5a00d184be7d37c4d5741ae8a60cae9a7a30c5d840325d6479701e1f61e37065fce81870", + "0x8b2f90cdb3add567b94f4c7fc89a8a57a0f06877639c33df2697f7c39e52c1869aadc98a2f8b85a58fbb02bb1bc1a441", + "0xaeb2c22d9186725ea40d3a4bf551482bddeef42c0ad33801e35361d3695769429449c2a13955cccab55778d3ff29b664", + "0x80bce007abd8ebe2238d465a312c2d125d1a695184b93108d728075595c7716786f9188e90ae37fea89009d087e71b07", + "0x86f5df2b83383c737bb6db4e435f496ebfd56b51300612c402bea9ac2f439ee7e98cbc2655d31646472ef983aa6ccbbe", + "0x880e8a19af5ad76f14cdf94396b8dacf061e02eeaba02d4c29ddf0d07c6d2a737c987d69ea2eee52f0db5a4dec318932", + "0x8b82368968f9b5bb175c95862ad403beee68d199a20d5dd618395daf11ff0c2e1fbf3a31c23d3e582556276b44e70b99", + "0x94a062abbdc5ba740077fb9de722ad2ccf3f6ffc8b4a9dfbb0bf2ff789bd529e7b9d8da520d0342af91808fc00431638", + "0x890b4ee1e9837a4c215616819dadbd3c6ed7586ad391498012a54d735c6df0b72c2dc3969d1b24cf6fe822f37f9c10e7", + "0xa7dfcf43c9c22fd22f47db490e8f0b8f42597a5b4ae3e7bc4a9b12252b32f89412a2aed946eec19b133cee89b4a70322", + "0xacbd9e85b9d9c3b068220f893d7b6368984f6cdb1cd06a784cc9571f0c632775ef890dbd51371e8701894cbf667d04f2", + "0xa9b1f84f053ef6f41c59b1758836a82d53932cc4b8ee9c2cafe705150e1c717e3f5c15fc21a2532c071e9dd9bccb4dac", + "0xb2c63345748a28d04680e3e451d1f7d430bc8ff2031b6bd4237a1f55dfadaec20d1854ac158cd6a1466dae525c1b9b06", + "0xa23e7b2e5b8f3e3b0e350e1a461708be9c1434d49fe2e51473e2e360bb0be140a96f8ddac99e3b804557cc25d3e44776", + "0xa4c4729a38f5f32f155ca4d1994b61802ee418b276486e2dcd681fec13316f3b6d4a8e76eb9f48e2df0339543b11326c", + "0x93be67dbdec2655edfe40dcdcc0a7e761b7259a9d909ebb12fd7c9a5d4efa10de065d2eb049660ed01ede2f26388d43e", + "0x932480849f97e32fb14d4a69af4073c377e949af7293951b3ca371a306d9e2096157f51c8e5036a44eb73c7c842c5aa9", + "0x8b5e79ddafd675ff88d8f65176321a08183429d42d7fc1e7cc3cfccdef0dc5824ee40f279a05edbf4d50418a4cab2126", + "0x962bd6fcf7c7f2a9c569d584658a735bd16440de2ffae236c68ccbf2ddc5e13836efb163690062537d52f7d8bbb24222", + "0xaf80793655c0b3ec3029673c50a7f212d297f9f80d7d1c7cb1409d292f3bd7dbb8b24581017d9f3964e3432f46e79ca1", + "0x94c8cf3c737c102e9e91216752c82b17e4e42074e08ce44e701c2f8ac7c08902b911cabf38c4c5bd41400eeb1fc97acb", + "0x8708ea7af8c86b2a1964edf64a9e9c56c7febffa742c3ff2e3088a61d3ccd63e135811212878ba7ad8a819e1859f4e95", + "0xab8e726d468417c168c892c10c7e2297e50c67e4283e5b48c3f3b014981ec482e211374f779faa0c1ead906f5dd4114d", + "0xa93911e672aa3d8dd686280cf062f128bd8eefc058fbaea52cc0a9bb255fda84e65ea546f662fc75fee4c5b24bdc61fd", + "0x8aae6d9289d8adf0f81e7990cc79cb704d0a975f03b9ec02be66089d62954fd9a8b005c5ba8179cede366d25ccf40869", + "0x91e44ca55de8ad3ab42816504813cd9ed9c6d64abf6373e8891f909cb49c8a951ee823cd1f947058d542f0bf6290a11c", + "0xa377f97e075b66e740b8476f085d50ce8ac21f206802384e2e072f6b9700a5f9cf0e6f2236307775c0e0d6ae8459d864", + "0x953c08d9f2a9d6ccb22cab906efda69ec1c228aa5c2ab93822b6f71c007fa3bced68c6a70ac605c6145e4af770b60de0", + "0x86d8dcf5a9ba81cf6a3149b2fff96e36639767e9de461bbd3ccc870634e8db331b98a888d7e8d3d70b6ed241d8ce54da", + "0x88db73952866ec07c49b484c6b18de70d439e67d971c1b436684d489253cb96d793cc4d9a4362b51dffce837dbd03bf6", + "0x970b7aa9070334b0649bea1f0b4e53fded64665f87e055e3527e0e567cb57a0e97d369aa16a005155cb69000073d7695", + "0x928c8aaf72b3f51e38c866ab457f75cbd7131b676817a3c6d522fb8f876b01a9ab3a84238eaadaa0a095ccd6c1ac060b", + "0x9561e78d16061b5361ba0be11387c3f6029415f83bcc8477b8729e88c55f4bfe74b59c1b24bec0eebd9779cdfcfbc96c", + "0xaef133788d1e04ac64f573f3ffab473209dfdcaf2c675fddcff83724d17b91d6340830409b391a94405d6ade005cd01b", + "0xb8ad4ab0a1ad6383e4cb12d479cde732f202687ebf886184507371ac277446b3bd1648c49c89343920e5d57fa6b255c3", + "0xa8d00257e331f342b79b3d25b74d300b070326b358f690edbaad5e325293d8b55078605a43ecd9dfd27206013db4c286", + "0xaa71abee2720052cce7a5a0c3968e64c2c540cc852dfe08b742fefe005dbfd10397f66386744c9bfbbaa40779c2ae190", + "0x80c6680857b88afd3ae8801677720100f0fdcb9e49c82f74b8ca5a27aef34e6df03462cf9ef5f80169c72da15be567b2", + "0x8c2f2865e132869fca5232ba5e6844ac0540a53a66971ad54ff91f186e011e5412450df9099fbe0b987be443867dfdb6", + "0x89cf681e0506baaa528043a15ab3bae09b8817853e889f0b3de138992e52612fa3e50d54b3686cbca6428a7644f58208", + "0x89ddf69b72b9ddf7d535f742bd3c942000061a5a54987f2ccc7a09e035be978cb32f653df9568526c5857a5df4321f59", + "0x9908a3288b9a9972c3f3f0d5923d9840756b74f31ae0b24ef2188465efaa5247b1ed13b774991bbe4c065c7e71b487ea", + "0x9454ea9a664390fb1ba79fbb5c0cc765d8ccd32a02d946a14353290fa2a1ba911605ff2e302c340e9ed6fbe8543ee6a9", + "0xaa4f4d9ef843ca3ba334d73af634a0ee800b3393f8f7701cd152274f4296eb79d63869d452b5e83976eca246203d6f03", + "0x8fce1e2e59dfc4fb46f3741d27772579fbf2f48acf1a38c49b0e5dae7d35f2624af3a46a48b89bd835b7d452ab0cec80", + "0x810ec0e58504ed556e788e23067296a8e4b4ef31257d508f05e5245bfe6d2c2f658fca8c81538c6c9ea6ed05a8f249a9", + "0xb6667bad0a7d49cd2dc60af85e373fdaac2af0d34fdee51a9fbc1fe8b77470c162a04da38228fe68b7d5247d43026734", + "0x8982971d57bdf35e0f34e867fecbe0c140d94101484ef4ea01b796633beba184f980c3ced28b24ff42de1dc504dbc854", + "0x86d8d1f3edef9e61058a58d966169a05f07fed0d93bd4f4a7cfca5a872b2aad0d1a78f8ec7784828e5813c8da577469c", + "0xb491624c3d5e517c9019258db6284d7533778e44b1a0060dec5f655a7b79057141079115f5cb1d8d97a90af33cd7563e", + "0x856e1cd4f9ab7cf323f5988bb5d272857d2fa90527f800362569a39defd93e37be2a60c11f498c482654f55560356f7c", + "0xa08884d0e642c479fc8e5a9837d1babbe63f3165c02a57b19d0547fa1fdc18ee382ea82a86cfd3135dec8f2aff793f53", + "0xb1a4de5ea703fa5ac8a70ec515bc65203a9415f6da109b67fa32843a39d7fa6232c9c13920d78c0f16e99fa5f6a27e83", + "0x931a2ee3220ac7888157c426d1b33b8a56f8879fecf1461af4cd6c85f94e193bd6ae6f8dc3946fc689e42bee213f0027", + "0xa844a78e65ea6f75bb55a5db1e78b88896caa1d54b624f218eeb302397dc98a084a2ff4b964acd0650667160928ceea4", + "0xb9c214280a15b423654a36b11646c928fb42ed2a692aedc01441c67522760df29c6ae7bbcb9237938a823188ad4d83f4", + "0xa19575f9bbdfccf970bb3754818e49c709d1bf0af015541182fc7203f7aab51cad31544072d52c0234a3b649d03d9a52", + "0x8cd1127b7485ea7f349e2c89a4b78fab3e5fabe5a95ff0cee10a3f4fd48940e431ca5e526f6342f7da93e32e8eaa1448", + "0x9906abc725e445092dd7dd0aef90f989e3c78aee96f3c0a67ccb62fb2a51363c71d783490fa5fdda0ff9ea69f5b9233b", + "0x8996df92e014c226e5ac724075c19d19a9204b2e086ed5e75a9bfa1f8391c4c77fd5c0b85a29f28b302a4af29d38735e", + "0x90225c9490b39d151a80a9f4d9a7f2595961c44779a54d5e195ec95096f77e30157c6c629cb1c36d995f6c3ee129ad20", + "0x85925b1dfe3884ae3a0e993b67b6c49685deeab6cf0d9997309961b7f727cd6133797bf04d21ef7b620d1d6392450b64", + "0x88a6c518e577a820d83f87e9d5f236f43d262756b1bae0fde72af241fcc192417ca9724428d17a3f9dd813712a772cac", + "0x8f501fd5634fddd00a8411c0e9c6947bab0dded26339821bc3543a64c519d9575c3129f6619c6079d5e95237c11cfeac", + "0xaf2b42945d7c81bc422a1bcdeb80027a1a243f89c65c173294d6c92e4cb3cd650740cac17408e7ba1a34d37d865b9bc5", + "0xabfa5e76f1112602ddf152aceaa9f588beda3aba1115d0823d6a6b074d28389fd4c8178e8a845262200b9af024a33a88", + "0x9732a0e3efcef5ad4d43811bcaffaa1418c791d3fd6ca4489d6cbbb7c44b55156d218f0fe86f2ec96ac306fefab2e694", + "0x8837a6c4e60839ffb0b59e94b37d81bf1ea392d44cc81717c1c9104468d31fb5fc3c35b1efd9991b5e7e9819c66a7221", + "0xb6545fd0b455748ac3482e0ead3b0157563cea7bf6bdd5ae2af7afe1ade921e5ba80466885ba73a89657a735c92658a2", + "0xb72fc49fd3be541bc26cb968ba4eb3078ce7c71fe0ac06340f7ac25c0befb86af03c4cf8f31c857f9e5d946401e86bb0", + "0x929f424548e29c3b47fbbd59ec00d17b00ee1c4f6b966c1fa7e0f8528d52078278f2852da976b8931fe813b0c3b71ac9", + "0xb37861ba981001aa6192cff06c13f041410aa60f965ea03dd48068b4295d61d2fa276c3f477f985f50189e33308c1876", + "0xa73c7cdffd646cffb255d2519d8e08dd8d9a9eca0610211177e259230b8f8c7ec8727015853197a0f11eec8b59d4f2bc", + "0x8da1260ce51220ad107c3127e871715bd738639cd90824d1c9f5b6181304f363b8bdbdb42c21e4e360cbdee496b573a9", + "0xaac6bbc35bce8b54820ef8d7219a4092c49aa5d4fbb187968cb91ac04bc44fa119766f8c630a727ba184cad19278d9c8", + "0xb964de0bd31847ada13dc3f6e1bdc679f421e262c03353e39f0ef1df720ba05e6d806dba15b6e10df559519ca125fc39", + "0xa62e4336b61f85eaa415f57e21cebc7d54c68f6febab02de76bc04a69658ab1d2f7cf0104da79448e32e2b7c92b684c8", + "0x897c6ca595bb2884b643ce8e69078431979d7e6e1b2dcc6effaf5a62fc906db6466f85020bf5930597adbd99e2ff90d3", + "0x932956e0ba09f6499f1ed231732a444b0adf17080237d9345d06d4262fe8a5fb0f704c919513ed42473751069c57dafe", + "0xa24b9cb4ea9c2203a95b0056bb95342c4fa0d91bcc25595fea0161e7d6f45595f7ea171e0ac1bbde13a6d8ca6ad10bf5", + "0xa7714728bc3318f6ac005e350de94f59495ef3972b328c673c5e608fa9059be3277b48f03a5a9634c3d03397af7d089f", + "0xb98732aec7a0a9a7998ba51e2b76e5232379482d0047f4876cd39918119776ae2683590f7fe5e44d12b3b3efdd916e8a", + "0x87700c3fe20cad8fa3041976c87ee761941d323f2d64a9818f20fcdf0259f796a11e55cdee31446bd19307cbe8becf09", + "0xa37cd03fd348694b2ea5cf081696d12dc4ae108da8d48695bf74c921b90612d18c1aa71b1071bbcc02829e05ba1363ab", + "0x830e4e7ac24fb3f64294e5c64563ab5708ebf0e133540b35b985390d68c420a6d680d779fc87245bb1f5c58e59c5ff39", + "0xb5922242a82565753dd2c1438008462d531f820af1b565756d4d27a30e3406ecc503b1e5b628012ea0329fd75561dd7b", + "0x91068438d2bfbb0666824d3cc2be488f2eaf3a8a9f21805838f9f2d582ca6bcb103b2f0f313b57bc86f87704aad7c7d1", + "0xa9a2133fe55e99114e526904f5fb3e2e141f31963562887a9fe6a262496dc405c756bf6dfdd6acb8853ef5a0a5146037", + "0x8e48e79f9eb1f8757b4c4afc4e3d6da4d368bb25b4d54e3a1f34f3af13d8037b0d465b29894f68272b79cc60fa676071", + "0x9378b90495b0e6468dce3102a97e9965a5d21fa4a6494d401888b8777bd58616b99d49177f2eb2796476ae84d20b67b7", + "0xb0aea247d7d7c7767519b87dd66f56c306d9eec88b0db8060bb97370099892957e2c950fa2e05f24f8ad097889cab087", + "0x89d0d48769ad81699d5b83f26ac49a29c3e835caee03469e93c11e5f4b8470eb02b52290bb2c37f06afb0746630803fb", + "0x94de42d8554583b24317d9ea283dad5849e2f124f659d0afa11414898ffdc4347a9c4ebe783dded21679337b58b67f4d", + "0xb76c3047eaecaf4a4e6fb6176c7f4a1d393fec3a360f4c711d6293a993aee39d5aea654fc6429c2e4d4955b12fea5c8e", + "0xa307fcef0915e3e3a27b94ddb9561e5d210a091714b73afbc0b3fa5e8140e8c3818f4914903975e8f78d0492d7784c25", + "0x95079c4a5008fb6ae0d653c00ad901a108df0b8c442a68492740eacd15048106b7c4cb5ee88bc6b1dc089987935bdba1", + "0xb65a354aa8e92d6ca2e11f4ed3c1ed011852bab8f0e5b8157a10c26db2748be688512423c11d582b3dc1da57b9d6a826", + "0xa32c2fc62c38eb19dea24b545d2537dfe596423f8ae530e562ba7eaac34139fb443d88f18f39d65d36a65ed1277973ef", + "0x81b83b37927e9a6a7c34cfe587dc9cfbd560db3ac57a8a88161fe4ae9a7c66843d32f6f568c927e2ff8f21d8b4299475", + "0x8b6993ef73c2021842060ec0424464412242aeb711da2c43d3985f9d15e4d936eb7a1b5098bfe892fcd3b6ba8bf42369", + "0x965535b46a18f94a1203fafa4dee5963742511ab77e98e471e03376847850357d543dc6ef2dbb765cbc1f03f66ebbc14", + "0xa9386ef496b4f96bd591847baf6dcf8520f7cb5aaf1713025ee894b40b10f243aef06c553376663488377fb8b1b0a022", + "0xa6bae4486fc16ec1f12817f2d47871c8bb61f5f1a2db5f828c6e2c06bca64b1ff7cf4c059a10d6bc2f561fc3a12aa38d", + "0xa2b6cda6a75fac16f324935cc1820bfdf013ae02c209802befecac0288d90263a7f84762dfb7c9aa1351415c03288714", + "0xaac87216619a8c50b5d54432ed5681b1cbb2c7084f33e9a91889bfbb94fd18c8071b79ebdb403ad81fea495bc1e37dcc", + "0x8bb3b3a7ceca82e4268ab52c00322d5d0822427e43c1d8b88b2f43c3dfae7100f6a29832d16454e093579cbaa1074062", + "0xa2363b4506b1464391a194412a73d47d0cd4ea1ffa541cf8b936c97a46bfeaebd1fec409c6aa2109d277bfae0ea7f0fb", + "0xb56911be2bbf1e564715191a526c2ae73bb6e85c45e3dc22bd9dd87cde620de93875c48b11e02ea66eebb68f533f353e", + "0x81609eacf4b2e78a9d7f469e0882ad24c86ad98dd18f466d321aa32a762171cfc334dcc049962ef5e63248ef48244229", + "0x866b26d3dbab7837edec84217c85653c6abaa617e0ba2657d67757fd1c7dfc0c7f83f6198fb85a49b402108d6fedeea6", + "0x9771f5796d5d47d22100c7ff7d191795677d53796f4a1e1aada949b372ec12decb6c49e28f2662e729d44f0e09eac063", + "0xa9fdfbfbe114c7f93806b988c50f8ae4e13a4d433f2e40c72b81d0ed7fe879db5e89216a0b0c8392a6d9d54f57760ecc", + "0x965336222244229fac41336464c36dac8700d5289c0aba78016db76e436289a0797af8c96d52583618f8c6dbe7b3562d", + "0x99719ac482b72d54fa515395847e9a65b733da84f7d10a0be82f34afc20159d64411aacca15041726251fd90ae06a9f4", + "0xab96b7ac88842ad0ab61f7550b7b4697d6a3b651cfa3c10ad404e7505c742e2c1364bbfd08ad0039ca3b81ffa9d6a6e5", + "0xae96088cf12f76140888582f6f6404b6f2666c048950166e37bbe46c1398fec343fcacd3e8f332f7afa222ca13fbdb87", + "0xb5b5c1ad493b2e72ce8ba698351f596cb85841f7f7055e31325cadbb4fec3e8045b335643190d6b97c3049d10551764c", + "0x85f066c7ffd2bfc4519f42f0778ce0e46195466768322a22673a073ebb66cd77c7b8b3a14157845cdb369d3f40911421", + "0x99f4f10397cb7ff47a2d9d2f29021d1ca96f0da01f8afd76f72457cba6e6376f925fcee28ce77475b90c9466042ac414", + "0x85116606b18f6e5404e9176570bf6d7a9d86116e5a29721a1b20d6b28a733886e2085a7563cbff45d1f11bf3d552ea12", + "0xa17d81b236fb138ed820d335dde2640ac3a44cccb5f11fc6bea5fe3132c4a9247b874e75fba55bdf8093f0f56310a999", + "0x8a16a5cfe10c5dbecb4fd9f4b0c370162071f88198e016111937199b87d006d1b24f3f412d853d7c6541e1c68076b70a", + "0x8cb83fd2b1afbad7c454430fb9dbf6530230b782c7dfb01443c2c16563e833c5b230f4c4268dc37a55a681a5f0bef420", + "0xb8851a8dd6a3a17619e7c84b18f29ac9680b456c03e8c8489376e6de9a22ea75d1730787ca5d269af44eeae47f87bc24", + "0xa8f990c9290456e849ae4cc0c320580fcfd50263af8945d01b00baddf801aa0a7bef2ac119d4d1b4be6290615c781656", + "0xb0fa1c28c8c67ff87427691047c362aa35de0be9b0121d83b116b23170ad2b712a0b5bdf6a57a25c59201ba165d5f0d6", + "0xafcd2f5e66a277cef775b636abb598ee9d7e3bc1b48b521da787dc561cea8d7ad963f593c3ac6f23a66a27c15876b775", + "0x92888863568ef01b40d51f467e8364cb1b09808238644bbee5ed118b392475e90c6a1e03a0ef826dff5ada8d10be716c", + "0xa8ddad388f2dc94294371d0ebbce02016c463a65bcf3a5366419a7a910d3d24748fb5716ddd81cbab44a2362ee3c077e", + "0x8b8ef4f818ca3de1683064ea7e968edc8d9fe2675b8bb2ae637a5784a20cd909d18eed45140189eb9f080c53c06376fd", + "0xa52d9c49db4819cf6280c220a6cd306a5851b771de3032f28c7f8750c20e80cbfda57323a55a8c03085b41f4f236b5ba", + "0xb01fbfa0f80ef574a1d6733899002a8672cc309e1014fec8e81ea1e96a7be9c247a570f825b7862e814e1f006a8227ac", + "0xb07e163eb0f96a51d74aa8a7fab5d23e44e37b1b1027ae9c4155280d8d159f0cdeecd3258c098a7358c5bf2fcf1eb7e2", + "0x80c4512a5bb5e8255488fed7b7e297988732473f0ccc1192cab716a88d035e23cc374a937fca7da87e18048ab026d9f7", + "0xb3e343b13c1d4c98b7706edbf362eab12b1fa87510d5cf168e510844b24c8a9624f1e7e0babf455c6d425741c23e1ca6", + "0x83e4b53953ef683c512756b3fea37756b3c562c88a15cddd902eeecf0de82d0345fb05feeba511e8a6de91aa1f722ef7", + "0x922512dd5ce444df62fded2c53a73385570804e7305cde401116c06dff5ec7812b776b8cccdfdafe422f1ba53b2b56f5", + "0x8d1f7feee880abfe9f09708ccf72f376013b2910886edcceb76018759b88b95cab9c0e8f176faf042729b405a10242f5", + "0xabb7cd087d0cea2cdbb47cdf9be2c6a0c6ec113e1ad5fac083f66a027697d477ec69f46b9aff40c239ad9959b9854e11", + "0xb10592443daa8708f8c882da795da07465efb9829305170bc3bdd781cb6651b503d3b21eca027486d413f1748f40f068", + "0xb14dcb895ab22335373d2b736628c1ed0e815072fd3844867ae24638aec60f8591c6885869ad0bfe509fa3fa3101a5f0", + "0x89631708996651bba6b2113626a2fe1ef0f2ea2f21857b2a1e5544ad31e8a53e755b6d611546ebbba4b2213acde65e72", + "0x82e9436700fcc5b842ac2f0482de4248ec9d1f206db3dd36917c00c7749bda257fedaec513d8a9ef3765057bf5aff25e", + "0xb1c2b26d93658451fb4e9cfcd77209dbfea909b2212c000fcc576ef29b808061c9f58827682cfa09e357c1722c3215b1", + "0x8be32f59768777a785d8b257f941215f37db8912183aef4a39a856b88cc680ae7124789c58cb3c6c6f06a951dc96a1ce", + "0x8cb60a3d0c9a1efb89f89f78e6f0e4bcf5eabeae6cb215e98cd7f9eb58699ed70dabed73a8b95daf32a5e4bf0d411d3f", + "0x8ec7156d6b672e631ebd88467f40caa9ba5411ab727602f3146b468bc00ae54fe44b3228572670215a0dbd59feb66e2d", + "0x97b7162101d740aedc894bd5f74b8cfa7ca7e7fe8363b05491c15e8cd54f21b0b09eb41f756b9089c379ea0ab189c468", + "0x8524c9de6be47cb6808df761ed03c505932ba715e757dfb3c97b6deb462433d98953ee6cbc7a576b6837e68eb16d3188", + "0xb024c8fc3fa4f602ab73448418548d9896200065a95e8a001f6c8d4cc3f53f18ec8b85524377fd93e2d2a18eb4c48b57", + "0xb344dc93d3057465592460b7f35dc015f4f8025fbcb44a645dcc3dfb37044d5681d8abd81bd544272dc57cd50048f29a", + "0xa7b270b94d9870f8afec3bf2ed58afb76f4ea576a2175502630d0d3f92f9152c1ab0c019f175f566eed29713dd97712d", + "0xb86dd953c40d4f5574bc7489323d71e9798f7c6f2dff8d41f6295655c5a275179ffb4bb8d2408b88226c98583a7c26b1", + "0xb73074289a5b08aa695de03ce2f5b106107c6cf2bee8061e3195056e799b0bd8b4172deff7f413ce8e477391ee6294cd", + "0x98b801a58ac7e083da541ba058c64b00ba709d4d0ba1683e5d83dfb80a29272fc2a33a18f32351b103b227abd5123da1", + "0xa7cf232c6ec6b9dfb32d729b9d4216688f6d2b6e68053ddfb293ebd5774218c69133baaccec7ba3da9b221af619c2ed1", + "0x8cc1d33ffedcea05f3c593e5b63dbfebdf26d05a5719cbf642997be929336b92457fd9df0d6be6c063918ada8fa2d322", + "0x8d273497dd9f822984f1d8dffd471cc703d03c342f022b2bb24492209a3889f010c4f7ec124f9fb9f884a1a11f84a414", + "0xb62cd013944d8d9d72fbe54897a94e804c93eb84a24beb0880cd98fd5d48fccf5dedf5076abcb1b857adcc986b729cb1", + "0xa1bc703a67ee709f7776b2871f2a88d8574c9e2910690c9242c162ad926ef2263d5260f5c19015ddd5ee1c8ad1a444ae", + "0x87de434e8ab5b1d067188cb9c12ed936c26ddb0ee76c4c9cee9bd1ea916e411a354bfab2ce77ed8c8ab5d8c62038f933", + "0xab128e9de30bad31dc2eaad851da1e39741ea61bd203b48e5671e37f7b4e3db86687574d3cea1f561bbea84f68cd17c2", + "0xb54576c9c4bc3b43270b83b89eb75cb7e89057c99e14021ca42237dce393dc6a8614c5af5c2f69160001b2ecbb407c9f", + "0x93adf38f161ea886f41e4af8e42c69c53a51074db9ecd7b7e4e36c858426237167aa49b79737625c9f9826dfd22f39ed", + "0xa6907c8dc4073d3d4d40df8302c1637c15f9197aad8511dc95c210f6a60b06f3aab2622b826d16596af27e42f2c9d5b2", + "0xa8b0c4a3a5d3dd5b6a85802039f48fc80350f6f0be2e55bdf75e3197a22f6547ff4a7dce38ef3667006128141364625b", + "0x8a5f4c17c729509309b2ac7e0dbadfbf0baabbcfb1fab02f91d055238faa3b66aae850ac9b8d7b7245f0a26bc5253c99", + "0x8bfc5d594700287da2a85a78630c616af8e555cbd7864ea604ba38eb75742fabf6aca12ed99a2439e2e046d8f048a29d", + "0xb0f91b7546613341cd95ea112e04b0963fbf7795f118c393fbdc37e37dc25244d10d987c13d6fa6eff3c4721fd0a328c", + "0xa70b6fdc66ce4c2e7f1d830b7765b7f0640ceb7306cc85778488964cbcc336ac378b74b9c4ec27358f27378380b3dec1", + "0x87387cd6b643721aac8e1a8533c27602d9632168d3a3532059163dc5e4613838bb4f07803e6852b23c58f7103d134f92", + "0x888722a5a56f5b6b00daba53991ab6fccc32a029a7f1748f779b57732285e56e09ecdb7d4848abb3dbf3e167cf8033c7", + "0xb7f5b9ffa8ba66f54cac387c197058eb9025cb3761550c78429db95f9e1e3b49c208ce86b6126c162a62939e1080895a", + "0xa53f38c068233b584211157c66d9d2452c811bcd340d8cfafd32b070c326169306975e558745d63e1617f4b4528a2399", + "0xb1c3e9b0f19993f973f038bc45be6a834b1cd3d56f112c857711c8e6c30303eeb0b205bd5dfe75e46b1f4d4bbb68fabb", + "0xa81fc28620e640ccb57dedd40c79b73b0c51565dc61097527b2341bbaa3e1c9ccf20f9d8da1c16704e881b24df0b7335", + "0x910a7f4960a0ec2aae66cbe2ac98f43646b017de84ef3d486c19b7809aa16813400bc2dccfc80e09c63422a9d4d88f56", + "0xa463868e3a8c2d2a7c49850be2740e01c7892c83063d381f405282b4c521cb6e3317361abaa92042c38bb68695c10bb9", + "0x991957100ea0f66cd4ebd23d9f6bc7aa62220f6ecb71ac947cbffc6f36f7891173670977bc58a6f57b9a1e8766100c2c", + "0x961dcbd2e6cb94574a33fd48b5d87e0623411574666d5d37f4ff7dc587980e2644cf056e002746088c3c3b0ee7044510", + "0xa27cdb374cdbff217370015d78c7f5c4674ec9948339475cc80a5805979a4c6a2614b6904f943374e96bb838549ea517", + "0xa567bd4a59f9df9f5f30a70cd9f6cea7dc0e19b7fca37fef5846aeb1697dcf7925a4735367be0828f2ded5007f711f03", + "0x823937a900e3b8705b657d40470357d91eeb339324f0fed58695ad72dda7c64f2a6b7bb7ae4a20cd1b2016cb9edbdd1a", + "0xb07f2248802ba7dce15b2698a60a4896323d37ecae6666a71cdf85878094bbd4e9c0e4733bd8bc6e9c850e57727e1d86", + "0xadfcdea69c5608f02630db045e5679f9f0768fbfa9c8e97bc9cf9cafe1f747d3813e7bb1adc6085cd57102afd71db133", + "0x908153d3eb2eb2b93c15aa606531b08981bcfc8b76684c2483bf869f335f9d8773a9aa3986ee54d9392856daaf82b684", + "0x8fbb2acf533e7d6e96e9b68e77f7a1df2ea6c652cd8862b946c93c084436d7349ef4a0c453197a9769e986322e9174b5", + "0xb83cf4ddee6140c9df0a08a39bfda79c0d55516fd799c1c24b59397b87a33ea5a0885b2998dadc354cb6f65a4bd946a5", + "0x957a52cb24f19106d80d4115a8a0843d047d157c4a8535775593c1dba9be24318dd434bf43a82aa7755897f895d2ed15", + "0xad93dbc2c055f9d7e42717391cfae64962a78bddbb9fd102a05cea520654d4a9cb6634234d3a188693c87c5b4c78959e", + "0x8dc4b8e49de9b05c33d2a98973e223c01ed5745eeaada3a4c0e474cc22430644a53a60c3d6efb1212ca298c4331763f7", + "0x948b0172df27db83e70fbfdc896ed82696876ac4c51842d270d9ce1e7f1fcc9487d781eab97f40074861401b809dd7a0", + "0xace190f75cc102a79412fceebc013bda8cf329798db4b4dba658e63228ca7f141bf0849d30139ffdededf98986f3066e", + "0x8f968dd6d7e06008a1374743b965a6204c11a610ad92705e8dbe6df3c58baf36b47c5d9988e4a417c80ffd5e7725da7f", + "0xb8ba0d5b36cc41f6839543d43166a08bf512f7b56040891ab80efefc774db28c833ecd444a703c75547fa1404fa1ec22", + "0xa29944dd0e5c861eb37c744c429a0dce596cdb2e5b0b2d2438a259a0faaf3d261faee1434bd28ebb2e6adab59ff3951d", + "0x85c70422fde0ac6e7a0574512eff2a19df8049757bf78b5a7d7870848626850f17e8b0a5661e5292f3df0f613886306e", + "0xa5ff5c3ca2c70b88d15633f9c38d2e065bcfb0e447adca33301a0d4f05b761049c8f795444f11e39357fe6bc0d7f1880", + "0xa2167cdb114d7707f1010e0be9cad488fe56cef65941c35a5878a100adbe522a8abdf7eab7bc689b8727fafb174032c2", + "0xad3f526ef9ed367b2a25c95453135510472581a758760d47eb9f9b57b04f8c061152e5a792584d6ca7124dfeb7e21703", + "0x86443033ece13fd386485115765aa95673be72b0543fac2138e1488d22419591176423213ec06e5e4549a025eb6aafd8", + "0x887e4ccd58603e6c9cc99bd2740bb1db2fc4127e8d3ec9cf41bcfa3589b0fe1931ed2a6140ae1199d323d2870882ef6b", + "0xb701f7d7637662ea7024d31e94245a5f745c7ca889f4f7a8362537df82b0164eae83da5a107a21c0ca889926aa50de49", + "0xab6bc11d6049cc5945011d3973eb2dbd5a3d786b3824bc125786e734887254a6ed61fdc2a97ea34e6b37b13cd97eb781", + "0x9901a1f44122bf5aec7cea28e9405c33567eb118752edc60f3cf6c80642370f86557cbd76478d6b0ea33be92a22c746f", + "0xb9f453650996f14629642bef8fea66c90105c8523f3875d86694100f8022d4fff2915ac9f9b9efd6f425751b113d5623", + "0xa5bf9385a1c94c09ec326c49b6b603f2de987b2878faf0263ed109410536543095c07320f762fb6fe56ee72a082daed6", + "0xab003c86dd62c801cb16b727fbd1037aeacbec0f76e8abda4c6d87066cf0a33dc1c61721f2134c3b78975efe013cddb7", + "0x8dd8c580c288168f896fd7ffbcf5c8167a55d34f17b2c362d0ada0f33a08cc0568b37b01cf0cef1fd5e2c2e250fcdf7b", + "0xacfe675aca83a774d3f526ad461f0deeebfc73a15ab3d37b224f8740ac2d9df238373e6cd1f03ca78a9daa0a796c96f0", + "0xa45cf3242600fb9733dd5e0dda1994e8d37fc483885a34a76cc16bd245f6d9c8d15bef360ef59d0a2c3cd59114280b87", + "0xb64097145d97cdc8b7a84edd1da7e84f8aa44c3c2a4823e6e8485fc3a44d94cde7d7ce8bfb3da5d583386461ccb42afe", + "0xa10ec5859c274c0972ec39ac80e461c29995b35d03603dc97dc30ff826ef24c5e52d5dc9296319ffc672b9e1d57d7936", + "0x9702ee805b70a1bfac7318e8470667ee20739e3db3030bbcb9a08568e96c9c8d2af2cbeb26837c43e04997457c623486", + "0xacb3f5a663333d1b4d54dd76a23c6601fd4540e2b050ec2a7fbf0b850b6f592837155e6bee5ca942406643f98bb2ca83", + "0xa577b96723f64d2671f1253fca72df86ef3247006c92cedcfb26eba4b4f4ba71bfffe1d5eb87b0192378d0303177fdba", + "0x8c397ac56cb723df015d0ef202fe486d1acb42f8129d3e4b37125a7ff9e81aefb1e19f477d528be1e6b18e7bced27ba3", + "0xa7a6e6994324a80ee0a85e8e8cf818f5f8d16d299f21b2fca8a9f65231982584afe921e76723701abea873275ce0c15f", + "0x82c8ee7a39e49528efa60ce1cbcb3017904de6beaeb751c406b64a94aa73af72932e32b63c1d3fa22619498fc46de6bf", + "0xa1d0193ac8bdd44ffcd37092a5dcf6e775824e5dee4c0aea5bd46f2e25b312fe58e1e6b9dccf9dd14f240d7ced4fe071", + "0x82c48967f22b8aa1dc63dbda0f66ff2f40f3ca9a7b3e752e1a950dd7daadf9afd81ae1fe3d0e440259dccbc1520d4e22", + "0xa69d43e6f962b728d223f6d474a923dd13c04eb8858f7fdd2df2c25dd4d13a0a69e71132f450613e8e2d9a65938f31f5", + "0xa613b731fe0d23ebf376cb1f3707ab9b2d428d1ea3a95faca9988a1ff4fcbde0a077b38b5942590e594307acf88c9db8", + "0xa7d2f249ec666f59dc51f9c31db6168f33a94b17ab95123d4b19aa00dbe9e1cdf340dc6f64bffc6dabb11912e10edbba", + "0x8e64b8f99ada5f317c6e2fd64ac17c4d6e5314c82848efe1eb97a5a52e6bf08923360dcb44c05d3fa59a82119610a898", + "0x865d9512ec4a18ab31e4062b2ea6c43ef32c7c58d89bb0afdad9fe57dadaddd2150f78a0e85086454812855bf09f31ef", + "0xb2d23f01a0d182abcd6862ab6f4bf924ccaac399ec143fe2614908dddec102e2feb8555479bfb71ec3476cbdd71b1137", + "0xb50d176e628e06258b518be78c6dcbc3c9b2b4a1ed4ba10ee822b3ebfeaedc4fa69c61c1985e1bb20ea9f3d6df7a27e5", + "0x8174953f4023e31e39f1cc3bad674bf2f1605ec9fc053948bb60dbf2cabade885376f8c76f45b638c95fdb14f5bc562c", + "0x92b95a12d1fb1ec489943b3a2a1c8e3c8c6a30d0767125b87fb491f9d4f8de0629afa39fb5c8a84078b08bcc26e88c4c", + "0x93f4b80d76689d5936aff6cf195d579ff5328ccd0f04db42522a225f96b0bde2088706356675f185186548006940898e", + "0xa5f7f4577943741def19df611c2ad3d459c386a5e3c765eaa5a0cb6c192873675cccbe62845418dbe47d7a9822e4038b", + "0xb59bdb196d59928326572807b2ff2edfc93a28632542b270ed462567d32bc36cefc40300619aafe4cd1e91c38d6c9c30", + "0x90df4b921e13ca1e63e8a5c9968ff64bbcc5b829e3421d74bf7f678aa1dccc1db9ed9dfe5aff05539bcc5379dd59e575", + "0x837b0b6813249c456631b2f2fea9402a2303a454a114149bc35efb400813397366eabeb4477f2cfe037f722d78a5849a", + "0xab5b33ae561312d9791bcafc8faf6d65f2c4260f126f11ab5c20c7626d88f2c00177588ec62ca763a7ca44c6ed60eb0f", + "0xb0ed2e48cf650a4267c3da1378b8164cf6b774200a5898155716f85f7abda093a60b802ce549811644e5f075d2b26067", + "0x8d47a4e27f448773fa2d592f052bbdbdf30cbef152db6d8cbeb3d7b1a0dc0f2c820ed7572eacddcb51c19a8268426b33", + "0xa56ccd0961bf238ccd197e5bbf430d7c637ff6e01590febab3529776403682ee32d0a776c3dbc6581f60002dac86c38a", + "0x9163bbdbf468be88a391698ab1f40a919517beb6c780062d4bab3bf8fd42eed6546a8c743e249fd61c3c347ea60ee185", + "0x8d59f46606f063e68198457917004ae50ebb99cccb07755825782ddb25b96c3cf8973a6c5092c9db71a4b8ed075876af", + "0x8ebffeae4fef7a83d81f31a88589e05f885dd0c0b4360545b22a18369a3e6762f187ea6a173f25419e70031861936463", + "0x96013c6b47119e017c8bf473b3d643d0bea1cc12d84d412c2b9f6f55f22543a6e15ff7e818e9799af43984ca2ec3bfb3", + "0xaf46ef7696d9908fb343a6754de37e31cbb41dc1a4ab8203d2a2483d1cb0dd3183e5015d8048ff146ec34a6c3f2eae21", + "0xae047ec4584a962a7ae9359292c98f4d8e0916dd98a414e2e15429ff30ffadb3e0296282f0f7e257495e8ec4bc0e5328", + "0xa16de787896a056d31e3f174418aa3882c03c879a292246a43dafb81f8e0e05564f1cd3ecfa251cdb159f63777fc6346", + "0x97d1c4a94182ada88aa3cac95520711802cd3889e3e057e99a72a69589fd222b241d35a54b04f42503756ec3c1a3d701", + "0x86be4ebe8b92f5bfceba757e1e2eb649f9803c8cb10130b88b13caab6bc04dac4e26d538b7adef68413b047ab9031252", + "0x95d4c0b08caa283ffa9e307f78db15470fca5b577189a33bcdf14c36d4ae3f571d004c5aa1e69172a4068e72b7dc25d3", + "0x965b7053a1d14f9091de5df8bf033a07b9f8d39a6d66979ab5424bbfa32b803075afc2d74e71235a0f881bacb6704689", + "0xa93e72836e2efc704f87065dac0463ddd4b063eab125d834df583d8833873f575a0179781b72aeb2a35533a34a395481", + "0xa2997d7c377060d910654550316ea7374a0329fcf30e743d613e2ebaa15b1bc6c936c2529f5466ef0e60ff53aa2b709f", + "0xaf5259d4d08617d9be068d1b79a8209497972910938831a435487395512187691d0cb021bd57eff0f694f32efc1487ab", + "0xa78b8318838b1049f308200782c4409fc6c97ca5bb6af28996eb191027c8935b7a43a41961ec046e6c8539376c1aa293", + "0xa4a6a9ec652d1c95883d21d3767b13a7e1dee73be907dacad197cfee025755db3cc7a8fb9f40146912f8a3f4c2c49c14", + "0xa8a8ab62334a3c67793fa0691a0d2e80ac1681ce64a02df93b78e4a2f6fbf3af9b160d9ca6b4e835d58ed60d8ce627d1", + "0x980c32e492464a6f36ce12ed06541e3b2eb098934c0ebccdcc984cdbfee4a506d15afe1a30a84d642322c2987d9d51a6", + "0x8ea8c1adfd73747db98705e9fe1aec441484d2e4862b84817cdf1262fcce91f56cd26073d4dd23b04f836e0962428593", + "0xb0f20edb8552d2b08613cb574e9de1c4dce1eae55ba9ab05dd7f2ca3590a7496d63d55af88b3dff881e16d8bf9147037", + "0x915af4e9a28b12ea126668db7de6ff0c2cc9935b138022fadbb1f385f327fdc927388c945b93d252cb51803c242f7e1f", + "0xa553e08f67c61ecc5c8955f7251cfe18cde02e6170845e70db1761bc00f42a31cc10de26d4c904200166311f32a3e56a", + "0x99f4b066a805512e16addb0bcb08d76f017213ca6aa6afb5c2fc621805c4e123bbe0aa85eb5a0f89d3112635905093e0", + "0x9236c5b0f4d2e58033735d7bd5d53ccbe82c05aa290149286a16a318043ffedfdca9d2d07817601d4216fed50c1082f0", + "0x90a4c7898c58c9af83f94095f6afd5ca65664f16c0af4c8121407cf0864fdeb09958500b2bd0b78950aa9051e3480928", + "0xa589666688e6e7f8e4d99b84d21a1f9ebfe681fad346a237de20a11a2b210eb99c4d3e2f645b23a85c93bcccd51f63f8", + "0xa010849ed4df0e3a8eb61f7fd114d05a8669bfa36cb95d089bb1964ea8f5fa26be0cd10fcd9b38b259722c5a14ba3a1f", + "0xb21f974a10a2dfe9987370ef4b6af294cbe8f4bbe35ce9400d0538c5f71287498054d73606e26f93e2f19584aa18e285", + "0x81fea77bad05c3bfa8d5d8409b189fd5c759613cd69ddb19b2d46673d4df944b2c7293989f79580d229d20959c74b18f", + "0xac962b0819a03d2a2fa42c492f54c3d293c6d5ead403c50f7a1ccc2faad58beeb0dfe888a928e505fea9e09807e13a23", + "0xb78b913f2ad9622d20c175ed23f80f235b5336343b0353f82383fa6aab99aef77cb489df822bb168e56496c1854f623d", + "0x8c06abf72913ffcb6b59bb8201c00034b447011880733aa6b563acc423e90bdae19f2a7a286943b55488fc863d09269c", + "0xb34168972fcd90c78286bfc6078ce559e3c216d8d1885ecd5044bf9f23a4ad15bfc9830aabb4273472c43e2980048586", + "0x88350e0ffe9b5576dd0afabc6d8445d25b2b9a0945c71e6b9a5587649ac5d95cbd722db5ea1e65d3fb8230c794fda5fc", + "0xa3bec1fc362a33f38795158f1b869e9ee857a7f2e1acb92c6a7dcfffa64443a5b7f6dffb656452e7f855051ae849be3e", + "0xa21f64c49334720883e1243a27575648f53637a644c308ff24f5c26bfe65cc690a5e46b8e432171f31c4229aff4db416", + "0x85dcd8ebef8f7f44372912b4a3a0dfe66a56f16c3757a8ec01b71aa81eeda9f8e5082f92e3ae8cbf3c1eddf5e6ffed03", + "0xaf3c1a770f34f2acc504f38ffa7a18cc4b38f8f84f310cdf2d7346b18824ebc7c7663cc0e00b44cfb5494fe6081aff84", + "0xa5dc7c5989fb5cea87c2d878d8436d858458171b667ab5200dc2cafd8af2d9c2bfe2515b0c002cdc9c3e61e4cfe4b444", + "0xb136dcd4577ef3a3a8bc946cf2ec79d3fab301114ee2a692a6c219e252c9128db63fedebc6bd6695a8ae58e7d28501e8", + "0x91d3a1ba625632d59dc963ed54c0310d0447df3e1d9151299722d10f8b26161bb73e0020d408b748fa6fd1db51adabd3", + "0xb89f1a2497b04b3f1b018dc88b52133e1d7470f97f846965fbc934d34dbc8d38f2d8b07d218e62c609de33b61831cc9c", + "0x92fec43fc5af23fda5dfab78234f5ea7813d8de34f8ec269c5fa35dd916b9143ff0033d35e7a284c0ef4f41047e98fe4", + "0x8a0b89cd35ecf5b6db26c39705b416a4b950aafaf3b00a9d75f864955e9074aac03826ff9393456871107563eacc024a", + "0xb04db63ebce71161fd42bb878e89155bc9e887329e164481077c6a1db092477370a362810d291444f5463437e0ec5906", + "0x88ecd5275592f8b133928770e2273a0e0c23424d72b9e505130b0599ba28d1c11eceb2318a49dee054a8ba0971874357", + "0x8eb0271197fb9f1eeedaadd8eb603b8753ada11abf04ce90950034f51f756ed6ec6a6182a47e1f3ae51e3a1f3ecdf467", + "0x81cc996bc6b12ac56a1ae3add4483ae4f2e2284e9d304f5fa1723231d0e5b196813b6dbbc20b70f5d51fcbb65bf284bd", + "0x8e1d94ecca2928c4c68fbc13199b6281f8782c75c119b763e0eb122f81c35f8fd079d1bd76b498393371a08dac95dd1d", + "0xa92f98bc09f8a91fd165bb8d05e3b5ec50121d760b353d7e4ea23c0e04ff29614ad9028a4a16bdfe323f2af647e515ce", + "0x82e8dc99a14da065200699e458150dc6d49ec0e098bbd91ab8f1fc1767e8732f53855499c8f24da7b9dd681100633be0", + "0xa67b6cb4eeab4fe5f4ebdf5649b7d61bf5fbf7b6cd2d357fdf348ba32dbfa9d6830b1265ea76a1c666b266e30d119182", + "0xa64e3af1d0e600bde18d7f53a4e8d89d296eab4bcd9cc3a9f476c5b8425e6e8082066948fbf40689f626e27e4830edfd", + "0x8f66b59782cbccdb31cb1bb2d6385307633ba4db31c375c0a8424a497b2fdf309e7ec1c95490324b9a909bb43041998d", + "0xb93f4817eb1d91ac78eb650c110f7c29df40df47ed1d5d3209c3abe5cf59a5e7aee3d1cd232bcce77e157b1a9daa2557", + "0x864b6cd72029640fc041fd3efa71bb210edb40589a26981724b944192c3c2543352b4b757836a7b0b13bf830f22b8374", + "0x9064a0ac94f2f133e287b796363f6d27e9646a8b531cd9ac0eb45b99fa73f327238161a43f7c4fc914036d69abd1473f", + "0xa40e60d4aaf9f50f7bfebd0e714fcfeba64e0f7ccaa0f4829144a7efeaf15a7cda2d62d771a76f98a45cda9196b0522b" + ], + "setup_G2": [ + "0x93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8", + "0x99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d", + "0x88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659", + "0xa2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3", + "0xaf565445d2ad54c83a75c40e8895f5ad7219a8c728bce9d58d7a83716e095432993ebbd3f6911c66415a6f920d1a4d171478509b54a114308a020b33bf4487a7a8d0aa76ae4676a9b54e765a680f562d3a4fcb2e92c58b14b49b5b2917cc258f", + "0x8aa99cfaf514cef4801599cadd780d222194ca1ad69a34779c2bcfda93e5dbeb931e13914421b5809a6c81f12cf7038b04a35257cc9e94c33761e68565b1274aa6a6f9d66477229747a66b308b138f92aa4326a3bf23df65a1fe33b3b289bfe1", + "0x99ba36d8b4f56bde026099278548b1afc0a987cbd7c9baa51fc8e6cbb8237a17636f1a44a385cec69b05a5802059956a11fe793cabb939c38800f9c239ca2518e898ade1ec2513c9ee492071a35aabd78182392a09123d28dbc233313c9120c4", + "0xa7dc40c36afccb30a2eaff250860b28b227c195cf05674704c567d77d6655c446ae835f8fc8667e71147ab02afcb2dad0babe60cbfa37d7c2cddc68d2dec54f28a4142f8353590a3902d5ddaa22066ab563dd1435dda83f276387b9767d69120", + "0x939e6cc97a8b88572852a5b7f25e4838556307f60aeafb5d2b6961edbcafd4b48cb6ac980ffbacf4be963f324ba81e3d12de4f1459d8c746d0762c66ae1b166027f7fbe641d9c48f3c7d97b06d956b0be51dcc9aab65f3e99e1388e63bdd79f9", + "0xb391e156541dfd4003d1697cdb7ec815b309807320574906b2e652ef0175828b356d215cd374b1b34d9f470b3fa0e643113e67b2273268f922f04f072cfb89008358185b25cd631f82911a3f20f90f75758ffb99bebb8076458ae1e9d1ae898c", + "0xb9ac9c84934cc2a85c876eff65577e1dfce1935cd6392c877dd881a7d2f5c3e9344f28c04f90c62a6db4237ca00f9e0d00cb5f63e3f060fc7303916e19273b6fe455f331cabbe2fe5a22d584484f0d4176120fec9819fbb0a01e6d38695acfcd", + "0x88209eb030c5d78734bf2c2a5c539653fd3c24b4c08e624f9ddc4a6550efbdc1054a56eb0c807595aad6de56fda326aa196d032a8b4b48d40140a2d77df3c7243eda6507936389a321a5811eb38e32ee433c788deeae1eb928b00940e2944bcc", + "0xa8632ddc9cf7cbc1e8b74a05b7d4a89618c64afe30367ca0c9550ae7d320bf4e51c5a69e1501a1d8bee4240d13d7835501aa39fdc401a74f4d5734e268a7ce29a1fcfdb0a8bc64e0dd4a9e8578d6985bc2bc6a3764ce7a3703f6fb2e52557a2b", + "0xa037ac67e8bb6f4193ac967e05d080a489f58ef8d3d30a89798246f3e4936121ee445b03e410a09e8ebc0db2e2477d110aad0ade99b0887f1eb016e750f42135866907f150bd6f4f99a8cb94281474166874808ebe03b118c5daab16dafdc38b", + "0xa50d9143116bffa3b237da8e1805327e81e9cd25e658289bd727d5f9e0020172cc8690dcfe31a240e5cbc48353b88c4908baa1dd7320165556e0aa633f62fcbe7870222d345a3bbcdb7ab6c07f0fd86be559964afabf56f0a8cbc0b4b91d477e", + "0xafa988ea6fa4f40c5ad07d2d580d29025ddf56d6ef1171a8b8de3464203f70b97d6f5ace72747345204b35150e06154d1477516a989ce8eea7871cc0d0de00a077c0fb23ad4837e409d0b885bf3f2dde11a30fa6273d662e68e09f461e52932f", + "0x97fa1a943ed8b81574304a3d03f4f15907f6e6e0cd36a66bd2ad2c75afafc70a61d3ff69b77ebe4dae9ca0fcedef80081062705e60bbb6ea0f1f398c84d2f8e4a3ac142ac66426c21ad5e9994ebbcc406af474c4aec5e32fadcb21875af7c9f1", + "0xb30a564614493886f14a5dd71c89457504f8c59a7ac01b665ed167e9a8f9ee5832198fd319ecd234196ee57031bdf3840bd5a923e203a1938bc795c704b5285389750e1fd10d7050061ba19db00a60a2c0384a7d661d7d48ebe6962272230859", + "0x84c8dea942cfae71cb02e705ec496d967425793ce8812e7ee53c2f23713abeaff566a658cd1c73dfd18187d16253a6ee0a623e82cd18e31cd1a1875d19c078835dc9292e141686150a88065226ada264740143e87c03a0f6c4da8c187438ebf4", + "0x8c3abae8aed60338f8c4ff80aab22f8a2ae56756a93566c906f490a97151d34a1c3318054e1c494c60cc53327ad86a2d02c6c76a406726ce4f88635bc32eff0db0b61762dc518b95fa8da82e87e4bf3de54f1d72180ef53ed7bc5413e6a9a510", + "0xa328230c92a6b1cef6a444bcb64edb992f71e3d7b93f0b6b8b408ba7c908db746d92ddb2c7588bab438ef3bc61be1c2f0dfc86ba2ff514b42b35c80f89b2e780f813ea1dfb977fbded2cd9b553b747fa952e227ebd8f071163d421fc337f04c9", + "0xb482cab423cd5f1c5df036070aade7aa016283d69619d664025c3feab866a0a5691d344b2ee2bedc5dedd1f9a73eae16003a3827c9e5bbe22ded32d848fba840ffad1141ad158f5c40bc8ae0d03781b9705d851a7f1391b096c576c0f4f2a6b0", + "0x919ee1df27fabcb21237a1b7b98f53d41d849e1b6a8f9e28c3fae2841c6b5a250e4041c737e6725476e5cd715e34d3880f58d80f61efaabc261bdc703e8750f48a923e9bf8980931b9fd9e40014c66c54b3e7c98241d76d1aa47af43313a65a1", + "0xac94830145dbe9a8f7e6e0fc1f5fb454502d22abcafdc2dd96c6933c604461fa83b2b37385f4bc454875a02a6d4157841250956783515d11c7456e7f11b745f12856d89f5feedaf6a61a483a6c33a21cd2ba0c18eb41a1a2e7fc33bb53e4c570", + "0xb209c699f1233735c5bb4bce848e4365fd76651ae2184d2279a90df0c2f69ffa2a24d84a9b9f274021072953c0d65e1a0202d490d6c37186af240114e445d87bff754b4824937e4f2c90a574061b1c4910fed88d90f698025a2a264e656cb8a4", + "0x93320dc0576b0d069de63c40e5582b4486d9adf5e69e77e3ebaf3da26976fe42147a65051501bc8383f99e7ba75479c70a6726c2cd08bf98c7481f1f819712292d833a879f21a1221a9610bc748fb5e911055122fdb4055cdc84e8bfe0f4df9b", + "0xa4380b240e998cdf668591f71a0c88ed143b0185a920787627ce65095f8223dc606fa5bce93377af100de92d663e675c0736d7f1973603a84a5c4162fb5e01c88c7493503ae1d7e9fbe8ece9b418397d68c21eeb88dae226e09875d372c646dd", + "0xaab48517d69135a16b36b685adfe9b2544a709135a21ba3e75981a2cba4ec81d1fe28ac0f72fde0c0001c15300ed6a810f58d3117bdd58d0149751d6508cf8a1a1ff7b63dd02d2730a9d6fe96c77c502fe8ed46d50a181ec4bb35e37dfbd6af4", + "0x8277265fe75ab89ce4ec65b33fb4084bec0a56d81faf2f7a9070d2ca3065678e03a790350eba56323a54e0285bc32fe8007d5259740fde226e16cbde8354eacd562294eb9b7f727ed72ffbdad86f467cf057c737b34b80a41deb92634ed866f5", + "0xaa40a24cb2ebe606d969392c03020070f044c95088d80f57f771b837c048342d2cd3474600d7660441090ffb8d2ffb7f0eddd67eb378e3e1477a6ba0bc38096d5d2d3355bc8b60f605f57f0c1899da591457440352381d2b38c0aa9acc7fe419", + "0x80815d10685808cb630820629bcd2fa9041c9b74433630c0b9c1b7f7e8edf1440b520217f76ec9a50c125cf4438aa66006a1928a9ed2321da7ea325c3d56b65462b72118ca2c99a0ea733aa11da9abbeda6cc71ffeed301ae70213a29e697dcd", + "0xac235d079f91b00b1fead7523da8f73a5409fa8970907af0c5d5e4c6a0996dccfcdb0d822d08c7fbc0c24799457d011d04312d20831825f23cf988141056a6814c8a1cac9efe37bdcbfa272aed24cd92810fea7c49b0d07683a5c53643872179", + "0xb8aa59534d75fa5ac1c2c3f963bf73899aff5210059dbde8a8635561c6249e5143affee3bd2fd57575213b52d9a73d5702525867a7dcbb1d0a49b98c2925556fc5463ff0209742046a24ab29e74257d6419401093cc4371944d811cc300b6a67", + "0x80bbfc5b816eea29a6d84e2217dee4d547306994d39e5592515e1b0807b67fe960d1d5addb0ff1a20c158bdb294c04bf093d28996121845a2c9268e2c9ac0f4067e889c6aaca62f8535d35b45036954bd069e3afa84f04721538c26003304c20", + "0xa535c17d0e151d0e03d42dd58ba8c715bee3fabca2890e0e016071d34184b6b34e770d2be29c8ec76b69bcc471d50f4d043c2c240e9b93a81cff7ee2724e02018dfd9b534e40be641fdb4884abcd83b76f517557ffba508f1ba2f56313f4de94", + "0xb237eb7465df0d325a3aa58269be2627e4978f9863f4f100ed4c303cb1f6549e606f2e3c9180824d8049191965c8dacd0a0c76cc56cb22cf1bcfdb39372c8aa29b4f7b34582b1719e6bd59c930d87d5ccd838743b585d6e229d5ed42337315c0", + "0x805c335a2a9d2de30809cf30808ef836d88e9453c510716f01696f14c72dd60505eca8f128970edc8e63a9aa1f8792ac0dd50dcc84fbf4cc8b32349c682a6a27bc7551c7aa273a94c1606d07710188d93579afe3be1781bded15a34ed6047922", + "0xb25dadf385ddd3c39bcb0a014d3d4f66127946b1aceae8809e3a03d66cc25e27142ca108316391f857fe82fdea4db2520cc73793b695eafbf3ade00ef7ec747b0457e49303f5e1a370f5263b436566fe24a0876e5fe088238c7be37a0718d65f", + "0xb0f753081cabe2c8fce73aba82ff67dbc9842598b3e7fa3ce2a1f534536f8ac63c532fe66552ac6b7adb28c73ed4c8a4184849be7c1756a4681ce29ebf5e1c3aa806b667ee6bd68f6397aba3215dc1caec6742f21d681e32cd1160d6a3b1d7ee", + "0xb798771eeb3d7a17c62ba5916cc034bba870da6b1ac14c2e1cae71af3ad4e0c0d1ff983f691e0e55289d5a33b131f2ec12430c9566dd71f4d8be9c79155357a5c30c5efcfd75bbe1bb6d5ada4d50604ea49ed838d3641f268ca6e25c9c4b6b72", + "0xb52554c017388b099804abbe565346591a086d9979e10140ddaccc0a3680e506db775d7cbeafde67563adf0f09f5c2420caf19629f4e8f03e6fe02e9416ecd5269989e482b90004a083967d1141387eb74865bac6bd17e7a6d5f58225e52d4b7", + "0xb520ff694520919023d44d53f98a7de2f78ff37b2d9193dcaa35556a6a0febf767781a4c961dce7c804bfdf81935f8f0082865253da52e79dfa1c5ff74d61495b2da76e167d46114709e877a7791a3a95e33a42f56b83f5f5afe271c67ae997c", + "0xb721401983440797a03d5b99f2088a0b249aa911969c34dd6c615b0060325da555d2ad99d931170c0868b0488a2234a4114cc0013d5163b833f5c45c5eb536421c016cf85788390176bb2dc4c196d6be26bbbfceae048b82f0d8039222e71c94", + "0xacd9d833ba0a8cbd8d1ba939a11ea0fa5607e1bc6e693ec318bdb097aedd042d76e695dcebebd142e2e4ac30b1905dff03ec36d9cc70577e4dbe5e9ed7c20c7afb13a7f0155f203c6b83b9f1ad3d20a0d4aef0fbbbcf466ffc1bcd482bc2f5e0", + "0x8cc1795de015f2b0e72116f169f3b4624b7738ceebea354e0bd9051c27b86f647ea36cad57ea6884c1a8adf9b45cd83514fa687e68878bbd613d793aa10986d5a0411f081689229e0d72133b3667b9f3f1a02211d0e680564eb1ea43393e1f36", + "0xaa9281c61113c343a108de1036570feefc72fb7a96ff11f73024de12b83f29631f5a8a5900e6f10b15227c6f7462881511271bf785ebdf95ce288100e5dab391f664f6ff76c72b65b34479a4f43e5e8eba292209d6654157286ad3242ac342db", + "0xaaf16866275082e59d415db317aa874267d048ee405a553e852e6d175711d31a1fee99912345915bce121f43bc3e00d81338e5fcd3c8a1012fb4f172a9fe15622dd368b4d9d5cb60d189f423b071791fe26cea7676aca8df07965cacf80b0cd0", + "0xaccc80b3d8a6ffa648487a3d3c0ce1aeeb5401edf3cf2e385ea4a6d5fc110054fcce38f01f1da7141bbed30eb7a0a6810c82212bbb9da75d6033082dbcf6bc6a5791f85aa0f045a10da5de015edbf369b4d23b32b0c058962d2ee88e6911f994", + "0x83f1089395a16077738cc7c9a6d6a3dc9033aac4abc508af5a1f007ca92e1a80b2e6f2dbda7fdcf0d5646de790a6201d0a9cfbcb6620a1426600e3a6a425ec004384f49fb9dcd166691a47177d45dcbcb761a11d46220b0aa09fc946131f7aa5", + "0x9246bb586d43cb817c2e15ed609156e9f1cd284ba2f4797bbfa51c0341e1ba382eaac059aa9f63fb88d228a1a932839a171e7c7d00199dc7c4d6c5ea038a02cbc3cc5297c70401520e70ebbcffacd6a703f62896f3c788f94dde3c33ab0ecbdb", + "0xa316cb7c74feb0563c56cc79015e2774fbeca458bf8e9fb07894f9d6bcd73f7fb9428e87c816e5629e4bf7f3ec567fbc091549471b75492dde08217cb334b716b4582b24384586e53388873a78a90ec01bd7c3bace9cfc52161467df16e27c33", + "0xade18c74bbe60d1d69f4a570f8e5fd8696c26cc9e02829040b6b14cb9c49a4b3263b5bd5e16ec0b29010b4be054c16ab09304e23442af7d7f5fcc60bc6c5634ab6e4aed7ef334b2785e4c7672d59a687278e42d310342db5e5975d716e6d1595", + "0xb7728800bb2039acf228fa3d8028569c426cb85d28b2b5820bbef938d5ca8c4df981d3e01a309e26ca101e8295d0f6990c03b8c239798323575874a4ee5bfe46cfe99b9657189142aacd8f8d1f26cf4c0e73c6397c31ba8f18102b9ea315b638", + "0x8fb14f2a9be193f54977ecd3021663108ea143627b9a9d9faff85d1a86b855f6c437eab435fad3304f245bd7732af07f1173494cdb802fb96e85d2db89e1643206e183f3b228ca8d3f586e71aa9308eaf0223100bf07942fc39e465016d1f775", + "0xac1e025e53d98fdb3380489dce82d9d4bd3a6c98f0a523b841cb09a6f26ddd4d22efd98776e78d10fd996995fd00e81e08d3c25dd14a54b25a9d483677a24bbb8d1cb41a443b2c71038e6893b1b30f70758424e0f2039a48060191389033ef55", + "0xa4c017311b9e930868132527a9849072b91db04fd36c619ae39c98da9e2174e6201d3c2ff1246c06b1b6815bbf3ea4a1116564f55ee2fe4c4d655e2294c0ded842cba209c255ca3d7b7f82d162f97890dfdeed087aa2f87cbfc61d61815da39d", + "0x89516315a3956b455843c2555248bd94dcb19993060fe75fdd51f7aa9c9147ab13997d8a98036a8f04bee5c91d78d2990907e35a52537a8ab3ed15f1a71afdcd38044a5b6e93f662b9d36c16933a881927cacae668c4c06ee6f004c9e3989bad", + "0xa1e78a011e210400c68ca76045f7da74119bff3cbe382efd2bd2ac76567c52d68d75536a91999d084043e1ce2d07d02e0b69fb99924101d2543521747536fbc51b0454aa9a4cbbec101121f597863a5c0fee2ca5eab35dff9b9085bef8b2b0d0", + "0x830fd8d083e39153ecab43cabb22e29d7b44a55fba467af4ddd3f069439d2972ef53c3518de788f96b3f4f64963987d0155ba27afc28643af3de8e476ff515a68285728167408f45d99e574680bda6bacdd4322e587e4aa99386e035c0e931ad", + "0xb89584da22237e3061d991b1a55a5e55dc637b8b671130d304587729348138ef87885180310efe9f9f6d3580b9d7fdcf0649e8a79d2dec8c25a9f53df0fac5d517db999029cbfdd7c2cbd3e9a5503e5d267d3d8ad752335915c92b850b14bafb", + "0x959b8030733799882c5e3735479924b013756e57b893f9792bab4043e2d362d77cf308166d782e3989caa771b8a0c0a01302cb7b5e8ca12e2d6cebd59d4cd173c9dc25f438bac597fab17b4ff44997a489c168e7204b7d7c21d0938f0a2e3b51", + "0xa0a9e5503d9afe0027891dab890c687fd5f5fac5741418490c64d7c15f59533dd603a50163c79402afa61bd02de486761983c94501da17e6bbe78c497f2122210071602f578adc0ebe7a4679f87fe77e09c8c122de69105f13455fea25f08e6f", + "0x9811487283ad620cd7c9b303ae2f348d0e6f5ee17b504baaa817ae207adb912a00d3cc36dbf48745eb899e6b6e22f09f0f9ba29d949ecd7350fbbfe87a8c7cdd5d0e687fc807751d07634aaf7c38baf3b24a0670c38fa6ccd7431436fc95525f", + "0x8a13aa5071c526e560def7d8583393942f07d88c9d8d26c98738fd65f57af2e3326dbb1edff0f39fe98eda4a13ed4fd71844254b954690154c4804e1c4a53df9dc4643f4b7b09d0860070f6b2318d0d63d28fb56bf5b6ff456a18dfc72fdfbbe", + "0xb9c90ff6bff5dd97d90aee27ea1c61c1afe64b054c258b097709561fe00710e9e616773fc4bdedcbf91fbd1a6cf139bf14d20db07297418694c12c6c9b801638eeb537cb3741584a686d69532e3b6c12d8a376837f712032421987f1e770c258" + ], + "setup_G1_lagrange": [ + "0x8d0c6eeadd3f8529d67246f77404a4ac2d9d7fd7d50cf103d3e6abb9003e5e36d8f322663ebced6707a7f46d97b7566d", + "0xa0d2392f030681c61c2a867862917e10f7678d882034bb89af3db87e6ab3883a304034643dc9688a04e41a5b831582bc", + "0x94298073048d70c74f36685e547d04b7311479daa05912e18ead64b2099a194bf48ec344273d58daf0b86b1d8f1d318d", + "0x85c4063d13499013dc2ccaa98c1606763e6b1e8cca20922d4cec12ecbaf006ea81ffabe6596d1ac7ba1daf7e63e30898", + "0x84c64bce36c6b5145c6880113366025ab9a8f88e3948d374e27be8b8f9f87402c70fec9b3c621a2d1d26764a84370d0c", + "0x8b206c823acf5294552ee54579fac0f45ea15bd273dbacd63b88cd7cddbcce23b56e52f8ea352e1e1d7dcd9b3991b413", + "0xb70aaa4038ba3f5ff306c647b4392d004950c53ad8f6713b5c9c21ac99f5c56cf57323dac500a1f4e9507c4746b07a2f", + "0x895f6d1fc70b52f838d81b24f4840729cd5988b649e9d6e6f6dbac4281d8818f39ebdae7e6ea139d7f98a832bd6f29f1", + "0xa71a2832bbaade974c9ef7505dfa24e1ba466a9951b7c2db56886be31c9c7b871f3ee76cb1fcc1aab4b906d6502bc9b5", + "0x9530ba64a21e27834609c00616bc63e8fc2dc7800e478ad728ec39c624f65bbc62cb48f59decb7fbf605ce1920d02622", + "0x8d0609affaf8619bb2f6c80699e5bc7783becbd5973630cdd227ae52d6d701c45f4270becca97701b40279fab588cf64", + "0x8f5d5b4c3bb8dc9a19e5a0f84df6322a79a00c7783c86254197d313a5b35d3965a1f7c0b9c4e39ec1e8f5d02d3aa0862", + "0x96aa47a3ba20b1cfe81eb26bef503225037fdf4c9df53bea1b520841875cd1db6aa8e0f34685da08b55a3ce7289e6de0", + "0xb4c27ee3f4b8c0031837160f0a75632f5b51b5850d52b530096443f54c2b264aeccc5c61b4fcc8de7074475f354fa0d8", + "0xacfd735cda20be1d6f425a7886629c91732fbb5a4e0350ca740a8fb5b39f2001071cec0b2a0f6ca35e1f35a5ea18d00f", + "0xae44d87b1d16d59504c602cbacde2c2791f1520391ca50154e6036d3953ca466cf93d6537da2adb729e6f9f4ffa87853", + "0x97b492872ce44941ea4668ffca83b82fac0f4021bd47e0a5ffeaaacb1b3fc924ee4d53b99f7bcafe0985caf0fbe5d1d3", + "0xb3fbe2f9103d293f49c6c6016d5913f041c9113295397388111a0fdf4245d8edd6e63b9a1a1c9c8f868d6e1988116880", + "0x805efa08fd2046c44c427b225c17bed8a1eb3320cdf94026fdc24c6d345a6cfebfd7475f85d2d1bf22018ca72d2761d3", + "0x9888bae0d83077d1dfde82fdffb1195565c31c519b80cba1e21aba58ee9ccb5677f74bfde13fa5723026514a7d839661", + "0x922e19d2646ba90c9f56278bddf74621cc4518ae2f042fb8245843e87cd82724c6d7c9a99907ac6de5f2187fd2e77cbe", + "0xa38f0e1faf97dd1e0804b44e4d150dbfa48318442d1c5255eb0c14ea56b50502f3c7cb216a0336e7c140398088dc01cf", + "0x93598ea391c8735799a1d4cd0456f34994ccdf4883fad57419f634f30fee595938bc66b066dade9ae52578818c00d899", + "0xa528dc920734cfaee9feacbc0baa5b73befb1ec6fbd422fcad09a9c1f8f8c40b5ea332b2cf04dc1d6d921e9da9ddfeb4", + "0xb38d45316bf78d11e796a34ee535814e6cde0e642f14108329c5b21f4fec18cd61f84a3025824bb8dc4cbd26b2ecc9bf", + "0x8eec35a7404c9a35dc6ad0260b7f0f7fd1bfe92a2e08bc72548b99ed9acdc378728a8ea9c6879a6e47e37edb0d28c193", + "0xa68a4446274ccd947c61bf736c5219dad680b99c6085a26719793e0d9dab26d5f8a0b28e71be6e1b9ea4ae39139f7f57", + "0xa0acb543f41ad12e3b2e096629ccdd719a001d0ff53bb151e9a37aa57852f7275a7bbd06dc2a06af9144524548164af5", + "0xb271e74cdbcf8b9143f8472174bdb068c23308ea807c60a554c185f7be6f231aac13347139837514171a876dfac5baa5", + "0x8195a460719000cd1df379ebbf7918f71301a50a2fa587505cc5b8c4534c3d2343f63d28e7ee991d7a1cebb15d380696", + "0x96202b60426773e8731dcbedbf613477f65940a19fb4be0f4f742b0c76ae9d88ecdb6d36cd4f12bb404dd5d360c819e2", + "0xb0a80fe60b71ca9e80157138de8787b8a786326179604b8a15a744e52662645987e5f859ef5c76492d560daf4624b9a7", + "0xa331ea8adf87daa5e2d458d0113c307edae1a84927bca7d484aca5f8c1b6378ab42981c44b0d916d7249f4b475f926f1", + "0xaa1a8f59ae0912abf191ea7e209ff401628278dfb2269db6d87cf33bd52af3dbffbe96513a8b210e965c853a554b787a", + "0xac4f4a0e1b1a155e1f22a9085b0b047fe54c8437dbbb8e9720fd6b0cdd76557d19ca2e885a48890f0247b1a72be0e287", + "0xa428465505eac7b9660eb0d495a7a00c8cc238de3a02ebbd2eb07e502e9868086e9584b59953cf1480c0b781295db339", + "0xb7b77e21e08f6357cbd3dcd3035c3e8ec84cdfa13c7baef6c67e0ef43095e61fd549694263d7def8b8adc3a0fdcc7987", + "0xabb991d17c5bdd264c592c55101e265cb3210c4157aee4079173fd51da1e0199eed1d6c890aab95817ec078561d771af", + "0x846a8e4f801faf5fbec078b09c362ee30a00b2b58a4871744d03cd118b913464233ff926e52b0c75fbfcf098ad25a1e6", + "0x947e91ffa32f38c1ccb72cca4bfabaee9e63ab74a16f034cabba25e462f7331ebe5a7ba393f69e91830415fa75b1b52e", + "0x8dc5e26adc693f4e300cab7385edca1a2fe14c8ee6dc0cd6d013cb5aa154dc380e9e81e259cbc59c1f38f7c4a57f1c7d", + "0x9818ef6605d6ea3b7bf4da5c6d6d8ed540bb94df4d14c974e1b79ed2fd1a0b897b8cf1ff671a181a697effd66b1644a5", + "0xb5eab6baf03af994fc32cc9dce388394c18c01cdafe7909fde948f3e00a72dc8f30d15977d0f114bd7c140f5f94cf005", + "0x83b2e9858d3b929f9a2ad66a91a2c0c44d15d288c17c12a1614301a6f2d61d31eaa540ca7781520fe4420afae0ec0208", + "0xab338fbd38bce4d1b7a759f71e5e5673746c52846eff3d0b6825e390aeeca8f9f123ee88c78fe4d520cc415cbae32bf1", + "0x81adb6322b8db95d1711304e5b59f37640ca88c03e6c7e15de932be5267dff7351fa17664113ecc528e8920f5bfdc0d1", + "0x89e2e0c0d769e4107232df741678a6bacb041d0154385450aaca8be9c3c18c42f817373962e7569d33935c35666a8a6a", + "0x8f0756fea8b34a2b471ec39e4448a6a6935e5432ec2859d222964a4c82777a340e1d702777aeb946fa405afc0438221a", + "0xa2bf90c505a6f03b3dd09d04e1e7cf301fe3415b273e263f15fdfe5d0e40f619b95e8bf00916d3eaa7d7f8c0bae41c8e", + "0x91d5c76b5542637588cd47279d0bd74a25dbda0d8ec0ff68b62d7e01e34a63fc3e06d116ee75c803864b1cf330f6c360", + "0xa9958c388d25315a979566174b0622446335cb559aff1992bd71910c47497536019c6854d31c0e22df07505963fc44ff", + "0x91d82b09d5726077eed6c19bcb398abe79d87ce16c413df6bf5932b8fd64b4c0fd19c9bf0fa8db657a4a4d4c0d8f5a2d", + "0xac6e0a86e0ee416855c3e9eef2526c43835f5245527ed0038bc83b4fcadb4ea5beb91143cc674486681a9f0e63f856b1", + "0xaaf00d6efd0c6efb9f7d6a42555abec05c5af8f324e2e579fc2ac83bdc937cc682d9bc2ffd250619c8bb098b8c84db80", + "0x963f5fcd8476d0dbeb03a62cde40e3deee25f55e7ded7572d8884975f38eddc5406fc4b0adff602a1cca90f7205a7fdc", + "0xa3805ee01512f644d2679511bd8607890ee9721e75ac9a85ab9fd6fceb1308d5b9b0e9907686b4e683b34aed0f34cd81", + "0xa483d7708465cd4e33b4407fe82c84ef6bc7fa21475d961fe2e99802d0c999b6474ef7a46dd615b219c9c7e9faec45ee", + "0xb6b5f9456f12d6781c41f17cdc9d259f9515994d5dee49bb701a33fa2e8dcbb2c8c13f822b51ad232fc5e05bff2f68ef", + "0x8766b721b0cf9b1a42614c7d29aad2d89da4996dc9e2a3baeba4b33ca74100ab0b83f55c546c963e3b6af1dcf9ca067c", + "0xac5e8da1154cf4be8df2bbd2e212b7f8077099b2010c99e739441198f65337c6f7ef0d9136453a7668fde6e1389c32c7", + "0xa9d6d2c8845e5f1fec183c5153f1f6e23421e28ce0c86b0ce993b30b87869065acad9e6d9927d9f03c590852821b2f9c", + "0xa320ca07c44f7ea3ff858fe18395a86f59559617f13ec96d1e8b4a3f01d9c066a45c8d8cf8f1f14a360bb774d55f5f18", + "0xb3adb00e1312dce73b74fbd2ea16f0fb0085bd0db10772e9c260e9ed9f8829ff690e3dfffacaddc8233d484bb69778b3", + "0x87b0c8d8a167d5199d0b0743c20fb83ec8a1c442f0204bcc53bf292ba382bef58a58a6d1e2467920e32c290fdc6dae7c", + "0xa74fa436a5adc280a68e0c56b28ac33647bdfc8c5326f4c99db6dbd1b98d91afb1f41f5fffd6bcc31c1f8789c148e2db", + "0x8a37349e4ba7558965077f7f9d839c61b7dcb857fcc7965c76a64a75e377bfea8cd09b7a269ce602cc4472affc483b69", + "0x8af813f62c5962ff96bf73e33f47fd5a8e3e55651d429e77d2ce64a63c535ecc5cfc749bb120c489b7ea1d9b2a5d233c", + "0x833021445b7d9817caa33d6853fa25efc38e9d62494d209627d26799432ea7b87a96de4694967151abc1252dd2d04dfc", + "0x8f78a715107e0ace3a41bff0385fd75c13bf1250f9e5ddecf39e81bacc1244b978e3464892f7fb2596957855b8bf9fc7", + "0xaed144134dc1cc6c671f70ebe71a3aadf7511eea382969bc5d499a678d2d8ce249ebf1a06b51183f61413eba0517012b", + "0xb39a53e82c5553943a5e45bc5116d8672ec44bed96b3541dead40344b287a7b02dbf7107372effb067edd946f47de500", + "0xb383844c3b20a8bc06098046ec6b406df9419ad86fac4a000905c01325426903a5e369af856d71ccd52fea362ed29db5", + "0x83815a7098283723eec6aa6451b5d99578bf28a02971375a1fe90c15a20963e129372ac4af7b306ee2e7316472c5d66d", + "0xb426b4e185806a31febd745fa8d26b6397832a04e33c9a7eb460cbf302b4c134a8a01d4e5e40bc9b73296c539e60b3ca", + "0xa6cabf8205711457e6363ef4379ebc1226001e1aaea3002b25bfd9e173f4368002f4461e79eeb9f4aa46f1b56c739ab9", + "0xa6e88ab01282313269cd2d8c0df1a79dada5b565d6623900af9e7e15351de2b0105cc55d3e9080e1e41efe48be32a622", + "0xb2b106db3d56d189ea57afa133ae4941b4eb1dc168357af488e46811c687713fc66bbd6f8500bbd13cdb45cb82c14d1d", + "0xb3a74780ff949d19e6438db280e53632c60dc544f41320d40297fe5bb7fcee7e7931111053c30fb1ed9019ab28965b44", + "0x8c67f32b9fdc04ec291cc0d928841ab09b08e87356e43fbbf7ac3ff0f955642628f661b6f0c8e2192a887489fddf07bb", + "0xb3be58bd628383352e6473fe9a1a27cf17242df0b1273f5867e9119e908969b9e9e7e294a83b9ea14825003cb652d80c", + "0xa867acf6ab03e50936c19a21d4040bfd97eb5a89852bd9967da0e326d67ce839937cab4e910d1149ecef9d5f1b2d8f08", + "0x8006b19126bd49cbb40d73a99a37c2e02d6d37065bbe0cfcee888280176184964bd8f222f85960667c5b36dfaee0ee35", + "0xac50967b8b7840bf9d51216d68a274f1d3431c7d4031fbac75a754befbbb707c2bb184867db6b9d957f3ba0fd0a26231", + "0xb5a794c928aff0c4271674eb0a02143ed9b4d3bc950584c7cd97b7d3c3f2e323798fd5ccc6fcc0eb2e417d87f4c542a2", + "0xa2ca3d6509f04b37091ce6697672ee6495b42d986d75bd2d2058faa100d09fd0a145350f2d280d2cb36516171bd97dbf", + "0x92cfa293469967a9207b37cd70392312faf81b52963bfbad5f9f3da00817d26e10faf469e0e720c3bb195f23dda8c696", + "0xa0dd5135da0a0e33fa922c623263b29518d7fa000e5beefc66faa4d6201516d058f155475c4806917a3259db4377c38a", + "0x8fc3ae8ea6231aa9afb245a0af437e88ebca2c9ab76850c731981afba90d5add0ea254053449355eccf39df55bd912ed", + "0x9727afe1f0804297717cec9dc96d2d27024a6ae6d352fee5d25377ee858ee801593df6124b79cb62ddc9235ec1ade4ac", + "0x8bcb2c53fcaa38e8e2e0fd0929bc4d9ddce73c0282c8675676950ff806cb9f56ebd398b269f9a8c2a6265b15faf25fca", + "0xa8bd9007fbbdd4b8c049d0eb7d3649bd6a3e5097372fa8ea4b8821ba955c9ef3f39ac8b19f39d3af98640c74b9595005", + "0x92c7e851c8bd6b09dfcbfdb644725c4f65e1c3dbd111df9d85d14a0bb2d7b657eb0c7db796b42bf447b3912ef1d3b8c3", + "0x98c499b494d5b2b8bea97d00ac3a6d826ab3045bb35424575c87117fc2a1958f3829813e266630749caf0fa6eeb76819", + "0x8df190d71e432fe8691d843f6eb563445805c372eb5b6b064ec4e939be3e07526b5b7f5a289ede44ae6116a91357b8b1", + "0xb5010243f7c760fb52a935f6d8ed8fc12c0c2f57db3de8bb01fdeedf7e1c87b08f3dd3c649b65751f9fd27afa6be34c7", + "0x889c8057402cc18649f5f943aed38d6ef609b66c583f75584f3b876c1f50c5dc7d738dc7642135742e1f13fa87be46c1", + "0x996087337f69a19a4ebe8e764acf7af8170a7ad733cd201b0e4efde6ea11039a1853e115ad11387e0fb30ab655a666d8", + "0x902732c429e767ab895f47b2e72f7facad5ef05a72c36a5f9762c2194eb559f22845bbb87c1acc985306ecb4b4fbbf79", + "0x8519b62a150ea805cdfc05788b8d4e797d8396a7306b41777c438c2e8b5c38839cfec5e7dc5d546b42b7b76e062982a7", + "0x862a53ba169e6842a72763f9082ff48fbfbb63129d5a26513917c2bca9ad6362c624ce6fc973cf464f2eb4892131eb04", + "0xb86cd67c809d75fdb9f1c9453a39870f448b138f2b4058d07a707b88bb37f29d42e33ce444f4fbe50d6be13339cae8a6", + "0x8cf5d8365dbbafc0af192feb4fc00c181e2c3babc5d253268ef5564934555fb1e9b1d85ec46f0ca4709b7d5b27169b89", + "0xb48f11a1809ec780bf6181fae3b8d14f8d4dc7d1721128854354be691c7fc7695d60624f84016c1cea29a02aaf28bfbc", + "0x8b46b695a08cb9a2f29ab9dd79ab8a39ec7f0086995b8685568e007cd73aa2cd650d4fae6c3fb109c35612f751ba225e", + "0x8d2f9f0a5a7de894d6c50baceb8d75c96082df1dcf893ac95f420a93acbbf910204903d2eb6012b1b0495f08aaf9992f", + "0xb334db00a770394a84ec55c1bd5440b7d9f2521029030ef3411b0c2e0a34c75c827fd629c561ea76bd21cd6cf47027f4", + "0x96e9ff76c42bcb36f2fb7819e9123420ed5608132f7c791f95cb657a61b13041e9ba2b36f798a0fdb484878cbe015905", + "0x99f8d701e889abd7815d43ba99e0a85776ec48311fa7cb719d049f73b5d530fa950746ffbbb7beb9e30c39d864891dc2", + "0x98169c20df7c15d7543991f9c68e40ac66607cbd43fc6195416e40009917039357e932d6e807f3a40bc4503ad01ae80a", + "0x84bd97dd9e4e2ba75d0dee7d4418c720d4746203d847ce2bdd6ed17d492023df48d7b1de27e3f5cb8660c4bb9519ae1b", + "0xa54319e06db7f5f826277a54734a875c5b3fd2fa09d36d8b73594137aa62774b7356560157bc9e3fdf1046dc57b6006a", + "0x90cfff7cd4e7c73b84f63455d31b0d428cb5eee53e378028591478511985bcc95eb94f79ad28af5b3bed864e422d7b06", + "0xa11c23cc8dce26ac35aea9abe911905a32616a259fa7da3a20f42dc853ad31b2634007aa110c360d3771ff19851f4fb4", + "0x9856fbee9095074ad0568498ff45f13fe81e84ea5edaf04127d9ee7e35e730c6d23fa7f8f49d092cf06b222f94ab7f36", + "0x818862dec89f0dc314629fffbca9b96f24dfde2d835fa8bde21b30dc99fe46d837d8f745e41b39b8cf26bfe7f338f582", + "0x831819d41524c50d19f7720bf48f65346b42fb7955ee6ecc192f7e9fed2e7010abccdfdeac2b0c7c599bc83ac70be371", + "0xb367e588eb96aa8a908d8cc354706fee97e092d1bc7a836dbcc97c6ed4de349643a783fb4ddf0dec85a32060318efa85", + "0xb7aaef729befd4ab2be5ec957d7d1dbe6178de1d05c2b230d8c4b0574a3363e2d51bc54ea0279a49cc7adffa15a5a43a", + "0xae2891d848822794ecb641e12e30701f571431821d281ceecbccaaa69b8cd8242495dc5dbf38f7d8ed98f6c6919038aa", + "0x872cf2f230d3fffce17bf6f70739084876dc13596415644d151e477ce04170d6ab5a40773557eeb3600c1ad953a0bfce", + "0xb853d0a14cef7893ba1efb8f4c0fdb61342d30fa66f8e3d2ca5208826ce1db5c8a99aa5b64c97e9d90857d53beb93d67", + "0x910b434536cec39a2c47ca396e279afdbc997a1c0192a7d8be2ba24126b4d762b4525a94cea593a7c1f707ba39f17c0c", + "0xb6511e9dea1fbccedd7b8bb0a790a71db3999bd4e3db91be2f1e25062fae9bb4e94e50d8ec0dcc67b7a0abce985200b2", + "0x936885c90ebe5a231d9c2eb0dfd8d08a55ecaa8e0db31c28b7416869b3cc0371448168cbec968d4d26d1cb5a16ebe541", + "0xb71c2ac873b27fe3da67036ca546d31ca7f7a3dc13070f1530fce566e7a707daeb22b80423d505f1835fe557173754f8", + "0x85acb64140915c940b078478b7d4dadd4d8504cde595e64f60bd6c21e426b4e422608df1ed2dd94709c190e8592c22d7", + "0xb5831c7d7c413278070a4ef1653cec9c4c029ee27a209a6ea0ad09b299309dea70a7aef4ff9c6bdeda87dcda8fa0c318", + "0xaa0e56e3205751b4b8f8fa2b6d68b25121f2b2468df9f1bd4ef55f236b031805a7d9fd6f3bba876c69cdba8c5ea5e05f", + "0xb021f5ae4ed50f9b53f66dd326e3f49a96f4314fc7986ace23c1f4be9955ec61d8f7c74961b5fdeabcd0b9bccbf92ce8", + "0x88df439f485c297469e04a1d407e738e4e6ac09a7a0e14e2df66681e562fdb637a996df4b9df4e185faab8914a5cef76", + "0x8e7ae06baa69cb23ca3575205920cb74ac3cda9eb316f4eef7b46e2bff549175a751226d5b5c65fe631a35c3f8e34d61", + "0x99b26ff174418d1efc07dfbed70be8e0cb86ac0cec84e7524677161f519977d9ca3e2bbe76face8fe9016f994dafc0ff", + "0xa5f17fe28992be57abd2d2dcaa6f7c085522795bfdf87ba9d762a0070ad4630a42aa1e809801bc9f2a5daf46a03e0c22", + "0x8d673c7934d0e072b9d844994f30c384e55cec8d37ce88d3ad21f8bb1c90ecc770a0eaf2945851e5dab697c3fc2814a9", + "0xa003ed4eb401cfe08d56405442ca572f29728cfff8f682ef4d0e56dd06557750f6a9f28a20c033bc6bbb792cc76cc1a8", + "0x8010408f845cf1185b381fed0e03c53b33b86ea4912426819d431477bd61c534df25b6d3cf40042583543093e5f4bb44", + "0x9021a1ae2eb501134e0f51093c9f9ac7d276d10b14471b14f4a9e386256e8c155bef59973a3d81c38bdab683cd5c10e0", + "0xa5abf269ceabbb1cf0b75d5b9c720a3d230d38f284ed787b6a05145d697a01909662a5b095269996e6fa021849d0f41f", + "0xb4b260af0a005220deb2266518d11dbc36d17e59fc7b4780ab20a813f2412ebd568b1f8adc45bf045fcbe0e60c65fd24", + "0xb8c4cb93bedbb75d058269dfccda44ae92fe37b3ab2ef3d95c4a907e1fadf77c3db0fa5869c19843e14b122e01e5c1f4", + "0xac818f7cdecc7b495779d8d0ff487f23ab36a61d0cf073e11000349747537b5b77044203585a55214bb34f67ef76f2d2", + "0x86215799c25356904611e71271327ca4882f19a889938839c80a30d319ddbe6c0f1dfa9d5523813a096048c4aef338cd", + "0xa9204889b9388bf713ca59ea35d288cd692285a34e4aa47f3751453589eb3b03a9cc49a40d82ec2c913c736752d8674d", + "0x893aecf973c862c71602ffb9f5ac7bf9c256db36e909c95fe093d871aab2499e7a248f924f72dea604de14abfc00e21c", + "0xb8882ee51cfe4acba958fa6f19102aa5471b1fbaf3c00292e474e3e2ec0d5b79af3748b7eea7489b17920ce29efc4139", + "0x8350813d2ec66ef35f1efa6c129e2ebaedc082c5160507bcf04018e170fc0731858ad417a017dadbd9ade78015312e7f", + "0x83f6829532be8cd92f3bf1fef264ee5b7466b96e2821d097f56cbb292d605a6fb26cd3a01d4037a3b1681d8143ae54d7", + "0x87d6258777347e4c1428ba3dcbf87fdd5113d5c30cf329e89fa3c9c1d954d031e8acacb4eed9dca8d44507c65e47e7cd", + "0xa05669a1e561b1c131b0f70e3d9fc846dc320dc0872334d07347e260d40b2e51fdbabeb0d1ae1fb89fba70af51f25a1a", + "0x819925c23fd4d851ea0eecc8c581f4a0047f5449c821d34eccc59a2911f1bd4c319dab6ece19411d028b7fdedece366b", + "0xb831b762254afd35364a04966d07b3c97e0b883c27444ff939c2ab1b649dc21ac8915b99dc6903623ed7adaae44870ac", + "0x93ec0190f47deffe74179879d3df8113a720423f5ca211d56db9654db20afe10371f3f8ec491d4e166609b9b9a82d0d4", + "0x8f4aa6313719bcfad7ca1ed0af2d2ee10424ea303177466915839f17d2c5df84cc28fcef192cbb91bb696dd383efd3b2", + "0x8d9c9fdf4b8b6a0a702959cf784ad43d550834e5ab2cd3bebede7773c0c755417ad2de7d25b7ff579f377f0800234b44", + "0x99d9427c20752f89049195a91cf85e7082f9150c3b5cb66b267be44c89d41e7cc269a66dacabacadab62f2fa00cc03be", + "0xb37709d1aca976cbbf3dc4f08d9c35924d1b8b0f1c465bd92e4c8ff9708e7d045c423183b04a0e0ab4c29efd99ef6f0e", + "0xa163f42fb371b138d59c683c2a4db4ca8cbc971ae13f9a9cc39d7f253b7ee46a207b804360e05e8938c73bf3193bab55", + "0x87a037aa558508773fc9a0b9ba18e3d368ffe47dfaf1afacee4748f72e9d3decc2f7c44b7bf0b0268873a9c2ef5fe916", + "0xa1f20cb535cc3aebd6e738491fe3446478f7609d210af56a4004d72500b3ec2236e93446783fe628c9337bcd89c1e8e1", + "0x9757aa358dfbba4f7116da00fe9af97f7ac6d390792ea07682b984aa853379ac525222ac8a83de802859c6dec9182ef7", + "0x815daca1eded189ec7cb7cbc8ad443f38e6ddb3fb1301d1e5a1b02586f1329035209b7c9232dc4dff3fc546cb5ac7835", + "0xaed86dfaf9c4f0a4b2a183f70f9041172002a773482a8ebf3d9d5f97d37ee7c6767badfda15476b3b243931235c7831c", + "0x8d032e681e89e41b29f26be02f80030fa888f6967061d2204c1ebb2279a3211d759d187bce6408c6830affa1337fb4e0", + "0x877bff5c2db06116f918a722b26422c920aeade1efa02fa61773fca77f0ea4a7e4ee0ecaaa5cfe98044c0ff91b627588", + "0xb9ee5310d0996a10a242738d846565bdb343a4049a24cd4868db318ea6168a32548efaf4ab84edfbf27ce8aec1be2d1c", + "0xb59f6928167323037c6296dd7697846e80a7a4b81320cfae9073ebd2002a03bdf6933e887f33ad83eda8468876c2c4fb", + "0x8167686245149dc116a175331c25301e18bb48a6627e2835ae3dd80dd373d029129c50ab2aebeaf2c2ccddc58dcc72ec", + "0x82b7dcc29803f916effb67c5ba96a1c067ed8ca43ad0e8d61a510ab067baefd4d6b49e3886b863da2de1d8f2979a4baa", + "0xb43824cd6f6872a576d64372dde466fef6decdbb5ad5db55791249fde0a483e4e40c6e1c221e923e096a038fe47dab5e", + "0xab1e9884cf5a8444140cf4a22b9a4311a266db11b392e06c89843ac9d027729fee410560bcd35626fd8de3aad19afc4a", + "0xa0dbd92a8d955eb1d24887ca739c639bdee8493506d7344aadb28c929f9eb3b4ebaae6bd7fd9ffe8abb83d0d29091e43", + "0x8352a47a70e343f21b55da541b8c0e35cd88731276a1550d45792c738c4d4d7dc664f447c3933daabd4dbb29bb83be4a", + "0x8ce4a1e3c4370346d6f58528a5ef1a85360d964f89e54867ba09c985c1e6c07e710a32cdda8da9fa0e3b26622d866874", + "0xb5e356d67dd70b6f01dd6181611d89f30ea00b179ae1fa42c7eadb0b077fb52b19212b0b9a075ebd6dc62c74050b2d2f", + "0xb68f2cd1db8e4ad5efdba3c6eaa60bfcc7b51c2b0ce8bb943a4bc6968995abe8a45fe7f12434e5b0076f148d942786be", + "0xb5c7b07f80cd05c0b0840a9f634845928210433b549fb0f84a36c87bf5f7d7eb854736c4083445c952348482a300226a", + "0x8cfd9ea5185ff9779dee35efe0252957d6a74693104fb7c2ea989252a1aa99d19abaab76b2d7416eb99145c6fdb89506", + "0x8cc8e2c5c6ddee7ef720052a39cab1ecc5e1d4c5f00fb6989731a23f6d87ac4b055abb47da7202a98c674684d103152a", + "0x8c95394c9ed45e1bf1b7cfe93b2694f6a01ff5fed8f6064e673ba3e67551829949f6885963d11860d005e6fabd5ac32c", + "0xadf00b86f4a295b607df157f14195d6b51e18e2757778fde0006289fabba8c0a4ab8fad5e3e68ddbb16ccb196cc5973f", + "0xb1714b95c4885aac0ee978e6bbabbc9596f92b8858cb953df077511d178527c462cbe1d97fdc898938bae2cd560f7b66", + "0xadf103f4344feb6b9c8104105d64475abc697e5f805e9b08aa874e4953d56605677ef7ff4b0b97987dc47257168ae94d", + "0xb0ce6ede9edb272d8769aed7c9c7a7c9df2fb83d31cc16771f13173bcdc209daf2f35887dcca85522d5fdae39f7b8e36", + "0xad698d1154f7eda04e2e65f66f7fcdb7b0391f248ba37d210a18db75dafd10aedc8a4d6f9299d5b6a77964c58b380126", + "0x904856cd3ecdbb1742239441f92d579beb5616a6e46a953cf2f1dd4a83a147679fc45270dcac3e9e3d346b46ab061757", + "0xb600b5b521af51cdfcb75581e1eccc666a7078d6a7f49f4fdb0d73c9b2dab4ce0ecafcbd71f6dd22636e135c634ee055", + "0xa170c5d31f6657f85078c48c7bbf11687ce032ab2ff4b9b3aee5af742baecf41ea1c2db83bcba00bccc977af7d0c5c8e", + "0xa9ef1cbb6a7acb54faf1bcbd4676cdeba36013ca5d1ac1914c3ff353954f42e152b16da2bdf4a7d423b986d62b831974", + "0xaa706d88d3bd2ce9e992547e285788295fd3e2bbf88e329fae91e772248aa68fdfdb52f0b766746a3d7991308c725f47", + "0x911a837dfff2062bae6bcd1fe41032e889eb397e8206cedadf888c9a427a0afe8c88dcb24579be7bfa502a40f6a8c1cc", + "0xae80382929b7a9b6f51fe0439528a7b1a78f97a8565ba8cddb9ee4ba488f2ab710e7923443f8759a10f670087e1292c4", + "0xb8962de382aaa844d45a882ffb7cd0cd1ab2ef073bce510a0d18a119f7a3f9088a7e06d8864a69b13dc2f66840af35ae", + "0x954538ffff65191538dca17ec1df5876cb2cd63023ff2665cc3954143e318ece7d14d64548929e939b86038f6c323fc1", + "0x89efa770de15201a41f298020d1d6880c032e3fb8de3690d482843eb859e286acabb1a6dc001c94185494759f47a0c83", + "0xa7a22d95b97c7c07b555764069adaa31b00b6738d853a5da0fe7dc47297d4912a0add87b14fa7db0a087a9de402ea281", + "0x9190d60740c0813ba2ae1a7a1400fa75d6db4d5ce88b4db0626922647f0c50796a4e724e9cc67d635b8a03c5f41978f7", + "0xab07c30b95477c65f35dc4c56d164e9346d393ad1c2f989326763a4cc04b2cb0386e263007cc5d0125631a09ad3b874c", + "0x9398d8e243147de3f70ce60f162c56c6c75f29feb7bc913512420ee3f992e3c3fb964d84ef8de70ef2c118db7d6d7fd5", + "0xb161b15b38cbd581f51ca991d1d897e0710cd6fdf672b9467af612cd26ec30e770c2553469de587af44b17e3d7fea9f7", + "0x8c5d0260b6eb71375c7ad2e243257065e4ea15501190371e9c33721a121c8111e68387db278e8f1a206c0cce478aaa2b", + "0xb54ac06a0fb7711d701c0cd25c01ef640e60e3cb669f76e530a97615680905b5c5eac3c653ce6f97ceca2b04f6248e46", + "0xb5c7f76e3ed6dc6c5d45494f851fa1b5eaf3b89adac7c34ad66c730e10488928f6ef0c399c4c26cbeb231e6e0d3d5022", + "0xb6cd90bdd011ac1370a7bbc9c111489da2968d7b50bf1c40330375d1a405c62a31e338e89842fe67982f8165b03480c7", + "0xb0afcaf8d01f5b57cdeb54393f27b27dc81922aa9eaccc411de3b03d920ae7b45295b090ef65685457b1f8045c435587", + "0xb2786c0460e5057f94d346c8ebe194f994f6556ab2904a1d1afd66c0ff36391b56f72ed769dcc58558ee5efaa2ed6785", + "0x965dbb0cb671be339afcb2d6f56e3c386fb5d28536d61d6073b420ee15dee79c205af2f089fbb07514a03c71bf54b4e2", + "0x90f2003e2286bba9cebff3a6791637ca83b6509201c6aed1d47f27097d383d5c2d8532bff9e3541d2c34259841cf26ab", + "0x902142d1224e1888ebbfef66aaf8d5b98c27927a00b950753a41d1d28a687a8286b51655da9a60db285b20dc81d5ea89", + "0xa5d364448bf0d0849e5104bdaef9cb2cc8c555f5d6d34239c68671fbe1252f7c8c75b83cea10159dee4da73298f39a12", + "0xb013a54c5b99e296d9419ad5c2aaf4545acd34405e57d13cb764e92132cc20d1a14b33e10caf22d898b608670c04f273", + "0xb92976dceda373331804d48a7847f508cafde8d15949df53dbda09d03908678db1e61ee637baad5f05b2b03ea6f5a870", + "0x968bcb308c7ad0813dc9b3170f23f419aecd7b42176f27fac698811795bf42659fea6b04dab4ef43595dcc990622041b", + "0xa9d0a20e9367ea831dccd37f4d97ea75e9aeec952947a7946d95e0d249c94024183ef79a624bdea782469824df0ee4e4", + "0x8521b9667453c3658703e5db365b13f0e0d2331ce611ff1e708f8124d8a81bb5e82871de4a66d45c1a6b0a3901bd901e", + "0xb9c88e76e69b0722c0a2f97e57dbc4a6f7456434cd694e2ff67f4e24740cffa4db03e2b18f07f22954ae7db2286e1fa2", + "0x8400e55aa9ab01d4cc0affd611127b5d8d9a9dbd897f3cb8e2050379983aa54249be17d7b7891977b2515bb44a483f65", + "0x8cbb967b4ed31dc40ea06822a94d54cbfc8845c66fbafa3474c8f5fe1ada97299ed4ca955d9d7a39af8821eabf711854", + "0xb4d266ee3fea264a6c563fd6bed46f958c2d7bd328225f6e47faf41a0916aef3b697574322f8b814dfb2f5c242022bf6", + "0x8f7c72d69a919450215ead660ffa9637642c5306354888d549fd4a42e11c649b389f67cc802a0184d10fdb261351140c", + "0xa5f9e494ea9b2393ec32c48aac76c04158ccef436d4e70ad930cba20c55fbf61e8f239f70b9d75462405c4b6317c71a1", + "0xb3befb259b52a44a6f44345859e315c20efa48c0c992b0b1621d903164a77667a93f13859790a5e4acb9f3ec6c5a3c6e", + "0xb9e4ca259b4ee490d0824207d4d05baf0910d3fe5561ff8b514d8aa5c646417ca76f36ab7c6a9d0fb04c279742f6167a", + "0x98fa8c32a39092edb3c2c65c811d2a553931010ccb18d2124d5b96debd8b637d42b8a80111289f2079d9ebca2131a6dc", + "0xa65e5aa4631ab168b0954e404006ce05ac088fd3d8692d48af2de5fd47edbf306c80e1c7529697754dbbba1b54164ba0", + "0xb94b7d37e4d970b4bb67bf324ebf80961a1b5a1fa7d9531286ab81a71d6c5f79886f8ef59d38ae35b518a10ed8176dcc", + "0xb5ed2f4b0a9ae9ace2e8f6a7fd6560d17c90ae11a74fa8bef2c6c0e38bfd2b9dd2984480633bca276cb73137467e2ce3", + "0xa18556fe291d87a2358e804ee62ddff2c1d53569858b8ae9b4949d117e3bfb4aefce1950be8b6545277f112bebeeb93d", + "0xa0d60b9def5d3c05856dff874b4b66ec6e6f0a55c7b33060cc26206c266017cdcf79b1d6f6be93ed7005a932f9c6a0b9", + "0x801fced58a3537c69c232ce846b7517efd958e57c4d7cd262dbec9038d71246dafad124aa48e47fe84ecc786433747c7", + "0xa5e9a8ea302524323aa64a7c26274f08d497df3d570676ecc86bd753c96a487a650389a85f0bc8f5ea94fe6819dc14e5", + "0xa8a2963dc9238a268045d103db101adc3b2f3ab4651b7703b2fe40ece06f66bf60af91369c712aa176df6ed3d64a82fa", + "0xa4a8ff0a9a98442357bcdd9a44665919c5d9da6a7d7d21ccdbbd8f3079b1e01125af054b43b37fc303941d0a2e7baee0", + "0x90ef893350f50d6f61ee13dfab6e3121f4a06a1908a707b5f0036cdc2fe483614de3b1445df663934036784342b0106f", + "0x84e74d5bc40aaab2cc1d52946b7e06781fbef9d8de6f8b50cd74955d6bdb724864c0e31d5ac57bf271a521db6a352bd6", + "0x832cdf653bbbd128e2e36e7360354a9e82813737c8ab194303d76667a27aa95252756c1514b9e4257db1875f70f73eb4", + "0xa0af8660ed32e6dbcc4d5d21b0a79a25ff49394224f14e6e47604cf3b00136de8f9ab92e82814a595bf65340271c16c3", + "0x9040b5caf5e4dc4118572a2df6176716b5b79d510877bbb4a1211b046596899ea193be4d889e11e464ffb445ab71907b", + "0xb9bf8354c70238ab084b028f59e379b8a65c21604034d1b8c9b975f35a476e3c0ba09dd25bf95c5d8ffb25832537319b", + "0xa7b492cc1df2a8f62c935d49770d5078586bd0fefda262eb5622033e867e0b9dc0ffc2ce61cd678136a3878d4cbb2b56", + "0x95a5ef06f38743bba187a7a977023b1d9d5ec9ef95ba4343ad149a7b8b0db0e8e528bfb268dc7e5c708bc614dc3d02c8", + "0x99dcf7f123df6c55aeff0a20885a73e84d861ec95cf9208ba90494f37a2dcaacebc8344f392547d3046616d9753c7217", + "0xb3e14f309281a3685ceb14f8921c1e021b7e93c9e9595596b9fb627e60d09ed9e5534733fcbdf2fbc8c981698f5e62ac", + "0x816a5e0463074f8c7fb2998e0f0cf89b55790bdbbb573715f6268afb0492453bd640dd07a9953d0400169d555fdf4ac8", + "0x8356d68f3fe7e02a751f579813bd888c9f4edcc568142307d1c9259caef692800e1581d14225e3a3585dac667928fa94", + "0x8d70ea3314c91bfc3f7c1dcf08328ae96f857d98c6aac12ad9eebc2f77e514afdbaf728dfcb192ed29e7ce9a0623ecbb", + "0xb68280e7f62ced834b55bc2fcc38d9ea0b1fbcd67cc1682622231894d707c51478ed5edf657d68e0b1b734d9f814b731", + "0xb712dd539e1d79a6222328615d548612eab564ace9737d0249aa2eefed556bbcf3101eba35a8d429d4a5f9828c2ac1fe", + "0x8da42ca096419f267f0680fd3067a5dbb790bc815606800ae87fe0263cae47c29a9a1d8233b19fe89f8cc8df6f64697e", + "0x8cb2ffd647e07a6754b606bde29582c0665ac4dde30ebdda0144d3479998948dae9eb0f65f82a6c5630210449fbd59f7", + "0x8064c3ef96c8e04398d49e665d6de714de6ee0fced836695baa2aa31139373fad63a7fc3d40600d69799c9df1374a791", + "0xaec99bea8ab4e6d4b246c364b5edc27631c0acc619687941d83fa5ba087dd41f8eaec024c7e5c97cf83b141b6fb135da", + "0x8db6051f48901308b08bb1feb8fd2bceaedde560548e79223bd87e485ea45d28c6dcec58030537406ed2b7a9e94e60cc", + "0xa5b812c92d0081833dcf9e54f2e1979a919b01302535d10b03b779330c6d25d2de1f374b77fe357db65d24f9cbcd5572", + "0x967d442485c44cf94971d035040e090c98264e3348f55deabd9b48366ec8fe0d5a52e4b2c9a96780a94fc1340338484e", + "0xa4b4110bef27f55d70f2765fc3f83c5ddcdfe7f8c341ea9d7c5bcee2f6341bcfbf7b170b52e51480e9b5509f3b52048f", + "0xa0d39e4eb013da967a6ac808625122a1c69bf589e3855482dedb6847bb78adc0c8366612c1886d485b31cda7304ec987", + "0xa92f756b44d44b4e22ad265b688b13c9358114557489b8fb0d9720a35e1773b3f0fa7805ac59b35d119a57fe0f596692", + "0xaa27e4b979af6742b49db8bf73c064afd83a9cfe9016131a10381f35a46169e8cfd1a466f295fcc432c217c7c9fa44a5", + "0x845961319cc10bcfbb1f3cb414a5c6a6d008fb3aac42c7d5d74e892cc998af97bc9a9120c3f794e4078135e16a416e38", + "0xa18dbe3015c26ae3e95034c01d7898e3c884d49cc82e71ddb2cf89d11cec34cc2a3dff0fafb464e8e59b82ce1a0a7a11", + "0xa954aed6d7124fa5bd5074bd65be4d28547a665fb4fe5a31c75a5313b77d1c6fc3c978e24c9591a2774f97f76632bdde", + "0x8f983b2da584bdff598fcb83c4caa367b4542f4417cc9fa05265ff11d6e12143c384b4398d3745a2d826235c72186a79", + "0xb2caa17d434982d8dd59a9427307dfe4416b0efc8df627dd5fc20d2c11046c93461d669cab2862c094eec6a9845990c6", + "0x8c2baa5a97ee3154cce9fa24f6b54b23e9d073e222220fdd0e83e210c0058fb45ce844382828b0cb21438cf4cad76ee6", + "0xb93437406e4755ccf1de89f5cbe89e939490a2a5cf1585d4363c21ae35b986cb0b981dec02be2940b4ec429cc7a64d4c", + "0xa90ac36c97b7ea2eddb65e98e0d08a61e5253019eeb138b9f68f82bb61cdbadf06245b9dfffe851dfa3aa0667c6ac4b8", + "0x8bcdd7b92f43b721ddbfd7596e104bc30b8b43bdaee098aac11222903c37f860df29d888a44aa19f6041da8400ddd062", + "0x98f62d96bdf4e93ed25b2184598081f77732795b06b3041515aa95ffda18eb2af5da1db0e7cfed3899143e4a5d5e7d6c", + "0xad541e3d7f24e4546b4ae1160c1c359f531099dab4be3c077e446c82cb41b9e20b35fa7569798a9f72c1fae312b140b4", + "0x8844a1471ff3f868c6465459a5e0f2fb4d93c65021641760f1bb84f792b151bc04b5a0421bbc72cf978e038edc046b8f", + "0xaf895aebe27f8357ae6d991c2841572c2063b8d0b05a2a35e51d9b58944c425c764f45a3f3b13f50b1b1f3d9025e52ad", + "0xadf85265bb8ee7fead68d676a8301129a6b4984149f0eb4701eae82ec50120ddad657d8798af533e2295877309366e9c", + "0x962e157fe343d7296b45f88d9495d2e5481e05ea44ca7661c1fdf8cc0ac87c403753ca81101c1294f248e09089c090eb", + "0xa7c8959548c7ae2338b083172fee07543dc14b25860538b48c76ef98ab8f2f126ecb53f8576b8a2b5813ecb152867f18", + "0xae71680366e11471e1c9a0bc7ea3095bc4d6ceb6cf15b51f1b6061b043f6d5941c9f869be7cb5513e8450dca16df2547", + "0x831290201f42ebf21f611ca769477b767cf0ee58d549fcd9e993fae39d07745813c5ce66afa61b55bb5b4664f400ece7", + "0xaf5879e992f86de4787f1bc6decbc4de7d340367b420a99a6c34ac4650d2a40cbe1cef5c6470fc6c72de8ee1fe6bcce4", + "0x8d3c27e1b2ef88d76ac0b1441d327567c761962779c8b1f746e3c976acb63b21d03e5e76589ce9bb0d9ba6e849ed3d53", + "0xab23b09c9f4151e22654d43c1523f009623b01fe1953d343107cef38b95bd10afd898964946d3cb8521bcbe893e1c84d", + "0x8a6acade9520e7a8c07f33d60a87fd53faa6fbf7f018735bffcbbb757c3bafb26f547ceb68e7b8b6bca74819bfcd521a", + "0x94db50080d557440a46b6b45ee8083bc90e9267d40489040cbed6234bebf350c788ec51557b969f95194102fde8e9713", + "0x8be8031f32504e0c44958d893649f76cec17af79efcd22bbedb78378f0a150845467e59f79a3f2a3b6a66bdf0d71d13c", + "0xa69a4ac47fd92e1926b5e14adcbebbef049848e8a00d4bb387340892e5a9333cae512f447201728d3b53c6cf980a5fdc", + "0x8fc713825277c5a8d9ef0a1f6219d141def6d8b30aff0d901026280a17d1265d563ff5192a0817e0e1a04ff447fb6643", + "0x8bf0a85569c4f0770ff09db30b8b2ea6c687630c7801302c17986c69a57c30f0781d14b3f98a10b50c4ecebc16a5b5ec", + "0x896baa4135d5621fd6b6a19c6d20b47415923c6e10f76c03a8879fd8354e853b0b98993aa44e334623d60166ba3e3ca9", + "0xb82cde1c2e75a519ef727b17f1e76f4a858857261be9d866a4429d9facf9ea71d16b8af53c26bde34739fe6ea99edc73", + "0xb1a9e1f2e34895a7c5711b983220580589713306837c14073d952fe2aef0297135de0be4b25cbfaed5e2566727fb32ef", + "0xb42ed0e9eaf02312d1dba19a044702038cf72d02944d3018960077effc6da86c5753036a85d93cd7233671f03d78d49a", + "0xa402e34849e911dbf0981328b9fe6fff834c1b8683591efd3b85aa7d249811d6b460a534d95e7a96fdd7f821a201c2c4", + "0xa774417470c1532f39923d499566af762fa176c9d533767efd457cc5e4a27f60e9217f4b84a9343ecb133d9a9aab96b7", + "0x83dc340541b9ef2eb8394d957cd07b996d2b52ac6eb5562cbba8f1a3312f941c424c12d1341a6dc19d18d289c681ef40", + "0xb2906c32d5756b5712e45dec53782494a81e80f887c6e1ef76e79c737625eccecb8fd17b20e6f84890d322b6ffde6eab", + "0xb89705c30cec4d50691bc9f4d461c902d6a4d147cf75ee2f1c542ad73e5f0dabe3d04cd41c6c04ab1422be4134cf1ad7", + "0x8c3293651f4c4fac688bf5837c208b15e5a19ce51b20dd80ffc7fca12d3e615b2773cfc3ed62a1b39c66808a116bde06", + "0x8fceb8ef481163527d1fc3abc7e1a5b3b6de2f654c3fe116d1367b177dcba2e0d2124a7216803513a3d53fc1e30435b9", + "0xb2a42c827da630aaa3eb20ed07d136aa11ba01b4c8efc0a57ebab7d5b851a15daa6ba118bcffbc20703916e430e30a87", + "0xa86340153abb3fe97414e2fde857e15aac27c9bb9b61258eea6766024f426ed0753f08f07f6b02b5375e1587ea3afcab", + "0xb006465e258e646f91ba889765113d3dc9bd657246c533cab6516d55ba054baa9d7276a3b0fa31730c3bd824845bf107", + "0xa08aadc09428719cde0050d064c0f42c5b7c4f6c158227d7636f870957d6cfe821b4c62d39279a7c98f5a75fcb7bbfba", + "0x885e7d47ce9b50d21b95116be195be25f15223a6a189387575cc76740174c3e9044f1196986d82856b3fb25cdd562049", + "0xb18c3780362d822cc06910743c4cbcef044823a22d12987fe2e56f3801e417f2e9cd31574ea1c5c6ee7673a14aa56e3e", + "0xa625570ef7d31c042d968018865aeeba34ee65a059ab1ec079c7a8ba1be9e24bce6afb7036c07d9d6c96ab014f95d661", + "0x8fc9bd4764adc4c300b5bd49a06dce885d1d8aff9bae68a47976d0cd42110aa6afa2d7b90b64e81c0f14de729f2fb851", + "0x91d88714cb669f5f00241aa5ab80dffb04109492ea9c72b59645eb1f85f3539c61db2ab418af986f42241df8b35445e9", + "0xb98f14e664df2590dd2d00b5b5c817e388e5d9fb074f718637c33b3d4969c89e82fdd12db8997f5ff3bf5bb5ca5dd839", + "0x86cb3d9f148cb2170317a4c22af7092155aa66ecff7ab1299b102fbbaa33ed2a284b97b08f529d2da9faea63fb98972c", + "0x92449f6b8a7c737ecef291c947cbd602c47d7fe47dc3426c2b413f3019169aa56e14c2a7216adce713e1c7bd5c08a83f", + "0xb08c1b9080bba88b44a65070948142d73c00730715fbdd01e13fc3415c5b4f3248ef514fa3ade4a918c9a820cccae97c", + "0xb0a05297da76e37c22be7383e60bba1cbc4f98ba650e12d4afcfcea569842003644a10ad73c9148958f7bf1ffa0a27d0", + "0x839092c1f4e9fb1ec0dde8176f013b0d706ab275079f00f8e774287dd658d1b5638d5fe206f5f2a141911a74bb120f75", + "0xa36bd669bdc055ece4b17ff6eac4c60a2f23324a5eb6d0d6c16a2fce44c39cfd52d1fa2b67f3f5e83504e36426fbfc40", + "0x8aa428323512cf769645e2913a72976d32da4c0062ffe468a6062fd009340f0f23c6b63285848a0e7631a907adb032a0", + "0x944800f7d43f41283eb56115ac39ccc5bf107ae5db6abcaba6936b896260cd09428a6b828c0bccebeb00541073dbf38e", + "0x8e700ca7c9e1538cf64e161dd8d16af56fc29d53c79648150d6d8c268b0c95c76acded723e29918690d66252bd75f5b3", + "0xb9c4ce35b5b16b4c39b6e85800c76b26e8d0999500fabc1e5b6234a7f8da18c621266ac0d5ebc085354297ff21ac89a5", + "0xa0c706d32063f1877f7e903048ce885f5d012008d4a8019dd00261a8bbc30834bffeba56cdeddc59167d54cc9e65f8fa", + "0x839813b736225087cbbcf24506ea7bf69138605036b764ec0514055ac174bbc67c786a405708eb39a6c14c8d7e0ec6ee", + "0xb1a5fef055a7e921c664f1a6d3cb8b21943c89b7e61524a307d8e45aa432e5765a27c32efdb32d88062cd80800a260de", + "0xb17f8202d9ed42f0f5cb1b1dbda60711de3b917a77f6069546fa3f86d21f372b8dd5cb86f1994b873ba9982404e08daf", + "0xb5211d54bd02d44d4d808ad57067606f3e9fa2cad244a5f2acef0edf82de3c496d2b800f7c05f175d01fa6ace28b44d1", + "0xaa9c6f8f489b35fdb7544116fe5102a34ff542de29262f156df4db4ea6e064f5ea20c4bd877d40377ed5d58114b68f19", + "0x826668b1f32e85844ff85dd7e2a8e7f4e0fd349162428bc9d91626b5ab21bdbacd1c9e30cf16f5809b8bf5da4f4fe364", + "0xb30d14917b49437f9fdbae13d50aee3d8a18da3a7f247b39e5d3e975c60bd269da32da4e4cc8844666fca0d65f4e3640", + "0x8c6918d8d94b36c6b9e772e9a432e66df16724e3b0660bde5ea397e6ef88028bb7d26184fbe266a1e86aef4a0dfe5faa", + "0x906d80ffd692c1dd03ab89be52e0a5a9e90a9cdbfc523d2b99c138ae81f45d24c34703f9cb5a666b67416e3bb6272bc4", + "0x8b07e8ba22b436e64f011cacf5e89c55cd3bfb72ae8b32a3a8922c4fccb29de6f73662d6e330da6aa6e732a2187ef3c9", + "0x9547466b4553a49adf59cc65d4c3c9401b2178947ebe3bd33c6e63cfb67d6be8729033158594f6f244b272c4487d6958", + "0xaafcccea41e05cb47223fa8dfec0dd55964268bd4d05e24469614077668655ac8a51d2ac2bfb22862f8f4fa817048c2f", + "0x870f8c1173e8fd365b0a2e55c66eea3ab55355990c311f3042377803d37e68d712edcc5a0a2e2f5a46df0c1c8e6310c2", + "0xb4288f792008f342935f18d8d9447fe4ddcfea350566e13dba451f58c68e27241af1367f2603a9dff6748e7fe0c53de4", + "0x91c58c0e537d3afdcf7783601dd9cda2aa9956e11f711b15403760cf15fc6dffb40ed643886854571da8c0f84e17adfe", + "0xa43fec8ee92febed32e7cdd4e6314a62d9d3052c7a9504057dfba6c71fdfbeff1cef945d8f087bd106b5bec7478ad51f", + "0x99cf5e0e3593a92f2ec12eb71d00eccec3eec8662333471b2cb3a7826b7daca2c4d57ffba18299189cf7364e2af5df6d", + "0xaf50f9ab890b7517ff1f1194c5b3b6f7f82eabc607687a8380be371a6a67b117aeb9b6f725556551b81f8117971706a2", + "0xaa352430887053602a54403bd0d24d6b5181b44aa976dfa190e21851699a88127dcc904c90a48ec44610056b5dcd36c4", + "0x964c821ea1902354736fa382a929c156bd67b9468d6920d47c27b9d0d304b6144118888d124c1f6785da596435ed2410", + "0xb2284a67af26b5f5aff87b4d8e12c78ab37c5eb6e92718fca8549f86f4f001b660fc4520456aff72c9bcddd686603942", + "0x83c54cbb997ea493dc75df4023071dce6da94268feaa2352373789616f012098270ba4fd60c791796a6f5062fb2cd35e", + "0x9143e8fee0b8f0f34c65c7750858093dcf165c6a83c026bfac2d5ffa746361eb4b6a14fdb43e403add901ac3735735a3", + "0x97d7748a5b278ee47b18c9e60689b12a0a05be47e58e78bf8c04b9e8b34e2e2f2d3ac3c25c76ab2e0a75e8a54777b7c8", + "0xb4e68f6f2d978a5411414c164c81ddb2a141b01ebe18c65a8626ca75d6432e5988310b50a888a78c3a0a242353525af5", + "0x8976f4cc3eaf2684718cf584712c4adaf00a4d9c521f395f937e13233b30329658b3deacfe7e29fac84c496047f2d36b", + "0xa40bcdf4b6e95f1535c88dddcbf2074ef2e746b7fd232bdfd2b88f2f6d4bbf21c6b263cf5fd3e12a03476f2f5ffe00d2", + "0x88c7b6337ee705acd8358ef6d2242d36b140afff0579a7784b3928a0c49698bd39c1f400e8a2e3eda5fbfb2e8f28fe51", + "0xa98612ba8b450a71d2075d51617ebeb7ca401ad3cbd9b8554850c65ef4f093ba78defb00638428c9f1f6f850d619287f", + "0xb7e71d3ffa18b185c1a6bd75668ff65d985efc0a0c19f3812cafde9adbfb59ffd108abeb376e6a8877fdf5061562f82b", + "0x8a3e5fd776cc26908a108a22b1b122d60cb8c4f483cbedcd8af78a85217bb5a887df3efed2b8b4ec66e68eb02a56ca93", + "0xb0d92b28b169d9422c75f9d5cb0a701e2e47b051e4eacd2fd1aa46e25581a711c16caf32f40de7c7721f5bf19f48b3f5", + "0x88895739d5152282f23e5909cf4beebda0425116eb45fc5a6a162e19207686d164506c53b745fb2e051bb493f6dbad74", + "0xadbccfed12085cd3930bd97534980888ee564dda49e510c4e3ca0c088894855ef6178d5b060bca8a8a1a427afdbec8a8", + "0x87d00674abd3d2e7047a07ed82d887e1d8b8155635887f232dd50d6a0de3fb8e45b80b5a05bc2ec0dea9497b4aa783ac", + "0x806e1d3dfadd91cbf10e0d6a5e61738d0dbff83407b523720dce8f21f8468b8a3fc8102acf6ba3cf632ca1cb2af54675", + "0x95a9dff67cf30e993071edede12623d60031fa684dfbe1654f278a1eb1eb7e1be47886d3f8a46c29b032da3176c0d857", + "0x9721973288384c70a9b191436029e85be57970ad001717edc76d44cbfa0dff74f8af61d5279c5cd5c92c9d0f6c793f63", + "0x95c22d1d9b51ef36ba30ee059dcd61d22be3c65f245d0a5179186874219c08e1a4266f687fc973e71f3e33df2b0f7fd3", + "0xb53ec083dd12cc42ae2bae46883a71f2a35443c9ce4ed43aa341eb5f616a53b64211ed5aac717fe09ef1d50f551ed9f0", + "0xa103dab6695c682400f60be8d5851ce07f12e4bd9f454d83b39c41ddcf1443bb14c719b00b4da477a03f341aa1e920cb", + "0xb522236988518e5363b1c4bb3f641ff91d3d4c4d64c5f065415b738160b4ce4b0c22e1e054a876aa6c6a52fa4a21dfa2", + "0xa6a00562f0879702cdba5befd256a09f44bf48e61780e0677ff8c3fda81d8e6dc76ba1b05e3494ca9a4cef057eba6610", + "0xb974a2ae631e0b348421f0cda5bd4ce7d73c22dd0fc30404c28852c33499818cab89fbf5c95436d56a0aab3bf2bbab51", + "0x9148cf2a7b7e773245d4df5a9d34cf6d9d42b1a26a4ca6bc3013feca6f3941d6c44f29ba9328b7fe6ce6d7f6565f8e4a", + "0xa34035c4a63e98528a135cc53bbbcfcda75572bc4c765f212507f33ac1a4f55563c1a2991624f7133c77b748bbe1a6da", + "0xa0c45923cfb7bd272ee113aecb21ae8c94dda7ad1fe051ddb37ab13d3bb7da5d52d86fff9f807273476c24f606a21521", + "0x81ec2ca57f4e7d47897d0c5b232c59d7b56fe9ce0a204be28256a7472808de93d99b43c824a0cd26391e6cac59171daa", + "0x8373852f14a3366d46c7a4fc470199f4eebe8ee40379bd5aae36e9dd3336decaead2a284975ba8c84d08236e6b87c369", + "0xb47e878a93779f71773af471ba372cb998f43baca1ae85ea7ff1b93a4dee9327e2fb79691c468ec6e61ab0eae7ceb9f1", + "0x8fc8f260f74303f26360464cfef5ee7eebcbb06073cef3b1b71dab806d7c22f6b3244ce21d0945b35c41f032f7929683", + "0x87e3c4e1dab00596e051ce780b9a8dba02ecdc358f6ddaeb4ec03c326e4b7da248404745392658eb1defff75b1ba25c8", + "0xaac95d8e3b7fe236a7ca347d12a13ec33073f2b2b5a220ecfd1986ca5c3889f0e6a9d9c377a721949aa8991c1821953a", + "0x91a483679437ae126a16f5dc3bba6e9bb199dfbba417f0dc479f22819b018c420edc79b602db6183c6591b1909df4488", + "0x94a4b2c663aa87a2417cad4daf21a88b84983a7b212ffcd18048a297b98e07dd4c059617136976fac1d9e94c8c25b8d2", + "0x83e2a690bfa93c79f878a63c0f69f57aabdd8bede16b5966ffba7903dc6ad76775df1fd5347e6f2825f6cd7640f45a45", + "0xa316af7ac11b7780d15312dc729499a1a63b61c4283e103ecce43c3b0cbb0f4bce6ff04e403f5c7cb670dee80c75ab99", + "0x8d0a911c54ee1f9f7e7794732ad87b434c3f356294d196a5e35eac871727fd32a49c27c2dfa10833f9e6f9c7ccbe0064", + "0x8b8db09028298a1f6362b346c8bfeced7cb5d13165a67c0559a9798a95b7a4a9810c02bb852289d47c59f507bd24ce77", + "0x962d57305c518f175ed5d0847fb52ddc4258ca0e4c9ddfc8c333a2ee9f8b4e48d25a3d7e644b785a5953e2e4063da224", + "0x92e0799491898271769250fe88b0cb9dadec98ac92f79de58c418d23ef8c47fcf21ddc90e0cd68bb8f1deb5da82da183", + "0x99855067125f6a6c3a3e58d3bd2700a73ef558926bd8320d2c805a68e94207b63eda6bdc5a925ec36556045900802d51", + "0xa724ae105ab4364a17ddb43d93da1e3fc6b50213f99b7be60954b24dc375c4f93a0737f4a10b4499b6f52667d5f3a64e", + "0x82070fb43a63fb50869b118f8940108f0a3e4cc5e4618948417e5cc3801996f2c869d22f90ca4ca1fdbef83c4778421a", + "0xb25c04365d6f24d5d3296c10d85a5de87d52a139ddbcbf9e0142074bc18b63a8bc5f5d135bd1e06c111702a4db4cee28", + "0x851093282dcda93e5c98d687a17a7ee828cf868f6c85d372d9ae87f55d0593d8f9f0c273d31f7afa031cf6aea6a7ef93", + "0x93f04f086fa48578210ed207065d80a40abcc82d8bfc99386a4044561d35748ff6c3da6489933c23644ad4b60726da8a", + "0x84b1b50d1e876ca5fc341bbedab5b3cc0f6a3f43ea7dd72605f74d0d9c781297b2f12b7872dd600924f1659a4cdf8089", + "0x81b0ba88c582d3956f6b49ca3e031c6400f2ec7e1cd73684f380f608101e9807f54866be0bb9a09c03953c4c74fbb3c8", + "0xa641af6ac644c41a55dee2ef55d3c37abdb19d52bc1835d88e7adda6b6ccd13987c5fd9cba9d318cabb541aa6a0c652e", + "0xa7b75b0624d04ad0901070e691eb2d2645b60f87e9d6b26e77a5fb843f846c32fc26e76ae93fd33fe3b857f87bc25162", + "0xa81ba3e2ed0f94c67cd02ba7360e134f8becf7ed2ed2db09b9f5ef0942f7073bfee74ca446067db6092f7b38f74ccc11", + "0xab80edcabab5830a24210420f880ebac4e41bf7650c11ba230f4889634dbf8e8e2309f36be892b071c67a3bab8fc7ed6", + "0x94d69b64675076fecad40fae4887fb13a8b991b325fa84e9d2d66e3b57646de71a58ad8fd8700fefb46975b18289250b", + "0xb44fc0df480cd753a041620fa655be9df74963ae03d4625847d5bb025ceb37f48d19c8c9c444546fba5fe5abb2868506", + "0xb56e2c51324d6200b3d9781b68b5b5e1617a68afccd28b3a12a4be498d2e3aafcd86514c373a9f3a001db733010c29cf", + "0xa359a0c172e5cd7ce25080dd2652d863d7c95a4a502ae277ac47f613be5991300f05978404a0acb3bcda93524dcf36e4", + "0xb01427a3dfdf8888727c0c9b01590b8ae372b7b4080d61e17ccb581bac21e61c4a58c75db7a410d1b2a367304e1e4943", + "0x95cb08be4a96c18fbf9d32a4bbf632242029d039a5fdea811488d3634cd86520d4f9806250a8c01855ee2481210f542a", + "0xb8594fe6c0717164058f08aedeed1853523f56cec5edbf0d2be271fa5e8bfd61f2974b0f3988d70f5baa2e7888c7ec1f", + "0x8f64ee89f59daf74fa1056803247c9d678783ee3917b12a201f30f7523957763e979ceaddb38bae20de40b9885728049", + "0xb6093ee4bdb837bcc59172e236f4bdbd439c0a5a50e2aa16636cbff81b51e92989eb5f80a3f75c37ae7b5b942e55b3d2", + "0x913b6fbb7b43e3e5c49e96cd8e82ed25c655e51c7b8ca82e8fbf92b01ac83c39d52f6f4efab5d39b0591a0538601a86f", + "0x81f42668479ca0bec589678dc0973bf716b632578690efe1a0f13de630f306fb4a189a98c2302572fd85d3877ee030b5", + "0x90ff89c38a9a7189f28d35a088657f52283670e7fec842fa91c265660ea2e73b0ad6c46703d649f406f787490b7a7e4b", + "0x9077b8b5f1e083183f3152ceb9c5491b5d4b86525a08879f7fb6d5e27f9f1a6867cf0d81b669a4a2d1f1654b67fa8d9c", + "0xa7a0275cf5b894adbf2e54a972310cfe113e811872111d6ee497d03750d9f6ffa5517b6c13a99b111a4a91e8e4dfeeee", + "0xa08976bf8125b7538313a584bbe710741d630cab067a204ad4501cc4938874ce7aa6a1a826259c2e82ef10a66f1f36fa", + "0x8aa45385b5b97f1f3e45f2bbf7a4f3e8ef068e628608484971c97adeb610ebd5deec31317e03eb6536808921062c04db", + "0x945b106b8f3ae85e60dfd34ef3dcc079bc6f0aab6df279ed000856efd51321462038ac0a1ca5db3ebf6379bc341e7c55", + "0xa4199c87a96f98cc9d8776fe6de131d2c706b481eb9e9a3bbc50a93d492d7fd724ea469f723fbcfb94920cb5b32c1d76", + "0xa5347b1b2f6149805de67546c5ed72253311099bf1473dbc63edcf14a0a5e68d401f5341338623fbe2e2715b8257e386", + "0xaf5dcd03ddc3769e83351d6b958d47a06d4e5224bd5b0ec40ffe6b319763fab8572002f4da294a9673d47762fd0e6e1d", + "0x82ec1031b7430419d83b3eea10a4af4c7027f32b91c3ae723de043233b4a2e0c022c9e0f5a1ac49753800f119159112d", + "0x8a744d911b67d03b69811f72e9b40d77084547e4da5c05ff33893468b029a08266fc07303f7005fd6099683ca42b3db4", + "0x93ab566bd62d3439b8fc620f3313ef0d4cb369f0f0c352cdaf8e5c9e50b9950ac3540b72f4bf5adcb9635f9f7ce74219", + "0xb2a211d72e314799bc2ac7030b8bbb8ef4c38ebd0ebb09d6cbd43bd40c6c61d80a3aad02cc73f5775a08b9657da20a48", + "0x98d60f0a98d28718e0c6dcccc35a53521ea7f2d8fe08ea474374a336b44cea4cd1c63b31f2ad10186822bfb54aca53e6", + "0x831f89cb94627cfe554d46ae1aad8c1cde7ebe86c4bd8fac4ef73ac2d5b491f5efa5dc4198cb8ffbec563e0606b91d89", + "0x8f8552583bc6cb3fb176b7202236ee4128faf0c8ec608f9150f8e011d8c80b42aab5242c434d622b6d43510eaef752c0", + "0x897bf27baaee0f9a8445200c3d688ae04789c380d1b795557841606a2031092328eb4c47fef31c27fdd64ba841d9d691", + "0xb57589a4af8184b4a8ceb6d8657a35522672229b91692c1cec3ac632951e707922a00086d55d7550d699c4828bcfaab1", + "0x98c2fe98095e026aa34074bcff1215e5a8595076167b6023311176e1c314b92b5a6d5faa9599d28fca286fadd4e3b26c", + "0xa034992e563bd31ede3360efd9987ecddc289bc31046aa8680903bb82345724805e6f6cf30f7889b6b95cf7319c3aea1", + "0x85c33d9f10cc7185f54d53c24095e621966065e0ff2689a9aa6bb3d63706796c37a95021738df990c2c19493c0d44b64", + "0xa8c1247d6de2215f45b50dd2dc24945ff9b93184bcc2159b69703b0bba246adcd1a70a12659f34c4ca4ba27dea6e3df5", + "0x83ebdad2834c97bf92aac8717bab2f5cb1f01026b964d78e2f3b44e99d7908e419165b345d2b2f125b903096584e6683", + "0xb0af6f7f81780ceb6e70adfd98e7702ec930c8ca854b50704c4a0fc8b887b9df60a6fe9038b487f3ed0eb8eb457307ea", + "0x933ec7e53882453898617f842ab2efae4756eb6f6ea0161cced5b62a0cdde4c08c7700d52f7546d4dd11a4c9e25d624e", + "0xadf6e6d4706025f85eb734f506dde66459c9537a1abf6189199cf219ae583b461e11c6242fce5f0795e4d9025270fabf", + "0x89e4316319483098761b0b065df4cfb542963b7a2556ba5425b6442fb0e596eb2a4f03e2dc8c617eebe8f243a12e7d10", + "0x90c5a147555759ebc4d0e15e957a548315f9994ef0c7a3f53f2d18da44fb93bf051d96ba8551597a6f3e701b926fd791", + "0xa151a9a5199c72c697b771cd81e550fc6f9596c752ae686ad988b316a7548360cf9785ab4645164d96cfdf9069a94020", + "0x80cba11a3977729d7948db5bcc186159f4cae7c0a835bb38bb781e287dd6c238508e748f23454405c9d5eed28e77df02", + "0xae4b92ea03cb8ad12ad3ec76869ad05acb09f9d07a3c9a87dec0e50d9a276fe5d3d515a8c446f3aa35cd7d340a22c369", + "0x8630062709a1f180f952de9f1ca3f41acce5420677f43d9619097e905a6237f1908d66db7a4dfdf1b2b92fb087e9944f", + "0x81defc33dd383d984c902c014424bddd5e53b013f67f791a919446daa103b09b972fa5242aba1b1dbe4a93149373f6c3", + "0x963891ecaea97e661bac2594642327a54f5a0beb38fcb1c642c44b0b61faab9c87b0c9f544a3369171b533d3ab22f8f1", + "0x932fadbff5f922ddcd4da942d57fe3e6da45c3d230808d800a3ca55f39b0b62f159be31a5924b395d577a259f48c6400", + "0x992ce13bd037723447f88aeb6c7722fd9510c7474192b174ea914ed57c195c44c298aec9a8cabac103f0a5b50051c70b", + "0xb032157b3e4fe69db6ce6bb10bdf706a853fbd0bee08c2ab89da51ad827425df5df498b90e7a30247a7f9e954ca986e5", + "0xb2478d4874578da3d5000893736bb65712e6aafe96e6fa5cf5878ae59ba0ce640dbe5d76ec2b5baca75af57def471719", + "0xa387c17b14dd54910fecf472f760e67cf71a95e9e965cc09484e19581ada65e79938b86136a93e287e615fbd4908e080", + "0x98f02be271d0f8841d8d561163f9e55e99b57aff121a93fba7a4654bcf15a0899811f00f5bcbfbebd98e365a0e332e97", + "0xa3c34f01d54cab52a8890391b8cf152cc9cdc16e7e53794ed11aa7b1a21e9a84d39ddcfbcb36c5df6891c12307efc2e0", + "0xa940331f491ec7ad4a9236ca581b280688d7015eb839ee6a64415827693d82d01710dc4bbd5352396be22781fea7a900", + "0xb10874ed88423731535094031c40c4b82af407160dfade4229ac8f4ef09d57b3db95c4a9d73c1a35704f6bd0d5f6c561", + "0xa9c5a4a7680261c1b0596f8ab631d73d4a7881b01e6559c628b5cdafa6dd2b6db2db64f3f2ab5841413a8a52b966a0da", + "0x8fc154564a61d5e799badc98b43a3587f804385a850adce9a115cbd2ad911f3fd4072b8e6b22fc6c025a6b7e7ea5a49f", + "0xb9caf7c6dcce3d378aa62c182b50bc9c6f651eb791d20fffa37ef4c9925962335fe0b3bc90190539312aa9ccf596b3b9", + "0x90c5b7acf5cb37596d1f64fc91dee90f625f4219fa05e03e29aebea416c8e13384f2996f8d56791bcf44ae67dc808945", + "0xab8d311fc78f8a1b98830555a447c230c03981f59089e3d8a73069d402a3c7485abe3db82faf6304aaca488a12dbe921", + "0x8a74fda6100c1f8810a8cacc41b62875dd46d5c4a869e3db46202d45a8d9c733b9299dda17ce2ad3e159122412a29372", + "0x8769dcacba90e6fc8cab8592f996c95a9991a3efecfb8646555f93c8e208af9b57cf15569e1d6e603edac0148a94eb87", + "0x854fd65eea71247df6963499bafc7d0e4e9649f970716d5c02fbd8708346dcde878253febb5797a0690bd45a2779fa04", + "0x83e12dc75ef79fd4cc0c89c99d2dace612956723fb2e888432ec15b858545f94c16fae6230561458ceee658738db55ba", + "0x8416ef9ac4e93deff8a571f10ed05588bef96a379a4bdcc1d4b31891a922951fa9580e032610ac1bb694f01cb78e099b", + "0x93aea6e5561c9470b69d6a3a1801c7eef59d792d2795a428970185c0d59b883ab12e5e30612d5b6cde60323d8b6a4619", + "0x91d383035aa4ec3d71e84675be54f763f03427d26c83afb229f9a59e748fb1919a81aca9c049f2f2b69c17207b0fb410", + "0xb1c438956f015aef0d89304beb1477a82aed7b01703c89372b0e6f114c1d6e02a1b90d961b4acbb411cd730e8cacc022", + "0xa1ee864a62ca6007681d1f859d868e0bcd9e0d27d1da220a983106dc695cb440980cfdb286e31768b0324b39ae797f18", + "0xb57881eba0712599d588258ceada1f9e59c246cc38959747d86e5a286d5780d72d09e77fd1284614122e73da30d5cf5c", + "0xa48f9ae05ba0e3a506ba2e8bbce0d04e10c9238fa3dffa273ef3ffe9ec2ed929198a46507c0c9d9b54653427f12160f9", + "0x8db18da7426c7779756790c62daf32ae40d4b797073cd07d74e5a7a3858c73850a3060f5a3506aae904c3219a149e35d", + "0xa2bf815f1a18d7be8ce0c452dfc421da00dcd17e794300cdd536e4c195b8c5b7ccc9729f78936940a527672ac538c470", + "0xa34c6f1f2398c5712acc84e2314f16d656055adcafad765575ae909f80ab706cf526d59e5a43074d671c55b3a4c3c718", + "0xb19357c82069a51a856f74cbb848d99166ce37bd9aca993467d5c480a1b54e6122ebddb6aa86d798188ea9f3087f7534", + "0xb440eac6f24d12c293d21f88e7c57c17be2bdb2a0569a593766ae90d43eccf813a884f09d45a0fb044ee0b74ff54146a", + "0xb585d42ef5c7f8d5a1f47aa1329f3b1a566c38bf812af522aa26553010a02bfd6e9cc78fdb940ef413e163c836396a5f", + "0xaca213b27f3718348e5496342c89fffc7335f6792283084458c4a1aa5fe0a1e534fcec8e7c002f36141308faae73ef2a", + "0xb24c07359769f8ffc33bb60c1f463ea2baad440687ef83d8b7c77931592d534b2c44953c405914ace5b90b65646c1913", + "0xb53dfaf381205a87ca4347328ff14a27541fa6436538f697824071d02d4a737ceb76a38dcc6e8dadef3b5bc6442f5109", + "0xb55972d8ed5197215c0a9144fc76f2cd562ca5f4e28c33a4df913363fd1388978b224c44814adb4c065c588a4ac1fe10", + "0xa3303bc650e120c2e9b8e964ad550eb6ac65ffe6b520768b3e8735565ae37eafdc00e3c15fae766d812f66956a460733", + "0xb11e53912ea0e40c3636d81d7637e10c94cc7ed9330a7e78171a66d02b7603f4cb9b3f6968104b158de254e65b81640f", + "0xb076bb9f6d396aa09c2f4706ea553b426fdfd87d7d69e438285b74d334e82f73973cb4dbd6cb1647493433dad65dbc41", + "0x9415828b1632175f0b733541e32c26a9c88fe12c721c23e595f2efceaa7f867f359e32564b7c032185686587ac935cf4", + "0x89579a112c306181c79aabdbf683e7806357febcb73bf5e8883862ae29618ef89498b62634404bb612d618fcd16da415", + "0x8761bcd55d04297c4f24899e8fb9f7c1fcd7449ae86371ee985b6a262e228f561c2584980694d9bf354bdf01543edb6a", + "0x9100c88bf5f6f00305de0c9cf73555f16a2016d71c50cb77438e8062bd549fa5407793a8a6a7e06398756777680a2069", + "0x9235dfef45aeff9c174898b0755881b7171ed86362854f0eabc3bc9256176c05a5dc27ca527c91c3fa70c0ec5fd5e160", + "0xac53b1d677cebab6a99381dd9072b8ac1abae9870ec04a1f8d2a59b6f1de797c1492b59af6948f5cf2b20599170f5bba", + "0x946542936b0c59156e8fd5c1623b41369bc2cbcc46ece80360dcb5e7cce718a3dd8a021f0b9c223062a4e43d910b634f", + "0xb1e9939b34e1fcc026e820fcfa9ce748b79499f8e81d24a3ef0457b3f507fe5fa37b975a47c143e92eb695623b4e253b", + "0x9382d9b5766f6ae960d8a8435e8b5666e57ef8e5f56219e7bfd02857afe5cb16f44d70a9e444cfb1008649ae9b863857", + "0x91770ed1215ed97dca1282b60b960be69c78e1473edb17cd833e712632f4338ff74bf435c3b257439497c72d535ae31f", + "0x8eb2cbe8681bb289781bf5250e8fa332141548234c5c428ff648700103a7cd31fdc2f17230992516c674aa0ab211af02", + "0xa823b71c82481bc6ac4f157d5c7f84b893a326bbb498c74222427ded463d231bc6e0240d572ab96266e60eb7c8486aea", + "0xa13ce4f482089d867e5babcd11c39fa9a9facd41a2c34ee2577de9ce9c249187e16f2b3a984cc55f9e45b9343462d6d2", + "0x8d80e7bc706059cf5151f9f90e761b033db35d16b80b34dc8b538adc8709d305a0c06933dcd391e96629cf3888c8bf87", + "0xabcd36cdd86c0fb57fb7c0d7a3b9af5fd9aed14e9f4e7e84b0796c5c0ad18c41585e8c46e511cef73dc486fe43f6a014", + "0xa947a5b6916f416fa5a69c31aba94add48584791148b27d0b3ed32c02a05dfc06f7fdc5006e3b2503bdf6e410e30f2fb", + "0xb158e621580659f1fa061d976b8591ac03b53ecd23d9eb2b08c1a20353d78438287749664d196020d469ef44b3b8752e", + "0x90a5a9540281e481ac4b8d29968f477cb006b56bd145529da855d65d7db0cf610062418c41a1d80c4a5a880c0abe62a0", + "0xb2c91808b6289d08a395204a5c416d4e50a8bb1a8d04a4117c596c4ad8f4dd9e3fb9ce5336d745fc6566086ae2b8e94f", + "0xaf6767c9b4a444b90aeb69dfddae5ee05d73b5d96e307ce0f3c12bccca7bc16475b237ba3bc401d8dafb413865edf71e", + "0x8dcecf624419f6517ef038748ac50797623b771d6111aa29194f7d44cfb30097ced26879e24f1b12a1f6b4591af4639b", + "0x954437559d082a718b0d6d7cec090532104ab4e85088e1fc8ee781d42e1a7f4cdb99960429707d72f195ff5d00928793", + "0x80f0b7d190baa6e6ab859dc5baab355e277b00ddcca32e5cebe192877ad1b90ead9e4e846ca0c94c26315465aeb21108", + "0xb8c29f181ed0bb6ac5f6a8d9016980303bb9a6e3bd63ce7a1a03b73829ac306d4fab306ac21c4d285e0d9acb289c8f2a", + "0xa7685079fe73ecaeabf2a0ef56bad8b8afb6aeca50f550c97bf27e6b4a8b6866601427fcd741dc9cb4ce67a223d52990", + "0xada2ebf6f2a05708d3757fbf91365ec4d8747eb4c9d7a8728de3198ceac5694516ab6fd6235568aecd8d6d21fef5ef48", + "0x846bc5da33d969c53ab98765396cab8dcdbb73b9836c9bda176470582a3427cb6de26d9732fab5395d042a66bdba704c", + "0x800a3a7ea83ce858b5ebc80820f4117efa5e3927a7350d9771cad9cb38b8299a5ad6d1593682bba281c23a48d8b2aa71", + "0xa002b18595dec90b5b7103a5e3ec55bdd7a5602ee2d3e5bd4d635730483d42745d339521c824128423dfe7571e66cbaf", + "0xb6b4e2067ac00a32f74b71007d8ab058c2ef6b7f57249cb02301085e1a1e71d5de8f24f79b463376fd5c848f2ab1c5bc", + "0xa3e03036db1b6117efe995bf238b0353ad6f12809630dca51f7daaaf69f7db18702e6b265208944bfb1e8d3897878a51", + "0xadd16712f66d48aab0885bd8f0f1fb8230227b8e0ffca751951c97077888e496d6bfab678cb8f9ffba34cee7a8027634", + "0xad211af2dd0748f85a9701b68c19edd4a7c420e497cb2e20afdc9df0e79663841e03b3c52b66d4474736f50d66c713ce", + "0x8c8a899ce0f16d797b342dc03c2212dda9ee02244c73c7511626dba845d11a0feb138441da5459c42f97209bf758cd9b", + "0xa17efc75c7d34326564ec2fdc3b7450e08ad5d1de4eb353de9d1cd919d90f4be99f7d8e236908b1f29cf07ae1ffe0f84", + "0x862d4a8b844e1b0dd9f4deff180456ebed5333b54290b84f23c0ddb2725ac20307e21cbb7343feac598756fe36d39053", + "0x9187fbb19e728a95629deda66a59e178f3fcd6e9d7877465aa5a02cea3baba2b684bd247b4afbf4aa466b64cb6460485", + "0x85ae5636688d06eab3be16e44fe148515d9448c6123af2365d2c997f511764f16830610a58d747adab6db5031bea3981", + "0x8aa8a82891f4e041ce6df3d6d5d7e5c9aaaffe08e0a345ac0a34df218272664c1b7be2450abb9bc428bd4077e6e5dcc4", + "0x8c3bcc85ea574dfe1b9ca8748565c88024e94374434612925b4e9a09fa9d49c0a56b8d0e44de7bd49a587ef71c4bff5f", + "0x9524f9dd866fe62faf8049a0a3f1572b024120d2e27d1be90ad8b8805b4e2c14a58614516281cc646c19460a6b75587c", + "0x84580d9c72cfa6726ff07e8d9628f0382dc84ce586d616c0c1bd1fd193d0a49305893eae97388de45ba79afe88052ee9", + "0xb5573e7b9e5f0e423548f0583423a5db453790ab4869bd83d4d860167e13fd78f49f9a1ffe93ddddf5d7cd6ec1402bc4", + "0xaff658033db3dad70170decb471aee2cf477cf4d7e03267a45f1af5fd18200f5505c7ce75516d70af0b0804ec5868a05", + "0x84a0eab4e732a0484c6c9ed51431e80cea807702fa99c8209f4371e55551088a12e33a11a7ef69012202b0bc2b063159", + "0xa68f8e730f8eb49420fe9d7d39bb986f0584c1775817e35bb3f7dae02fd860cddf44f1788dc9e10d5bf837886b51947f", + "0x946002dd6cf7a4fd3be4bf451440e3f3fd7e9b09f609fa4e64767180b43146095dfc4b6994287f8cfa6d1390d144be71", + "0xb7f19777d0da06f2ab53d6382751dc5e415249d2c96fce94ef971401935c1d1f7d3b678501e785cf04b237efe2fe736e", + "0x81e5c66dd404fc8ffd3ac5fe5e69ead7b32a5a7bc8605a2c19185efcc65c5073e7817be41e1c49143e191c63f35239c1", + "0xb5f49c523532dfa897034977b9151d753e8a0fc834fa326d0f3d6dacc7c7370a53fc6e80f6d5a90a3fbec9bbb61b4b7c", + "0x8fc8e78c07319877adfaa154a339e408a4ae7572c4fb33c8c5950376060667fbfc8ede31e1b067933d47e3fdbf8564d7", + "0x859cfef032a1a044532e2346975679545fbb3993a34497ce81bdcc312e8d51b021f153090724e4b08214f38276ee1e0d", + "0xae476722f456c79a9c9dfdc1c501efa37f2bff19ab33a049908409c7309d8dd2c2912aa138a57a8d5cb3790ca3c0ba2f", + "0x89acbbeffb37a19d89cfe8ed9aa8b6acf332767a4c54900428dd9ab3bf223b97315aca399c6971fe3b73a10a5e95a325", + "0x90a4a00418fdf4420a4f48e920622aae6feb5bf41fd21a54e44039378e24f0d93ccc858d2d8a302200c199987d7cb5e4", + "0xa3f316b0bd603143eba4c3d2f8efe51173c48afe3c25b4ca69d862c44922c441bd50d9a5040b7b42ba5685b44071c272", + "0xa22f4dc96fedd62b9a9f51812349e04d42d81d0103465c09295a26544e394a34abdc6ded37902d913d7f99752dbfb627", + "0xa49f51baf32d0b228f76796a0fef0fe48a0c43ec5d6af1aa437603d7332505be8b57b1c5e133bc5d413739f5ae2ce9d0", + "0xa9e4fe133057a0cd991898e119b735b31a79811307625277c97491ff5d864c428cfa42ae843601d7bb05c0313472d086", + "0xb987edfe0add1463a797ff3de10492b2b6b7ef0da67c221ab6f0f2b259445768a73fbe495de238c4abbe4d328e817c49", + "0xb7f0e4532a379a4c306bbef98b45af3b82b17175dfe0f884222ed954c12f27d8a5bdd0cdeb1df27ff5832ba42a6dd521", + "0x9471bc5ad5ec554acfd61b2eb97b752cb754536f95ae54ca2cbd1dc2b32eb618881f6d8a8b2802c1a4e58c927067d6cf", + "0xb4c84f09225cf963c7cc9d082efe51afbbbe33469dd90b072807438e6bde71db8352a31bb0efde6cd3529619812ef067", + "0x8f08005a83e716062d6659c7e86c7d3b51e27b22be70371c125046de08f10ea51db12d616fbf43e47a52e546e7acaac7", + "0xa8937e66a23f9d9b353224491f06e98750b04eca14a88021ee72caf41bdce17d128957c78127fba8ef3dc47598d768a7", + "0x80ad991de9bd3ad543cddeaa1d69ca4e749aaefb461644de9fc4bd18c3b4376c6555fc73517a8b1268d0e1e1628d3c1f", + "0xb22f98bca8fe5a048ba0e155c03e7df3e3cee2bfe8d50e110159abdb16b316d6948f983c056991a737b646b4d1807866", + "0xb0bb925c19ca875cf8cdbefa8879b950016cc98b1deb59df8b819018e8c0ad71ea7413733286f9a1db457066965ce452", + "0x95a991e66d00dd99a1f4753f6171046a5ab4f4d5d4fe0adfe9842795348a772d5a4a714dba06b4264b30f22dafa1322f", + "0xad91e781fa68527a37c7d43dd242455752da9c3f6065cd954c46ae23ce2db08f9df9fec3917e80912f391c7a7f2f7ffa", + "0xa202d3becbf28d899fe28f09a58a0a742617c1b9b03209eca1be7f072a8ada1f7eac2cc47e08788d85e1908eb9d3d8ee", + "0xa360ccb27e40d774d5a07b4ebed713e59a0d71b3ee3f02374e7582b59ec4a5ce22cc69c55e89742ba036dd9b4edd8f34", + "0xa10b897a946882b7c9e28abbb512a603ffa18f9274369843eb3491524a321df1f572eea349099ac6e749ea253c901ea0", + "0xb782a672cd344da368732ecd7e0a1476c2af04613d3eb6da0e322f80438af932bd6d49be7a6f69f7c877512731723d89", + "0xaeccee8dfd764e1adcfc4bf669e0fa87a94e7c79324333e958df47888bff5cec358b8b5bbb48db54822b54d11bbb4bc6", + "0xad4953913662a9ee8753a354864339f43916f2c2390d0a3f847c712b42718ee00ee14158d730709971941e8680d54560", + "0x92ccb31d6c9e8940c7e8a4873e7eb9de9fb2fa2bac344fa367062ea451fd49a6920a45218dca3ee968711397d2a01536", + "0x9448d9b2b3d12dde9b702f53373db8b8595f9d1f9de2ebee76de292f966f375316953aadf6bfc0e4e853e1fa12d8f02c", + "0x8919230878a7219da8c80a4b7d00b9169fb503e72d79789dd53863c243b8d0fb0a819d46fa636d805d0b9b1d15d1f2d9", + "0xb6581ab01215aac023f5e6f57419b6aa63c0743c07caf57d4e146b56b02d90ce1423f70489ac3a11e5c968cb924f937c", + "0xa793ec1b1fe56a76920296af06073caadfd6f1d7e30950f8ca13de3de45fe275ca4b361f5249d9405264c3a06ebb5502", + "0x86385b4a4e1bfb5efe7bfef8fd0dfeba7f4400852237cab60febb1dfa409e497a649e81284b5a15fe680b78927256756", + "0x85d10600de96103daa7c90657174b6cb4a1286df5379f1eda9f11c97f9df57043c290eb1ae83658530fe0fd264867b86", + "0xae01b2396d0f598c21659cd854c15edd4904a34d22278aef97c9260a14a8b250b52d972d304ac4b187c24d08795d5355", + "0xb91b3e4b6fc06e88081fe023ef1b773d82c628eb0f73a2731a9aa05b0dc89b7aeef2eea60125d302e696f45c407aeac2", + "0x986d0f478e33af7568eab6bb26a55c13ffd7cae27525b4abe2f3a994bdb11bbc73d59bdb9a2f6b6ba420a26f8f620ba6", + "0x9746f4fdeef35feaff1def0ea5366b64f21ed29749ae6349f9cb75987e7f931952f913f446100f2a6b182561f382e8eb", + "0xa34a116cfde1acbce0d7de037f72a7ca30ab126d8f4815b2b8bcb88e0e6c89015a4daaf4d4ce8eae23eb5d059cf9a5cf", + "0x80c3ea37f6a44f07cc9c9c881990f2a5deb9f9489a382718b18a287aa3c50ee6ebe8fd1b3afb84a3cf87f06556f4ca15", + "0x97cff3bc88cfc72ce5e561f7eeb95d4ffb32697e290190c7902e9570c56b3854753777fc417fd27536fc398c8fefb63b", + "0xb8807232455833e4072df9bffa388ae6e8099758c2a739194719af7d9ed4041974a6cd9605f089de8b43f0e12f181358", + "0x96f79fca72f75dc182c71f2343f0c43b06d98563fd02d2e1fbc031b96601608d8a726c811a74bb51ab8b0a3ce3632dc4", + "0xb5262761680a4235a8c1257de4735cdcadf08d5d12c6e9d4f628464d5c05dfff3884a9ef2af3b7724b5a8c97e6be74eb", + "0xb6ce0eada73433d98f8fae7d55e4ea2b9d9d7a0ae850d328dd06991f27b1f03e470868fb102800ff3efe4ee1698531b9", + "0xa37b7d9fe9d3fdfbc72c59cf6cacc7e7a89d534dea3d73121f7483331aec8ab3fbff58ffabb943b75d6f86df0ba43262", + "0x93fce9be8a27fcaa1283d90d3e87265a6221ee302ec708161a42bd00ffe8e726743d9e187e1bf4307c0e3f25afbb1d44", + "0xa4ea919021346ae7ea69d5e8f46d860b24c35c676b62f4e577c90e0c05c5646fe73721b143b7c38835dd4b443e6c3676", + "0xb79983a5948453f70dfa4c396ce1945204498fe79f40c0667291bd0fdd96ed0b9ea424571f7ade342275c854c9f03d9e", + "0x866f8e395ed730b614b70bf999cad6e87e9086c1f5aea8d69020b562ee285dd0fb93afaca0dd13a0713f74a3f9340f01", + "0xa3fef158782292c6139f9a0d01711aa4ed6f5cac11d4c499e9e65c60469ae3afbde44fb059845973a4b3bbca627b7eb7", + "0xb4a2c0321b68f056e7d8051beede396fa2f0704d8aa34224f79f7b7a62eb485fc81889cb617019622fd5b5fa604516f5", + "0x8f0e3edddbaead9059df94de4139e3a70693c9ea9bc6baaa5695dddfd67263b33926670159846292801941b9a0c6545b", + "0x9804e850f961e091dadd985d43d526ba8054d1bf9c573ed38f24bbd87aeaad4dcba4c321480abc515a16b3b28f27bb2a", + "0x95f330da28af29e362da3776f153f391703a0595323585220712dae2b54362cc6222070edd2f0dd970acfbe2e3147d5c", + "0x82d03b771231179cc31b29fe1e53379d77b5273b5c0a68d973accd7a757c7584dbb37f0507cdfde8807313ec733a6393", + "0x81b3c39a9f632086e97b7c1f0ec7e2eaf9dc3cb0d84dec18a4441dbdc9fe9878fde4bcfa686bca1a9522632a353a5566", + "0xa2db124ab2b493d5f9a1e4ca6b3144593c2fc8bfac129fd79da11dfbb7ef410a234fda9273a50a5ca05d7b37cc2088a2", + "0xaa8550633c9449228702690cc505c0fc4837ea40862058e8f9713622b34d49fdc3a979b9317993c5da53b5bb5b7f4974", + "0xae783bcf7a736fdc815d0205b4c2c2b2fee0a854765228f76c39638ba503e2d37f1e28f6bdf263923f96fead76b4187b", + "0xb5ec86092c1d250251e93bab2f24e321afd2cd24cf49adfcbed9e8bc5142343ae750206c556320551e50fc972142f0da", + "0xb3b5791b590a6e9b3f473d5148624014aa244495249322a5d75cde2c64117ff9d32f4b0698b0e4382e5e7f72933061f8", + "0x876c6a9162c17b16d6b35e6ce1ba32e26aec7dd1368bceab261ab880ad845c91e54b96a52c7d3aafbfbafc0e37139dca", + "0x902ddb5774d20b0707a704486457c29048776a5b88c377b14af6616c8ddf6cd34f49807df9c9d8866d6b39685cfb0f19", + "0x8b87f71f94bc96de927d77a5d7123fa9cdda8c76aff64a5e6112cbc2eca43b07f8376db3e330f8af6a1db9b948908a6a", + "0xa69a5922e572b13d6778218e3657f1e1eea9a9682f6eb1b731d676d03563e14a37ff69bc5e673c74090ecb0969a593f7", + "0xaff3510d78ba72f3cf5e3101847b7c4a956815aa77148689c07864e8a12dd0ef33d5f6c8cb486e0ea55850161f6afed0", + "0xaa9c459cb2a008d94cbee2c6b561d18b0d7c6ffa8a65cbf86ae2c14eec070ee9d5324f5d38f25a945ddcd70307e964c4", + "0x8310e15b050b1e40ece7530b22964bde0fd04f48dfffdec5a0d1fb8af0799a7fdc1d878139fb7cb8d043d3a52c2d1605", + "0xb8f0856ce2c4034ee4041d0383f25fb0eeefc00b82443311a466fc18608313683af2e70e333eb87e7c687e8498e8a1ce", + "0xa8200a75c158fbb78474cab8a543caecd430b5d8b9964fc45d2d494dd938021cd00c7c33413ad53aa437d508f460a42a", + "0xa310091472b5b42b02176b72d5f8120bdb173025de24b420e3ca3fb9a386c39092a1d1bb591c6f68ee97a268a7ff9e95", + "0xb23f1bf8bcec9cb5232b407115eead855fd06f5bf86ba322ad61d45460c84f0f36911aba303de788c9a0878207eac288", + "0xae4c129ad6d08be44690bb84370e48bfd92c5d87940750ee2c98c9a2604456f7f42727ab211989657bb202f6d907df04", + "0x95992057d654f3e189a859346aa9aa009f074cb193b7f5720fa70c2b7c9ce887d886f6cff93fa57c1f7c8eaa187603f6", + "0xad12d560273963da94151dd6be49c665d7624011c67d54ab41447452a866bc997e92a80bdd9ca56a03528e72c456dc76", + "0x8e4eda72e9cfcaa07265bb6a66d88e9ce3390ae1a6b8831045b36ea4156b53d23724824d0f0bca250ce850c5926fa38f", + "0x980fe29c1a267c556532c46130fb54a811944bdfea263f1afcdab248fa85591c22ac26167f4133372b18d9f5cce83707", + "0xa7da9f99ddde16c0eac63d534a6b6776ad89b48a5b9718a2f2331dce903a100a2b7855cf7b257565a326ddc76adc71a5", + "0x8ca854c55e256efd790940cb01125f293e60a390b5bd3e7a60e13ac11a24f350a7eb5ebddfa0a2890905ca0f1980b315", + "0x9440335818859b5e8f180893a8acedceabaaa44e320286506721c639a489b5bfb80b42b28902ee87237b0bd3dd49552a", + "0xb9da545a20a5e7d60fd0c376dcaf4b144f5c5a62c8ffa7b250c53ce44be69c4e0d5e4e11422ef90593ae58ae1df0e5d3", + "0xb75852a850687f477849fc51e0479703cd44428671c71bfdd27fe3e7930b97d2fc55f20348ca4e5bc08db2fc16a4f23c", + "0xb515081d8d099e4b6253c991ca2d3e42633f5832c64aa8f9cde23cb42c097c2c3717c46c5f178f16c58295f97b2b3fe7", + "0x9506c9902419243e73d3197e407985dd5113f16c6be492651bbbf9576621942710aea74522d6fb56d5b52c6ccdaa4307", + "0x952673ae27462a0f6c9545eede245c2f8e2fd6077b72a71f5672f1a5a02c263bc2a66f24f0e30376feb7a8187b715f08", + "0xa8f1e2085ed666a8f86b474d9589dc309d5c83bd53e745f8e09abe0dfbaf53e5384c68580672990344d4aa739438b4d8", + "0xad6e04d4a67a5a5529ceaf7de6e19416be5b4c436610aa576ac04aee3b73317da88f891121f966393a37f52b775a2dd8", + "0xa35a884736f08c7f76923ae7adb17fdac04e6c505178bca9502eaa2ed16d4d93fa953fb6dcf99e9e9962a6eb3eeead00", + "0xb8af72273360bab4b3ca302cf0659717cbfb335fbc9ad4ffdd3340113ece9e63b2bdbd611e5f6b740a4689286f9a452d", + "0xb1a1f4ba2640800c3ed3892e049f6e10f8a571efa3bbe21fe2d6cee8fded171c675a3bb8aa121e2d1d715de84bad2e2b", + "0x8102a6c3598b40da4d6e8eccfdd5dadc8d6262e38b69c5b211b0732f4c6e3045d79fba12770a0b2b66f1e9f4664b1510", + "0x90979587d75bf12819f63832beea7dcbef101f6814bf88db4575bfcd9cf0ea8eceba76d4d6db17630b73b46c1acfe011", + "0x8dd98f14d2beb5b5b79cc30f6825ec11ed76bd5a8864593ffc0c2baffab6872bad182e1c64b93aab8dd5adb465fa5cec", + "0x8083334dadc49c84f936c603a2857f174eda5659ab2b7214572f318aba3ebd7b1c50e7cbea57272b9edf106bd016df3b", + "0xa634d08d2e8641b852e89d7ccab1bab700c32fb143bcbea132f2a5fb2968d74ded2af4107f69818798f0128cc245a8cb", + "0x94fc2dccf746d5b3027f7cf4547edf97097cd11db8d6a304c1c2ca6b3aba28c1af17c08d2bbb66f88c14472e0196a45e", + "0xb257a6fb01424b35e414c1c002e60487abb3b889d74c60cbdbf591e222739c6f97b95f6962842401f5e2009e91b28c55", + "0x81955bdbf25741f3b85d5044898dc76ae51b1b805a51f7c72a389d3b4d94b2e3e0aa1ec271685bbcf192ed80db7367ab", + "0x86eb229b66c542514e42b113b9de7d4f146861a60f2a253264873e7de7da2ac206e156ff11f2de88491b9897174fe2f4", + "0x8b8db00533afbb56b3d7d7a9a4a6af3cebb523699ffcb974603e54f268b3ef739c41cd11850b9651d9640d72217c3402", + "0x8b7cbb72a6c4408d5f1b61001e65de459790444530245d47d4ee8e2d17716695283f21540bd7ac4f5a793a0d00bdf1d4", + "0x875920b9bab4bc1712e6af89ae2e58e9928c22095026070b07e338421b554d9f96e549ac3706c6c8d73f502913a27553", + "0x9455d192db7b039b3e8f0bc186c25ff07dfbe90dab911e3c62e3bd636db8019ed712cbb0ecd5cbb9a36c11034e102aba", + "0x8cb0b28e5d3838d69f6c12274d6b1250f8843938065d0665b347977fa3c1c685caef6930bae9483ed0d0a67005baad76", + "0x94df2e14aae1ae2882ab22a7baf3dc768c4a72b346c2d46bfd93d394458398f91315e85dc68be371f35d5720d6ca8e11", + "0xaacd94b416bfbeb5334032701214dd453ad6be312f303b7bec16a9b7d46ab95432a14c0fbf21a90f26aafb50ec7bb887", + "0xb43d26963665244633cbb9b3c000cacce068c688119e94cc0dac7df0e6ee30188e53befff255977788be888a74c60fc2", + "0xb40d67c9ad0078f61e8744be175e19c659a12065fe4363b0e88482b098b2431612e7c2fa7e519a092965de09ceafe25c", + "0x82cd4a4e547c798f89ce8b59687614aa128877e6d38b761646d03dc78f6cdd28054649fb3441bcd95c59b65a6d0dd158", + "0xa058e9700f05cef6e40c88b154d66a818298e71ae9c2cf23e2af99a0a7dc8f57fbe529d566cb4247432e3c1dee839b08", + "0x95c6f84406466346c0b4a2a7331ac266177fb08c493d9febb284c5ca0b141ccc17aa32407f579666b208fb187c0227dd", + "0x905d1d47a26b154f44d7531c53efbc3743ff70bd7dba50c9b9d26636767b0ae80de3963c56d4604399126f4ad41a0574", + "0x83dfa11c520b4abaefe1b2bc1ce117806e222f373cd4fb724f3c037c228e3379d27a364e68faa73984ba73a0845f1b9a", + "0xa16e54786ba308a9c0241aff8f1bf785dece387d93bd74aa31de0969e3431479e2c0abebff9939a6644d2b0af44f80bb", + "0x81ac565212365176f5be1c0217f4e7c9fdbc9fe90f16161367635d52edcf57af79290531d2e8b585e1223d33febd957d", + "0xa296f4b09915e5d80ff7274dc3ffc9b04f0427e049ea4ef83dca91095275e8a260ef0335c7b6585953b62682da8c8e99", + "0xa9150626208168a21ae871192ca9f11c1f7f6e41e8e02de00732de2324d0d69fe52f8762155c9913ee408a034552e49a", + "0xa42a56008ca340c6e9ff5a68c8778bb899ba5de9e7508c0cac355c157979a7ff6a6bd64f98b182114d3831cfa97ee72b", + "0xa4f05adf22c051812279258eea9eb00956b04ef095f2ca175f775ff53c710fb0020266adabd1dacaee814c4f1d965299", + "0x967492e78ac0bceb8ad726ea0d2292b760043d16d64a6b1bb896e32630a7bf405c2b20e4e00842ae519a21697ff8db2d", + "0xadbf05e9b5931ae3dd24d105b5c523c221a486a4123c727069b9e295a5bc94f3e647a3c2cde1f9f45dbd89df411453c9", + "0xa1759c0ebebd146ee3be0e5461a642938a8e6d0cdd2253ebd61645b227624c10c711e12615cd1e7ea9de9b83d63d1a25", + "0xa4c5945d635b9efc89ad51f5428862aefe3d868d8fb8661911338a6d9e12b6c4e5c15a25e8cb4a7edc889b9fa2b57592", + "0xaff127675ea6ad99cb51c6e17c055c9f8fd6c40130c195a78afdf4f9f7bc9c21eed56230adb316d681fc5cacc97187da", + "0x9071294e8ff05b246ff4526105742c8bf2d97a7e7913f4541080838ecfd2dbc67c7be664a8521af48dbc417c1b466a85", + "0x990880b0dd576b04f4b4ce6f0c5d9ff4606ec9d3f56743ac2f469ac6a78c33d25c3105cf54f675e300ac68073b61b97a", + "0xa8d1a62ce47a4648988633ed1f22b6dea50a31d11fdddf490c81de08599f6b665e785d9d2a56be05844bd27e6d2e0933", + "0x8ea5a6c06f2096ded450c9538da7d9e402a27d070f43646533c69de8ea7993545673a469c0e59c31520e973de71db1b4", + "0x99d3a098782520612b98a5b1862ae91bcb338ab97d1a75536e44b36a22885f1450a50af05c76da3dd5ca3c718e69fdd4", + "0xb987451526e0389b5fe94c8be92f4e792405745b0a76acd6f777053d0809868657ba630aa5945f4bd7ce51319f8996f7", + "0xafffccc5ddd41313888a4f9fee189f3d20d8b2918aa5ad0617009ea6d608e7968063c71bd5e6a1d7557880d9a639328d", + "0x8ac51a02505d5cadfd158dde44932ab33984c420aeceb032ed1ee3a72770d268f9e60ccf80ce8494dfc7434b440daafd", + "0xb6543e50bd9c6f8e0862850c3d89835ddd96231527681d4ab7ae039c4a3a5a0b133a6d40cdb35c8a6c8dbb8d421d3e2b", + "0xa2ba901f4fde2b62274d0c5b4dbbea8f89518571d8f95ec0705b303b91832f7027704790a30f7d9d2cdafde92f241b3e", + "0xa6974b09280591c86998a6854a7d790f2a6fbe544770e062845cfc8f25eb48c58f5dfb1b325b21f049d81998029ad221", + "0x890baeb336bbf6c16a65c839ffaab7b13dd3e55a3e7189f7732dbcb281b2901b6d8ba896650a55caa71f0c2219d9b70e", + "0xb694211e0556aebbe4baf9940326e648c34fda17a34e16aa4cefd0133558c8513ffb3b35e4ee436d9d879e11a44ec193", + "0x97cf9eb2611d467421a3e0bfe5c75382696b15346f781311e4c9192b7bca5eb8eaf24fa16156f91248053d44de8c7c6f", + "0x8247f88605bd576e97128d4115a53ab1f33a730dc646c40d76c172ca2aa8641c511dddad60ee3a6fbe1bb15cac94a36c", + "0xae7ecd1c4a5e9e6b46b67366bc85b540915623a63ab67e401d42ca1d34ae210a0d5487f2eef96d0021ebecfd8d4cd9a8", + "0xaec5123fff0e5d395babe3cb7c3813e2888eb8d9056ad4777097e4309fb9d0928f5c224c00260a006f0e881be6a3bf8f", + "0x8101724fa0ce7c40ea165e81f3c8d52aa55951cc49b4da0696d98c9fafd933e7b6c28119aa33f12928d9f2339a1075d1", + "0xa8360843bab19590e6f20694cdd8c15717a8539616f2c41a3e1690f904b5575adb0849226502a305baefb2ead2024974", + "0xade5cad933e6ed26bba796c9997b057c68821e87645c4079e38e3048ea75d8372758f8819cde85a3ab3ab8e44a7d9742", + "0xab1fe373fb2454174bd2bd1fe15251c6140b4ac07bda1a15e5eabf74b6f9a5b47581ef5f0dbd99fdf4d1c8c56a072af7", + "0xb425e1af8651e2be3891213ff47a4d92df7432b8d8ea045bb6670caf37800a4cd563931a4eb13bff77575cbcae8bc14f", + "0xb274799fe9dd410e7aed7436f0c562010b3da9106dc867405822b1e593f56478645492dbc101a871f1d20acf554c3be6", + "0xb01a62a9d529cc3156bc3e07f70e7a5614b8d005646c0d193c4feb68be0b449d02b8f0000da3404e75dbdfa9ca655186", + "0x878b95e692d938573cdb8c3a5841de0b05e5484a61e36ea14042f4eadb8b54a24038d2f09745455715d7562b38a8e0df", + "0xa89e998e979dba65c5b1a9000ad0fd9bb1b2e1c168970f2744982781306bbe338857e2fac49c8cafda23f7cc7c22f945", + "0x85880fdf30faed6acce9973225e8fe160e680a55fc77a31daacf9df185453ad0c0552eb3fd874698ad8e33c224f7f615", + "0xac28d20d4bbb35ba77366272474f90f0ed1519a0e4d5de737adee2de774ccd5f115949e309e85c5883dbc63daaa6e27b", + "0xa1758ac86db859e323f5231ad82d78acbe11d53d3ebf7e644e581b646eede079d86f90dc23b54e5de55f5b75f7ea7758", + "0xae4c0b84903f89353bf9a462370f0bf22c04628c38bb0caae23d6e2d91699a58bd064e3c2b1cbda7f0a675d129f67930", + "0x95f21a099ffc21a0f9064d9b94ce227b3ff0a8c5a2af06ff5ee6b7f3248a17a8ca2f78cd7929ef1d0784f81eddefcd48", + "0x8d06fbc1b468f12b381fd1e6108c63c0d898ddf123ea4e2e1247af115043c4f90b52796076277b722dd2b92708f80c21", + "0xa300f39039d8b2452e63b272c6d1f6d14a808b2cd646e04476545da65b71a6e29060f879409f6941c84bde9abe3c7d01", + "0xadecce1ccc5373072ba73930e47b17298e16d19dbb512eed88ad58d3046bb7eec9d90b3e6c9ba6b51e9119cf27ce53f2", + "0x941a7e03a64a2885d9e7bee604ddc186f93ff792877a04209bbee2361ab4cb2aed3291f51a39be10900a1a11479282ca", + "0xacbcb1ab19f3add61d4544c5e3c1f6022e5cc20672b5dc28586e0e653819bdae18cda221bb9017dfaa89c217f9394f63", + "0xb8d92cea7766d3562772b0f287df4d2e486657b7ab743ed31ec48fdc15b271c2b41d6264697282b359f5cb4d91200195", + "0x957360ecb5d242f06d13c1b6d4fcd19897fb50a9a27eb1bd4882b400dc3851d0871c0c52716c05c6c6cf3dee3d389002", + "0xabd2a23abbc903fbb00454c44b9fb4a03554a5ef04101b2f66b259101125058346d44d315b903c6d8d678132f30b1393", + "0xae9572beff080dd51d3c132006107a99c4271210af8fbe78beb98d24a40b782537c89308c5a2bddfdfe770f01f482550", + "0x82c7e5a5e723938eb698602dc84d629042c1999938ebd0a55411be894bccfb2c0206ac1644e11fddd7f7ab5ee3de9fdc", + "0xaba22f23c458757dc71adb1ce7ef158f50fdd1917b24d09cfc2fbbcbe430b2d60785ab141cf35ad9f3d0a2b3e2c7f058", + "0x8eff41278e6c512c7552469b74abedf29efa4632f800f1a1058a0b7a9d23da55d21d07fdbb954acb99de3a3e56f12df6", + "0x8abd591e99b7e0169459861a3c2429d1087b4f5c7b3814e8cee12ecc527a14a3bdda3472409f62f49a1eb4b473f92dbf", + "0x82dcbff4c49a9970893afc965f1264fcab9bae65e8fb057f883d4417b09e547924123493501c3d6c23a5160277d22a8e", + "0xb5a919fcb448a8203ad3a271c618e7824a33fd523ed638c9af7cfe2c23e3290e904d2cd217a7f1f7170a5545f7e49264", + "0x96d6834b592ddb9cf999ad314c89c09bedc34545eeda4698507676674b62c06cc9b5256483f4f114cd1ed9aaec2fba5e", + "0xa4e878cf4976eb5ff3b0c8f19b87de0ef10cd8ec06fe3cd0677bd6be80ba052ff721a4b836841bdffb1df79639d0446c", + "0x8e15787a8075fd45ab92503120de67beb6d37c1cc0843c4d3774e1f939ac5ed0a85dad7090d92fa217bd9d831319021b", + "0x8506c7fea5a90cd12b68fdbbae4486a630372e6fd97a96eea83a31863905def661c5cdead3cf8819515afe258dbcd4d9", + "0x952ef3bc16a93714d611072a6d54008b5e1bf138fd92e57f40a6efb1290d6a1ffcc0e55ff7e1a6f5d106702bd06807cd", + "0xa5f7761fa0be1e160470e3e9e6ab4715992587c0a81b028c9e2cf89d6f9531c2f83c31d42b71fca4cc873d85eba74f33", + "0xb4811f0df11ff05bf4c2c108a48eece601109304f48cde358400d4d2fa5c1fdaaf3627f31cb3a1bdd3c98862b221720d", + "0x9207ad280b0832f8687def16ad8686f6ce19beb1ca20c01b40dd49b1313f486f2cb837cfbbf243be64d1c2ab9d497c3f", + "0xb18a8c1e6363fadd881efb638013e980e4edb68c1313f3744e781ce38730e7777f0cba70ea97440318d93a77059d4a2b", + "0x901faf777867995aac092f23c99c61f97eeadf4ac6bcb7791c67fa3c495947baef494b2aace77077c966c5d427abbf92", + "0xa123281aca1c4f98f56cff7ff2ae36862449f234d1723b2f54ebfccd2740d83bd768f9f4008b4771e56c302d7bfc764f", + "0x8cffe1266468cad1075652d0765ff9b89f19b3d385e29b40f5395b5a3ad4b157eed62e94279ac3ec5090a6bad089d8b3", + "0x8d39870719bc4ebbcecba2c54322111b949a6ed22bda28a6cea4b150272e98c9ded48cc58fc5c6e3a6002327856726ec", + "0xb3d482c00301f6e7667aaeaf261150b322164a5a19a2fa3d7e7c7bf77dc12fa74f5b5685228ab8bf0daf4b87d9092447", + "0x801acb8e2204afb513187936d30eb7cab61f3fbb87bfd4cd69d7f3b3ddba8e232b93050616c5a2e6daa0e64cef6d106f", + "0xac11e18adda82d2a65e1363eb21bda612414b20202ecc0e2e80cc95679a9efa73029034b38fd8745ce7f85172a9ab639", + "0xb631d6990d0f975a3394f800f3df1174a850b60111567784f1c4d5bba709739d8af934acfa4efc784b8fc151e3e4e423", + "0xaeda6279b136b043415479a18b3bbff83f50e4207b113e30a9ccfd16bd1756065fc3b97553a97998a66013c6ac28f3d8", + "0x8840b305dc893f1cb7ad9dd288f40774ec29ea7545477573a6f1b23eaee11b20304939797fd4bcab8703567929ce93ad", + "0x963cc84505a28571b705166592bffa4ea5c4eeafe86be90b3e4ae7b699aaaca968a151fe3d1e89709fe0a3f0edf5d61a", + "0x8e1ec0d0e51f89afea325051fc2fa69ab77d6c7363cc762e470a9dfa28d4827de5e50f0b474c407b8c8713bad85c4acd", + "0x909f313420403cb36c11d392cf929a4c20514aa2cb2d9c80565f79029121efd5410ef74e51faba4e9ba6d06fcf9f1bd1", + "0xb2992b45da467e9c327ac4d8815467cf4d47518fc2094870d4355eb941534d102354fbda5ab7f53fbf9defa7e767ca13", + "0x9563b50feb99df160946da0b435ac26f9c8b26f4470c88a62755cdf57faebeefffff41c7bdc6711511b1f33e025f6870", + "0xa2a364d9536cd5537a4add24867deec61e38d3f5eb3490b649f61c72b20205a17545e61403d1fb0d3a6f382c75da1eb3", + "0x89b6d7c56251304b57b1d1a4255cb588bd7a851e33bf9070ee0b1d841d5c35870f359bc0fdc0c69afe4e0a99f3b16ec2", + "0xa8ae1ee0484fe46b13a627741ddcdae6a71c863b78aafe3852b49775a0e44732eaf54d81715b1dca06bb0f51a604b7e2", + "0xb814ecbfbc9645c46fc3d81c7917268e86314162d270aed649171db8c8603f2bd01370f181f77dbcbcc5caf263bedc6c", + "0x8e5d7cc8aad908f3b4e96af00e108754915fecebdb54f0d78d03153d63267b67682e72cd9b427839dca94902d2f3cda7", + "0x8fc5ff6d61dd5b1de8c94053aef5861009cb6781efcca5050172ef9502e727d648838f43df567f2e777b7d3a47c235dd", + "0x8788eea19d09e42b0e3e35eb9bcd14f643751c80c6e69a6ff3a9f1711e8031bbe82ccd854a74a5cfcf25dda663a49a62", + "0x95d441d8cd715596343182ddcecb8566d47eaa2d957d8aea1313bbed9d643a52b954443deb90a8037a7fa51c88eec942", + "0xa15efd36ef72783ccdc6336ef22a68cc46b1ecec0f660cfe8a055952a974342bf30f08cb808214bce69e516ff94c14c5", + "0xacc084d36907a16de09a5299f183391e597beaf9fa27d905f74dc227701a7678a0f5a5d1be83657de45c9270a287ec69", + "0xb3fd385764356346061570beb760ccf3808619618fd7521eb0feadc55b8153ef4986ff0cbfcbd4153ad4ea566989d72a", + "0x91ec6b26725532e8edfda109daa7ce578235f33bd858238dfa2eb6f3cd214115b44cce262a0f2f46727a96b7311d32e1", + "0x96b867ccddb73afe1049bda018c96cfe4083fff5bb499e6a4d9fd1a88a325144f9a08cb0aee310e1bb4f6a5793777e80", + "0xad10c18465910152676f1bc6a40986119607b5c272488e6422cfda2eb31da741af13a50f5de84037348014a869c8e686", + "0x86ade2dbc4cceb52b84afe1c874d1e3644691284c189761febc4804b520adf60b25817e46f3f3c08d2ab227d00b93076", + "0x998b949af82065c709fc8f63113a9fecdd1367fc84fc3b88857d92321ba795e630ce1396a39c2e056b5acd206ee011d8", + "0x8dec440bbd17b47dfd04e566c2d1b46f9133023b982fdc5eaeae51404bc83a593f8d10c30b24e13aec709549137cae47", + "0x89436ff47431b99f037cddaee08bb199be836587a7db6ed740317888638e5f4bebbb86b80549edff89678fc137dfb40a", + "0xa8e9960746769b3f76246c82cd722d46d66625e124d99a1f71a790c01cec842bcf6c23c19cc7011ec972cedf54dc8a4c", + "0x980979dafedfd75ff235b37e09e17361cfdda14a5ac3db0b90ed491abfd551916016b2254538da7f4b86ece3038b1b1c", + "0x8ec340ca7654720bb9d2f209985439ebbc3f9990ef27e7d7ae366e0c45b4ed973316943122119604ea9a87fc41ebd29f", + "0xab24440a40ab238d8cd811edb3ef99948ae0f33bf3d257b22c445204016cce22b6f06a1ca979fa72a36c4ddedc2b3195", + "0xa1bcd2473ac7cfebfa61c10e56cae5422c6b261a4a1be60b763fcbcdf2eae4ccf80695f09b062b6cf5654dfab0ee62a5", + "0x9027a613ce7bd827110a3a0e63e83f652e9bc7f4ce8da26c38b28ee893fd0c38bdb20f63a33470a73cb77f776244ab4a", + "0x86911cc8aeb628197a22bf44d95a0b49afb8332c38857fba8e390c27c527b8b45335e22b0f2e0a3395c16ced3c1ed2e8", + "0x8f0529a330a3e9967dce09357d774715fd305bd9e47b53b8b71a2a1303d390942a835aa02fb865a14cfed4f6f2f33fe6", + "0xb71ec81a64c834e7e6ef75b7f321a308943b4bad55b92f4dbaf46658613cebf7e4b5b1bc7f1cdc5d50d1a2a0690e2766", + "0x98d66aaed9fb92f4c7bb1b488ccbca5e570aa14433028867562a561d84f673ac72e971cbe2cb3cbbb0a702797dc45a7e", + "0x8380aa94d96c6b3efd178de39f92f12ca4edd49fe3fe098b2b7781e7f3e5f81ee71d196fb8e260d1d52f2e300e72e7bc", + "0x8c36296ff907893ac58cecadd957b29f5508ae75c6cc61b15ae147b789e38c0eace67963ae62eff556221b3d64a257a2", + "0x97e17676cbc0f62a93555375e82422ee49bc7cf56ad6c3d69bb1989d1dc043f9f7113d0ed84616dde310441b795db843", + "0xa952229615534c7e9a715409d68e33086cdaddf0aec51f4369c4017a94ec3d7113a045054d695fb9d7fd335527259012", + "0x817b90958246f15cbd73a9679e10192ca7f5325b41af6388b666d8436706dea94eafffbc3b8d53057f67ad726dbcd528", + "0x95776e378c8abd9223c55cd6a2608e42e851c827b6f71ad3d4dc255c400f9eccf4847c43155f2d56af0c881abef4acfa", + "0x8476c254f4b82858ecbe128ed7d4d69a6563fd9c5f7d4defc3c67e0bfa44e41cfd78b8e2a63b0773ce3076e01d3f6a7d", + "0xa64b0b189063d31bcae1d13931e92d5ab0cfc23bf40566ac34b5b8b711d0e7d941102e6beb140547512e1fe2d9342e6c", + "0x9678460acff1f6eae81a14d5c8049cdcd50779a8719b5c5861762a035b07f7fa1b1ada8b6173f9decf051fd5a55bebd8", + "0x88398758ce86ed0388b13413a73062adb8a026d6b044cd1e7f52142758bed397befee46f161f8a99900ae6a2b8f6b89f", + "0xa7dfaf40637c81d8b28358b6135bd7ad9cc59177bd9bc8e42ba54d687d974cdf56be0457638c46b6a18ceaa02d3c53f3", + "0xb0e885e5d48aa8d7af498c5e00b7862ed4be1dad52002f2135d98e8f2e89ca0b36cf95b3218aad71d5b4ada403b7045b", + "0x803b0e69a89e8de138123f8da76f6c3e433402d80d2baba98cde3b775a8eda4168530a49345962c4b25a57257ba9f0a7", + "0x8ce6ef80dadb4b1790167fbc48be10ef24248536834ff2b74887b1716c75cb5480c30aa8439c20474477f1ac69734e61", + "0x824764396e2b1e8dcc9f83827a665ef493faec007276f118b5a1f32526340b117c0df12bea630030a131bf389ec78fc3", + "0x874edb379ce4cc8247d071ef86e6efbd8890ba6fcb41ea7427942c140347ebf93e8cf369d1c91bd5f486eb69b45bce70", + "0xadadcb6eb4cafa1e2a9aef3efb5b09ffa2a5cf3ce21f886d96a136336be680dabc0a7c96ec327d172072f66d6dcdbb39", + "0xb993591b280e1f3527f083d238a8f7cf516d3cf00c3690d384881911c1495192a419b8e37872a565ce8007eb04ebe1b6", + "0xb125faaeca3f0b9af7cb51bb30a7c446adbb9a993b11600c8b533bff43c1278de5cdda8cb46a4df46f2e42adb995bce8", + "0xa7efe1b57326b57c2c01720d4fdf348d6a84d35f229d32a8f2eb5d2be4e561ef8aea4d4d0bcfcbf17da10a8e49835031", + "0xa6bd4f5a87574b90a37b44f778d5c7117d78eb38f3d7874bad15ae141b60eed4ab0a7281ed747297f92e0b3fe5f9cafa", + "0x94b5e3067ca1db3c4e82daf6189d7d00246b0360cb863940840358daa36cb33857fde4c01acd0457a90e15accee7d764", + "0xa5ff3ab12197b8a07dd80222a709271ab3b07beba453aacbaf225cfb055d729e5a17a20f0ff9e08febf307823cba4383", + "0xa76dd8aa2b6a957ed82ecec49b72085394af22843272f19360a5b5f700910c6ec65bf2a832e1d70aa53fd6baa43c24f6", + "0x8dfcbe4143ae63c6515f151e78e6690078a349a69bb1602b79f59dc51dea7d00d808cf3e9a88b3f390f29aaae6e69834", + "0x8c6134b95946a1dd54126952e805aeb682bc634c17fe642d5d3d8deffffd7693c90c4cd7d112890abfd874aa26736a93", + "0x933531875561d327c181a2e89aaaac0b53e7f506d59ef2dfc930c166446565bd3df03bab8f7d0da7c65624949cfbae2f", + "0xac6937c5e2193395e5bb69fd45aa6a9ae76b336ea7b6fd3e6aeac124365edcba7e918ec2c663fb5142df2f3ad03411a6", + "0xa8f0f968f2a61d61d2cf01625e6ac423b447d3e48378ea70d6ff38bc98c42e222fe3cbcb04662b19973a160dc9f868a2", + "0x94100a36f63d5c3a6cfb903c25a228389921684cc84f123390f38f90859f37ec9714942ffe6766f9b615101a3c009e43", + "0xb5321b07f5b1eb2c1c20b0c8ab407f72f9705b55a761ec5176c5bcc6e585a01cae78546c54117ca3428b2b63793f2e65", + "0x9922f61ed6763d1c4d12485c142b8ff02119066b5011c43e78da1ee51f10a1cf514329874061e67b55597ca01a7b92ab", + "0xa212eb2d72af0c45c9ef547d7c34ac5c4f81a4f5ec41459c4abd83d06ec6b09fdab52f801a2209b79612ae797fa4507b", + "0x8577d2d8f17c7d90a90bab477a432602d6918ca3d2af082fbb9e83644b93e21ca0bced7f90f6e9279eaa590f4e41dc4d", + "0x9002d424e3bebd908b95c5e6a47180b7e1d83e507bfb81d6ad7903aa106df4808c55f10aa34d1dccad3fab4d3f7a453e", + "0xb9050299bf9163f6ebeff57c748cb86f587aea153c2e06e334b709a7c48c4cbfba427babf6188786a0387b0c4f50b5ce", + "0x852ae1195cc657c4d4690d4b9a5dea8e0baaa59c8de363ba5fccd9e39ec50c6aa8d2087c8b7589b19248c84608f5d0a8", + "0xa02ff5781417ca0c476d82cf55b35615f9995dc7a482124bc486e29b0b06a215fbe3e79228c04547c143d32cd3bac645", + "0x8d7bc95e34bc914642e514a401448b23cf58bce767bab1277697327eb47c4a99214a78b04c92d2e3f99a654308b96e34", + "0xadb28445d3b1cc7d4e4dd1f8b992a668f6b6f777810465fdab231fd42f06b5bada290ba9ae0472110366fad033da514e", + "0xa0c72b15a609f56ff71da17b5b744d8701af24b99fbc24a88588213864f511bfa592775e9ab4d11959f4c8538dc015b8", + "0x933205a40379d5f5a7fb62cda17873fbbd99a0aaa8773ddf4cd2707966d8f3b93a107ebfe98b2bb222fe0de33ef68d03", + "0x90690c1a4635e2e165773249477fc07bf48b1fd4d27c1b41a8f83a898c8d3763efb289867f8d6b0d354d7f4c3f5c7320", + "0x99858d8c4f1be5a462e17a349b60991cb8ce9990895d6e42ae762ce144abc65b5a6f6e14df6592a4a07a680e0f103b2a", + "0xb354a7da06bd93fb5269e44925295b7c5049467b5cacce68cbb3cab60135b15e2010037a889cb927e6065053af9ccb77", + "0xaf01fc4ac396d9b15a4bbd8cc4fe7b30c32a9f544d39e88cdcb9b20c1c3056f56d92583a9781ddb039ec2eeda31fb653", + "0xa8d889fb7155f7900982cf2a65eb2121eb1cc8525bbee48fae70e5f6275c5b554e923d29ebbd9772b62109ff48fb7c99", + "0xb80edae6e26364c28749fd17c7c10eb96787053c7744a5cc6c44082ae96c5d3a4008c899a284f2747d25b72ecb9cb3d0", + "0xb495b37503d77e7aafc226fca575e974b7bb6af2b7488372b32055feecc465a9f2909729e6114b52a69d8726e08739cb", + "0xa877f18b1144ff22e10a4879539968a01321cecde898894cbe0c34348b5e6faa85e1597105c49653faed631b1e913ec7", + "0x8c235c558a065f64e06b4bb4f876fe549aab73302a25d8c06a60df9fad05843915ac91b507febca6fe78c69b51b597de", + "0xb4c31398b854ccc3847065e79329a3fdae960f200c1cce020234778d9c519a244ff1988c1fbc12eb3da2540a5fa33327", + "0xb7bd134b3460cb05abf5aed0bc3f9d0ccbfac4647324bedbdf5011da18d8b85dc4178dd128f6ddbe9d56ea58f59d0b5d", + "0x92594c786c810cf3b5d24c433c8a947f9277fe6c669e51ceb359f0ae8a2c4e513a6dad1ae71b7ded3cdca823a51e849b", + "0xb178535e043f1efcce10fbec720c05458e459fdda727753e0e412ef0114db957dc9793e58ec2c031008e8fb994145d59", + "0xb31da7189abf3e66042053f0261c248d4da142861bfd76a9aced19559be5284523d3e309ef69843772b05e03741a13fe", + "0xb190a8c1a477e4187fecff2a93033e77e02de20aae93dda1e154598814b78fdf8b9ff574c5f63047d97e736e69621462", + "0x98234bd1d079c52f404bf5e7f68b349a948ec1f770c999c3c98888a55d370982bfa976e7e32848a1ebb4c7694acc1740", + "0x99b9eeb33a6fb104bba5571a3822ebe612bf4b07d720d46bde17f0db0b8e8b52165f9b569be9356a302614e43df3e087", + "0xa1e3915b0dd90625b424303860d78e243dda73eecd01cba7c33100b30471d0a1ec378c29da0f5a297008b115be366160", + "0x975118bf6ca718671335a427b6f2946ee7ece2d09ccfb1df08aa1e98ff8863b6c8b174c608b6b2f4b1176fb3cbc1e30d", + "0x903cb1e469694b99360a5850e2ca4201cad23cfccce15de9441e9065eb3e6e87f51cba774ab9015852abd51194c25e57", + "0x821f7ff4d0b133e3be4e91d7ff241fa46c649ff61fc25a9fdcf23d685fe74cf6fade5729763f206876764a3d1a8e9b24", + "0xa1ee8db859439c17e737b4b789023d8b3ce15f3294ec39684f019e1ea94b234ec8a5402bc6e910c2ed1cd22ff3add4de", + "0xaf27383148757bdf6631c0ea8a5c382f65fc6ab09f3d342a808ca7e18401e437cd1df3b4383190fdf437a3b35cbcc069", + "0x8310551d240750cef8232cd935869bad092b81add09e2e638e41aa8a50042ce25742120b25fb54ebece0b9f9bdb3f255", + "0x8b1954e0761a6397e8da47dc07133434ebe2f32c1c80cd1f7f941f9965acdf3d0c0b1eb57f7ff45a55697d8b804e1d03", + "0x8c11612381c6be93df17851d9f516395a14a13c7816c8556d9510472b858184bf3cc5b9d14ded8d72e8fb4729f0b23ba", + "0xb413ac49121c7e8731e536b59d5f40d73a200c4e8300f8b9f2b01df95a3dc5fe85404027fc79b0e52946e8679b3a8e43", + "0x8451e5c1c83df9b590ec53d1f1717d44229ed0f0b6e7011d01ea355d8b351f572866b88032030af372bd9104124df55a", + "0x8d0a5c848ec43299bc3ea106847ed418876bc3cd09b2280c2a9b798c469661505ed147a8f4ffba33af0e1167fdb17508", + "0xa6aa97a1f10709582471000b54ec046925a6ad72f2b37c4435621c9f48026d3e332b8e205b6518f11b90b476405960a9", + "0x97696635b5a2a6c51de823eea97d529f6c94846abb0bd4c322b108825589eba9af97762484efaac04ee4847fb2fb7439", + "0x92fd142181fe6ca8d648736866fed8bc3a158af2a305084442155ba8ce85fa1dfb31af7610c1c52a1d38686ac1306b70", + "0xae3da824ecc863b5229a1a683145be51dd5b81c042b3910a5409ca5009ba63330e4983020271aa4a1304b63b2a2df69e", + "0xaecc0fe31432c577c3592110c2f4058c7681c1d15cd8ed8ffb137da4de53188a5f34ca3593160936119bdcf3502bff7c", + "0x821eac5545e7f345a865a65e54807e66de3b114a31ddeb716f38fe76fdd9d117bee0d870dd37f34b91d4c070a60d81f4", + "0x91a02abb7923f37d9d8aa9e22ded576c558188c5f6093c891c04d98ab9886893f82b25b962e9b87f3bf93d2c37a53cb9", + "0x99a96f5d6c612ee68e840d5f052bf6a90fecfd61891d8a973e64be2e2bdd5de555b1d8bffbd2d3c66621f6e8a5072106", + "0xb1d5ec8f833d8fbb0e320ff03141868d4a8fff09d6a401c22dbefadbb64323e6d65932879291090daf25658844c91f2e", + "0xa06afd66ebc68af507c7cf5ab514947ca7d6ccc89fb2e2e8cb6e5ae0f471473e5fba40bb84d05f2c0f97c87f9a50cb73", + "0x83de3ca182bcf1eac0cc1db6ad9b1c2a1ecd5e394e78add7faa36e039a1b13cb0d1d2639892489df080fbf43e5cef8d5", + "0xadf77fc7b342ff67a2eddaa4be2f04b4e6ceaca8ea89a9fc45cc892fcce8ac3cf8646cfa5aab10ac9d9706ce4c48a636", + "0x8509a430ef8dc9a0abc30ef8f8ccdb349d66d40390fb39f0d3281f3f44acb034625361270162822ef0743d458a82b836", + "0x8350fc09e8617826f708e8154a3280d8753e7dbbcf87e852f9b789fdbeb10bf3fed84fb76edd7b8239a920c449e2f4b7", + "0xa2e7a29da8391a5b2d762bf86cb6ae855cdfad49821175f83f4713dd0c342a0784beba98d4948356985a44d9b8b9d0f7", + "0xa99c50a1a88b8efe540e0f246439db73263648546d199ef0d5bc941524a07d7e02b3ef6e5b08dc9e316b0b4c6966823e", + "0xb34ba55136c341f4ca2927080a07476915b86aa820066230903f1f503afebd79f2acf52a0bc8589b148d3a9a4a99f536", + "0xaf637be5a3e71c172af1f2644d3674e022bc49c393df565ea5b05ce6401a27718c38a9232049dd18cbd5bf4f2ce65b32", + "0xa2972ba7bfa7f40c2e175bb35048a8ef9bc296d5e5a6c4ca7ab3728f4264d64f2d81d29dce518dc86849485ff9703d7d", + "0x8c9db203e8726299adeb331d6f4c235dc3873a8022138d35796fb7098887e95e06dcfad5d766ceaa2c4fb0f8857f37fa", + "0xa82bfbaa9a6379442109e89aad0c0cfc6a27d4a5db5480741a509d549c229cb847b46a974dde9f1398c6b3010530f612", + "0xb2d8ef6e091a76dfc04ab85a24dbe8b5a611c85f0ed529a752c2e4c04500de5b305c539d807184e05f120be2c4a05fc3", + "0x8c6ffc66a87d38cea485d16ee6c63ce79c56b64ae413b7593f99cc9c6d3cd78ef3fa2ab8a7943d2f0e182176642adadb", + "0xacbc92de68b2b04e3dc128109511a1cbe07518042f365d5634e8b651cb1ac435ea48eeeb2b921876239183096ef6edee", + "0x979c4e1165e0ecfa17ed59fb33f70797e000ddbb64acf5fc478cccde940451df051e51b6449c5b11a36afa7868af82e3", + "0xa5a017c5a94952aeae473976027124231abe50460cec4db3ebeb8b1290525776be7c15d108b749c2a1e4b018de827915", + "0x8b6922ab1db925eed24b2586e95f5c709b79d2408a8fa2a71057045ead3ebdd0cc72bee23d9064cd824166eda1e29318", + "0x89a991087a0b5805fcc5c6c5f6ac27e100da0d3713645aa9c90114e68ca9f185f21155eb7645a2c6c0616a47291fe129", + "0xae6ef954c942cbfd37f8f2dc58a649e2584d6777e7eb09ae6992ccde283ac4f4ec39e3a5cda7f7c60f467fb308d37f08", + "0x9335ca5ccac59b39eb2bcef09c54b778ebb690415ba13fe5c8e4b6091d9343a01cc9baa6228cefd8dba98f0710f714da", + "0xa0211c9328be2b46f90ff13614eeffb4c1285e55580db3874610653219926af1d83bda5b089fd37a7c7440a0f1d94984", + "0xa82e097dfa782c40808fac5d8ed1c4fccf6b95ef92e22276fd8d285303fcf18c46d8f752595a658ee5294088b9dc6fc0", + "0xad108fcd0ead65f7f839a1337d520f5bd0cb665ee7100fc3f0563ff1d2959eb01617de8eb7a67c9b98b7b4892082acdb", + "0xb89e6aeabcb3ee3cbf12e3c836bab29e59d49676bcf17a922f861d63141076833f4149fe9e9c3beed24edfacdf1e248b", + "0x8477501bd91211e3b1f66c3bfd399ef785271511bc9366366ce95ec5ea95d9288ab0928a6b7887aba62de4da754d3eaf", + "0xaeec40c04b279096946b743ad8171bf27988405e1321c04894d9a34e2cbd71f444ff0d14da6cda47e93aa6fe9c780d50", + "0xa703bd2d8a5c3521a8aad92afef5162aed64e9e6343d5b0096ca87b5b5d05e28ed31ba235ab1a626943533a57872dd01", + "0xb52d9dfc12c359efb548d7e2b36ddedaefdec0ef78eda8ac49a990b3eb0ed7668690a98d4d3c7bec4748a43df73f0271", + "0xaf887c008bad761ee267b9c1600054c9f17f9fc71acfe0d26d3b9b55536bca5c8aebe403a80aa66a1e3748bb150b20ef", + "0xad2f7a545ef2c2a2978f25cf2402813665c156bab52c9e436d962e54913c85d815f0ba1ce57f61e944f84d9835ce05ea", + "0x91a0a9b3cfd05baf9b7df8e1fb42577ec873f8a46bb69a777a6ac9f702735d6e75e66c9257822c781c47b9f78993a46b", + "0x939fdc380fb527f9a1ddecf9c9460f37e406cd06c59ce988e361404acbfcb6379f2664a078531705dbc0c375d724137b", + "0x8bbbe5d5a0d102b8e0c8a62e7542e13c8c8a6acb88859e78d8e1d01ec0ddff71d429fcb98099e09ff0aa673c8b399dc4", + "0xb67a70e4ef138f48258f7d905af753c962c3cc21b7b8ae8b311a2356c4753f8cd42fdee09ac5ed6de31296ead88c351a", + "0x8d21539e7dca02a271ce7d16431773bbe30e6a03f5aff517132d34cdd215ad0da2f06aa4a2a595be489234b233e0852e", + "0x892ae11513f572cc5dc8b734b716bb38c0876e50e5e942631bb380b754e9114c34b0606740301e29b27d88439fb32071", + "0xa8780dc9faa485f51b6f93a986bc4e15b166986b13d22ec2fefc6b25403b8b81c15cc9ac0025acc09d84932b15afa09b", + "0xb01af013360cd9f2bb9789a2b909c5e010fe6ff179f15997dee1a2ba9ef1ccec19545afdecfcb476f92fcdd482bb2b5a", + "0xb5202e5d5053d3af21375d50ad1ccd92538ef9916d17c60eb55c164767c3c74681886297b6f52e258c98d0304d195d3d", + "0x8f6adbcfbb0734bf3a4609d75cf2e10f74ed855a8b07cf04ac89a73d23b2e3e5cf270a1f2547b3d73e9da033a3c514b0", + "0x8abe529cd31e4cb2bd75fa2a5e45bd92cbe3b281e90ffc7dea01ba0df17c9a3df97a3fde373cce5d25b5814cf1128fed", + "0xb8bbf51187bb3bb124da3870e2dfecb326f25a9383e5cc3323813487457010b9055811669c3da87105050825dc98a743", + "0xa5c83875fe61ebbdd3fd478540d7e5a1ad0f8c790bad0b7dd3a44831e2c376c4fffbc6b988667afa1b67bfaa2dbbb256", + "0xa0606b3062e4beba9031ba2a8e6e90aa5a43ba7321003976e721fd4eedb56486f2c5b10ba7a7f5383272f4022092eacb", + "0xb485cc5e001de6bd1bbc9cd8d777098e426d88275aaa659232f317352e1ddff3478262d06b46a573c45409bc461883e1", + "0x916449580b64a9d8510e2f8c7aee0b467a0e93b11edc3d50725bcbc3ca53c2b8bb231fdc0fc0ed5270bf2df3f64750d9", + "0xb2e687caa9f148c2b20a27a91bada01a88bff47faaf6ed87815db26bb6cdd93672199661654763a6b8b4b2012f59dcca", + "0xb6933f7f9dabc8fb69197571366ac61295160d25881adf2fcc8aaabc9c5ed7cf229a493fd9e2f1c2f84facd1f55fee84", + "0xb01eb8b2cf88c75c3e31807cfc7a4d5cafded88b1974ba0a9d5aaeda95a788030898239e12843eda02873b0cabe30e2b", + "0xa3ca290fa6ce064514a3431b44ecdb390ef500629270202041f23bc2f74038147f338189c497949fb3126bae3a6e3524", + "0x93b0f8d02bd08af74918b1c22131865aa82aba9429dc47f6b51354ba72e33a8b56684b335a44661aa87774931eb85974", + "0x81eebeb9bd92546c37c98e0a5deba012c159f69331a89615cf40c5b95c73dcdbf3ceb46b8620d94ff44fcdad88020c1e", + "0xb350e497932382c453a27bb33d2a9e0dbadf4cd8a858b6b72d1f3a0921afc571371e22b051b97da3bb08694c4ca3a4e8", + "0x8c7052f63ba16f14fa85d885aa857d52f04b3a899a4108493799c90c0410de7549be85bec1f539f1608924668df48e5a", + "0xb397574d1fb43de0faaea67d1d9348d67b712b1adce300d6dc497bca94e0994eef8707c285c5c9ac0a66022655a8420b", + "0xa934661d2168ae1bd95b1143c2e5c19261708aeb795abad8ec87f23dc1b352fa436de997ebb4903d97cb875adb40dc2b", + "0xacf535fa1b77255210e1b8975e0e195624c9e9ffd150286ccd531a276cadc12047a4ded6362977891e145a2bd765e6b9", + "0x8cc32356015d7fd29738dcc13c8008cdbe487755dd87d449ab569c85d0556a1ec520dbce6c3698fc413d470c93cb0c92", + "0x8787c7b3b890e0d3734ac1c196588cacf0a3bde65e2cf42e961e23dbf784eef14c07337d3300ed430f518b03037bd558", + "0x99da90994030cbc2fb8a057350765acac66129a62514bbd3f4ec29d5aab8acdd5f4d69ca83efe7f62b96b36116181e79", + "0xa306424f71e8b58dfa0a0564b2b249f0d02c795c30eee5b0ad276db60423210bba33380fb45dbe2c7fedd6ee83794819", + "0xb207a35d31ce966282348792d53d354bbd29ac1f496f16f3d916e9adbf321dc8a14112ca44965eb67370a42f64ca1850", + "0x89e62e208147a7f57e72290eefccb9d681baa505d615ca33325dfa7b91919214646ca9bdc7749d89c9a2ce78c1b55936", + "0xac2d0ec2b26552335c6c30f56925baa7f68886a0917e41cfbc6358a7c82c1cb1b536246f59638fb2de84b9e66d2e57eb", + "0x8f1487659ecc3b383cebc23a1dc417e5e1808e5c8ae77c7c9d86d5ab705e8041ce5a906a700d1e06921f899f9f0ee615", + "0xa58f1d414f662f4b78b86cae7b0e85dfddae33c15431af47352b6e7168a96c1d307d8b93f9888871fc859f3ed61c6efc", + "0x94f3626a225ac8e38a592b9c894e3b9168f9cf7116d5e43e570368ee6ee4ab76e725a59029006a9b12d5c19ddce8f811", + "0xb5986e2601ad9b3260e691c34f78e1a015c3286fdd55101dcef7921f6cbcc910c79025d5b2b336d2b2f6fd86ee4e041e", + "0xb6e6798ddd0255fbe5cb04a551a32d4c5d21bdfd8444ff2c879afe722af8878d0a3a2fe92d63936f1f63fea2d213febf", + "0x86bea9bfffef8bc11758f93928c9fdfae916703b110c61fa7d8fe65653f8c62c6fecd4ff66a1f1a7f3c5e349492e334c", + "0x9595a4606284569f4b41d88111320840159fd3b446e00ec8afd7ddaa53dd5268db523f011074a092f8e931fc301a8081", + "0x83b540a6bc119bf604a7db5f6c0665c33b41c365c12c72ca4fa7b0724115bbb0ff1ae38532c3356e8bb3ac551285929f", + "0x92c6daf961ca4eb25293e1794cf85cda4333cf1c128207af8a434e7e0b45d365f0f5baaefc4ebd5cd9720c245139c6e2", + "0xb71465f3d7dba67990afc321384a8bb17f6d59243098dbed5abd9a6ffc7a3133b301dd0c6ca3843abbaa51d0953abbed", + "0xb15d93482d2ee5b1fec7921fcc5e218c1f4a9105a554220a4fb1895c7b1d7a41f90bbf8463d195eecf919fcbe8738c51", + "0xa79c98e70931ffd64f4dcf7157fbae601a358261e280fe607eb70cef7d87f03efa44cf6ba0f17fbb283a9c8a437d2fdb", + "0x9019d51a6873331f8fe04cb45e728a0c8724a93d904522a9915c748360ddf5cdbf426a47b24abf2005295ed2a676cbf0", + "0xb34cc339fec9a903a0c92ce265e64626029497762ff4dcaaf9bb3994298400ce80f4fb7dbe9ec55fe0c4a522c495cb69", + "0x8fda9be7abfe3b2033cad31661432300e2905aef45a6f9a884e97729224887a6ec13368075df88bd75c11d05247bef15", + "0x9417d120e70d6d5ca4b9369cba255805b5083c84d62dc8afec1a716ead1f874c71a98ad102dac4224467178fe3228f62", + "0xa0a06b64867eebb70d3ce8aaa62908a767fb55438a0af3edf9a8249cd115879cde9f7425778b66bb6778cb0afeb44512", + "0xa44309d3e1624b62754a3a4de28b4421f1969870f005ac5dc7e15183fa5b3ad182bcd09cca44924e03fbdb22f92f8cf8", + "0xaea80f1c3a8fc36cfb5c9357d59470915370b2bec05f51f1d0e1d4437657e2303ba2d1ac3f64cf88f2df412dff158160", + "0xb3f1557883d91b24485123d2f3ae0fce65caa533c09345ae6b30d2ac49953acee61c880c57975be7b4f5558d3a081305", + "0xb52cb1e56f0d147cfb58528b29c7a40bab7cfc9365f2409df7299bfc92614269ff9de3cb2500bbc4909f6a56cf4b9984", + "0xaa4f8fd0f5f87c177ee7242f7da76d352db161846cd31523a2100c069d9e4464170eec0bffc6d4da4f9e87017b415dbd", + "0xb5b61f52242985c718461a34504f82495d73cbb4bc51f9554b7fe9799491f26826d773656225f52a1531cd5bd6103cde", + "0xad12ba9697804ede96001181c048f95b24ba60761c93fb41f4b4a27e0f361e6b1434e9b61391bacaf0705fdaa4a3a90e", + "0x9319286cbda236f19192ae9eb8177e5a57a195c261082ba1385b20328fb83ed438f29d263dddae2f5278c09548830c4a", + "0x88b01ee88c3a7ae2c9f80317dddbaa2b7b0c3a3c23828f03ff196e244500410c9ac81c2e2d3e1f609d4b36ee1732738c", + "0x8e31f30600a9d629488d44a008c821c3c57f13734eaee5a19f0182a2de9e538fff7d982980d7fcc725c969f29f7c2572", + "0xb215740eea98b4bb14197a803a8975700ad2f25a25ef3628eae10166d56c823301f6dd62ce3f9ebf2d42d1f33d535004", + "0x8fb0fdb253d4bcc6693642779be13a5b816189532763dfd7da868cfacfdb87cb5ebe53b18b69dfd721f8d4baf3c1d22d", + "0x8cdd050a447f431ff792156d10381aaf83c6634a94b614dd5b428274538a9cc1f830073533b4fd0a734d6dd4f8d9c4ce", + "0x81b01ee8c72ac668ad9dd19ead2d69cac28c3525e613e036e87aa455c2da9651cc8fcc97c451a8c8a071a4eb69623cd1", + "0x8d9e02dc9ac83f861b3745bd69216232144c47cb468a7dbc49083ed961f978e34265b3f42c400339120bdc4644fe5711", + "0x89e9410455b34cba9db0a5ea738e150fae54dd000d61e614f3274a6c8102ba7cd05b0936f484a85711ad9da7946f51ea", + "0x91f9d4949678f8e6f4b8499899818bdd0f510da552b5d79d8e09bf3b69d706ab36524b5e86d3251318899b9223debf6b", + "0x8b3c38eec7e1926a4be5e6863038c2d38ab41057bcfa20f2b494e9a0c13bc74c3a44c653402eb62a98e934928d0ebccb", + "0xa5cfe465bfbf6e8bfbd19d5e2da2fc434bd71acd651371087450c041aa55e3c4f822361e113c6c3d58646ed3ba89d6da", + "0x918665b8810bcb8d573ca88b02a02c62eaa5a4a689efb5c564b0c9183f78144e75d91fd1603e17d2c77586cbe5932954", + "0x997dace0b739aeb52ba786faae5bdf1d48630a90321f9ceebfa9e86d189a3d79d7b04e459ac8e4adcfe83a5ce964eb1c", + "0xa5a1ca9f0ccc88017a616d481d912aab3f0e154b673f1131c5d9c9c3f5f147d25b6392b2c31e49f7bb7eb2697d05dbec", + "0xa76e99bec509eff01bf6767a06ac97ebc6671cb58bc3d4acc2803580a874885453dbba2e1bba26e45f8d2bda5f688860", + "0x956c1362c8123c5d9ebff7049e851235d69fa645f211ef98e2b6564f2871114a12224e0ec676738d77d23c709dd28a6c", + "0x885efede83b1a3e96417e9f2858ab0c7a576fc420e8f1f26cabf3b1abeec36bcaa63e535da177847f5e0afdb211bf347", + "0xaffca2257f292a2db52f8b1bab350093f16f27ef17e724728eeaec324e2513cd576f6d2e003cc1c6e881334cb2e8bf22", + "0x8dac963d34dcc9d479207a586715e938c232612107bb2d0af534d8da57ad678555d7c1887fadca6551c4f736ffa61739", + "0xb55e600a6bbde81f5a0384f17679d3facb93a7c62ca50c81a1d520cf6e8008ac0160e9763cb2ca6f2e65d93ca458783b", + "0x9485e6c5ab2ebfb51498017e3823547b6ab297d818521ceac85cd6c3aa2d85ae075a0a264ae748fc76ce96a601462ffa", + "0xb4d8abca786c0db304a6634fba9b2a40d055c737ed0f933e1739354befdae138dae3c8620a44138f50ebeaf13b91929f", + "0x8bde7ca39c7bda95b1677a206b16c3a752db76869ea23c4b445c2ff320f2ee01f7358d67a514982ee3d1fb92b7bd7229", + "0x8f8cd0acc689b6403ee401383e36cae5db2ff36fc2311bbadf8ebb6c31cbcc2ca4ffac4c049da5ba387761ef5ec93b02", + "0xa06f42d5f69a566ff959139c707355bbf7aa033c08d853dce43f74a9933e6d7b90e72010ef3fcb3d12e25852343d1d31", + "0xb10ece7cf6b69a76dba453b41049db0cdf13d116cf09c625312b150ee7437abd71d921eda872403d7d7ce7af1e6dccb7", + "0xa3d820318e0f3b54fba7a4567912a82d6e6adf22b67cfc39784683a8e75f77538e793d9708aae228fa48a71abb596195", + "0x8758fad55b68a260bea3bd113e078fd58d64a92f7935ff877f9f77d8adc0994b27040cfc850126c7777cfdfb2428a3e5", + "0xb504913ee96c10f00b848cd417c555a24bc549bf5c7306140eff0af2ada8cb5e76bed1adb188e494332b210fbf24e781", + "0xa00e019a40acc7aab84c1cc27c69920ad7205c2a3dc9e908a7ef59383695c9cb7093c4bcbc2945aab2655119552e3810", + "0xb1000b4c4f306672e39d634e5e2026886a99930d81b8670a5d4046db9621e44997c4b78f583374a09c60995f18a6fd4f", + "0xa6c5053c4e748540ad2b622c28896c9d4ca3978ca4784ac8f09da5314a245f5cdc5d6203c84e6e0bcb3081829720a56d", + "0x8e37e67a70205a5c7da95de94ac4d0ebd287c1c9922d60c18eec1705030dfcbf74ae179e377c008bf5a8bc29c7c07cce", + "0xa66bd7c0243319b553d5cb7013f17e3504216e8b51ba4f0947b008c53bcb6b4979286b614a4a828ee40d58b5ef83e527", + "0x97e2110b0fb485508a2d82ecc2ce1fbe9e12e188f06c7ef2ac81caeeb3aca2c00e5e6c031243b5ca870a9692e1c4e69b", + "0x8734ce8bbc862e12bea5f18d8a8d941d7b16a56ef714792fed912ca9c087497e69b6481fdf14efe1f9d1af0a77dac9b1", + "0xb441dddac94a6a6ae967e0e8d7ab9a52eb9525fb7039e42665e33d697e9a39c7dcef19c28932fb3736e5651d56944756", + "0x918b8997f2d99a3a6150d738daed2ff9eb1f5ed4a1c432d18eab4a898297f7ffbffd1e4ae9037acf589b1cd9e1185ef6", + "0xa0247b8ac4d708cf6b398dc2d5c127a291d98e8bef5f195f820c4fddb490574ba4f62647c2d725237a3e4856eec73af0", + "0xb45636e7e0a823c2a32e8529bb06fcccfd88e9964f61201ee116279223ed77458811d1b23bcb6b70508d16d4570a7afb", + "0xa99c1188fa22b30b04fda180d2733586ea6ef414618f1f766d240c71f66b453900d3645541c019361027aebe0a0f305f", + "0xb4c2f758e27fe233f7e590e8e0c6de88441164da3fcd5211a228318d3066dfdafc1d40246dd194f2b597f6fe9600b3d7", + "0x972530819445b11374c3043d7855d5f1d3c4922b3b205d0bf40162c51605375dd0b61f49cd7f3d39a533a86a13005989", + "0x992b533a13e5d790259bfdfdf1074f84a5e5a0a0d7be9cd6568cdc1662524f1a6666a46da36cea3792ba6707850f4d86", + "0x9875d130457e04dc6ea2607309bfbb900ad3cb5f3e0574f808d27b20cbf6f88389d87dca19998680c5bc30d1df30a41b", + "0xadea8494a69e83221edf360ab847272b5c47eba5404665fb743d98c0682732c30085ae3ec82bc1e8e4aba8454c9b1849", + "0x887d4c624ce05e224216c5f6fa13c5741012ac33330bc291754782f0bfe668decdc98c0e43a1ce28323effe6b639f477", + "0xab6b167aeb5e93ab155990b94895e7e7ff6dea91384854a42cc8a3b9983495b4b3c33ab1b60b2b6450ccf0418fada158", + "0xa7588d0b7c6a6bc32fc474aa0f4e51dfb8e6e010346ad32c59d6f99e6f0522424111a03a4f56ba4075da8009ee7a63e9", + "0x94d645cc3936db1563568193639badfc064dd5bda8d0631804ee00b09e141b200619e07506b5a8225130541436327194", + "0x8d695c03cc51530bdc01ee8afcd424e1460d2c009e1d7765c335368e5c563cf01a2373c32a36400c10e2bf23c185ed19", + "0xad824a0a7ed5528e1f9992cbb2050785e092b1ea73edd7fb92b174849794a5b04059e276f2941e945bc0f3e46172f2af", + "0xad6ed2af077a495d84f8eeed7d340b75c0d1c8b7c5a854dfc63ab40a3d0c2b0d45016d30b3373a13f0caae549f657976", + "0x82454126c666023c5028599a24be76d8776d49951dfe403ebf9a5739b8eb2480c6934a34010d32cd384c91c62a9aa251", + "0xb57070006793eca9fa2f5237453ed853994ad22c21deb9b835e1fb3fbc5ac73aec265a4a08de7afae1610dc8c42b7745", + "0xad94667c791cf58875eb77eb17b6ad02de44e4ba2ddc2efe4d0ff22a5e1a090c670354437847349fd61edc4ba5606f07", + "0xb2aac0c345ffc00badaab331c12a22019617b004d32c099c78fa406d683744d96d51d1237ad0842f9f54655186f8f95b", + "0x8fed51076cc939b354e3b69034a594e6c9c98425ccf546154ab087a195375128444732388d2eb28f82877de971ec2f58", + "0x8e521c0093deb9dff37888893db8ffebc139984e7701e68b94d053c544c1be0d85f0f98d84b2657933647b17e10a474c", + "0xa2c6c9a307aff9b1dea85f90fa9e3b8057fd854835055edeb73842a7ef7c5ae63d97c51fec19dd8f15d696a18a0424a6", + "0xa3390b25a9c11344ed1e8a0de44c848313026067a0f289481673c2c0e7883a8fc9f6cab6ccd9129729a6d8d0a2498dc2", + "0x82770c42b1c67bbd8698c7fe84dd38cc5f2ad69a898097a33b5d7c5638928eb1520df2cb29853d1fa86a0f1bcc1187e8", + "0xa6fdf7a4af67bc4708b1d589135df81607332a410741f6e1cc87b92362a4d7a1a791b191e145be915aa2d8531ee7a150", + "0xaecac69574188afc5b6394f48ba39607fe5bb2aa1bd606bc0848128a3630d7d27101eb2cea1fb3e6f9380353a1bb2acc", + "0xa23fd0c52c95d0dffb7c17ec45b79bf48ed3f760a3a035626f00b6fe151af2e8b83561d0b9f042eaae99fde4cbd0788d", + "0xa5f98068525cdd9b9af60e0353beb3ac5ac61e6d3bac1322e55c94b3d29909d414f7f3a3f897d5ae61f86226219215c6", + "0xb2a4d724faac0adf0637c303ff493a1d269b2cdbec5f514c027d2d81af0d740de04fb40c07344e224908f81f5e303c61", + "0xadeadb3521e1f32ef7def50512854b5d99552e540ec0a58ea8e601008de377538c44e593e99060af76f6126d40477641", + "0xa18b7fc2fcd78404fed664272e0fef08766a3e2bc2a46301451df158bd6c1c8aa8cf674dd4d5b3dedfaceb9dd8a68ae3", + "0x83bcfb49313d6db08b58c6827486224115ceef01ca96c620e105f06954298e301399cdd657a5ff6df0b0c696feec1a08", + "0x8c94391eba496e53428ec76dfe5fa38f773c55c0f34a567823316522a0664a3d92bff38ec21cf62ac061d7d1030650c5", + "0xb1fa196ccfd7d5f1535b2e1c002b5cde01165c444757c606b9848bc5f11b7960973038fb7cc3da24300fc1848e34c9af", + "0xb139f6c6449449638de220c9d294e53fc09865a171756d63bbf28ec7916bf554f587c24bddf51dd44372d15260d8fe25", + "0xb716242299d4ee72b5b218781b38ca5e005dcf52333364f85130615d1dbf56216af8ee2c9c652d82f7aab5345356538c", + "0x9909f24e4ad561aa31afd3a3b9456b2bd13a1d2e21e809a66af62fec5f95b504507ac50e81d2233da2b223f5443e7585", + "0xae863530a02cf3a757f72b945c8c0725d9f634d2ff26233478d1883595ff9a1eef69e8babffdbfa161452fc204f5b5a1", + "0x8eb82bde283b6a6e692b30236cbf41433b03eda8dad121282772edd56f144b1ebf5fb489d18c6ce8776135771cbb91e2", + "0x9296141fadf8dadc885fff4999c36efa25ec76c5637a8300a1a7dc9cf55bcedfe159e0ef33f90eee9be8c4f085734e10", + "0xb6c07f2e6fcbd6c42a8b51e52fbcd5df3aa9f7c3f0b3c31021de1aec2111d0a1c36b5ab489ba126af44fd43cf31c2594", + "0xa70ca669c357535b363d16b240fd9cb9c5ba1b648510afc21218ea034e9bf5f22717ae31ff43ef89dded95b7132fa58f", + "0xb350721f8f6b4d164fd08aca30cd4dece9b4a81aed0ac12119c9399bab691d5945814306f9a61f0106b76d4d96f7b9d6", + "0xb6886076c9d8c344bf3fb6975173d00fa82866012894f31c17e6fc784fbc0dd2d24d6a1cddd17f7379c74566a23219aa", + "0x87636e4a83ceadc170a4b2517b19525c98e2163900401996b7a995b2f3da8d6ba2ab92f909eade65074fac07cf42f6fa", + "0x8ff61d87c4699a067a54b8540e8642f4c7be09d3783ec18318bcba903c6714fcd61be69165e07e1ca561fe98e07507de", + "0x85485d6b569ac20e6b81a9e97ef724e038f4fee482f0c294c755c7b6dad91293814f143bfcfc157f6cfa50b77b677f37", + "0xa49256cb1970cc1011a7aed489128f9b6981f228c68d53b1214d28fbcfb921386cc7cf5059027e667a18073efa525a74", + "0x87bc710444b0c3e6682d19307bedc99c22952af76e2d851465ee4f60e5e1146a69f9e0f0314f38a18342e04ece8e3ed3", + "0xa671a6cabfd19121a421fdfe7732eccbb5105dfb68e8cbcf2b44ae8465c99e78c31b99730beca5bc47db6fc2f167203a", + "0xa2f3270c184629f6dfc5bf4bdd6e1b8a41e8840a1e4b152253c35c3d9e7ab4b8e3516dc999c31f567e246243e4a92141", + "0xb9795a5a44f3f68a2460be69ecacdbb4664991ebbedffed5c95952147ad739e2874c099029412b9653d980a2d4307462", + "0x959053faec9a966dd5a4a767a3154e4b8e4f56ca540ae53e373c565dda99fb626f725e5a5e3721c82918f8c5f2e9e0a3", + "0xb3ef9d6a1b3cd44a3e5112819fa91cb8a7becc3f5b164c6f759f93171d568497b01c8e743f4727b341a1296a0dbadf4f", + "0xb852dfdfbe2b8c77d938fad45f00737e14eacf71d5fecbb3e4f60052ec9efb502c38c1fcecaf71da69eabe8b33852a67", + "0x921c7007f26bdd4139e919dfe27d87b489a0bc5bd6fb341e949e4451f14c74add0489b108c9c9666a54c5455ac914a9f", + "0x86b63d73ba31c02e5337f4138e1684eccdc45ab5e4f30e952fb37d638b54ecec11010414d7a4b7aa91f7cc658f638845", + "0x853c55e0720b66708a648933407795571fc11ad5c234e97f92faabce9e592983dfb97a1705047ee803648ecf9fbb2e5c", + "0x995fe7d1dc09bb0c3c3f9557c4146534778f5ea9c1d731c57440fdcf8094f82debf19090b5d23298da1ed71c283b3ae5", + "0xb9c49c911a0c4d716b7baec130f9e615bfa7d504aa8766ed38878a93c22b1f6353503d4f7f425d4902239fb4689429df", + "0x80504d964246789a09dcd5c0298680afb6fe50bca3bb9c43d088f044df2424a1828de10e0dbdc5c0aac114fa6d9cf5d1", + "0x90249351f109f6b23a49a610aaa3b2032189fd50e5e87cdc3b20f23ed4998af3a8b292bf9fbab9bd1cbe0a1371081878", + "0xabb5f0148850f0d80b429c2b9e0038772432340ef0862ccb5dcb7347026ca95bf9a5857f538e295aebd3a6a5027adb4c", + "0xb92ac9c0f7e73150798348265e5f01f3c752480c72613c6894a95e9330bba1c642b21b9cbd8988442b5975476634b4fa", + "0xaf3fbcc825abd92c6d7ea259467f27045e288f27a505e6a3c9ec864aa08fcaca0d4123034513dbd4c82d4814075708ab", + "0xa738232a66030e0e9c78e093a92fcc545b10e62fb0ecb832bbbc71471b28eb6ec422a498c2402e2c6d74983df801e947", + "0xae60194ce2035edd1af253b9eefbb4b1b7609c9678256c89c3cb076c332a9f4442c3441ad2ecc9d73265359bdadc926c", + "0x8b2fd55e686f16725fc0addb4065f696275852320b03221fd22889825d66fae5bb986b03c47452e32b3a32c1fdfc8dfd", + "0x8e2e1a36673b7729b07e7bc5014584e1c03e9552f7440fbfda0a6a7f41953947fcdf8d666f843bfc03dcca5b06a14318", + "0x95a3df04368c069f3fd32a20b627c5f043e952167c9e80bf5914bbf2086879909c60e089bbd488725ab977c0e6051728", + "0x9856403b2211d0152d4eec10db7ec34c16ac35170714b75af3ebc398a676c171b24b6f370361de0f9057ba444293db14", + "0xa2cb484b758af5fd8e2baca7f0406f849c71255e58ef110d685cd0c1137893a25d85a4d8582e3ced7dd14287faa95476", + "0xb0f697b6a42f37916b90ab91994ae4a92c96dc71e4da527af41b9d510bc2db5a9b4f29183a758074b6437a1e62b2d1d7", + "0xb39c49266aae46f257b7ae57322972fb1483125298f9f04c30910a70fe5629dba0ec86b94cc6ba16df3537a55e06f189", + "0x86cd5595b5b769dfd9ceb68b11b451f6c5b2e7a9f6f6958eac8037db1c616e8a9defb68a0d6c2287494d1f18076072c1", + "0xb462e8fa9a372d4c1888fd20708c3bed1cb00c17f7d91a0481238d6584fbbf2d238e25931154f78a17296a12825d7053", + "0xa5ef28286628ba509bac34c9f13158d0013239fdca96b5165161f90b89d6e46295822ebdf63f22d7739911363a0e0e86", + "0xa629a95a24e2545862b41a97ecba61b1efa792fd5555dc0599c175947e9501bffc82b05a605fd5aabc06969ccf14fff4", + "0xaf83467e4b1f23a641630cc00c38d4225ff2b4277612b204d88de12a07d9de52fb4d54a2375a7fd91eb768623c255376", + "0xa630f29fb2e9a9e2096d7f3b2f6814ee046ebc515f6911d4bc54ad8a5a821a41511ff9dcfbe3176f35c444338ecd0288", + "0x950dedc11bd29e01ba9744bec681ad9462127c35e9fcadfacc9405ec86b985a1b1c4f9ac374c0f1fa248212e5e170503", + "0x82e8e7be8011ee0fd9c682d26a0ef992d0191e621d07fd46a3a5640ef93a42e1b98a33cad1f8017341a671d28caebb03", + "0xa075860554e712398dac2fb0375067a48d0e4ca655195cefc5ccb1feb8900d77124aa52a12e4f54f7dab2a8f1c905b5b", + "0x81d2183d868f08714046128df0525653a2dc2ff9e2c3b17900139c9e315b9f4f796e0fb9d1d8cbadbaa439931c0e0879", + "0x81fb1456969579515a75fb66560f873302088cde2edc67659b99a29172165482ca1f563758c750f00086b362ae405322", + "0xa13c15ab19203c89208c6af48d2734bb0873b70edb660d1d5953141f44db9012528d48fb05aa91d16638cbda2ca8f0cc", + "0x8ba46eef93e4ec8d7818124a0b9fcfe2bcf84a98db3545d2b3d0192cfadc81fc667dcc22ab833c3e71508d0f3c621fe4", + "0xb9bd60d2266a7d01e1665631a6ed6d80ffc0cd7f088f115a5d4ea785c518a8f97d955e2115b13c4960302b9825526c92", + "0xb26fa4e87142150250876083a70c229249099331410f0e09096077fdf97b31b88dc57a3e3568d2a66a39af161cf5dfec", + "0xb9d147564124728b813d8660ba15fa030c924f0e381ad51d4e0cf11cc92537c512499d3c2983dd15f2e24ca166070d70", + "0xb6fb44e1a111efb3890306fa911fafda88324335da07f7de729b2239921ef15b481630a89c80e228bec7ab6444a0b719", + "0xa6cd9c7acac052909ef0cf848b6012375486b59b7bac55b42c41f0255b332c1d45a801f6212d735be8341053bd5070b9", + "0x864258d69234786af5de874c02856fc64df51eff16d43bfb351b410402ab28f66895aec4025e370a4864f19ff30fd683", + "0x84370fa1243b64b3669dd62e1e041ff9bd62810752603486aac3cba69978bd5f525c93cbc5f120d6f2af24db31ec3638", + "0xb983c2cdc1a310446de71a7380b916f9866d16837855b7d4a3a6c56c54dab3e373a6fc6563b8309dc3b984d4e09275d6", + "0x914f8587f876470f7812fa11c6f67e2dd38bf3090e8928e91fe2fe5595bee96cbe5f93d26fdced6b4e7b94f75662b35d", + "0x8b47bcb111d91aa3d80e4ceef283824aa00d1faeb6fe4111aecd9819869c0e1f6f4b6fb2018aebb07a0f997412cda031", + "0x95b2befa98f9992450ca7ff715ae4da8c36dd8adcfef3f0097de6e3a0b68674b05cbf98734f9665051bb4562692641e0", + "0x8bcd1651a2bfce390873a958e5ff9ca62aac5edd1b2fd0f414d6bcf2f4cf5fa828e9004a9d0629621b5e80fbbd5edb90", + "0xaf79bed3c4d63239ac050e4fa1516c8ad990e2f3d5cb0930fc9d3ce36c81c1426e6b9fe26ac6a416d148bf5025d29f8b", + "0x881257e86b7ab5af385c567fde5badf67a8e7fff9b7521931b3ce3bac60485c0fe7497339194fb7d40e1fad727c5c558", + "0xa1b40b63482cd5109990dfb5a1f1084b114696cbbf444bf3b4200ab78c51dad62c84731879ea9d5d8d1220e297d6e78a", + "0xb472212baa2a31480791828ca5538c3dcc92e23f561b0412f8cc9e58839d1625ddcaf09c8078d31ac93470436843cd74", + "0x8f516d252b1863cd3608d852a2857052bb2a3570066d4332fa61cb684b10ac8d1a31c8d32f2a0d1c77eee2ad7a49643d", + "0x8d20b75c51daa56117eda2fd5d7a80a62226074b6a3ff201519f2054eecfeff0aa2b2f34b63bea3f53d7d0ce5c036db9", + "0x8282f433229e7948a286ba7f4a25deb0e0a3c5da8870562c3646757bef90ca1e8d3390b0a25b3f2bf45bf259a4569b77", + "0x8a2dbf4b55cc74f0a085d143a88ebc8c2a75a08eab2703d13a00b747eaddc259a3dd57f7330be938131835a6da9a6a68", + "0xaa0bc51617a938ea6a7b0570e98b8a80862dd9e1cf87e572b51b2a973e027bcd444ef08e0d7b5dee642e0da894435e91", + "0xaa7319ca1ac4fe3cc7835e255419eeb7d5b2d9680769cc0ca11283e6147295db75713b71a9312418a8f5505cd45b783d", + "0xab3f9c465663dc90fae327a2ee9cb7b55361a9b6fbe713540a7edd3cff1c716802fb8ad4dd8fb0c945d96b3b44c5795b", + "0x913a2ae88acffab12541fc08920ee13ab949f985a117efe9a5b2c76f69f327f60c5b5ad3fa5afa748034ac14298fc45a", + "0x9008f044183d2237b723b235953e4d8b47bec6a7b300d98075555478da173b599ba9c7c547c2f111ce1fae5ac646e7a3", + "0xa26b4cc42b353e1c18222d2e088d7f705c36be12e01179db440f10fcfa9691d31fc4fc7e7ee47876f1624e6d44be1021", + "0x995e75824f322294336bfa2c5d1a319f0d77f6a0709beabaf1b43015d8a78d62447eab907349524734170f0294d1ca7a", + "0x8b96f04a19dbe4edc71d1f2c6d3475ae77962e070ec5797752453283c027c6b29b6e58e8b7eb5c3f9770557be7e80b67", + "0x8621459865234734bcfaa492ca1b89899525198a7916ccc6f078fb24c8bf01154815bb5b12e1c3d0a10bd4f1e2ea2338", + "0xab52174541185b72650212e10a0fe2e18ccfd4b266a81233706e6988c4af751b89af87de0989875f7b5107d8d34c6108", + "0x966819d637bdd36db686be5a85065071cf17e1b2c53b0e59594897afc29354ecba73bf5fc6fa8d332959607f8c0a9c27", + "0xb7411209b5ab50b3292c3a30e16f50d46351b67b716b0efb7853f75dc4e59ec530a48c121b0b5410854cd830f6c4b3ea", + "0xa5dc04adbadce0af5dc1d6096bad47081110d4233c1bf59a5c48a8e8422858620f4be89bf1f770681be2f4684ee4cce7", + "0xaf77a8f83cffb5f8d17be0ab628dedcad63226c9b13ce4975fb047f44bfef7d85e7179aa485abb581624913eddbb27ec", + "0x82bf28dc58c893c93712ce297cc0d64f70acb73a641cb4954ccf9bf17597f6d85eecf5a77c8984ab9afbe588562a0ee9", + "0x988a7cef9a178e8edb91f3ec12f878fd68af2ac0762fa0a48a2423e24f765ed8f7837429fd8bc0e547e82e6894e63008", + "0xa5d5969311056d84b3ee87f49286fac0bd9a7220c196cea4f9dced3b858dcdba74718eab95b38bd5d38d2d1184679c98", + "0xaf4d51b3ded0aaad8f12bef66c0616e9398fc42618852ac958e6ab2984a720a6111ac55b249d7e4523051740e12b346f", + "0xac635b4a49f6fbb94a5f663660f28431ba9f7c5c18c36ebc84fd51e16077de7753595f64619b10c16510ecbc94c2052d", + "0xae25eb349735ced1fe8952c023a9b186a1f628a7ddf1a4b6f682354a88f98987ac35b80b33189b016182f3428a276936", + "0xae3ab269690fdd94134403691ba4f5ed291c837c1f5fdc56b63b44e716526e18abb54f68ca5d880e2fb7bea38e74c287", + "0xa748b03b2bd3fbc862572bc4ddc0579fa268ee7089bcfd0d07d0c5776afcd721302dbb67cb94128e0b1b25c75f28e09a", + "0x8f09a2aaa9ba3dfe7271f06648aba9cc1ea149e500a7902d94bb9c941a4b01d1bb80226fd0fd2a59ad72c4f85a2a95d0", + "0x853d55ad8446fd7034e67d79e55d73a0afcb5e473ed290e1c3c7aa5497e7f6e9bbf12d513fc29e394a3dc84158a6d630", + "0xb1610417fb404336354f384d0bf9e0eb085073005d236a0b25c515d28235cea5733d6fbd0ac0483d23d4960064306745", + "0x86de805b3d4f6fbb75233b2cf4d22fcc589faa2ac9688b26730cb5f487a3c6800c09bb041b2c6ab0807bfd61b255d4c9", + "0x893b38c72cf2566282ee558d8928588dca01def9ba665fcb9a8d0164ee00dedafbf9d7c6c13bcc6b823294b2e8a6a32c", + "0x8e50de7a70ac9a25b0b5cf4abc188d88141605e60ce16d74a17913a2aff3862dec8fbbf7c242cf956f0caae5bcc4c6bf", + "0xb5cf09886a4fb4ce9ea07d1601d648f9f9d1a435b5e1e216826c75197cd6dafd6b2b07d0425a4397a38d859a13fdb6dc", + "0x859dc05daf98e7f778a7e96591cc344159c1cbe1a7d017d77111db95b491da0a9272866d2638a731923ca559b2345ebe", + "0x8ff1792f77ecdfbd9962f791a89521561c7b82031a4e53725f32fe7d99634a97b43af04cbf3e0b0fdff4afa84c49eb99", + "0x81e2cd8a221b68ae46dd7ce97563bd58767dc4ce1192b50ff385423de92206ff585107865c693c707e9d4ed05f3149fb", + "0x8fce7da7574e915def0d1a3780aa47ef79b6d13c474192bd1f510539359494ddc07e5412f9aac4fc6c8725ade4529173", + "0xac02f5df60242734f5ead3b8a62f712fefdb33f434f019868a0b8ddf286770244e2ddfb35e04e5243ba1e42bcd98a6a5", + "0xa8d69783349a442c4a21ecb3abd478a63e2c24312cb2d2b3e10ea37829eb2226a9b8d05a8c9b56db79ffaa10d1f582d1", + "0xb25b5cca48bf01535aba6d435f0d999282845d07ac168f2ca7d5dba56ee556b37eab9221abdb1809767b2de7c01866c1", + "0x8af7e1d1f4df21857d84e5767c3abe9a04de3256652b882672b056a3ab9528e404a8597b1ad87b6644243f8c4cd3799f", + "0xa6718308dfa6992ae84fcb5361e172dbbb24a1258a6bd108fd7fc78f44cc1d91be36e423204a219a259be4ab030f27ff", + "0xb99cbe3552c1a5259e354c008b58767c53451932162e92231b1bebfc6a962eb97535966a9bd1dfd39010dfcda622d62a", + "0xa8458f6b8b259581f894e4b5ce04d865f80c5a900736ca5b7c303c64eaf11fe9cb75e094eece0424ba871b2aee9f7a46", + "0x914f763e646107b513c88f899335d0c93688ffa6e56c3d76bff6c7d35cb35a09f70dc9f2fe31673a364119c67cd21939", + "0x9210f2d39e04374f39b7650debe4aceeb21508f6110ab6fc0ab105ec7b99b825e65753d4d40f35fad283eeff22a63db0", + "0x98729cf927a4222c643b2aa45b3957b418bce3f20715dd9d07997a3c66daa48dd62355dbd95a73be9f1d1516d1910964", + "0xa602c399f1217264325b82e5467a67afed333651c9f97230baf86aec0dd4edeae1e973cafef2ea2236d6d5b26719954d", + "0xac9632921d45900bf3be122c229ba20b105b84d0f0cba208ccdce867d3e9addfb3ef6ece9955950d41e1b98e9191ef42", + "0xa76ce1f53e1dc82245679077cb3bca622558f2269f2d1a1d76b053896eba1c3fc29d6c94d67523beb38a47998b8c0aa7", + "0xb22b51fcc1b328caa67cc97fb4966cb27d0916488a43248309c745cd6e2225f55ad8736d049250fa0d647e5f8daa713c", + "0xb7645c1923a6243fa652494fe9033fa0da2d32a0fb3ab7fcb40a97d784282a1ffad3646c499961d4b16dadbc3cbb6fd6", + "0xacab12b490da690db77c4efdc8b2fe6c97ac4ba5afb5165d6647fdd743b4edbad4e78d939fc512bebcf73019c73bae40", + "0xad7a0fcd4e4ccb937a20e46232a6938fccf66c48a858cf14c8e3035d63db9d1486e68a6bf113227406087b94a0ece6a0", + "0xa78605beaa50c7db7f81ab5d77a8e64180feea00347c059b15dc44c7274f542dc4c6c3a9c3760240df5f196d40f3e78b", + "0x8763315981c8efa9b8ae531b5b21cfc1bbc3da3d6de8628a11dcc79dee8706bd8309f9524ec84915f234e685dd744b69", + "0xb4a6c48531190219bf11be8336ec32593b58ff8c789ee0b1024414179814df20402c94f5bfd3157f40eb50e4ef30c520", + "0x8dac8a3f152f608ce07b44aee9f0ed6030fa993fd902e3d12f5ac70bf19f9cde2168777d2683952a00b4b3027d7b45ea", + "0x8baf7dfae8a5840c5d94eabfe8960265f6287bb8bc9d0794a6d142266667a48bec99b11d91120907592950a0dddc97d9", + "0xb8595e6ea6b8734d8ae02118da161d3d8d47298d43128a47e13557976032dad8c2ccbfff7080261c741d84d973f65961", + "0x8b93979c51c8d49f4f3825826a5b9121c4351e0241b60434a3c94f2c84f0b46bbf8245f4d03068676166d0280cf4f90c", + "0xaceb0fdaf20bf3be6daebf53719604d3ab865807cc2523285f8fef6f3fc4f86f92a83ad65da39de5bd3d73718a9c4bd2", + "0x814dd41764a7d0f1a14a9c92e585f154a26c8dbf2f9bff7c63ae47f1ac588cec94f601ccc12e8a63a7a7fce75a4287f2", + "0xb47b711848e54fa5c73efc079d0a51a095fa6f176e1e4047e4dac4a1c609e72099df905958421aee0460a645cba14006", + "0xaaf7bd7e1282e9449c0bc3a61a4fca3e8e1f55b1c65b29e9c642bb30a8381ce6451f60c5e0403abc8cee91c121fa001f", + "0xb8b0e16e93b47f7828826e550f68e71a578a567055c83e031033c1b7f854e7fc8359662a32cc5f857b6de4aff49e8828", + "0xb3eb70b8c8743a64e1657be22a0d5aeb093070f85a5795f0c4cb35dc555958b857c6c6b7727f45bf5bedf6e6dc079f40", + "0xae68987acd1666f9d5fa8b51a6d760a7fb9f85bf9413a6c80e5a4837eb8e3651a12e4d1c5105bfb5cfa0d134d0d9cfc2", + "0xacd8fa5742b0bac8bd2e68c037b9a940f62284ff74c717f0db0c033bf8637e4f50774a25eb57f17b2db46e5a05e1d13d", + "0xa98dac386e7b00397f623f5f4b6c742c48ab3c75d619f3eaf87b1a0692baf7cb7deac13f61e7035423e339c5f9ae8abf", + "0x99169bd4d1b4c72852245ebfbc08f18a68fb5bcce6208dd6d78b512b0bc7461f5caf70472b8babf3e6be2b0276e12296", + "0x937d908967f12bf7f728fe7287988c9b3f06c1006d7cd082e079d9820d67080736910bc7e0e458df5bae77adb9a7cbc1", + "0x8c50e90ce67c6b297fd9406c8f9174058c29e861597a0f4ed2126d854a5632fa408dfa62ad9bb8b6b9b6b67b895d5a4d", + "0x8f4840a91b0a198226631a28e7a2e893fc6fed4d5eb3cb87b585aac7f4e780855a353631ad56731803296f931e68a8d0", + "0x96a4b8c64d3d29765e877345383bf0e59f4ac08798ac79dd530acd7f3e693256f85823ad3130fb373d21a546fe3ca883", + "0xb0dce7a6ab5e6e98b362442d6e365f8063ba9fef4b2461809b756b5da6f310839ac19b01d3fd96e6d6b178db4ff90ee1", + "0x8f012cb2be5f7cb842b1ffc5b9137cafef4bd807188c1791936248570138f59f646230a1876f45b38a396cbdd3d02e08", + "0x94a87b5ce36253491739ca5325e84d84aaff9556d83dcb718e93f3ff5d1eecf9ae09d0800a20b9e5c54a95dfebfcecd3", + "0xb993ec5f9e82cc9ceeb7c5755d768bc68af92cc84f109dfaf9cf5feb3aa54881e43c3f598ba74ed98e8d6163377440ca", + "0x92f845d4d06a5b27d16aef942f1e3bcbe479b10fef313f9ca995315983090511701b39ccbb86b62d0c7c90a2d1f0c071", + "0xb6ec6da0f9e7881e57fa3385f712e77f798abc523609a5b23e017bb05acc6898825541aed7fe2416c4873de129feceea", + "0x86b181183655badfe222161d4adf92a59371624a358d0ec10e72ee9fa439d8418f03d635435ec431161b79fd3fa0d611", + "0xb5e28eeed55fb5318b06a0f63dbf23e00128d3b70358f1c6549fd21c08ef34cb1372bc0d4b0906cc18005a2f4cd349bf", + "0x85c4d3fddda61dbfb802214aa0f7fc68e81230fb6a99f312848df76cddc7b6dfd02860e8a4feb085dad1c92d9c6c65e0", + "0x80f7fdec119309b2ac575562854f6c2918f80fc51346de4523ec32154d278f95364fdef6f93c7d3537a298dd88df7be6", + "0x9192c1949d058614c25f99d4db48f97d64e265a15254aa6ed429e1ef61d46aa12355769f1909a5545cd925d455a57dbe", + "0xa0b1e7d928efc4dcbd79db45df026ae59c20c1a4538d650c0415ab7cb0657bc1e9daeacc3053ee547e8f9c01bdbd59c4", + "0x893e84c41d3a56bca35652983c53c906143b9ad8d37b7c57f9dacbeb7b8dd34defc6a841f5b9857ffb90062bbd8e9dee", + "0xa7f89a448349dbc79854cf888980327f92aedc383c7fadd34fdc0eaa4f63d751315b4f979e14f188854ef4d16c9e8107", + "0x833f2774a96187805f8d6b139c22e7476bce93bc5507344d345008080fb01b36d702b96e4c045617a23a8ca1770b4901", + "0x80e46e86d68bd0a48ac6fa0b376d5bb93a5d6b14f08b3a47efa02bb604c8828c2047695f1f88fc5080e5548e1a37130f", + "0x943f42b7b4ad930059a26ad06b62e639f06c1c425d66066c55134e97c49abe412358c7cb994fcc1cf517ea296bca1f68", + "0x8b9d4fe835dc6a2cbf85738937bbfb03f0119ab8df04a7d68860716ce6ee757dbe388a1e8854ddb69fe0c9fa7ed51822", + "0x909030c7fde2591f9ea41ae6b8fa6095e6e1a14180dda478e23f9c1a87b42c082a1ea5489c98702f6ccd2ba5812d1133", + "0xa715ec1beb421b41c5155c7ef065bbb50b691d0fa76d7df7ee47683d9e4eb69b9ea3e62fc65196a405d6e5e29e6c2c60", + "0x8c9e801cb7ef780a535be5c2a59b03e56912acbfdb00447bfa22e8fc4b11dceecc528f848d5fba0eec4237d6f81f4c79", + "0xb96b6af857c3bc0344082bd08ec49a9bed478d4d35b85a2099b1849cd6997521c42225305f414cdd82aef94b9e1007d3", + "0x8764db720b4e44a4d2527f7f9b535a494a46c60e28eac06bf1569d0703c4284aefa6cb81fbba9d967286f9202d4b59ea", + "0xa66fd2f9158e1ffcdd576cba1413081f43eed00c7eb8f5919226f7b423f34ac783c1c06247819b238de150eb5a48d977", + "0x82c52e817ac3bb0833ea055dec58c276c86ca5181811cf7a483b3703a06ea1bee90ae3aeaa2cffeaeba0b15fe5bf99be", + "0x987d07cb276f7f03a492cfb82bba6d841981518286402d3e69e730a9a0e29689a3619298124030da494e2a91974e0258", + "0xb34f2c5740236bc6d4ae940920c5bc2d89ff62a3dd3a3ec9a0d904d812b16f483073db1e53b07f2b62e23f381d7bdbe5", + "0xa1c0679331ab779501516681b3db9eefb7e3c0affb689e33326306ada6d7115fafd2cc8c1c57b2fa6c2072552f90a86e", + "0x94805e30d7852fc746e0c105f36961cc62648e438e8b9182fc0140dbf566ec14a37ad6e7f61cacb82596fc82aed321e5", + "0xa42fb00b29a760141ff0faaeb7aca50b44e7bbc0a3f00e9fb8842da7abfcaae6fae9450abe6ba11e8ecf11d449cbe792", + "0x8fb36ce4cfa6187bfe8080ac86b0fa4994f20575fb853bd8ffa57c696179cc39f58ff3b4bd5a2542ff1c8b09015539df", + "0xa1c54e7aa64df7fb85ce26521ecfc319563b687ffecd7ca9b9da594bbef03f2d39f51f6aaff9a3b5872d59388c0511c6", + "0x855e48fdb8f771d4e824dbedff79f372fd2d9b71aa3c3ecf39e25bf935e2d6e0429934817d7356429d26bf5fd9f3dd79", + "0x8ae6157a8026352a564de5ee76b9abb292ae598694d0ea16c60f9379e3bb9838ce7fd21def755f331482dc1c880f2306", + "0xa78de754e826989de56fe4f52047b3ffd683c6ceaf3e569a7926f51f0a4c4203354f7b5cfa10c4880ba2a034d55a9b0d", + "0x97609477d0a1af746455bbd8cb2216adacc42f22bfd21f0d6124588cd4fec0c74d5bde2cdba04cdbfbff4ac6041b61b1", + "0xa03dc3173417381eb427a4949c2dbfa0835ef6032e038bf4f99297acf4f0ba34a5fc8ccf7e11f95d701f24ee45b70e27", + "0xaad6283e85cd1b873aeb8b5a3759b43343fdadc9c814a5bf2e8cf3137d686b3270f1ec2fb20d155bbfd38c7091f82c44", + "0x92ab94ed989203a283d9c190f84479c2b683615438d37018e9c8de29c2610bb8fccd97bb935dca000d97d91f11a98d65", + "0x8c0444a0b9feb3acb65a53014742e764fa07105e1c1db016aec84f7a3011d9adc168dbba8034da8d0d5db177a244d655", + "0x95a33d25e682f6c542d4e81716cc1c57ef19938409df38bf8f434bc03193b07cedd4e0563414ce00ab1eebbd3256f3e7", + "0x8716c30e3e4b3778f25c021946c6fb5813db765fde55e7e9083a8985c7c815e1b3d3b74925ba108d9a733ddf93b056af", + "0xa186aabc10f1fff820376fa4cc254211c850c23a224f967d602324daec041bbe0996bf359ed26806a8c18e13633a18a8", + "0xa1e8489f3db6487c81be0c93bade31e4d56ec89d1a1b00c7df847f5cd7b878671015f5eaa42ee02165087991936660b9", + "0x8f688c969c1304dfa6c1a370119d1988604026a2ab8e059016c5d33393d149aae6e56f3ee2b5d25edc20d4c6c9666ad9", + "0x91950b651fefd13d2fa383fd0fdc022138ce064ee3b0911157768ad67ed1fb862257c06211cf429fba0865e0b1d06fc8", + "0x86cff4080870d3e94ed5c51226a64d0e30266641272666c2348671a02049ae2e8530f5fb1c866c89b28740a9110e8478", + "0x88732c4d9e165d4bb40fb5f98c6d17744a91ff72ca344bc0623d4b215849a420f23338d571a03dd3e973877228334111", + "0xafcc476ad92f09cf2ac7297c5f2eb24d27896d7648ba3e78e1f538c353ceeb1e569917a2447f03f3d4d7735b92687ba5", + "0xb622aa475e70d9b47b56f8f5026e2304d207684726fb470a0f36da7cb17c30dd952813fab6c7eb9c14579aacca76f391", + "0x802cf5630c0407ae0d3c5cf3bef84e223e9eb81e7c697ea10ec12e029fc4697ce7385b5efab7014976dacc4eb834a841", + "0xa08596493f4cd1b8ac2ec8604496ee66aa77f79454bb8ab6fdf84208dc7607b81406c31845d386f6ac8326a9a90e7fc5", + "0xa54652ca9e6b7515cb16e5e60e9eabbccbc40bb52423d56f0532d0bac068aec659a16103342971f2cc68178f29f695db", + "0xa3ab54875cb4914c3a75b35d47855df50694310c49eb567f12bbc5fa56296e11f4930162700e85ba2dbfdd94c7339f91", + "0x94183a040285259c8f56bef0f03975a75d4def33222cc7f615f0463798f01b1c25756502385020750ac20ae247f649a1", + "0xb0004261cc47b0dc0b554b7c6ebf7adf3a5ece004f06e6db3bbac880634cdf100523b952256a796998a5c25359f12665", + "0xa25dfeb0e18ebe0eb47339190f6a16f8e116509ab2eef4920f0d3ff354e3ead5abe7f5050b2f74f00b0885ea75b4b590", + "0xab10ef2f5dc0ede54e20fa8b0bce4439543db8d8b31e7f8600f926b87ec5b8eea0ac2153685c7585e062ffac9e8633c3", + "0x8386eac1d34d033df85690807251e47d0eaacb5fe219df410ab492e9004e8adabb91de7c3e162de5388f30e03336d922", + "0xb6f44245a7d0cb6b1e1a68f5003a9461c3d950c60b2c802e904bc4bc976d79e051900168b17c5ac70a0aed531e442964", + "0xad12f06af4aa5030b506e6c6f3244f79f139f48aec9fc9e89bbfbd839674cfd5b74cea5b118fb8434ba035bda20180af", + "0x88511306dfe1e480a17dba764de9b11b9126b99f340ceb17598b1c1f1e5acbdd1932301806fe7e7e5e9aa487a35e85de", + "0xa17cdf656e1492e73321134a7678296a144c9c88c9a413932d1e4ca0983e63afc9cdc20fd34b5c6a545436b4db50f699", + "0xb555b11598a76de00df0f83f0a6b8c866c5b07f7ac2325f64fb4a0c2db5b84e0e094d747186c3c698ee4d0af259dc4c7", + "0x88014560587365e1138d5b95c2a69bdae5d64eb475838fee387b7eb4c41d8c11925c4402b33d6360f0da257907aa2650", + "0xb220634e6adee56e250e211e0339701b09bf1ea21cd68a6bd6ee79b37750da4efe9402001ba0b5f5cbbfcb6a29b20b0c", + "0xac5970adc08bc9acec46121b168af1b3f4697fb38a2f90a0fbc53416a2030da4c7e5864321225526662d26f162559230", + "0x97667115b459b270e6e0f42475f5bce4f143188efc886e0e0977fb6a31aba831a8e8149f39bc8f61848e19bcd60ceb52", + "0xb6c456b36c40a0914417dd7395da9ed608b1d09e228c4f0880719549367f6398116bf215db67efe2813aa2d8122048f2", + "0xab7aef0d6cda6b4e5b82d554bd8416a566d38ded953ffd61ef1fcca92df96cdcc75b99a266205ff84180ab1c3de852a4", + "0x81d354c70ce31174888c94e6cf28b426e7d5c4f324dc005cd3b13e22d3080f3881d883ca009800f21b0bb32fa323a0cf", + "0x94f3440965f12bee4916fcc46723135b56773adba612f5ce5400f58e4d4c21435e70518bdef4f81e595fa89e76d08fc6", + "0xa6683e7a1147f87cbeeb5601184cc10f81bca4c3c257fd7b796a2786c83381e7698fb5d1898eb5b5457571619e89e7d6", + "0x8ca29539600f8040793b3e25d28808127f7dc20c191827a26b830fff284739fb3fc111453ff7333d63bce334653a0875", + "0x98a69644048b63e92670e3e460f9587cf545a05882eb5cba0bcbd2d080636a0a48147048a26743509ab3729484b3cc12", + "0x84d40302889c03c3578c93aca9d09a1b072aadd51873a19ef4a371ca4427267615050c320165abece7f37c13a73d4857", + "0x87954271e3de3f0b061c6469d038108aac36f148c3c97aefb24bf1d3563f342ea6c1c1c44c703e1587a801708a5e03f8", + "0x86b6f5367e04c5caa3ec95fd5678c0df650371edac68f8719910adf1c3b9df902cc709a2bddc4b6dde334568ca8f98ac", + "0xa95fed2895a035811a5fee66ca796fdecce1157481dd422f8427033ed50c559692908d05f39cb6bea5b17f78a924633c", + "0x8ba05bdadde08a6592a506ea438dbdc3211b97ea853d1ad995681a1065ececce80f954552b1685ef8def4d2d6a72e279", + "0x90b6b7494687923e9c5eb350e4b4b2e2fa362764d9a9d2ebb60ee2ad15b761e0850c9a293123cf2ef74d087693e41015", + "0x8819ea00c5ea7b960eb96ab56a18c10a41fd77e150ab6c409258bc7f88a8d718d053e8f6cb5879825b86563e8740808d", + "0x91e42031d866a6c7b4fd336a2ae25da28f8bde7ace6ff15dc509708b693327884e270d889fff725e6403914546055c28", + "0x85763642052f21cf1d8bd15fd2dc0c2b91bba076751e4c4f7a31fbdb28787b4c6a74d434d6ef58b10f3ad5cde53ef56d", + "0x8b61c36c7342a1967a1e7b4c01cddf4dce0e2025bc4a4a827c64994825f53e45277550ceb73c34bb277323fb784aa3c6", + "0x80b9634a45c8b3770e993257bd14df6a17709243d5429969ab8b9a4645bf2a94f9b3cd3d759169887b4aa0eb50f4f78c", + "0xb5c44db9439dd8aa4edd151d95e48a25c1154e1525c337f97109f40131db81a4898344c8c3144c270bdc835c269b3477", + "0x863080fcbc227eea32d0dc844f42dc642fbda7efc398ab698be3a3c6f3bf8803dea6ba2b51fed6151f9522b4ab2a8722", + "0x8481e871129e9cb9d2d109c513cbba264053e75192e967f89659dcfcc1499de9ae7a1ac4f88f02289150231c70b4da01", + "0x834d8183698d3d2d1352c22c373222cb78d0f4c8cb15e0ad82073dde273b613515ebcd184aa020f48f8e6fc18f3e223c", + "0xa227e300f0c5bc1b8d9138411413d56c274cc014ae8747ec9713f3314d5fae48bb6f8cc896f232fd066182af12c924e4", + "0xab7242835e91ba273de1c21eb4fca8312bdda5b63b080888b96a67a819b50294a7f17a7dc0cd87fae5e7f34bc24c209a", + "0x86eb27c898a5d6c3618c3b8927acee195d45fe3f27b0991903520a26fb8021b279e2a8015fbbba5352223ae906c7c5d6", + "0xa61b1c200b0af25da8ad8e29f78d000a98683d1508ae92ee7f4326a7c88e0edb645b6cb5dde393ac74d322895e77ba24", + "0x887739318c710aae457b9fe709debff63bfbb3ffbbb48a582c758b45d6bf47a7d563f954b1f085c3bc633ffd68c93902", + "0xaacfcb0e2b0a868b1c41680487dc6600577ce00aa2edeee8c6141f4dc407217ddb4d37b79e7c9182258c750d12a91508", + "0xad8cd2cf5ccd350cd675a17f31b86a0e47499c6c4c11df640a5391bb10989c9c70df0a3ddeba9c89c51e15fedaf67644", + "0x8aba897d32c7ef615c4dfa9498436529c91c488a83efc07ba9600875c90c08b00f66a51469eb901451b6e18e7f38ffd7", + "0xaab8a600609b80e36b4a6772308bac77929a0c5d8d92bbc38e9999186a1c2bfdbef4f7a2b1efba9c17a68dc15a9373ab", + "0xb95811d1454307a30c2ac8588c8104804b06c1aec783fed75a6f12c9df626be57865850100f1ad28073e3867aca941cf", + "0x8b119d3bd4ee644469457df5d8a0020fd99b8b20bd65ab121cf95a7f55e50dd8945fcf1dff9d269d9d0b74b4edbc7726", + "0xa980b912df832ea09353fd755aa3eec9eb4cfd07ca04387f02a27feab26efa036fca54cc290bb0c04a8a42fdfd94ce2f", + "0x91288e84da1d4ee2a4dad2df712544da3a098fdb06a5470c981fb6d6f3dcc1c141b6f426d6196ff3df6f551287179820", + "0x98b0473bcffcbd478fd1b49895c61dd2311dab3cdec84f8e3402f8add126c439ffcb09cae3b7f8523754090d8487b5a9", + "0xabe76988cf3065801f62a1eb3cfe9f8185bd6ab6f126c1b4b4fde497ca9118d02a0db3fadccd4ca98826b30475fa67ef", + "0x94a316a0faa177273574e9e31989576a43e9feb4cc0f67aa14d5c1967c4e10fc99db3ef4fdca2e63800a0b75f4b84256", + "0x975ad39adadc7e69e34981be2e5dc379b325dc24dddacc0bb22311ff4a551a0020a8bdecf8ab8ac5830ca651b7b630ce", + "0x8b3bc73b640dc80ac828541b723a968fb1b51a70fa05872b5db2c2f9b16242c5fe2e8d1d01a1dbeaac67262e0088b7b0", + "0xaa8d892a6c23dbc028aae82c1534acb430a1e7891b2a9337cedb913ff286da5715209cffb4a11008eae2578f072836cb", + "0x8dee9747a3ae8ed43ce47d3b4db24905c651663e0f70e2d6d2ddb84841272848a1106c1aa6ba7800c5a9693c8ac2804e", + "0x81e2c651b8b448f7b2319173ecdc35005c2180a1263e685a7e3a8af05e27d57ec96d1b2af2cae4e16f6382b9f6ec917c", + "0x98a9a47635de61462943f4a9098747a9cf6a9072a6d71903d2173d17c073eff3fc59b2db4168515be31e6867210ecbcd", + "0x912b2398505c45b0bb4a749c3f690b1553b76f580b57007f82f7f6cce4fadd290d6df9048258978c8a95ef9c751a59a2", + "0x8ac8f0893fe642111ef98ae4e7b6378313a12041bbca52141e94d23152f78c2e4747ae50521fc9c5874f5eb06976e5cf", + "0x946b4a8eb05b529aaed56ac05e7abeb307b186a7835623fa4e85ed9eb41a4910663c09ea1bd932a2c467d28776b67811", + "0xa4be51abeddd40e1da6fdb395d1c741244988ff30e10705417b508574b32dce14d08b464486114709339549794df9254", + "0xb33b6b7d66cb013e7afeabbd7ed1e0734eb0364afe4f0f4c3093938eec15f808985fb7f3976969bf059fa95f4d8e335b", + "0xa808adbcf0049f394914482483ee0f711d9a865615ff39b5313ed997f7a0d202ad9ed6e6de5be8a5c1aaafe61df84bca", + "0x8856268be15a78465ad00b495162dc14f28d4ef4dcf2b5cba4f383472363716f66dabc961a6dbdda396e900551411e41", + "0xb16ba931e570e1bf124ea3bd3bdf79aed8aa556697ea333e6a7d3f11d41538f98dcde893d0d9ba7050442f1515fb83b1", + "0x91ecde1864c1a9c950fd28fa4c160958246b6f0aa9dda2a442f7222641433f1592d38763c77d3f036a3dbb535b8c6d8f", + "0x92cda991f69fbf8e55c6bf281b07fff5dbbb79d1222b8c55686480669247b60212aac27aa7cccd12fcee94e7a759b8af", + "0xb1d9b5b4e996b375d505d7250a54c12d32372c004a9cabf1497899054cb8b5584b1cef1105f87b6e97603ccbf2035260", + "0x86e98bde8b484fb809b100f150199f13a70c80813ad8b673bf38e291595e2e362ad1fa6470d07d6fbe2cf7aeac08effc", + "0xaa12f7c39ba0597a8b15405057822e083aca3cee6ed30c4e0861eeb22620823588d96c97bb1c3776b711041c4dc3d85d", + "0xb477b34f29334f3bae69c7781d574342b7c27326088f9a622559ab93075c7357953ae84eb40e3421f453e04e9b4d5877", + "0x9625067cb2120ce8220a469900aa1d1bb10db8fe1609988786b07eb2b88e0ddb35a3eccd4b6741e1fa2365c0db6b1134", + "0x997b92af7765f587d70ea9718e78a05498cd523fc675ad7b0e54a4aae75fbeac55d0c8d72471471439dacd5bfcfae78d", + "0x88b59eaea802e6a2cf0c0075bf3fd6891515adcb9adf480b793f87f1e38d2188c5ed61ac83d16268182771237047ec8a", + "0xa57d078b230b1532c706a81eaabfef190fb3eb2932f4764631e916a0f0d837d6014da84ede100abaf610519b01054976", + "0x94ed5c5b96f6afa9f2d5e57e1c847ae711839126ab6efb4b0cf10c4564ff63c819d206fdc706178eb6a0301df2434c01", + "0x980296511019c86cc32212bad6e4a77bc5668b82a2321a1ecabc759a8bbc516183a4787c7f75f9ee7f1338691dc426cc", + "0xb10ef97db257343474601fd95f9016c205e28bd22bf7b8f9e30c3b14aca1cc9a11e6404ff412ef269c55fb101fee5a37", + "0xb670d5d9c77fc6aa14212dd3eae100620f3510031b11a9625aa40bf31835c9fd717753b555bd159b1aa64a2104929340", + "0x862054fabf6d6d529a7584d1a48f72d2eb216caf959c782ec36c69c26aef4595415d19a28b041946811b34a629105241", + "0xae4bf2ccd7b0f3774653848b5b4d39e5517dcbcff30d8441d78bc387ff42b573f16b7b0a7366e6ca5cef1dd9f0816df9", + "0x8f810527badcb49f1542a0ccd12e3541efa084243f7106eae003458c176f4c1f01daae9d4a073c2cb2aced747e8a4576", + "0x8a32c2067aaf6baf32db67acd4974a22a6da33db5444028a7c8c4135f9c84e102dc3b2c635b15afa6dc907d0270daffb", + "0xb15fc057f306a60b20c8487125b6b334ab749cf70eb8a30c962f625bb203ebd0d2a315949ee3b7a99e3d91acec384806", + "0xa37f145d321359b21cba7be8b64dfae7c67a20b7b324f27c9db172d58e77a49fa02ed3d06d09d7644bf1fd81f4aab44b", + "0xb338d2e39a485ee4297adcf5e58e16c3cc331c5dffeade0be190907c1c5bdfed38537a6d81dc39a2cdfc1bc45e677886", + "0xb69d84d8511b3aedfdc7c7e66f68b24e12e5a2365dbbe014bddd2e99e54143428cf8b74cf12c0e71316038aa5300e87e", + "0xab210cc38661667450561a1857337879633f5d5bf2c434a3df74ff67f5c3ba69a7880872f19ae4dcbbb426462cd7d0fb", + "0x94538ef487a58a5ff93a5e9616494c5f066715d02be5b249d881a00bd0edfe2fe19dd7a5daa27f043d1dbb5ac69cf58d", + "0xafb47a899c1b25fe800241635fa05de9687a69722802ad45434f551971df91d8ca9edda0d835d82eb8f36ff9378ed7e8", + "0x827a10d7536230887283a9b1dedccc6b95ef89cb883c4ee7b9821058b0f559704d1636670c0ada2b253bf60b7cb8a820", + "0x97cc07965065d64409f19fb2c833b89ca3a249694b16b58818a6f49d3800926627ce0f87e5c0853ae868b4699cfdee5e", + "0xae0c93d44780ef48ea537cf4cb8713fd49227f4b233bc074e339d754b5953e637a7289c6f965162701e4b64e4eaec26d", + "0x80953053397c4c0ba9b8e434707f183f9ced2a4c00d5c83b7dc204e247ad7febc1855daeb906c53abfdf3fe3caca30c4", + "0x80f017e87b471b5216ebe25d807be6c027614572337f59f0b19d2d1f3125537478cb58e148f3f29b94985eac526cd92f", + "0x8a8e1c0d49801a8dd97e9e7c6955fc8b2c163a63bd6a4be90bb13e7809bb0dddc7a5025cc7d289a165d24048eac4e496", + "0x8530e5b5c551a2e513d04e046672902c29e3bb3436b54869c6dea21bab872d84c4b90465de25dff58669c87c4c7d2292", + "0xae3589d389766b94428e9bde35e937ed11aac7ead3ce1b8efe4916c9bfff231d83b7e904fe203884825b41022988897a", + "0xac02e629a900438350dd0df7134dfa33e3624169a5386ea7411177b40aa7a638e8d8aef8a528535efdbe1ca549911c0b", + "0xb1ac60b7270e789422c3871db0fa6c52946d709087b3b82e6eba0d54f478520b1dc366bb8b7f00ff4cf76e065c4146eb", + "0xa7465e1f8e57de1a087144d3c735fee2b8213fcbf2b9e987bb33c2d4f811de237bf007402e8d7f895563e88b864f7933", + "0x8ab0007ba8984dee8695ec831d3c07524c5d253e04ec074f4d9f8bd36e076b7160eb150d33d15de5dd6e6fb94f709006", + "0x9605bbe98dadd29504ce13078c1891eca955f08f366e681d8b5c691eadb74d6b1f2620220b823f90ef72eb4ab7098e16", + "0x942a083d07c9cb7f415fedef01e86af4019b14ef72d8ab39fe6bd474f61ba444b9aac7776bea7e975724adb737e6337a", + "0xb9a49a8c4e210022d013b42363ac3609f90ea94b111af014f2c5754fbc2270f6846fa6a8deb81b1513bb8a5d442ea8dc", + "0x99cd62b177d5d7ce922e980cc891b4f0a5a8fa5b96dfc3204673fbef2e7fb2d7553bbacd7b2e6eca4efb5e9a86096e2e", + "0x94e30b65b3edd7472111566dde7fab0e39a17e1f462686050f7134c7d3897e977550faf00174748cbeaec6c9c928baa8", + "0xa32fbcb29f3391d62092f2720e92b6ef4d687d8a3eae39395e0464669a64a38fe21a887f60bc9519d831b9efde27f0f4", + "0x8f1492c4890d8f9deecb4adada35656e078754dcf40b81291e7ef9666d11ba3747a478f9420a17409d7d242cecd2808f", + "0x8942960b319ef65812d74cb1d08a492334db58d41e8437e83ddf32e387d9f3ad36834f59e6a71d1afb31263773c3ec49", + "0x88d692f4976c99e763b027df9c2d95744d224724041dfbe35afc78b1f12626db60b9d0056b3673af3a1741eaf5f61b43", + "0x9920cd37eab256108249a34d3f1cc487829cc5f16d1bce3a2328fe48b4de735ebde56c8b5cf4e532a4d68792387257c5", + "0x87d34c9f5a913b806504a458c843eda9f00ff02ad982142543aa85551208cab36ebf8b3409f1c566a09a60001891a921", + "0xa2ee8339c96f790b3cf86435860219322428b03ea7909784f750fe222bc99128d1da2670ad0b1f45e71a6856c7744e09", + "0x84bd257f755de6e729cc3798777c8e688da0251a2c66d7ba2e0ce5470414db607f94572f5559f55648373ce70e0b560e", + "0x8d0e170714ddf5dde98b670846307ab7346d623f7e504874bfd19fbf2a96c85e91351ba198d09caa63489552b708fbc8", + "0x9484cc95d64f5a913ed15d380c2301a74da3d489b8689f92c03c6109a99f7431feb8a07d9f39905dcef25a8e04bcec9b", + "0xb14685f67dd781f8ef3f20b4370e8a77fef558aa212982f1014f14b1bdd8b375c8a782d1b8c79efc31b41eec5aa10731", + "0xb22fb1541aa7d2b792aa25d335d66e364193fdbf51b24a90677191cae443f0ce40a52faf5983d2cb5f91f0b62a5f20e1", + "0xb06fa9489123ab7209d85e8c34d7122eb0c35c88ee6c4c5e8ae03a5f1ae7c497c859b0d62e0e91f5e549952330aa95a4", + "0xb5cd71617ff848178650e6f54836d83947714d2e074d8954cfb361d9a01e578e8537d4a42eb345031e3566c294813f73", + "0x848d39ea2975d5de89125a5cbe421496d32414032c1e2fbc96af33501d3062745b94e27dfe1798acaf9626eabff66c79", + "0xad35955efd5a7b6d06b15d8738c32067ffa7dd21cf24afc8ea4772e11b79b657af706ce58a7adcc3947e026768d9cdaf", + "0xaff6d7c4861ff06da7cb9252e3bd447309ad553b2f529200df304953f76b712ac8b24925cf4d80a80b1adaa2396f259a", + "0xb4b88d35e03b7404fc14880b029c188feecb4d712057f7ba9dedb77a25d4023e5a2eb29c408fde2c0329718bdaf1ff63", + "0x88e96720e2f7c63236cca923e017ca665b867ba363bc72e653830caf585d802fad485199055b5dba94a4af2c3130a6f6", + "0x982675dc0299aeedba4b122b9b5f523ca06d54dc35da0f21b24f7c56c07f4280265fb64cec2f130993521272c3470504", + "0x95c77d418490e7e28293169cf7a491a7dcc138362f444c65b75d245c1b986d67c9e979a43c6bd8634dae3052df975124", + "0x8fd6c4dff54fb2edc0bdd44ccd1f18238c145859ccd40fbfbc1cf485264445b9d55ffd4089c31a9c7a0543cc411a0398", + "0xb153eb30af9807b5fe05d99735c97471d369c8a1af06b2e2f0b903b991eb787ab5a88c6e406e86225582acf8186ad5ef", + "0x826b55de54496751b0134583b35c0c2049b38de82821177e893feeeeb76ceeb747c7a18312cb79a6fc52f2c18f62f33e", + "0x91650d7205b232c495f1386bea0c36e136a22b645ffd4f5207f5870b9ce329c44524781c983adf2769f4c05b28a8f385", + "0xb8d51a39162ebb38625e341caacc030913f7971f178b3eee62dc96f979495a94763ea52152198919c6dd4733bc234f64", + "0xa1fbd3673f2ae18a61e402fe3129b7506d9142f2baca78f461579a99183c596b17d65821f00d797519e9d3c44884d8a6", + "0xb7c5f5407263398cf0ed3f0cf3e6fcebdd05c4b8fd4656a152cedcdbf9204315f265fd8a34a2206131585fad978a0d6c", + "0x94fa71804e90f0e530a3f2853164bc90929af242e8703671aa33d2baad57928f5336e67c9efdcbd92c5e32a220b4df07", + "0xb75dcea5ad5e3ed9d49062713c158ebc244c2e4455e7a930239998b16836b737dd632a00664fded275abe4f40a286952", + "0xa02f7b37fc30874898618bfcc5b8ff8d85ef19f455f2120c36f4014549d68a60a0473ddfd294530dfd47f87fbd5e992d", + "0x8b48e1626917b8ba70c945fe0d92d65cab0609f0a1371fd6614d262d49fe037f96991c697904d02031ec47aab4b32f48", + "0xb368f02c21d4af59c4d11027e583ca03ef727f2b2b7918ef623f529ceac76753a05a4ce724ce2e018da6ecc5c1c1261b", + "0xa95cba06eeae3b846fc19a36d840cbcf8036c6b0dc8c2a090afcf3434aaf5f51ef5d14b1e9189b1d8f6e4961bf39bbf8", + "0xb32ca4dfbeb1d3114163152361754e97d3300e0647d255c34ec3025d867ed99e36d67ebafe8255b8c29be41864c08edc", + "0x8e4eddefa27d4fe581f331314d203a6a0417c481085134d8376898f9260f133e2bf48576528d62adf29953ad303e63a7", + "0x92b7d5505833f00d5901ae16c87af028de6921c2d1752a4d08a594eb15446756ea905b0036ae6ffe6b8374e85eb49348", + "0xb50e9018d3c4e05ba9b28b74b6634043f622d06aa8123da7cd0bc482b3131912149214d51bdfd887484422e143c3c1c0", + "0xab980a2f5317dfcb92baa4e2b3eb64a9ac2a755da6c11094d57e781ae5cf43e351824f1dd3abb4c6df75065b3784210b", + "0xaaabb009dfcb0bae65a0aee26ed74872c226965c52a6ed0998209e020a9ee806297dba4b15845cf61e1a514de5d125db", + "0xa1fe78f67000ebb6e90fe33e1a9dd5489be6e15fedb93b2a37a961932b77137fe85d46e89a132ecf7bcfb7aa95e16757", + "0x85bc6e7d660180de2803d87b19ed719d3f195ea0a92baf9bfff6113c743f4237f51355b048549913e95be8ddf237864d", + "0x87a167968c4973105710e6d24ad550302ee47fe1f5079d0f9f9d49f829b9f5c1cd65d832d10fe63533e9ad1fa0ad20f5", + "0xb2ad1a7b95b8a89d58e0b05c8b04ae6b21b571d035ae56dc935f673d2813418e21a271cccaf9d03f0d6fa311f512d28c", + "0x8268e555319992d5ac50cb457516bd80c69888d4afa5795fcc693d48a297034f51e79f877487b6f7219cfdd34f373e14", + "0xb235411f1f6d89de3898642f9f110811e82b04ad7e960d1dd66ec7a9bf21de60e00cfabcd3004f3b5c4f89f5d9c7422a", + "0xb6963effcfe883f7ed782a3df3c40edd70f54ceca551859bcccb5d3e28fd2c1fcbdd7acc7af24a104687fd02b53c704d", + "0x862645c944e1e2909b941578cc5071afd7353fed1c2c99517e2de7573037704ef5d35accf6ec79b8269da27564209d50", + "0x90f585eeb1a053e2f18c1280c9d6a561c0bc510b5f43cd68370ed6daac4b3749852b66c371397b6a7c1ece05ee5906c9", + "0x876d9a3686feb79ce781e87ac3e3fbeef747b6ab031285e808c8a73f73f55b44507850dcaa745c0791d2cae8ad61d74e", + "0xa7ecc3b8c10de41a7bd9527228a0d3b695a651a5b5cb552a3664a887077d39ee60e649aecd68ed630da6288d9c3074ad", + "0x83529f1f2b4dc731ea05c1ee602fa2e4c3eebe2f963f3625959ba47657be30716d64e05e8b7e645a98bf71c237d9c189", + "0x834ca6b14428c30a4bc8d5a795596820af6f3606f85bee9f3008f3fb94b3adffa968d21a29e2588d7a473d8b5d3a8b42", + "0xb8d08cd8b73430984fd16e8db0525ae2b76253c92cccd7b3470add4d12d082eafb55a72bde04870924d0bdaf61f76c5d", + "0x96ef32df669690c2391f82136fc720231e4a185c90ba79eef7beaadedf7fbeb56ed264825564bdc7da01829b47f4aa88", + "0x93d637b2f04d71891a80a1ee93fd9c9046d671bc4c15c4e597cfcc36f4ae85a7efc111359628965fd10d36c39129b160", + "0x89f28dd3f7bc43749d0e3750c136385d4ffaf2c40354d3be38341416d755de7886d8108d83721b36f99feb3bccd73c88", + "0xac6392e274659f4c293e5cb19859828f101959c4c0939920a8dfed0e2df24a0cbf89a7aa983e947318c58791c893928e", + "0x83b2d4ce42c2fa0f672cd911365d1f1a3e19f1c38f32bedc82820ad665d83ae5fac4068e4eca6907bd116898966fed92", + "0xb5e0144d6e59a9d178d4ee9f8c5dba18d22747fcdf8dc4d96d4596a6e048e384cd1e211065f34109c9ed6b96010d37e5", + "0xb1a65e6b38c9e84b3937404d5b86c803c2dac2b369a97cbf532cfdd9478ee7972cf42677296ad23a094da748d910bc48", + "0x849d7f012df85c4c881b4d5c5859ab3fb12407b3258799cfc2cb0a48ae07305923d7c984ff168b3e7166698368a0653d", + "0x84d9b7ee22bf4e779c5b1dd5f2d378ef74878899e9dbb475dfdcd30c2d13460f97f71c2e142c4442160b467a84f1c57d", + "0x964e497ef289fac7e67673a6cb0e6f0462cd27fc417479ecb5eb882e83be594977fb0c15a360418886aece1aaf9f4828", + "0xae1226222098a38ce71f88ab72de6ededb2497e30580e7ae63d4829dcc9c093bdd486102b7a7441cb06253cf0df93772", + "0xa72865b66d79009b759022e53b9eedbd647ff4b1aab5d98b188100d01fc6b5d8c02b80eb6f53dc686f1fdda47d4722b8", + "0x93aa8d7d8400bdfa736521133c8485c973d6d989ec0a81db503074fe46957a3999880fd9e4e7f44de92adf6ac0abe99b", + "0xa75e5ab84399962ada1f9ebcfc29f64405a1b17cd0a983950d0595b17f66386393d95a5aa4c6c878408984141625141c", + "0x91b1e5e75f4b55ec2e8f922897537082a1414eedc2bc92608376a626d8752d5d94f22f0e78ea1970eb0e7969874ad203", + "0x83bf9c308424ef4711bfa2324d722f550d95f37d7f7b4de0487ccf952b89d7219ca94e7fa25bee60309efefd9a0e4716", + "0xa42060476c425ff7979456d3c5484bc205fb1ef2d7149554a4d483d48e2a19119f708c263e902943bcf20a47e6c7d605", + "0x8170c45ea126e6367aa5f4a44b27f7489a5dd50202cb7c69f27a2bdf86d22cf6b00613b0080d75fca22439eeaaaa9707", + "0x8e5a82da70617697e42c6b829e1889b550c9d481408fe4cf8dc9d01daccabdec01f9e1b8c27dc84902a615d539bf9bc6", + "0x80606c51401d0bf5f2700ebce694c807ab1f7d668920bdcccef2775e0939472419a8f404567bd4f9355095517eb4d628", + "0xa40314565d60d0ddf8995673e8c643b1baa77a143b3d29433263730a6871032260abc1320e95af8287b90aa316133da0", + "0xa87e07e84435f9e8a51ce155cd3096aa4b20d18e493c9dcbc0ac997ac180f3a255bf68ccd8195f2564d35ec60551a628", + "0x84d2ab98416643c457bf7ddd9f1aa82967ecea189db08f3558f56803fe7001693ed67ec6ca8574c81ec1293b84a7c542", + "0x937c3b955889ceae77f28054ce53d75f33cfe3a04f28e049cea8b8ade2a0440d5e2e8c4f377e6c1ae2115d68cc95fc16", + "0x885a911f16845fe587b15ce7cd18cc2a84295bf609732340f74e0f5275b698cffed3e9aa1440e19e6940a7fa8f24c89c", + "0xad90059a50c399996aaa0a10a8f637b7bab0dd5d9100301f0159a2c816596da55c30b2568d1717705fd2826b117a42d6", + "0x828de9ff1e095c189da1f1ee18009afe14613ac696025add6f4e330488e02d5f1a90be69edd9a17bfb3355a0ca77b525", + "0xb7aedb8394064a58dd802be6457555c0cf7b94805ed00cc66f38449773f4b1865feaee3a6f166eb51b2123b89d853a4d", + "0xb09c564ff37ccea34e90f2d50a40919a94c2e10d4fa58ffeaed656f88f9f4ae712d51c751b1b8f443dc6c9506d442301", + "0xb24882d66b2ebb0271ebb939c72308d81f653940e70d6f1bcaae352f829134aff7f37522cc42de9e7fe6243db2c4806f", + "0x8e6f8dd906e0d4eb8d883f527e926ad1d8156b500c4cfa27214450c8112267c319900de2443c87bed1e4bb4466297dd5", + "0xae42f4578e8d79b6aa2dca422ada767e63553a5ee913ff09cb18918116905b68f365720a1a8c54c62cce4475ba5cdd47", + "0xade639bcd5017ea83ec84689874175ed9835c91f4ec858039948010a50c2b62abc46b9aee66a26bf9387ab78f968b73e", + "0x8d310a57aeb123cc895ee2fd37edc3e36ce12743f1a794ad0e1a46d0f5e4c9a68b3f128719ed003e010f717ec8949f43", + "0x8606c086fcf3e2f92c1b483f7e2a4d034f08aef1a9d5db9e8a598718e544b82544268a0a54dfed65b4d0e6027a901d47", + "0x8ccd95dd673d8cfdfa5554c61bcdbe6bb5b026403a320856fe51571e7c59504fe1c035f2ad87d67827339d84c0e1a0c6", + "0x955a7cb4afcf70f2eb78756fc3a82e85ab4330eb89a87117294809beb197d1d474001e25306e8ad71daab6928abf6d64", + "0xae6b44ec6294736ea853ddeb18fc00cce0ac63b38170ff0416a7825cd9a0450e2f2b340d27a7f2e9c5ac479b4cb8a5fe", + "0xa88ec3f12b7020dd593c54376597b056e70c772c0ec62c24c5bfd258b02f772161b66e5dcd95c0c0fceb23433df9ff23", + "0xb4a83933b4de552dba45eedf3711f32714e58ae41d4dab8a6114daeb06e90a5a5732c70384150d04124ac6936ca9804b", + "0xb8b7c4fa549b0fa1dc9c1f0af0750d6573f1648767751882d41f0dd7e430e3934590757e1c8b436ac35381bdde808117", + "0xab598b911234a98cfde07234cfc0d2fddfc5cb9ea760212aa3e175a787ce012965c8fcfdf52d30347f5f1b79cf4a0f54", + "0xa9d354f9dfbd1976e5921dd80cbb56b2e15df53ce099ecb4368eff416998130d7830209282aaf1d4354129845f47eb80", + "0x8c889afff546c721969e4d8aae6e6716ad7c2e9c1914dd650e30419ee77d630efb54dfffb4ec4ff487687b1864bf5667", + "0x94ed2fa79116c7c8c554dc306b1617834dd3eab58baf8f0d085132c4688ca4a6bd38420281283678b38970a3f02b9a94", + "0x944fdc8f0516d22f1672193d183833d3e3b043e26807fb2123729a0216c299785b1c4e24b5aa56e9bbe74fa54d43e22a", + "0xa48521454a3e0c10a13d8e810fad9d0522c68eea841821a8e0e57811362f7064a8f9c50f79c780a02df7df8c277feaef", + "0x8f3d26670ab55e1bd63144e785203373b2b13b76cac305f0363e48a6339fac3364caa3fceb245527161fc2fac9890912", + "0xb4d6fe71001cb4141f6d8174dd7586d617cfccb54471e1fbce30debc2b1dead62cab29565abb140b682811c6231acb03", + "0x91dc8afc4934fcc53ef851462a055cc1c3c87d7d767e128806891738427606d2fbfa832664d2a7f95f8ffe2cf0c44dc6", + "0xb297eb432c74071764272c1b1663547ba753e66bf026643bfc0e42a9c5cdfb05a88083ad67d6ddfe6ab290678c607b29", + "0xb343d1df85be154faeb5b21741a5ac454ca93f70a0b83a98f5901d1be173a1b2969d43e646363c5d4975924e1912599e", + "0xb2d74a66e4dfc41128aee6a3f0ff1e5137a953ed7a2a0ab5a08d7ea75642f12bd150b965c8f786ad0caf55ef7c26be4f", + "0xa54141faa8dd9a567c3cd507e4fc9057535ffe352fa1e8a311538fe17e4a72df073fbf9371523e5390303db02321650e", + "0x8e229a58f1acc641202d2a7c7e120210b9924e048603b9f785a9787ad4688294140ef3f4508c8c332d2dedafff2485be", + "0x9523554c11d39b56e6a38b3b0fadb7a9a32a73c55e455efdcfda923aff1e9f457d1b7cbc859b5ecbb03094eae8b87d38", + "0xa199ffdff1812aaea10cd21a02b3e7bf3d8e80e501aa20bb2105b5f4cb3d37265abcda4fd4c298d6c555e43fa34517f8", + "0x97f1285229b07f6f9acd84559afef5daad4320de633c9898b8068c6cb3b19b4468b4445607559ddf719f97d2410e2872", + "0xa1dfff82908c90fc38ec7108c484735f104e6ce7f06097e1e80f6545702b6a0bc2a2706203cd85162edb7e9294fdedba", + "0xb12a706311c617d6c19e964e296072afce520c2711086b827cff43a18e26577e103434c0086d9d880c709df53947b48c", + "0x88503a6f48cef2f5cd3efa96a5aacc85dc3712a3b9abbb720a2cff582a6ea3c2afc49288b6832c8599f894950843ac11", + "0x83ed63e38dfbe062fe8c7e6bc2eeb5a116f1cc505c6b038990038de6051281f9062e761ea882906ccff69c9c5b8a4a25", + "0x911090d5d0231dde1189408dca939daddcb69a812ac408d1326060f0220781bcc131c9229e6015540f529d9fb33d9b0a", + "0x8a8352f1d9e5c7e80276e4448f997d420d5a7e0e2d5be58ae4106f47f867d1caa478b2e714d9c3263e93e5cc4c7be08b", + "0x9362f1ea9995f9b3850ebb7c8d5bf95927ab5ea25ee00e85d7456b3bf54459798b1fffde049d445c0d0587b0ab0a1694", + "0x8859502b391273f4a00b6c0e87e5cdae676b7baf6c402f12b3360db6a5dfb4931ece4da0e1e4d98c7a71c3d01a183a9b", + "0xa9a5edf474120f9bbec9485d8b1e6f83be68b10de3d765219b0bf3e5d2840e478f1fb2bf806d78a8b8ad22ec50cf7555", + "0x82c75daf983b06e49f0d75a042dfaae8cc92af050293d9059d6e8b01ca3ab2597e7adfc1159ed805513488944e739fa5", + "0xa5cf240f04a9bfa65b811702c923d209e01f9535e217fa55ae3e0d1eb3257d6749e5587e727091e860609d1df29a1305", + "0x95608ab8ade1c9fb814bad78d9cc99a36ad3e9562d5319830e4611ceea508ef76be04639294be9062f938667e33bce6e", + "0x8e44181f35c38b02133473de15560ae6588ac744cfdaf5cdfc34f30ca8e5ff6c85eb67dddc1c7d764f96ed7717c89f06", + "0x8007b6ddece0646b7e9b694931a6a59e65a5660c723ebdffb036cf3eb4564177725b1e858ed8bc8561220e9352f23166", + "0xa2d9d10fa3879de69c2a5325f31d36e26a7fb789dc3058ee12e6ccdda3394b8b33f6287ba1699fce7989d81f51390465", + "0x81993d0806f877ca59d7ffa97bd9b90c4ebf16455ea44b9fe894323c8de036c5cc64eacf3f53b51461f18fa701a5860d", + "0xa20030f457874d903b2940ec32fa482410efecb8a20e93f7406fc55ab444e6c93fa46561786e40e9bf1e3c7d5d130bc8", + "0x80c72d4985346ac71a231e7bbbb3e4a91bf50142af0927e8eb86069303eb4ce7fca1aa5b919d5efc82f2f09b41949acb", + "0x91b857d2f47f1408494940281127ba4b9ac93525788e700889aa43402eedea002e70eded017f5f5263741ed3ee53a36c", + "0x97445d007f08e285ea7f4d25e34890e955dac97448f87d8baa408e826763c06cbd58dd26416ba038d6c28f55bcea2d3a", + "0xa409c89526c2886f6a6439e2cd477351fc7f886d1a48acc221d628e11895a4eedd426112a368a0dbd02440cd577880a8", + "0xa2c6adc7866535f6ffc29e00be4a20fa301357e1b86dff6df5f8b395ad9fb1cdc981ff3f101a1d66672b9b22bd94ec0f", + "0x8887fc53ffc45e4335778325463b3242190f65ae5d086c294a1dd587f62dd0d6dc57ca0c784bf1acaa5bbba996af201c", + "0x9731d3261a7a0e8c7d2b11886cd7c0b6bb1f5c57816944cc146caa518565034cea250eeee44ddffaeb6e818c6b519f4d", + "0xafe91c706efb9ee9e9c871e46abde63573baa8b2ea2b61e426cd70d25de3cc8b46d94c142749094287a71f4dfadd3507", + "0xae7bdf6ecc4fc0d8d8a7fa7159aae063d035f96ca5a06b6438b6562a4eee2b48d9024dbe0a54cfd075eac39b7a517f2b", + "0xa382e5205bfa21a6259f42e9ebc11406b5da2aad47f7a722212fdd6fef39117dd158a9991ff95e82efa0826625168a1c", + "0x862760c80bf44c2d41c2a9a15c887889eaeea32acc894f92167fb6f72593377c228499f445ccb59794415597f038ac9e", + "0xb4e96595a91a611c4563d09f29a136a4c04f07be74dd71a6bbabc836617ecb95494e48971a8229f980b2189fd108d2e5", + "0xb5e7200357317c36244c2e902de660d3c86774f7da348aca126e2fc2e2ba765fa0facd29eebcb3db3d306260e91a6739", + "0xa64c7133156afee0613701189c37c1362e2b4414f7e99408e66370680c554de67832c30c211c2c678dab5cfcdcecb3f7", + "0x88f4cb67b1db497a91a0823ee3541378133eb98777842d73e43ab99efe8aa52fa02dfb611c1691be23684618394988d6", + "0x89a9382a147d7387d0ff9516ee0c75cd1f8ee23333f4a2c9693d1a8cbe03680bc5b10c43c238c2190db746cac409bf39", + "0xad510bcc067373d40b05a830bf96fac5487de1ad5b708a13f62484c09b00fba6c5b00b981004e5ab3f28e55c9a5bce26", + "0x8384156d7117675547279ad40dc6bf81e8f9a57b2d8cfebeea6b9cd1d8534dc0cf704068bc3ba0815010cd8731d93932", + "0xa818fb76e53165b2f86c7f2317d64cf5e45f48405a34560983cd88bfbd48369e258ce2952233a8ce09c464e07afcade6", + "0xab19a4ed90527e30796064634b66cdc023bc5966e2c282468f5abef7879fc52986d5bb873a796b077d10e7b374b60309", + "0xa17dafe2484d633fe295f8533662631b0bb93cdb4e7cd6115271f20336f602f7f8b073983cd23115093c7f9891c4eef5", + "0x804acbc149d0334c0b505a8b04f99c455a01592a12f64d1ec3b82b2f053ccc4107e47f418f813d6f400940c7c8700a4a", + "0x965e097a825d8511d095b247554ec736bcb3701ead3ba785bd425cbabd56f4b989764e0965a437fa63e7e16efd991fc0", + "0xb6701675ca27d7a4084f06f89bd61a250b4a292ee0521b2a857c88c32b75f2a70b97f98abce563a25d57555b631844e0", + "0xabbdf65fcbdf7d6551ccd8d6e5edc556f1ecd275ccd87ee2bda8ea577c74615f725aa66e0911e76661a77f5278e0c2b9", + "0xab715ae372c900239a0758a3524e42063afc605b8fb72f884dc82ab9b0ff16715f3fb2fd06f20f15f9e454f73a34e668", + "0xb45f41ea1d25a90af80a8a67c45dea881775fed000538a15edc72e64c7aa435a5e4375dcdedc5c652397c02b0bc61b16", + "0x86f7be9252f8ed9078e642c31a70a09639899f7ffcd7faaf1a039fec8f37e1fa318fba0ed1097f54fc55d79900265478", + "0xa30e5ed4277dd94007d58d5a3dc2f8d3e729d14d33a83d23c44ddfc31c6eac3c6fe5eb13b5b4be81b6230cfd13517163", + "0x87e723d916f5fcda13fab337af80354e8efe6b1c09ae5a8ceeb52df45bfca618eb4bec95fefef3404671fb21e80bf9db", + "0xa521b8a04dc3abd3e9e0454b9a395b3638e5394dc2d60e97fda61b0a1880d1d73a64a4633f3d7acbd379bde113240d03", + "0x851686c79c5403d5f05fbaac4959fcbfdfb51151bec55e10481b3c16e3be019e449907ae782ca154f76a805543d5755d", + "0x8ec1929e746b6c62b0c3fdd8f4e255e5c707e6e0d8d57ff9e409ae2dd6e76fdb50af923749992cf92d1b5f2f770bafbc", + "0x9175f7b6820d47205c9e44f8c684833e1e81da46c1fdf918a4dcafbc3231173f68370d442a20e45f8902bcab76a4e259", + "0xb4f66c698115333b5ac00c9fe09aa9e1e9c943fbb4cce09c7d8a6ed4f030e5d97b48e944fd6d3e69ac70f1ae49d35332", + "0xb958878b875eead61a4416a4597b1c567ddbb1eaaa971033f4a656f01a277822c1f4ea3972045156c2a5a28d159f5ddf", + "0x8188de8ad5258024d0280137a40909d24748137ac7c045dddd2bc794eac8edd5850b9d38f568fa8174b2c0593bb57e96", + "0x91152c7bafce7a0358152221081bc065796fa4736bfc7d78076a0a6845287cde2ee2a2c9b96f500297c0a00410634888", + "0xa5328ab939a2d3bd4c21e5f3894c02986b6590ad551c7734be3f4e70380eb7bc19629e9031b886ce3b4074ee4edee63a", + "0x97c4d49db40e266bcedaacb55edca4e1ebf50294679b271f3a2332c841705089b5ba96ef2064040fa56c36bb1375a8d9", + "0x85cf0514f340f9d865b32415710d7451b9d50342dbf2c99a91a502a9691c24cd3403cb20d84809101cd534408ddf74e8", + "0x950c3d167f59f03f803dcba3f34fe841d40adc31e5be7eefff2103d84e77a7cbe4f14bd9c3dfa51cde71feb3468a9c00", + "0x96a69624e29c0fde3b92caf75a63ac0f3921e483f52e398652f27a1ec4e3cc3202f17af1f66224731bc736a25638d3e4", + "0xaeac4170cf4b967227f66212f25edc76157eb4fb44c84190b520ecc2946470c37da505790e225fd1b0682bef7fc12657", + "0xa94146a04e3662c50c2580ae1dba969cbb3fb0f43a038729c9e8be6ed45860b2c7de74f248dfa50ccdbe2ecaf3f2b201", + "0x917b8e2880e85b8db723631c539992ec42536146e7091d4a3f87d37f051b5da934d84393523814f19962c78e6cb12ef8", + "0x931f140ff8f7de79e399f5cd8503558d566b5c2ab41671724dd38aed08dd378210f01ac8fa9911f3047993dbc10cf8c4", + "0x859eb9b560bc36273694f8ae1a70d25e7f206013597c4855a11328162ba1254bb736f1ae41240c8ec8dea8db035e08f2", + "0xb4ad2cb2c3a3e6ab1e174f2dbfb1787a8544f3c9109215aa6d33265ef269455e3cde9858738b4fe04711a9cf9050e7d4", + "0x8a3b342b87b19c0cdb866afff60317e722013c02dee458ba71e7123edc8b5a9f308c533b9074c7dd0d684948467502d1", + "0x89185ac5cc5ea8f10a1f2a3eb968bb5867376d3cff98ef7560b9a0060206c4046ff7001be10b9e4d7ad0836178eba7e4", + "0x845f48301f25868f6d0f55b678eab1f8458e3321137dba02b4cfbb782cbc09f736a7585bf62f485e06a4e205b54a10b7", + "0x931a6c523d4a66b51efadb7eefadba15bf639d52d1df5026d81fd1734e7f8d5b51b3f815f4370b618747e3e8eb19699c", + "0x8eb3a64fa83dcd8dd2258942aea3f11e9cf8207f2fdd7617507c6dae5ea603f9c89f19d1a75d56eaa74305a1284ce047", + "0x912a5050ed6058221d780235fb0233207c546236316176a104a9761bc332323cf03786dbac196d80a9084790506e0a88", + "0x945fe10ec8dc5e51aa6f8ba7dace6f489449810f664484e572bfe30c2fe6b64229f3c8801e2eb1a9cb92ff3c4428cdf7", + "0xb62383bf99c7822efd659e3ef667efee67956c5150aea57e412cbd6cd470807dfaad65c857fada374c82fcfca2516ad1", + "0xa727a31c45b2970d08a37e169ea578c21484dde15cb11f9c94eaaf3736652619ce9d3a44e7431d50b0e75b658ebbc1da", + "0x97bf54ea9b84b82e4616027bd903ef6152439f1c6a8e1bae6db1d10fdf016af2cac10ff539845833dfd1ddad1403aa8c", + "0xa08cf36437e010e59b2057aedb7192e04b16f1cc66382cdef3490b7ad1544ae51f03e87cba0fe43a275841c247a2a0cf", + "0xacafab9fa28c1a607df2246490b630ddda1ecf0885ad24c2ecb2c2c1b7b9c7de8066714bf5b9b25f61981d08576789ec", + "0x851f0375128d2782586223467d0a595f4c5baa79616622a32f7d6ce1f08af06f8a109bd6527f88d93367dba17be661e8", + "0xa2f1187c2a7cbf776653ff834ed703dd32e68eaf36f0700709be929f4c0ce5fa1d9930d1e3ea2aa01c7a16239e66cb33", + "0xb3721f4a5d24ca112f020cb3f849543bf0e7f84b470fb00126ae80aaaa6f2c208d8359cd82ad9fbafd3ef2ac70656fb2", + "0x98773ac3ce9528c73cfd8e7b95976ce597f67e146357642ac4fb6cb35046f3f39cf6c4a7b5af5c7740dda358aa0d2d08", + "0x92c883a5d820541692af75be1b25dd4a50a4b91f39f367a551a7d5ad6065a26b60d68221a01e4950559717b559c2626a", + "0xb82e46dd25fd1234dad26fbcd8bb5177d7b87d79d362ffb9c2f6a5c16eb2ff324d135996fcd6274d919634597869d772", + "0x82a53ed356ced5e94d77ee2a7f6e63f2ad8240aff2d17c5012cf5d1f18512c88c24793339b565dfbb659bd7c48dcbcd2", + "0x84d20c7859b35a1cae1ff2b486d50822f9e6858b6a1f089ce4c598970e63e7c0f7dfbcb3337845e897a9dedf9d449dd3", + "0x974892e5cf5ee809e9353d00e9cd5253d04826a8989d30cf488528c5dcdcad7650e23b4d228c3eb81f6647d2035a9e02", + "0xb2327854910dbf3d97fe668da5fc507e179c4bc941f39bdd62e8b6035f004449c467240f656417e501f32dee109f0365", + "0x88888f73475613d45d0b441276b1dd55835b69adfb27e26c4186936dae047b85478cca56be8dc06107b89a28f3bbb707", + "0x836ba22e40511feff81a5dace3df54e2c822b55e66874dd1a73929994ec29909ffc2a8e39bfc2d16e316b621eb4a5ec6", + "0xa754cedcccf4165a8d998f326f3f37d2989f92ca36d9da066a153c4aab5a62bb0011896bcbf90f14c18e00488d4123bd", + "0x86c26fa9584314292c4b7d6fe315f65dadd0f811c699e6e45c95a7a4ea4886c57dc5417b67edd78e597d037c7689568e", + "0xb205589648aa49ef56637712490e6867aa3b85b2b31e91437a249fb51bdb31401bff57b865c9e27293b30014b4604246", + "0xafab0843ede582e5a1898ee266235066b94ea378884eaf34919ceaacc0e2738e1074b6ed41e0a1dd9711563e24f0215d", + "0x996ed65fbcab7611eada5bd0fd592d3e44705098b8b1dfba6dcdbdcfa1382fe893fa55270a0df0be0e1938bd71ab997c", + "0x881bc448a5ef8c3756b67ecb1a378a5792525d0a5adb26cc22a36c5df69e14925f67c9cb747a2f7e5f86ba1435509d7c", + "0xb219303c02c9015c6a9a737b35fb38578ab6b85194950a0695f7d521206e1e12956cd010d4d6c3bc3fafd6415845d5d1", + "0x91748829bbd005d2ec37fc36fee97adaccb015208b74d2f89faa2e4295679f7685298f6a94b42d93c75ca9d256487427", + "0xa41d6fd33b9864ebc404d10a07b82ba9d733e904875f75526d9a1f1c1c08b27160dcdb9023c5d99b8ff8a3461d57281f", + "0xb68978d39c97d34f2b2fea61174e05e05e6e49cde587e818b584201cf59b7096cf1807b68f315119c6db8d6110b28a9f", + "0xb64e66cec798022d64ce52477475d27ea7340817fe7f570617f58c3a9c74071d7ea6b54743d4f520b62aecad9a3a6620", + "0x87b2b9e1c1786b7824f239a857024780a1457e51c64599b858118885833fb87a17d408bc09dcc0607d15ec1e53683a74", + "0x9814799bac07dab4f0c934cc3c051676ca13abd49cf8d4739864e5bb9f2a8474897695113f49239f28832a8658332846", + "0x806931a1526a843a9c2045943d616a8102b02b1f219535a1f1fbda659a1244f1bfead52ca7f1851ff8a97169b91c9ec0", + "0xb8678249595a9641c6404c35f89745b93d8e7b34d9d44da933a1b2f1606972624c5108f1c04eb42e454d0509f441ed9e", + "0x81426714851741045a4332eb32b6dfe6422a4a2e75b094fb7c3f37da85648c47ee8af1e54ba26f4e1b57ebe32d0e8392", + "0xb7a1875ea3f119fe0429fd9068548f65cf2869f8519dbbce0b143e66127cb618c81d7578e8391d676b2f3963e9d87f43", + "0x872220a803ea0c6294cdc55aceea42cfacfd7a482982bcb90c0361c351a900c46736a890609cd78f02fb5c8cc21fa04b", + "0x974f0380197b68205ff4bb2c9efe5626add52c0ad9441d7b83e6e59ddb2ed93ad4e9bbdbf33b3e0a206ed97e114ea0f2", + "0xa840f2d9a74fca343aedb32ac970a30cbb38991f010d015dc76eb38c5bb0bfe97dd8951de925a692057262e28f2b4e9d", + "0xb0913c3ce61f12f9fdc4be3366ed514c3efc438f82fc58c4de60fe76098fbc033a580ec6e4531b9799611c89a8063a66", + "0xa0180d533eee93b070dac618be1496f653a9a0e4e3455b58752bf1703ec68d0be33ec0b786f9431ef4208574b0ad316e", + "0xa4a6b871bc95d3aa57bed90e14a0a1dda6e7b92b7ae50e364593ce6773fbf736672b1f4c44e383af4c3cc33e017a545a", + "0xa3f44cf19fe52bacc4f911cab435a9accbe137bdbe05d34bdd8951531eb20b41d17e3540e8d81e6b3eea92c744562ee5", + "0xae6b6d0ff3b30ff0b7f9984ef741cba27ffb70d558de78b897199d586cf60622ec2d8a9d841712fe719cf0f97628842c", + "0x87abf72f98c81d6d3a57ab1e224fe4b502ab0d8090d8abc71791271550b721c220d4e2e7da3be94a20c0e63d98e39a50", + "0xb2f73ebdfe7133af57353052f4599776e16862905e64d97e1020c4bb84132e476d1ab79a9fb71611410f3f9d56c95433", + "0xae1a928253af2b210d31e1b64c765fcbd20a96b8d53823a6b9b6e7fc62249abf4a66c6a6aedb0b687e7384af9a845e0d", + "0x99c54398627833ca1435718154de171a47c709e4d5c58589fdabe62e72f2a7a11ae561bc31d7cbe92df4aff23e08cd0e", + "0x8a1310bbf1a31fae18189479f470977d324dec6518a5d374ab2ffcc8f64412fb765df57d2ddf69b9a6efaeb2b4c723b8", + "0x898312c6c0d3d3438229b19a8a233eca8f62f680c2897f4dd9bbcacde32c5996d56ac0e63e3e9360158761185491ce93", + "0x81b3f965815b97bc6988d945496a51e4a4d8582679c22d138f3d3bd467ed1f59545da2d66e7b4c2e0373628ae2682686", + "0xb9aca91c6e6f4199beb6976b28e0e35e36e8752618468d436b1cf00d8d23538d0747920e5b2c31f71e34dfe4d5c86a0d", + "0xb908f4aa18293295b8cacfda8f3ea731bc791074902c554764c603ab9a1de1bbc72654fd826bffc632d95ce9f79c27d9", + "0xa7316ae1baf4b1196961d53be7fe36535499287aba9bc5f3bed4323039b4121b65bb0bd15a14c1b9cd8b65ede3566da2", + "0x815e39208f205c5fac25ac9988c14a62ab01657c7737a24472d17b0e765644bc2cbb7ff1e8ea169b8b0b17b6996c4704", + "0x89a451d2b740cdaa83ccaa9efb4d0ff5822140783979a4fee89eda68329a08c018a75d58bd9325bdc648b0d08340b944", + "0x8cd08f768438c76bae6bee1809dd7be38ec42e49eb6a4d6862db7698f338bf6b4b409088e4f3d1c5bee430295b12a71f", + "0xa4bd8c312103a4bfeb25b0cfffec7a1c15e6e6513b35af685286333c1dce818ffeb52826f2f5bada6b67d109c4ab709e", + "0x93afbef5382d89fa539ca527f3e9b4a8e27ab69fd5d5023962cc6d8932b33cb4dfc5f14343e1a3749bfd5e100c9924e5", + "0x8d8e69d046992ec9ff14f21840809166cae8e0e9e7c8f14fb29daf163b05abe6611daa4010960e1141c5ab24373fb58e", + "0x96f8e72e96ba673c9265e9cc312f6b9c3b931745fc62d2444d59404bb08e5fb02ddb60715181feb9971cbd954526a616", + "0x8d444c2b8e4d0baadb79e3147a2ee20f1bfe30d72eb9a02f15d632185fb8f4e8c3116066f7de1ebfe38577aaccacb927", + "0x971410c0b10e3698f4f64148b3d2148fc6a4a22217fcf4253583530a9d6fbec77e2cf6f7bb5e819120a29c44653de3fc", + "0x99e7e1857bd5ee57007b7b99494b1f1c6bf1b0abd70c054770427d59a3c48eda71b7de7a0d7fcf6084a454469a439b41", + "0x8c8a4cd864894f7a870f35b242b01d17133cb5dfdf2e8007cd5f1753decc0d1fd41be04e1e724df89f1d727e760fdb15", + "0x890a24328bdeaaadf901b120497d1efa17d798f6f4406661e46ecdc64951f9d123d724ab1b2b49e0e9a10d532dd6f06c", + "0xa7cbe1f42981c9518608569a133b0b449e9d67c742d62f0d3358112c97e65ee3f08ec0ff4894ce538b64e134d168e5c8", + "0x87c976dea77b3b750c3a50847f25b851af95afbaad635f9bb9f7a6ba8f0c4faeb099dd777cf7eac41072a526474cb594", + "0x9882aa5e9bcc4ea2dd3de4bb5a0878a672bea924b50c58ae077563b6df0268910a60e969d3da1694ae7394ad0d9acd3d", + "0x90d35ce677327c461fb5dcb032202e851af1d205e9d21a34ed2b95635f13f8fb8dfa470ea202ccfa4b08140d0cf1d636", + "0xb3b4cbb521cce2b681e45e30a4d22078267e97ccdbdc611b2c9719705650dd87e0ca6e80cf2e174f8f8160be94232c36", + "0x95892b00478e6b27ed09efe23a2092c08e691b4120336109d51e24efbf8aba31d59abf3cf55c0cdab1c210670b9743ba", + "0x8643018957fb8ef752673ad73102d0b928796c6496e22f47b6454c9ed5df784306f4908641ae23695db46ebfcfb0b62b", + "0xb166ce57669bf0543019ecf832d85164c551c3a3a66c05b17874bccd5d0ae87245925d6f8edc62ac13dbd5db265823a2", + "0x89fb4800ce4b6c5900d58f1a216ad77a170ea186f3aa0e355840aeedcf374e92a15ae442800c9d60334544be020b17a4", + "0x8c65e586215a97bf11ffc591bce5147b4e20750e82486cc868070c7736c3de697debc1f335674aef24b7afdd41922d93", + "0x90f68ce0c97d2661d3df1040ce9c4fa106661a719e97c7b2d7c96f0a958930c57d6b78d823a2d41910261ae1f10e7b0e", + "0xadda85e1287371ccbe752aa2a3c1d5285595027ba4a47b67baf7b105a22fb8548fa2b5b3eb93ca6850ecc3995f76d3dd", + "0xb26535d218f48d6c846828f028c5b733594ce01186e22e412dd4f4a45b3d87d2ac1bfe5d54c987e4e8aaddeb86366d7d", + "0xa081bd86962ea3d4fd13df6481f3aeaabdd7ceae66f7bbb913e601131f95d016cf147d045253d28457a28b56f15643c8", + "0xb3d852cef4c8b4c7a694edbf6f0e103f3ae7f046a45945c77a1a85ec8dad3423636a89058fafc6628aabff4dbb95c2ba", + "0xb424ffc94e06e6addc90a6324e0482814229b5902e2a266d0c2d716e40651b952bc9f00d7dad9b6050377a70a72c7f24", + "0xb2cafd908cae0ca22eaa2d9a96175744897a20eb7b0a6d43b0098cb1c69e3cb55373888201e4ed32816655eb7d8a3dd7", + "0xb61177ecf1ae9d7e7852d98cbf6080d9f1e33c90f2436720b4ea4690437e8c7850c3754768fc1312cb4e838d855c5ccc", + "0x81b486644e1ae22cf0ba3a37e1df34dc186c82a99ab35ad6f475c37babdea574ddfbe5811d4aa020581292a793d66bd2", + "0x97ae848a823ea7a99f91834e537fb47208f616c08fe32c8f8fe06bd35c9b638698c513265d0b4de9e572a2f9692b98e2", + "0x81b8fef4ea5d399c65e78f40e47c559ada86d890777c549ce362e7ab81b3bfb00d5ff4ae4ee30fd7bda7ee90d28f85d8", + "0xaada6912cc748923ea40bf01922c06c84bc81b2ab0bb3664a0579b646f03d47ce88de733ac7f2cb9be4a8200584cdb71", + "0x89b48b9c79332f8f58eac9100ada5bb7decdc4b1555c5d383e2c1ce447efb0ebdff9c50bb52bc3042107f33a61ab2520", + "0xa32ecca8b870b2b6e9d10b5c1d8f925b3d629d271febad65abed316262bb283c60cade0e91047fbd0fac53ac6db372b9", + "0xb829cd1f13409e3573a8e109c9541b0a9546e98b6c879a11152b5564477ada4d8cb4b3079040e05a5cb63d75ef11eaab", + "0x91f3b100baa19e960b170fe9e03b799faac5b9c6f305c56115940bf81f6e64dcb9cda77e8de70ed73a21c0e8a74acc58", + "0xb25b5e872c84065aee04822bbcb4f3bdff57fbd7cea314c383765cc387786c17de3d5bb3de3ae3314bdede14542bfac6", + "0xa89bea9eca1f5a17a3efccfa4987d8e5366b0dba70ef1fef43aaea83c528428d1498c8b056ac27f16e8946ee93f7028e", + "0x818a1f7b0b8b06ea0514d6b4a0296da4f69cb18ac8e48c5579e6ba2880b06215fcbe81672566b8b94fcc3c0cadecb191", + "0x98dd6e6b4b4d63d9aa7464a2be08ae8babac4da7716a3f109340bc9187d59c6ca0c88e6877a67c65096f64a3ced22a4b", + "0xa2069c5bac4f6590042aefb37570cc20908b0df9d0130180f565ed8a53b4ea476a274de993561fb4d009f529fe7aa1cd", + "0x860b7ec2410f033a7b0c5ca08f88a0ad29f951a5ebd5383408a84367e92f1bd33bee3b87adef2466b7e33b47daabf30e", + "0xa408855a8414102c3cb49f47dda104edf0887e414723da59b6b6537ada7433529f6a4d1a4ad4fe311c279213cdd59356", + "0x8ca0d81dcb43b89a4c6742747d29598ede83a185a8301d78c6e7f1c02c938441360a1ab62a5e571e3eb16fe17131cbc0", + "0xaf7875a495cb4201cdb26e23b7c76492f47f8dd4c81251de2397d73d4c8d5f419cdbad69ba88ef0dc3552e460dbcd22e", + "0x80e901e433dca34f3d386f39b975e97f7fc16c7f692808221fb2ee60c1aaa8db079cc48c7d72fd548aaf8dde8d0b8f05", + "0xb6062319e13926416e57a0ffc65668bfa667e708a4e3f5cb26d8a6a32072f5b790d628052d5946c5068dd17cf4a81df8", + "0x90094b569e8975f8799863798912dbf89b12d2c2d62b3e5fac7efc245436fcd33af23b8c509ae28c6591d3f020966e06", + "0xa504f72d3d06a0c9b188a1035c7c6d80047451c378b6c5b2ffa1f8cecdb64871cb6440afb296974c0a528e5e563061a1", + "0x959061c4924e133a419e76e000e7c62204093576ff733ce0b8ae656ec6045ef94c5a1f3c934fb76fa9188c5eb397a548", + "0xa8b9d0b58de38cb86cb88fb039a7c4c0c79e9f07f03954af29013baa18fc2633883f8f9ca847209c61a8da378f9075d3", + "0xb16d8341da4ff003ed6d1bbdb3be4e35654a77277341fe604b4c4e4a1cb95e61362094fb3d20ab8482ea14661c8b9852", + "0x8ea4ca202e3aed58081a208a74b912d1a17f7b99a9aa836cfaa689a4a6aa9d9fbfe48425cad53b972000f23940db4c5c", + "0x96a372f55e9a25652db144ec077f17acc1be6aa8b4891e408f1909100cd62644a1c0296a3ddc38cd63ef46bef4e08462", + "0x87df40018ab3a47c3782e053dbd020f199fda791f3109253334a71be4159f893a197a494de8f94d6f09efa5811a99977", + "0xaff82d2ea6b3ad28d0ca1999a4b390641d727689dc2df6829a53e57d4f6418196f63a18495caf19d31fc23fdff26d5e2", + "0x9091053c4a18a22d13ad309313b6d2133a96df10fe167f96ec367f9b8c789ecca7667f47d486fc5ba8531323b9f035ac", + "0xa4842090515a1faccc3d8cadbb234b7024254eba5fdfcef0d15265c7cec9dc8727c496ad4e46565d1f08504c77e511d2", + "0xb1d8a37b1a97883d5804d0d2adaa8dbf0c2d334ef4b5095170b19613fb05e9c648484093d0c70d545cf9b043b449c707", + "0xb1ea40f3dd1c3d437072f8adf02c32024f32488dd59389d1c3dfe78aca3df0bab7767f6ded5943cc10f50555da6092f5", + "0xad219c6a8149f10391452892b65a3268743baa7402736f810a35d56cdfed83d2172b03f15c205f0dc5446baf855907a5", + "0xafe44c3e1373df9fc53a440807fa6af8ebc53f705e8ee44a162891684970b04fb55d60bc2595626b020532cb455ee868", + "0x859ae154b017eae9be9da5c02d151de747cc23094d8f96d5db7d397e529b12fb55666f55e846e2bbe5e6f5b59c9d8b05", + "0x8aa01354697de23e890fe54869cd3ec371f1be32064616ca3a556d3019541ba8e00d683f1396ca08e48988f7f7df5de4", + "0xb8f682487460b9d825302c40a7d6dd0353ff43bf24cd8807cdfa46c043e3f5a7db182b27a8350b28e91888802a015af4", + "0xb6d4d6c3ac40f8976b50be271cf64539eb66dc5d5b7cec06804dfe486d1e386037b01271cf81ef96dba5ea98a35a4b43", + "0x9385a2fd1cd3549b0056af53f9e4a6c2dfcd229801ffda266610118ade9a568b33e75b6964e52fcc49c8e3b900e1e380", + "0x98f4aa0e4ef039786cbd569536204e02b0b1338568d1d22bb5bc47b5e0633fb7ffe1da93eb9d825b40b9b7f291f84d51", + "0xb7b3460cf706dc270a773c66d50b949dabad07075021d373c41fbb56228355324d120703e523ea3f345ef7249bfff99d", + "0x81b826255f95201987513d7987cdc0ca0529524d0e043b315a47583136dbada23a114d50d885bb3f855fa8313eff801a", + "0xafdc6c35161645a14b54f7b7a799910e2e07c8a5efe1827031a2eecd5d9263b3baa367fdd867360fabc41e85ab687e74", + "0x817b361ce582153f2952f3042e235ee2d229e5a6b51c3d3da7bbe840b5c6ec2f01446125045848d15fd77dc46c8a8fe2", + "0xaeb599265398af6e5613297d97d2b70222534590fcbd534d68b24a0289b6366ac8188b753f6fd1000ee73ef44f8fb7af", + "0xa5a9e528b606557be64460c1ad302a43e741357827b92ddc50766a7e6287740fc23bd528d9faf23345ce8bff527d5bc7", + "0xa8d3b3b438d5f75efaae6ce7b67c2212899ece5b5bdc9bac655e271fd1846ea8560e646fdbded3d9363eefe29473d80d", + "0x984c7976d557e2f591e779c2885f5033da6f90d63a898d515b5da3adbffa526764cd8eb679b771573fdf7eed82c594ec", + "0x8ac748689cc3280e064807e68e27e234609e3cc87cb011f172204e1865ad7fdc78bec1672bd6e6fddcf4e7902b0f38bf", + "0x877bb392059540b1c8f45917254b8cc34fb7e423952bdc927e0a1622efec4113fa88988686b48134eb67ddebcb7c3ef4", + "0xac04b154ccd307ca20428091585e00121b61bae37b22d5d2a1565bc1134be3c81ccf3715fffebe90744164e5091b3d9a", + "0x90745c04278c3a47ceea491d9dc70a21a99d52648149b1ab623b5396b7d968fd3c4d1a2d08fc5638e8790463e0cf934e", + "0x80bf26ca7301e370f101cc69e7921e187cf5315b484fc80a872dec28bb65886569611a939958f4a3d2d3da4350011298", + "0x87cbf4d6f0c06cc5f24e0f173a5f2f9bf2083a619dcce69a8347c1a6cd1d03325544610f2984eb87a13241e6ab9a22b7", + "0x8909368817a515789ff4d19ed26afafa5729a24b303a368ea945a9287bc9facec9e1c8af19cbec8dab4acbb6a6ddf6c7", + "0xad8d2f82b08e0990dfd6b09fd54db3a30fd70aad218275550f173fd862347e1258a4716ca2bf4c40e4963850b2277eab", + "0xa9467ceacf9337cae4f2c7eeb3e03752ac7d77692b07d5e5d75c438fbe7dc2029ff84f7759372a0ddfa953b4ec7e9e38", + "0xa5feb7669e84b977cb1a50ff3a39c28f7ad1ecc33a893fdf1ddae7a0d8a4c5f6fbaff25cc56631b708af038a961f3b55", + "0x8f2e1fa07963ba18db890b44c3b9ae7f8992b702a5148679df69e4d9d4b1c082b2bd2ae53f96a4fe24b54f3dc1588f17", + "0x896778f35cbecb43f001277c306e38a9c637275101f1a09546f87378b10ccc025644bc650b3b6c36e4fd0c09fbb3df35", + "0x91dc702778176a4d089dc65502d703752dd9a766f125ffef26bdc38fe4abcae07cdea14102c3448d10f8dd6c852ee720", + "0xa5df3004cec6b68b937cadded0dd2f48bd3203a903a3e1c22498c1193f4567659ecaaf3deb7ed7cf43796da9188f5dc6", + "0xb18b4c8ffcb8599c24d9851abf8ee43047cbd4c9074c9cfbf88376a170da4554978988f550afde8a45306ca32713c204", + "0x8370bc38c84da04d236e3c5a6c063e1db6613dcc4b47239d23efdcb0cf86846955b60da3e50f17b17cd3f7e0c29302d9", + "0xab7d6bb6be10aa52ef43abbe90945e78e488561afb959dc2fe768f8fd660d267c7203a2b7bdfa1b44cd07898f4849e06", + "0x965c96047d82d76ec2cfe5035fd58d483cd2cb7f65c728ab3049562c5d1943096d6a5014c05babc697d79c07907cf284", + "0x9614f7006aef6f0478ebd37fbf17276fe48db877394590e348c724059f07c3d1da80d357120d3063cd2b2bc56c58d9d6", + "0x819c7b2a1a4bb4915b434b40a4e86dd7863ea85177b47a759bc8ecd8017f78d643982e8a091ee9a9e582f2b0208725a5", + "0x8e159a185b5790a3ed444b6daab45f430f72f4ac4026750cbd5c7cd7947b5e00f2b10eaaf5aadf8d23054c5b29245546", + "0xb48cb6f6c0aaea04833e10d735b67607846158b6663da380ef01c5bca3c9d537611716867dc2259883e5bc9daed57473", + "0x8b48ce8b5ab76b7d662c29d0f874f5eec178baf3f14221bffd5d20e952f54f3ed053182a486da1d1f400e0acef58f673", + "0xb6fd3cba177bfbcb5e7ebb1e3c1967cad5848c09c615ba2a6c277908f8b1f4f1ac5f184c33f2a401e8bdafcaed48bb88", + "0xabd8f44c4a447de8fde1c119f4fd43c75b4cc99de9c817a019d219d4b2ad2a73b60606c27e36e9856a86bf03e7fc861f", + "0xaf9f7e8b3e9e8599c7e355433c503a05171900a5754200520fd2afed072305be0e4aebb9764525d2c37a5a7eede72025", + "0xa0960a58bd2681804edd7684793e3cbb0e20d1d4bd8721b192baf9aee97266be14c4ee8b3a3715845dca157ba2fb2c1d", + "0x949a37213209adfbfa4e67c7bad591c128352efd9b881c1202cf526bf4f657140ef213acf0efeb827a0c51a1f18809c4", + "0x9192fae84a2a256f69a5e4a968d673bebf14ea9a2c3953f69fe0416f7b0fafa5166f3e4588d281f00d6deac1b6ec08bc", + "0xb1a249662f34a88d2798eae20c096268d19f1769d94879b8f1aa40a37b3764349b8e6ab970558436a88a5aa5c37e150d", + "0xaea87086dcd6de0b92886b3da0813ff271a7107ab1a3cb7021b85172c1e816a84dbb1a8fdb47e8a8eb5e6fcddd5b919a", + "0xa586b5078b3f113eec9f074430bcf9aabe4e82752e5b421c6e31d1c2a911512e34154bf8143b5197e820c5af42aa8ac7", + "0xa6eda122e400a6600f025daa383685a10f72f62317a621698bd0106b331077b05ac1afc68ece7a2e285c54a366921a3c", + "0x8875e9ba654ad7b1d57ede84e2b702600416d40f7475fe2df25dd1b95c0178a227ee187547898e5b9d1ce8ce9ebd15c9", + "0xaf2cb289f8c75f4ddae9e3ef9c1977fe4d4d513e411777b03b996f5baa372eb995b5ca96255fad9ace776168806ecc42", + "0x8d24c465d26bd93290f45ef035bb6dde4530d9d7d051baf583b1f8b98e9886de262c88b5709084710cffa7c767b4c27d", + "0x8cf35b1b28a7726645971805170392d522f5e7e6cb94157fe9c122a987051c1c90abe3c5bdb957ef97b1c45dd9bba05c", + "0x93e2bbd82a3cb872cea663f9248b21d4541d981f3f8d5af80a43920db5194857f69e2884753f6ed03b6d748dbfb33620", + "0x8b774b97657db654ebdafce3654d645f849203452e876e49dad7af562491cb6531bd056f51cb5b2e8f0a99e69bd8566b", + "0xb5333c49d3e1c4c52f70f3a52f0ad77165bed6ad9dcbfaf1364e7a8a0f24570e85a218e4c2193f63d58a7dd975ceb7a5", + "0xb4a34c443e4fdaab8e69fcda1fce5e72eaa50cf968f5d3d19084d049c5e005d63ab6e1d63dee038317da36f50ffb6b74", + "0x824a224009c6848b92d6e1c96e77cb913fee098aaac810e2c39a0e64d5adb058e626d6a99be58593d921198edd48b19c", + "0xa86f1fdd2e1ba11ebda82411b75536fc0c7d2cdb99424e0896d7db6cae0743ee9349ffa5bff8a8995e011337fa735a9d", + "0xb406b5b89b8bed7221628b0b24eb23b91f548e9079a3abd18be2ed49baf38536a2c1ec61ab1ddc17928f14b006623e7b", + "0x8a7ea88d1f7420e2aaf06ee90efa4af798e2ec7cd297aacd44141471ed500107fdd93bd43b6de540314ef576646a7535", + "0xa7a8c071e68bbae9aca110394cf56daad89404dff3e91ea3440670cd3d0423b67905e32b1ba7218fd4f24d2f8bd86ce7", + "0xb959830f152e4d31c357be1ded5782aed5d6970e823cf8809434cf4fddd364963bc7cfda15c8f6b53eda16ab20ca3451", + "0xb59232c8396c418238807ce07e0d248ad2045289e032678b811cc52730f99b480eb76f6adf985e6d5e38331d4bb2b9d5", + "0xa14092fddecc1df18847ab659f6cf7c8603769a4e96fbe386d8303b225cebbbe8f61d6ab3dca08e3ed027e7e39f2641f", + "0x941cb0632acd395439f615c6b4b7da9ed5abf39700a8f6e6f3d3b87a58a1a7dbb2478a6c9ff1990637ada7f7d883f103", + "0x951b8805ecb46c68101078847737e579206f2029e24b071bae6013e9dde8efa22bce28aa72c71708caf4e37f9789a803", + "0xb2cbf22e53f6535fa950dd8de4aa6a85e72784dd1b800c7f31ec5030709d93595768748785ff2dd196fbedf3b53cd9d7", + "0x8d84ea3a7eafb014b6bd6d57b02cab5ac3533aa7be4b86d2c5d53ce2d281304409071100d508ed276f09df81db9080ea", + "0xa2204b60836cba8bf29acd33709e6424226ae4d789ef6b280df8a62e30d940bc9f958ff44b5590d12fa99fcde2a4a7a9", + "0x86692c58214f326c70eb2aaf2d8b26eae66fb624f143a3c144fd00f0249e30e0c832733a7822fac05c8fe74293768ace", + "0xb1cb3d64eb5b9ca0e01211128f990506fba602cd1417da02237205aa42879ae2a6457386da5f06434bcb757f745f701d", + "0xb3eb4290a53d5ff9b4596e4854516f05283f2c9f616ec928a0934b81c61afc351835f7eca66704a18a8b6695571adb30", + "0xb0bfb1d44b039d067d7e0e2621e7c4444a648bce4231a6245179a58cd99758ec8c9e3f261d0adb22f9f1551fceb13e4a", + "0xa29320f71a9e23115672ea2b611764fe60df0374e0d3ff83237d78032e69c591a4bdec514e8b34f4b3aeb98181153081", + "0x8a6abe9c8a048002b2ff34154a02c2f13fc6dbae928da47c77f3e5b553ea93d8f763821a6ead3c6069677870fdff7ff3", + "0xb73ab66a62f427e1a5e315239a2e823e2a43550d245cff243c2799eb2e4701fabb7d5f9ce74a601b5ee65f6555dacf64", + "0xb64858e98b9c10de8c9264b841b87e7396ba1da52f0f25029339ca1d13f7f9d97f4de008cfe12a1e27b0a6b0f2c9e1ab", + "0x807d2440d1f79a03f7163f5669021f3518094881f190cb02922eb4e9b17312da5e729316fe7ba9bfffc21ed247b033cb", + "0xa7f06458d47ebe932c2af053823433a8a06061c48f44314fad8c34846261c8c3f7f63d585a7930937327ad7d7ca31a6f", + "0x82ac2215eba9352b37eb8980f03374f5e0a2f439c0508daa7a32cdce398dde2a600e65a36795a4f5cc95bbcf49b01936", + "0xa1882c83a2f946d54d74a008eac4aed70664db969e6799b142e0d0465e5662ba0d224a1cc33be339438d69bdad446ff6", + "0x8009776f7a34a3c8779e21511fa409b0c5a38e172d1331acc29a16114e002f5f2f001381adb5fb3427a100752d775114", + "0xb24441019af4a0df2dc68e3a736f358da0fd930c288398a18bb5a8d9a1e98ea376395f19d8e03a5f020b83fcb709f1af", + "0xac72b4de3920c4f3c9b8ea90035cd7ed74d34b79e79aab392f057c3e992ebe79050cc1c6ccf87120e4162b29419147de", + "0x973e75577cd2a131a0bd568fd44e43554ac5a9ea3bf10f02d1ad3ac6ce9dc7a8a7ea93aacf3325f7d252d094a0de1376", + "0x98a114de2a86f62c86862de37c328bf6a7fccff4d45a124addbe0eb64debe365409fcb72ce763f2a75030e1ff4060c64", + "0xaff753e1dd4707f1a359eaec06ebef1903242889a2cb705d59dd78a79eb5b894731f5a91547479506145ca5768877dec", + "0xb856e4234858b5aa515de843e8bd4141c15a4cc02c51640e98a8aaa1e40344f1ff8ef7c3b913ea2ae7411713daa558d2", + "0x863525eb2f8147a6d1d0d4304881795bfed348913cd7f38d815d929a426788b69e41f022dba5fdcaf56c85720e37fefe", + "0xa14ad76b145a6de2e0f8d4f615288c1512701a7b3010eb8a95941a2171bc23561e9c643764a08c4599040a3b4f5e936a", + "0xa18bfc66f6139dcb0485a193104fec2e7d52043837a4c0cadb95743e229712a05cf9ce4ccb482f36ff1ce021e04b574a", + "0x991c8e6678077d6e5f5733267c1819d8f7594e3b2c468b86a5c6346495a50701b1b05967e9590c15cef2f72bc10a38f9", + "0xa034e7f9b547b047c99b99a0dd45509b0ac520d09130519174611de5bcdb9998259e1543470b74dcd112d0305c058bad", + "0x95ffe0d02317b5c6d5bfddbcec7f3fdfb257b26ad1783bb5634d983012e2ea1c6b9778009e1b6d10564198562f849ac0", + "0xb3db442aa4adb33577583b2a4ad743f41efe0e1f87bfc66091d1d975333ffc00b4afc43057bcb88a7d68b0c9695d38dd", + "0xad2e97d10d7c53d231619e3f2e8155a27ea4f2fb3c0cecf5c7f14f4cfcdd21f62ea46d843b21df748b2892131633fed2", + "0x905d7aad6d3b56bad48694b6b20b27e370ebca8b91d0821e48e2f9cad39910c26cc11c77c266894db3d470485a63ed11", + "0x99bfadefca796ce6af04ede65ba5ef5bf683ff7e2852bb9c406fda77b95ef382289853dfe4d933525071e4cab8ce3936", + "0x94d9905ed4ef92107d0adb9ea38f085a2a24b8f792108bec702d747c215b1f14aafd486ea0c07ed42602b12d8f602b93", + "0xa78dce23ca09dda2d5e7fe923290062546825286d624de35ac5756b6c8ae030e211f4f9c9c8d18a924f5880e3b383d1f", + "0xabce9e2128ff51fa17e73d93e63d7134859b2f328eedbcefb337c39e752d6750d9cffe6abfcd359c135dc5a12018827b", + "0xa9ea7d91e8a3524acb3182bedd7e1614d37b48f8eb2d8f677eb682d38408b8d512786d8bb65811f4d96788b9378e59b3", + "0x912c9f804fb57dd1928f8274be58b42618f589fc72a7e5b6cb4d4b5d78c547f80737cdd77ebe5d2b71eaf60b8fd2b663", + "0xb7227ec9a62d5538974547f717fdd554ab522d8782667fc3e9962e9c79a21134ef168371bf3b67e28d0964e92cf44028", + "0x89440a781c812a19c758172bf722139598023ed0425374fbb0d91f33be7b7f62a36d7aa34696c4fb0da533bd5dd41532", + "0xb31e4a9792d6e9c625c95aa3c0cd3519410dec07940afab820ef9f63017415d237a47f957d0b591b6de399ffc2a8a893", + "0xa66ec47393df2693be161daaa88be0cf07b430c709ca97246d10a6080ae79db55c9e206b69a61f52512b868ba543e96b", + "0x90ca425dee74cc6a7e8eb1755cf9b7b76ba2a36ab851333b0fb7b35e8e6e189702456f2781ad87b4215993d62230ff4f", + "0x88b64741f93a2ae5d7b90b22a5e83c9d56bcee5c6bfcedb86f212acc776cc3ebd0b62cc025f596cd8db4f4b6a7aeebab", + "0xa1b6c7d2358bb201b42264f8fbebaa242ef105450bab21b4a2f16f368048c16ad1f3695841787eb33a0192f1f6b595eb", + "0x8a932f1cd227ceb18389791ed9ea1ff26571715ed1ab56601a994795713a8f7f031d1e8472ec3eb665b7bfbbca8ca623", + "0x8bb2e34a2bf77f9f657dfc51ff296a6279a4d7d15860924f72b184fb7d5680320c7769954b9dac73c4bfe9c698e65e58", + "0xaf54e7367891c09f2cea44cc7d908d37d058162ec40059d32ded3983a4cabfe5057953878cf23bfad5292dbd0e03c0e1", + "0x8a202532b9205385cf79f0299ddcb3156fd9fab09f9197bce762b5623f75c72ab1d74334ee6f0d289007befe222bf588", + "0x83bd0f5896eaad58cfa7c88fc5ed505cd223f815dcfe93881b7b696cdd08b8b5ede03ea5b98e195c1a99c74ac5394c1b", + "0xb4a84d9940e58e3b4f804e4dd506f8c242579cfa19323c6e59047e5a1e35150699a2fab2f4862dba2f0ee4ed1d8970f8", + "0x8c9ec477d057abebc2e2f6df5c4356a4f565bde09f499a131967d803d4bf36940ca2ed9d4a72adbe0a4a8b83fc686176", + "0x8598f43c32623fd5b563d1ec8048ffc36db3d7f9b3a784299811687976f64b60585b2a2707050a3c36523b75d1e26716", + "0xb55eb07014fe5ad3e5c9359259733945799e7429435d9bf5c72b2e0418776e329379433e17206f9f0a892d702a342917", + "0xa5ed942eda7b36a3b0f516fafd43d9133986e4c623b14c0f6405db04e29c2d0f22f1c588150f670dbb501edda6e6dd4b", + "0x92b6abb28cefab2e332c41c98bfa53d065b7d262638389603a43f4431e6caf837b986254c71f7cdacf4d6cc4064b0195", + "0xb01806178a28cc00d1561db03721eef6f6539676d93dd1fa76a13b42a31d38797e99b1848de92fd11821a342b04f3f72", + "0xa2f10303437acfbb5912e186bbff1c15b27ed194c02cbc1c5b482b0b732c41fa809136e8e314e26b5bfe57690fe3b250", + "0x9990207fcc711102e7e941b3ac105547a3e7301390e84f03086c99c6d3e14efff3a2e2b06e26227f496d88d5cdaa3af1", + "0xb903cdb0c2fd578612398c30fe76d435cd1c2bab755478761244abb1e18ba8506fd9c95b326422affbcaf237309959d7", + "0x99e0c12cae23f244f551d649302aac29bfdeb2c7b95578c591f512ad7ac562bd47e7c7317ac9bac52c9ea246617bdb48", + "0xb996d267ab5149c1c06168ee41e403be83f99c385be118928d6e2c042a782de0659d4d837f0c58b26df0ce22049a5836", + "0x989001b8414743765282f7e9517e4b8983a929341b8971d7dd8a87d246f6c8ba5e550c983566ddd932c22948f4fa5402", + "0xa0b006a2c9124375364b8fc5ddb543a7468fa6d321ea046d0fd2bfdaef79e5e3600b3d56190733491ca499add1298c7f", + "0x80881d6f3ee507089b7dfb847fc53dd443d4384ef6fce878d07d9b4a1171eefea98242580e8a6a69664699f31e675cfb", + "0xadc48ef53d88b9d70409ed89cc3be592c4bd5eb65d9b1b28f2167dc4b12406889c00f2465c554f3aff673debc2997ccf", + "0xa62f5d9f167b9f4a4aab40d9cd8c8a48c519f64a1985823e20e233191b037c02e511b0280487112a9f8b1f1503b02db7", + "0xb89aa2d4fb345a1d21133b0bd87f2326eb3285bd4da78b62174bf43d30a36340e4217dbe233afb925ab59e74c90fccf0", + "0x932ba22acdd2f9d9494da90958bf39d8793af22417647d2082d2c3e6a5e17a2d14b0c096139fa8fa3f03967ca2f84963", + "0xb67b107e71d96de1488b4154da83919d990502601c719e89feabe779049ddf7e4fb7e146eb05e754b70bbead4449efb1", + "0x84509de1b8dc35aa2966d8a48501f725d59b4c65f3abf314b2009b9a573365ae3163c1f276708c66af17de180aae0868", + "0x849153fe837a33fcb32c5fa6722c2db9753e984867c112a364eb880d87467782142d1c53a74b41df1dec7e900c877e1f", + "0x903d05c73ae043b69b18e980a058ce2254d008647a8d951175b9c47984164b34fc857108dcc29ad9df0806d7e90405f4", + "0xa6b05917ac32c0b0eeea18f1ef3af5343778c543592078fdf6a1b47165013e2676bfe6a592a24efab9d49c4bd92b8fc0", + "0x8648482f6947a5a8d892a39f098160aae1a648cb93e7724ea9e91b0d1a4f4150b91481f6e67d3bf29ff9d65ba4fa61a8", + "0xa6ecaabc38895013297ae020686f04ea739c4512d2e3d6f2d9caf3f54000fb031f202e804ee615eb3357714a18657bcf", + "0x912f5935acc2dd20d5ef42b2ad5b307c925324a84a3c78ff66bc5885751934bd92f244e9636b60a744d750a2a7621198", + "0xa0d6f261a776c5b114298f5de08d6e3372649b562051ea2470d3edfc376048793e18fc57ec84809b463dc72496d94329", + "0x940744cd3118d1598c248b38503f6f1fbdbe7a147e683e5b3635140aa91679f8d6c1472600f8e9c36117a60203be6b4e", + "0xab81737c839fe340f6f1fb7275811cb0c0d5fe8bbc265f6a56c6c68d0291bc7234eaa581ff26f8929d9a5bed4aac7002", + "0x8df47341160f1c728c3e31be17a32e42b54faaa1286ef2c7946882ca4dd46443b8428f3654616c6e4053f1cda2e11994", + "0xa721067e75c3c791f4d9f58d4810ac9621606e29c6badb593d6bb78c39968b45be1777ddb9bf03696d4d4be95b2dc1bf", + "0xa4e399213d3c4350c2d0cbe30757ba7e1f9680f58e214ff65433b36232323744c866a87d717851ba1dbd6769599f69a6", + "0xb0be851d1e43dee27abe68f85e2330d94521b5f1c1a356ad83fcd09162c0ca9c2e88bccbcc5bacfa59661764361867a3", + "0x86111bdd3dbfca232aa5802a6db41d639502e43a2e24cb06bb5d05c7f9b5ccac334d16b61d1c5eaac4fa0cab91113b46", + "0xa4f805b11c174c34250748b9beebfb7c8c243198fb13463911906ee4effe7d331258a077e374b639a0c5cdcdff166b7f", + "0x87e4cf2c6f46d2dbac726a121127502921decf0195d7165e7bbeec6f976adb2d1c375eaa57f419895a2c70193215dc4c", + "0x8ff06de2c1c4d0744483bb4f7c5c80bf9c97b4df23e86c0bb17f1498ea70e0ee3af20827da5e8cb9d7f279dc50d7bd85", + "0xab112c0116471b4dc3fd1e6d918f99158eb7a08153e891ddbba2fe5bf0eeb188209e3019176e758231c3df937438136c", + "0xa67f89194e99e028a5da57747268e5ef66fefb881144043429920d222d37aaf268ebf73ca1da659fcdac3b4e7a65092a", + "0xb4da1dcc791566140d6abeaa2923cb6b21a6e6aaa30bb4cc70011e931eefa71f96b7e05358c0654bad7ce45191ab9fa8", + "0x8283933231bca359db588c80e043ad6ea765fb0cba5ef233c5d514ba01ddd1b409efbadb368f26763402e4576dc4655f", + "0x97f568ce3edacd06f3e31a15462f5f9818a8c3fdbcf92b1ac5840b0b6e73166a154013dd52e85a18e8ead3fc9e54aca0", + "0xa9cd1601c41e5ab2018f986443914fb703ddb6b06a36c06fb58065f2fee8e1751071ef924ea3ad76f0c19baccb1b5f8b", + "0x92aad71bb7e929cc35a48020d16a5822f4f106a7f59985005a5ae5ba8e8016ec33727610393498f56b4f353b3d5161b8", + "0x89427780aa4e7ac894c681fbe2889153b94db883f17f109bc9caa93f0c259dda42aab502bbefaf572c56f70abbc42db8", + "0xaa8cf76ff847dfe59534432ed8520bb48bf412c28497747dce04d2b2a54ba843c3be1564630cb49ec0217167847ba590", + "0xa1570a6748a2303e74a31c2131d05ab372ec006ee92ef74c42f2e9a250663bebdfb3777e7ad91f50c954889a59c2d434", + "0xa4c2b1bbc48199c31ea8d8196729eab00ce0200350d4aa9f23347a3289355e5828cb2f93036a14d2d9ec575fb3835239", + "0x84819d0bedbaab5bf8afdf23f59a7ec5f50da3063cfdd1ef5fc4ca4c1fe68980b5c80e30a49f38e5816765e81dfc5a57", + "0xa57cfb5e877b88202f589be777605deafbfc85ed1357af03a18709cfb4b668a271199899243cd3750f1cb77ebc40bba7", + "0x8d95934bbb0efaf3339f27cb96de46e4486aa58a2c40dbc77c1c3ac7c27a228062824b9045c046631b2e286e8549603a", + "0xb99a8356abeee69f40cb3bd8c87e8039a1e076897dde430bfbf989dc495c48609a7122bc6c1d1c32ccac687b47d5558a", + "0xaac2edcf2fe5d3f1a84e8f1f27ece920eabe7793bf0ed5290cda380752e55d57a55a362c5253bebb71e4a55f2c437ff6", + "0xaf7c76876072c3b0091e22b9c5b27ce99bf1f0079ea1a7816ad9c06e9e5fc407595c7f4f9953e67d86fb2da656443dc3", + "0x9175b64d104f78d3310c9c02f82e04c8e9878d2044ea5ee9c799846a3d23afa5fa2aa4af7350956136c69a0eed03cb2e", + "0xb3328e953317494a3d976e7f7c3d264258a5d4b2c88e12d06786a9e7b2affd41086762ef6124c6a6e5b6b028db933c14", + "0xa49d166065e19d39299ee870229e4a04be81acd6af3a2201f3a291a025dd5f8bc3e676ee123cd4b9d8455f6a330b395b", + "0x85fa15bc8947ba03681d87b50bd2f8238b1c07849a7ed4e065053fad46aac9dd428186a6dd69dc61b5eba6ffec470831", + "0xb6fcb2f694a47d3879b374b8b2967dcd59bd82a5d67ae6289a7326c18791b1b374e12571e8c8ea16a4bfc5525ced3ec4", + "0xb6115f52566aa90ccac2aab6d2dbf46eca296d047db1eb29a1b8a2bc2eef7a24e90407f8dae528806aceb2a1e684d49e", + "0x9707e66220233f6a48a93e8dec7b253d19075eaa79238e519b82ce1ac5562cca184f8a1c14f708a96c34ad234673d646", + "0xa0822903fb3825eae07ee9d3482277c0b8fc811856dfe4a51cf24b373f603924166fc5485185f99c4547cd6476b62270", + "0x88dac6366c439daaeee2532b2ddbe206132cf6e12befbb8e99870ac684e04e62de150cba0e22e395a0b858948f40808b", + "0xa72dfba9caad3179f43fead0f75e33ba5342470d8c9cb7c86d30d2c7ce7244a8aafd1d558b0ec8e2a9436de2c2e95ccc", + "0x8d696046defcc32cc19954c559213100f0ba273ea12abb55ca7c42818071d853846bd4213af2c41ecd4442f6b4b511b1", + "0x89d6f2d52cf65414da15a2fb1911c53afbfb50bb5f2638844abfc325ff2651cd9130be4beff05dc4046adfc44394a182", + "0xafb91abd7c2a9cfe62855ede3c6960ad037fe8778364a2746ff7c214c55f84e19a474a9a0062b52a380d3170456ee9c6", + "0x87f724a16ec8fdae8c05788fa3f823ecc3613df46581a63fc79b58f7c0dc2519b6b23e3dd441a0ca6946dfe4bc6cd0ce", + "0x86760f90f6bedfba404b234e90fbf981d26c29b87f2fa272c09540afa0f22e6682d08c21627b8a153c0feb27150458e2", + "0xad4d0342f255a232252450ce4209507ba619abfd1ffcb9c5707cfa45f89be41d88f1837acea993a1c47211b110250b4d", + "0xace54b5889bccdf1d46c4ca21ed97cca57f7d12648381411d1b64afdfc64532a12d49655776ea24cf5eabe34145705ad", + "0x936dac693d0c1b1e5de1701f0bc46aef6e439e84bc368a23c0abe942eb539a2950e8929265786fcdb18d40a44bda14b9", + "0x94fafbc544decec1d489b9ad6b23410b9de4779f9f44aabd093d7fab08340a4646a8cba31633e49c04d2690b8369a1d7", + "0x98157e757f1a677c5d9d65c47759727a4dbc49fec2da4d9889c4ea90573fb42e2a8d72eaef92b782ac6f320970f09363", + "0x8eaa0498c191c810c7e1ca7398f7c80dd0a7e7d7829ed07039490f60e7c2ae108843c06fe38fa36d45d63da46cba887c", + "0xa0ae116e5b0d2dccf83f056ad876037225687904e0290fe513fdc6b2dbe4cbf5fac1d828352e64734895895840b3c57c", + "0xb592b318dbbd7ec4872aae5e64bdf2305db2e5e8cfe0ad77b691f542ba5e066dd20b09b0b08ff0d798bd79ad946ddf7f", + "0x879e50c8c3e7f414ad2b38632bc482b71759cd561aeb2215550186ebb4559e4cf744cdf980512d8321954b3458d21e11", + "0xaed5c6c7ce0407d7b2c04785fcb9deadb9b9413e37cef5b1d918f474cccc7de012fe1fa6f5fa93cb7ef9ac974d9fbc20", + "0x892274a9f0afc68fa74be276c2a16de5cec674193f96b27a80bbb9f3add163f85716b531f3c920b98577a0225f84e8ca", + "0x938fb7a53266b997a7669596577af82f5289b160b7fcf06d76eee2a094696f6f12b28c2c65b833a52529a116c42e6c7e", + "0x892083929b6067f5045b1208f3dc8f0ee25bd0533a8831f5c23bb4ff46a82d48f0a34523359df5061d84a86b718d5060", + "0x99159ae9574df6c16273eda66b6d8b79a327940e335b28c75d647f4744a009f4b5f0f385e2017bd3e7fbf59e629cd215", + "0xa03e5757ef7738eba32d396923ff7ef82db2c15bb6adc8770fcb37260b7bda3be62473bc352a9a2ef7ec8ebe0d7688bc", + "0xae3c24a85c9b1fa55158b2acd56d2016f70dca45a23f3ef7e0c6b096f4a7c54c14020d61bec7c7f87be4a595bf254209", + "0xa920a6f9cc803fe31352fca39c13f8ac1e8d494fcf11b206092227c2af38469b1fbc068b8fe014800b70f137107aafc4", + "0xb893853be57519ffa6410da605e7d3a746ebadec4788c7907f6e0dde9f20f5a6a01181148b874b3decf9b4814846a11a", + "0xb46f43918c5195729f6532439f815d1eb519e91005bc641a4a30ae88700982bf4ed07a342e77945780317c297c903755", + "0x8e431bf4497d0ef6538c93c4bdda520179301a0104eebcfd104efa1edea876818d7d31079656f01a5ff76c4f5fcd71df", + "0x92e3dbcb580dfb9cc998f878052b0c3be1c5119e5249ae9bad3538ebb0f0c4ab5a959b04033b96d61836ef07784e6b64", + "0xb712d9d63aa888156f4ec83e939c6bad53de18045f115f54fbf4261fb02f10a8a46a8d716ab43d4acbad3b02283c32fc", + "0xb2334e776988b4f772446a47c87416b4f19f9b44164a5f828424d3f35ef10baa56afe810d49b0b86b786b9c0227681a6", + "0xa3f25ad18e435ef585fa90e6cef65a8ba327e5e33701979e27e64ef7d8e09e2591e52bff9c5749d35643456d18625685", + "0xadcfa48ae43cac6fa9866b4cce10a243969965942c891d5e6c0e5b03bd4763f9b63779fbf40d26ac674534fe7cc478d7", + "0xa0eb3448e045038740e2ee666e88aa0f8b8e24b1b55d7d4964f01bfc0c581f7e9d4c0e79f8cfbfecfa8b024b216c8ea6", + "0x8110aa1d82f11965af4f4eedb4de09ee9c353481b2d7ee7a2bc2f302d2a5ae6c31ebc6451309ba7c305da41070b0f666", + "0xb074fdad419d42783ebda17f19863aa499eec71fda5aab6cdcc389276b7bf08053795d15890175ca3dc89f6d8d17758c", + "0xa14665846d95d7d5f0b5381502080c822776ec0994ccb1ae1ffbb3f19205ce9c7c9bf9c2d2ca098807ce99f29e4f07a0", + "0xb4884842670a333cb5548a842fa2971881e26b442dfab0b91d6bf3b4cbdf99adbbc9d14fe2bb46872cfcabedae85db30", + "0x94549b01cb47ba16c0cf6f7522c833545397de0b3388c25d03e60132eddada6401682f9ffd8c50d1a61b4d2dde37461f", + "0xa790c9b4cec96e4c54777f3e03cea5769b20382cdcaf1de494bac2b9425eaf453eff643c62ab284cc1af33bbd36013be", + "0xb1b45fd298ed11609aa1ae6c5ac655e365bb451de1b9fc92aad40422ba85c6a454f33b8142acabe55171328c13d92edf", + "0xa74cea9e7096e38327064f058a3cdaa34e6eafaa9c7d58f753c40be67998152380fbd612b9dc0751bda7befcdffcc749", + "0xb18978dfc5efb07b7ef992c7b0cf5d1b4ca551578b1dd13057b7aced8b1deb9f2036e1e3116248a803e922659d206545", + "0x8153c07603cdff6622835a9853b795274390abf7197d7a192193bec44acb43e8cd50b56c11a03f4a2a27124c36974f3d", + "0x86b987f30bb9a37cc91d22dffffcd346ec5773e846a6c2b8f9e03b25ffcae859c470c901c4e29695d325dfe4eee927bd", + "0xaf5e980b9507d10d5269c1a5d02bc16f4f009b663e413ea6a7c655250f3a21c608c12f4002269a05d3779907e7be7d69", + "0xa6f737fab2af9f27bfb8ca87f5fdab6ad51e73ccf074e90576db57b309dfa0a95f9624526dfa4feaef39c388802f2ae9", + "0xb7ed51f699f615f58a7ff4f99d52c4ce7a8d662843c1f4d91f1620fa119b80a0f6848f9fb6c4b9822dc019830e7dfd11", + "0xb71f27f291aa6ef0723ed79c13a1c7a1c40198ffb780a129d9d20e250406bc91f459705b2b6674c9bb412a7b5dd9ff07", + "0x9698cf8f638c3d2916fefa5f28c6050784479f84c2ee76a8aeda7e562630a6ae135b445ec4e29af8588ca5ad94a67f49", + "0x9270aa5030966a9990d8bc71b00b9a7a1d7c1ad8f4c7f78a31b3d7f86467332f21407c74a89ba4f574d723acaf0d2042", + "0xb1b82faceed8e2297cd49cc355471d15ff8dc2ccc78f6944c8f7a75d3ad1629a2e2f1d0a2ff7fa2b3c38cd19839aa5e9", + "0x8a8c4ed49dc9bd961773edf8d41d04385b11bbd3577024639a39319cc7068380236bf73fce0b83e6535bd3f95cef0e65", + "0x8d04ec1e7d148b7e66910ab45a0e6bf409612a3b560bfa784e26f2963152821c646a655cf17a0ce3d4ba4c4ebeeb4a1e", + "0x8e9d707f6186d93accb60813715ed1f6b3001ff6d2f87daf8b906bd0b988c1833b2ccd80dee9bdefb45901e81bb82971", + "0x9762317ca6a5e6fe0b2991e0fa54b5fbf419dd0550d70074957d65cd7ebf79ceba607dd40d709ed635c822b3b4da2cac", + "0x82b53cd9a1eca2f5d3256723dc4b6531ca422bd87bab36243c727d1952db58d7288ab11467305d875d172ce165b1e4a5", + "0xb4dbeafa05c87029ae257bee1ed7603645fab41f6ba7ac8b57ced5b4774a72ba3e671c2433a93acc3c498795b5cccc42", + "0xa916d3ab7f0e7cef294e11c97c910a19c338ad8e615406e6d1c8995b4a19c3b2527100cc6b97a950ec5a4f3f6db7d01a", + "0xb9a785c7123609bdc96f8dd74500c6c77831d9d246f73244de964910b4045ce3242c881271bb1a4bc207d67de7b62e97", + "0xb5f94084f695d0821c472e59c0b761e625b537c8ae3a09f11d9a57259e148cfadba1e43bf22c681b6b32390121cec208", + "0x8f91b36d8570f19a90cf3ed6d5bb25f49a3315ddb566280c091fe2795c4e25ed2c6a1ef8d2669b83f2d7bb78fc8c40f5", + "0x80f27359a73ed8fdd52762f0c7b9f676be2398b1f33c67877261480bf375f975f626c2ca3e7a9f59634db176ed672c98", + "0xb96b91e3d5148ca793edefe4ca776b949c9305acb6f3a3cf87767a684014d2c8f2937c2c672eef8510f17d2da5d51385", + "0x99c4e1ca2cabd4388ea2437dbdf809013d19be9bd09ff6088c8c0cfdb9ecf8fd514391a07b4288dd362434638b8834d9", + "0xb6fdfb812e145f74853892c14f77c29b0c877d8b00055fd084b81360425b3660cd42236ecc853eadb25253e1cd8445c4", + "0xa714af044ef500104576898b9409a9a326ef4286a45c3dae440bd9003fdf689c5f498f24a6f6d18502ce705c60a1cf14", + "0xa9444e201be4a4d8c72119b3d3b13098afee6e5d13c5448fa2e9845cc9188239778f29b208749c960571dfa02b484f05", + "0x91c826a6b8425f93ff395d9fdfa60dbfa655534c36c40a295906578540b9a0e6b94fd8d025b8b8611433022fbbc4fb0b", + "0xa355d76bc3cc48ba07026197130f25a593ec730d2ef0d5d2642bfcad745ecbe5c391324bc2485944060ff3100c952557", + "0xb5f9b5a289a6f9a7252cc1f381c892bdb6836a5998f323ee21ae387936148ad1ad7cc6eca37ecece36404b958ae01e8e", + "0xa3c7ae04a6208851f6cc40ff270047283b95218905396c5dedc490e405061cbefd1251ecf77837d08c5ec1c77d2776ce", + "0xaa02ee387dd2cc7a23cf5cd582da0bc84bb33a7158d76545cbd6e06b26a6f30565dc712d7a8594c29f0529a892138802", + "0x8aff025c841f167fadaf77a68284c355ace41d6df3a9f1e41a6e91454b336f0b69ea34cce495839b642a7c43997a8fd9", + "0x82eccf0b6b4b6460f676d677266451d50f775446df313fc89bdf4c96e082340f6811939d215a54ba0fe30c69b3e43e25", + "0xaf324d871b038ff45a04366817c31d2c1e810359776fb57ac44907c6157004e3705476574e676b405d48a48bfb596f59", + "0x9411dcca93ef5620ce375f379fea5c1017a2dd299e288e77b1ab126273631a299d7436f3bf3c860bf795e5faaaefa804", + "0x934fca809e66f582c690c3778ea49de2e7940c0aeb8d7edad68f2edccdfda853d2c4844abd366fbc2215348935e4b2e2", + "0xa1b1fa4c088418f2609d4dea0656b02a8ee664db25f40d53d8f4b1be89a55e5abecbf2c44c0499874abeb3d3a80acf71", + "0xae6ed7a0ba6280c679b0bf86111afad76fc5d930e9fb199df08134ba807f781d7e0b8b9b2c8c03b02d8cc20dbe949a28", + "0x937d200a72fe4ab8d52f6cb849e322bc5959632b85a93c89744b33e832e8dcf1dddd6ffac0c049b03c105afb8930f7f5", + "0xb4b4a46ebe0c5db16004933c08ad039d365db600a13d68be5346b1c840cce154f56c858874e866de8c3711e755c6e5dd", + "0xafcbcb7170c8caa2b77d2b3388dc2f640aeb9eff55798aeceb6eb6494438be05a2ae82f7034b2d439a45ad31d8c64b07", + "0xa2c676273081b8761f58e0b11306ddb6a4cde3d90e7c47b434468700c5b749932819b01efd7637ca820e10fc28dfb427", + "0xb445715162d834c9ee75ac2ff8932ace91c8242d67926b2a650217e4765e0531c2393c9438a52852d63dbbe2cceaafc5", + "0xa0c0ebdc1480fb238a25fbfc77fae0db6e5e74b91809f0ff20a819e56b8c3141549615d1bd7b99829898f6028e8c86be", + "0xb3d11933e9d1db8ca617934261ed26c6f5ca06ba16369e7541482bf99c4f86520d43fbb10f4effb2fdf3cc70a189fdb5", + "0x888ac610f8fd87a36b5646e1016eaf6dbca04aa0cc43f53a1046d74a658c4d2794606e79fb07fae57cf9d71ed339f4b6", + "0x979818dab00c58435dc0d0d21185943f95819d2a13531abd2d798e1773c4bbd90047f4eebe117868743db75604a50227", + "0xa6fbcd2656e475065fe44e995e8e2b5309b286b787a7597117e7acc3bb159e591a3e7304ef26f567b5720799d8ae1836", + "0xa03f0ac08d2101ec4d99ca1443eea0efa767a65448a8ecd73a7818a99e863a04392bec8c5b8e5192834e8f98d4683f13", + "0xb3c4ea8c6c3ee8aab2873d446ad702000b0e927e0991c9e30d83c6fe62a604efdc3ac92453313ff0d5e0ac6952922366", + "0xab25c857f26830631113d50145e961441b5e35d47b9e57f92466654dffebde43e4f78b0867d20929f97c2888c2f06509", + "0x98950aa5a70ef41f274775f021a284d4d801a2efe2dea38460db8a3a8c08c243836d176e69127c2cd17497b0ca393e9e", + "0xa9698113febfb6d87fcb84bad82ce52d85a279d3a2933bdd179d53cfe8d6c6c68770e549a1e2947e7528a0e82c95d582", + "0x832b504513266259db78478bd1b5a3b0f3bf2c6d25f1013e64bf0cfae9dc23da8ecd25f7f1047d2efb90e5f1d9b4b3cc", + "0xb588bba7bcc0d268ab260d5c1db2122cee7fd01583c7cc27a8ae6b48b29f34c6ea8a6acbb71b9b09c6156ec0a0766142", + "0xa73d2223c7afadc381951a2e9e7bcb7b5c232369f27108c9f3c2ced2dc173e0f49531d0ca527eb142fbb70285307433f", + "0x9152cd6b97bd3278465348dde2095892f46342aed0e3d48675848c05b9aee6ef5ad7fe26e0dcd4ab176532289d40eedd", + "0xa7812a95a43b020721f688dd726356dda8ebe4de79b4f0fdef78615795e29681bff7c6ff710ff5b2d6ae3fd81bdb8507", + "0x83724c16049e9eaae3269ea8e65caa212f0592e0190b47159bb3346208ccb9af3cfe8f6c3176fa566377da1046044ab8", + "0x877634ec37c7dcd3b83705b103c31013697012795f11e8abf88d54bc84f2c060f665f0c3b14ef8087d3c6a8a7982d64f", + "0xb3e53aaacef7a20327bdbba8cd84513534d2e12fd5e1dcf2849f43146e098143b539ebd555623d0ecc46f5ebb4051fca", + "0x952d58ecafca9b7ffc25768ee4f05ce138f0289d72978eb5e5d3b23a0daedcb17478890afdce42e30d924d680e13c561", + "0xa10dcc725f9a261de53dd3133858c126f6aa684cf26d92bce63a70e0ff5fff9610ad00d2b87e598b0a7548cfd1ffe713", + "0xb7bc5d0c6b665d5e6f4d0af1c539d8a636550a327e50a0915c898ac494c42b3100e5fae0074c282d1c5073bf4a5456fb", + "0x8adc330d3b49ddf3ed210166afc944491aaedb28cb4e67472aeb496f66ce59184c842aa583bfb1a26d67d03b85065134", + "0xb2df992a1310936394a1ebca94a7885b4c0a785638f92a7b567cfb4e68504ac5966a9e2b14891d0aa67d035a99e6583a", + "0x96f5da525d140739d19cebb706e2e1e0211edea1f518e040d361d5aca4c80f15be797f58cb4cd3908e4c360c18821243", + "0xb2c0d9173a3d4867c8842e9b58feb1fb47f139f25d1e2332d6b70a85a58811ef99324bf8e52e144e839a4fe2d484e37b", + "0xad95a7631ddb4846d9343d16533493524dfd22e8cbfc280a202343fccee86ab14446f6e7dad9bad9b4185c43fd5f862e", + "0x97f38ab82a51a7a792d459a90e7ea71c5a2f02d58e7d542eb3776d82413932737d9431bd6b74ec2a6a8b980d22d55887", + "0xad4e4c57ec3def5350c37659e8c15bd76d4c13d6de5453493123198dda2c2f40df349f20190e84d740a6b05e0b8f3deb", + "0xa691bc10810d11172a6662e46b6bbc48c351df32f325b319553377f525af44a50aaa02790c915b3a49824aa43f17fff0", + "0xa80ccac79bb4014ee366dbf6e380beb61552bd30ef649d4ec39ab307e4139b7775e776fab30831517674ff3d673566f6", + "0xb11e010b855d80e171705ab9e94364c45998e69d9120e4ca4127049b7a620c2eec1377356e7b877874e767f7c44afef4", + "0x96bfab7777769a1e00ce16ada6667a0d21d709e71bd0371c03002427d138d9172640cdd5c529c710fea74bb9d19270c7", + "0xa5bffd2c30e29633b4ecf637c1e792c0378252e2a99b385a093675940b48de2f262c275332ed4765f4a02467f98e3ddd", + "0x8d11929d67a6bd8a835b80660a89496250c766e713bddb2cd7052d67b92c39a38ce49005d38b4877856c4bef30fb9af4", + "0x8e704597a0dba1dbd1ff8c9755ddac3f334eeeb513fd1c6b78366603ebc1778231deb8e18f2889421f0091e2c24d3668", + "0x904fbb3f78a49e391a0544cf1faa96ba9402cba818359582258d00aff5319e3c214156cff8c603fbc53a45ede22443e9", + "0xaf12ac61eaa9c636481a46fd91903c8a16e7647534fc6fd9baa58ae2998c38ffbd9f03182062311c8adfef0a338aa075", + "0x87f2e544b2993349ab305ab8c3bf050e7764f47d3f3031e26e084e907523d49e1d46c63d0c97b790394f25868e12b932", + "0xa279a7bef6de9d4e183e2bedaf8c553fadfc623a9af8785fe7577cadced02b86e3dab1e97b492d4680c060ea0126abeb", + "0x8ece08667ed826f0a239cea72e11359f7e85d891826292b61d4edbdc672f8342e32c66bec3e6498016b8194168ba0e0d", + "0x90a15162586e991b302427bc0307790a957b53ab0e83c8b2216f6e6302bc496cb256f0f054ff2cccdfe042763de00976", + "0x9966c0413b086a983f031a39080efde41a9fedcaf8e92897ce92e0c573b37981f5ea266b39dc4f4fb926a1bce5e95ad7", + "0x9515be2f65a57e6960d71bfb1917d33f3f6d8b06f8f31df30fc76622949770fea90ff20be525ae3294c56bc91efb7654", + "0x86e71c9b4059dc4fd1ce7e28883e4f579a51449cab5899e371118cdb6afe2758b1485961ca637c299896dea7c732151b", + "0x8695b4ff746d573f8d150f564e69fe51c0726c5d14aa1d72d944f4195e96165eca7eba8cac583fd19d26718b0ce3eb61", + "0x813eecf402151c99c1a55b4c931716e95810fc4e6d117dfc44abbf5ef8dcdf3f971d90d7fa5e5def393681b9584637e0", + "0xa9caf7219eed1db14b7b8f626f20294a3305ed1f6c22f6a26962772c2fa3e50b5234f6d9ba7fa5c3448824c2a15271b3", + "0xb2b2ee20de9b334f2d82cbe0d2e426ca1f35f76218737d0069af9b727a1bfc12d40cf8b88d4afcbeaadf317b7f7ad418", + "0xb853960749521a17ff45f16ac46813d249c4e26e3c08fd33d31ef1ed2b2e157c9cb18bd2454fb5c62690bdd090a48f60", + "0x88772297d2972471b3db71f3ddbf5945a90154768ca49fa6729a5e2299f1795445fb3d4d969d1620e87dca618fbc8a6c", + "0xa2bb783fd13aee993e3efd3a963ebc8a8eacfc8450042f018f2040353de88c71ac784b0898bdff27f606c60a3d5ef2c6", + "0x9210903ac619edca0cb8c288ed6dcc93c472f45182cd6614a8e2390801ddea41d48a4ac04a40e2f0adfd48f91aabe2ea", + "0xa621d00f83260c22db9fa28757ea81dabcc78b10eeaaf58b06b401db6cc7a7d9a6831a16f171ead4e8506d0c46a752ca", + "0xb25c525bf6761a18bbd156ac141df2595940c7b011ed849dbb8ac3a2cd2da6b63ba4755324d70dc14c959deb29fb9ad3", + "0xa35111d0db3e862e1b06249d289e0fc6b110877d254f2ae1604fb21292c227a8b6d87dd17a7b31166038d6860b1bd249", + "0x90bf057309867d95f27637bd10ef15ceb788f07d38aca7ad7920042293d7c4a1a13d4ca1d6db202864d86d20a93e16cf", + "0xa88510e110b268d15dcd163ba1e403e44b656771399ac3a049dcb672a1201e88bf60bdd1d303158888a3d30d616cc0bd", + "0xb33b7e1f765e9cbd5eeb925e69c39b0a9ea3348ab17f1dbb84b66f4a4b3233e28cbdeb0903d6cfe49ec4fc2f27378ff9", + "0xb777da64fa64d9bc3d2d81b088933fce0e5fcc29c15536159c82af3622a2604c2b968991edea7b6882c9e6f76b544203", + "0x8ea598e402a056fd8031fbf3b9e392347999adc1bd5b68c5797a791a787d006e96918c799467af9ac7f5f57eb30b4f94", + "0xb6901a389bf3b3045e679d015c714d24f8bbe6183349b7f6b42f43409a09f0d5bd4b794012257d735c5fdf6d1812554b", + "0xb5866426336d1805447e6efc3f3deb629b945b2781f618df9a2cc48c96020846e9108f9d8507a42ba58d7617cb796c31", + "0xa18ccc6ad1caa8462fa9bec79510689dd2a68d2e8b8e0ddbeb50be4d77728e1d6a18748a11e27edd8d3336c212689a4d", + "0xabbd48c48a271b6b7c95518a9352d01a84fb165f7963b87cdc95d5891119a219571a920f0d9ceedc8f9f0de4ab9deb65", + "0x94a4e5f4d7e49229e435530b12a1ff0e9259a44a4f183fb1fe5b7b59970436e19cf932625f83f7b75702fd2456c3b801", + "0xaf0a6f2a0d0af7fc72e8cb690f0c4b4b57b82e1034cca3d627e8ef85415adec8eb5df359932c570b1ee077c1d7a5a335", + "0x9728025e03114b9e37ed43e9dcba54a2d67f1c99c34c6139e03d4f9c57c9e28b6b27941d9fca4051d32f9b89bec6537b", + "0x941601742d1e1ec8426591733a4f1c13785b0a9b0a6b2275909301a6a3c6c1e2fb1ffa5fdcc08d7fb69f836ae641ced5", + "0xb84b90480defd22f309e294379d1ca324a76b8f0ba13b8496b75a6657494e97d48b0ea5cfdb8e8ac7f2065360e4b1048", + "0x95cc438ee8e370fc857fd36c3679c5660cf6a6c870f56ef8adf671e6bf4b25d1dbad78872cc3989fdfe39b29fc30486d", + "0x8aafba32e4a30cad79c5800c8709241b4041b0c13185ea1aa9bc510858709870b931d70b5d9a629f47579b161f1d8af7", + "0x865b0155d9013e80cba57f204c21910edbd4d15e53ae4fee79992cb854dc8b8a73f0a9be92f74893e30eb70f270511bc", + "0xb9a49ce58d40b429ac7192cdbf76da31300efc88c827b1e441dd5bdb2f1c180d57808c48992492a2dc5231008629159f", + "0x8d1438b10f6cd996494d4c7b5a0841617ec7cf237c9e0956eac04fda3f9ded5110ec99776b816e3c78abd24eb4a9c635", + "0xaf2dd18211bb8a3e77c0a49d5773da6e29e4e6fa6632a6eeb56c4be233f6afe81655d977932548de2be16567c54ffbd7", + "0x92b92443f44464f2b48002a966664a4267eae559fa24051983bcf09d81bed5bcc15cb6ff95139d991707697a5d0cc1ab", + "0xa1864a2bac0c0dd5b2fb1a79913dd675fe0a5ae08603a9f69d8ca33268239ac7f2fed4f6bf6182a4775683cb9ccd92a8", + "0x948e8f1cf5bd594c5372845b940db4cb2cb5694f62f687952c73eb77532993de2e2d7d974a2ced58730d12c8255c30a2", + "0xaa825c08284fa74a99fcfc473576e8a9788277f72f8c87f29be1dd41229c286c2753ff7444c753767bd8180226763dfc", + "0x8384d8d51415e1a4d6fe4324504e958c1b86374cc0513ddf5bcbffabb3edcf4b7d401421e5d1aa9da9010f07ef502677", + "0x8b8223a42585409041d8a6e3326342df02b2fe0bcc1758ff950288e8e4677e3dc17b0641286eaf759a68e005791c249c", + "0xa98a98cc2fb14e71928da7f8ce53ab1fb339851c9f1f4bceb5f1d896c46906bd027ef5950ca53b3c8850407439efedd4", + "0x866f44d2e35a4dbffe6cd539b6ef5901924061e37f9a0e7007696fb23526379c9b8d095b417effe1eecda698de744dcb", + "0x91774f44bf15edafdf43957fdf254682a97e493eb49d0779c745cb5dbe5d313bf30b372edd343f6d2220475084430a2e", + "0xab52fc3766c499a5f5c838210aada2c3bcc1a2ec1a82f5227d4243df60809ee7be10026642010869cfbf53b335834608", + "0xa0e613af98f92467339c1f3dc4450b7af396d30cefd35713388ccd600a3d7436620e433bf294285876a92f2e845b90d0", + "0x8a1b5ca60a9ae7adc6999c2143c07a855042013d93b733595d7a78b2dc94a9daa8787e2e41b89197a0043343dbd7610f", + "0xae7e4557bc47b1a9af81667583d30d0da0d4a9bb0c922450c04ec2a4ae796c3f6b0ede7596a7a3d4e8a64c1f9ee8ff36", + "0x8d4e7368b542f9f028309c296b4f84d4bde4837350cf71cfe2fa9d4a71bce7b860f48e556db5e72bc21cf994ffdf8e13", + "0xaf6ed1fbff52dd7d67d6a0edfa193aa0aab1536979d27dba36e348759d3649779f74b559194b56e9378b41e896c4886f", + "0xa069ba90a349ac462cac0b44d02c52a4adf06f40428aef5a2ddff713de31f991f2247fc63426193a3ea1b1e50aa69ded", + "0x8750f5f4baf49a5987470f5022921108abe0ead3829ddef00e61aedd71f11b1cdd4be8c958e169440b6a8f8140f4fbf9", + "0xa0c53cefc08a8d125abd6e9731bd351d3d05f078117ff9c47ae6b71c8b8d8257f0d830481f941f0c349fc469f01c9368", + "0x94eea18c5ed056900c8285b05ba47c940dff0a4593b627fdd8f952c7d0122b2c26200861ef3e5c9688511857535be823", + "0x8e1b7bd80d13460787e5060064c65fbcdac000c989886d43c7244ccb5f62dcc771defc6eb9e00bae91b47e23aeb9a21f", + "0xb4b23f9dd17d12e145e7c9d3c6c0b0665d1b180a7cfdf7f8d1ab40b501c4b103566570dca2d2f837431b4bf698984cad", + "0x847a47c6b225a8eb5325af43026fb9ef737eede996257e63601f80302092516013fde27b93b40ff8a631887e654f7a54", + "0x9582d7afb77429461bd8ebb5781e6390a4dde12a9e710e183581031ccfacd9067686cfaf47584efaafeb1936eae495cc", + "0x8e4fd5dbd9002720202151608f49ef260b2af647bd618eb48ebeceeb903b5d855aa3e3f233632587a88dc4d12a482df9", + "0x87b99fe6a9c1d8413a06a60d110d9e56bb06d9f0268dc12e4ab0f17dd6ca088a16ade8f4fb7f15d3322cbe7bfd319ae1", + "0xb562d23002ed00386db1187f519018edd963a72fca7d2b9fcaab9a2213ac862803101b879d1d8ac28d1ccae3b4868a05", + "0xb4cc8b2acacf2ce7219a17af5d42ce50530300029bc7e8e6e2a3c14ff02a5b33f0a7fecb0bb4a7900ea63befa854a840", + "0x9789f0fe18d832ff72df45befa7cabf0a326b42ada3657d164c821c35ac7ed7b2e0eba3d67856e8c387626770059b0c3", + "0x986c6fe6771418549fa3263fa8203e48552d5ecb4e619d35483cb4e348d849851f09692821c9233ae9f16f36979c30c2", + "0xa9160182a9550c5756f35cea1fe752c647d1b64a12426a0b5b8d48af06a12896833ec5f5d9b90185764db0160905ca01", + "0x82614dbd89d54c1e0af4f6ffe8710e6e871f57ef833cbcb3d3d7c617a75ec31e2a459a89ebb716b18fc77867ff8d5d47", + "0x8fc298ffba280d903a7873d1b5232ce0d302201957226cddff120ffe8df9fee34e08420302c6b301d90e3d58f10beeb9", + "0x898da9ac8494e31705bdf684545eee1c99b564b9601877d226d0def9ec67a20e06f8c8ba2a5202cc57a643487b94af19", + "0x88218478d51c3ed2de35b310beedf2715e30208c18f046ee65e824f5e6fd9def921f6d5f75fd6dde47fa670c9520f91a", + "0x89703ae7dff9b3bc2a93b44cdbab12c3d8496063a3c658e21a7c2078e4c00be0eecae6379ee8c400c67c879748f1d909", + "0xa44d463477dece0d45abb0ebb5f130bfb9c0a3bbcd3be62adf84a47bbd6938568a89bc92a53ca638ff1a2118c1744738", + "0x95df2b4d392143ee4c39ad72f636d0ed72922de492769c6264015776a652f394a688f1d2b5cf46077d01fda8319ba265", + "0xaa989867375710ed07ad6789bfb32f85bdc71d207f6f838bd3bde9da5a169325481ac326076b72358808bd5c763ba5bb", + "0xb859d97d0173920d16bc01eb7d3ddd47273daac72f86c4c30392f8de05fee643e8d6aa8bebdbc5c2d89037bc68a8a105", + "0xb0249ec97411fa39aa06b3d9a6e04bbbcd5e99a7bc527273b6aa95e7ae5f437b495385adaefa4327231562d232c9f822", + "0x8209e156fe525d67e1c83ec2340d50d45eba5363f617f2e5738117cdcc4a829c4cc37639afd7745cbe929c66754fd486", + "0x99fd2728ceb4c62e5f0763337e6d28bf11fbe5df114217f002bc5cd3543c9f62a05a8a41b2e02295360d007eaab796a6", + "0x902ebc68b8372feeaf2e0b40bd6998a0e17981db9cc9d23f932c34fbcc680292a0d8adcea2ad3fb2c9ed89e7019445c2", + "0x8b5653f4770df67f87cb68970555b9131c3d01e597f514e0a399eec8056e4c5a7deed0371a27b3b2be426d8e860bf9f2", + "0x8f5af27fdc98a29c647de60d01b9e9fd0039013003b44ba7aa75a4b9c42c91feb41c8ae06f39e22d3aed0932a137affa", + "0x81babb9c1f5bcc0fd3b97d11dd871b1bbd9a56947794ff70ab4758ae9850122c2e78d53cb30db69ece23538dc4ee033e", + "0xb8b65d972734f8ecae10dd4e072fa73c9a1bf37484abcfa87e0d2fcecac57294695765f63be87e1ba4ec0eb95688403a", + "0xb0fe17d0e53060aef1947d776b06ab5b461a8ef41235b619ca477e3182fadaf9574f12ffc76420f074f82ac4a9aa7071", + "0xae265c0b90bf064d7a938e224cb1cd3b7eca3e348fbc4f50a29ac0930a803b96e0640992354aa14b303ea313cb523697", + "0x8bc10ffde3224e8668700a3450463ab460ec6f198e1deb016e2c9d1643cc2fe1b377319223f41ffeb0b85afd35400d40", + "0x8d5113b43aea2e0cc6f8ec740d6254698aff7881d72a6d77affd6e6b182909b4de8eb5f524714b5971b418627f15d218", + "0xae2ef0a401278b7b5d333f0588773ec62ead58807cdee679f72b1af343c1689c5f314989d9e6c9369f8da9ce76979db6", + "0xb9c1cb996a78d4f7793956daaa8d8825dd43c4c37877bc04026db4866144b1bf37aa804d2fe0a63c374cf89e55e9069f", + "0xa35f73851081f6540e536a24a28808d478a2bb1fd15ee7ff61b1562e44fbafc0004b9c92c9f96328d546b1287e523e48", + "0x82007f34e3383c628c8f490654369744592aa95a63a72be6e90848ad54f8bc2d0434b62f92a7c802c93017214ecf326e", + "0x9127db515b1ed3644c64eaf17a6656e6663838fed4c6612a444a6761636eaaeb6a27b72d0e6d438c863f67b0d3ec25c5", + "0x984c9fcc3deccf83df3bbbb9844204c68f6331f0f8742119ba30634c8c5d786cd708aa99555196cf6563c953816aec44", + "0xa0f9daf900112029474c56ddd9eb3b84af3ed2f52cd83b4eb34531cf5218e7c58b3cab4027b9fc17831e1b6078f3bf4a", + "0x90adbcc921369023866a23f5cea7b0e587d129ad71cab0449e2e2137838cea759dec27b0b922c59ac4870ef6146ea283", + "0x8c5650b6b9293c168af98cf60ad35c945a30f5545992a5a8c05d42e09f43b04d370c4d800f474b2323b4269281ca50f8", + "0x868d95be8b34a337b5da5d886651e843c073f324f9f1b4fbd1db14f74aba6559449f94c599f387856c5f8a7bc83b52a1", + "0x812df0401d299c9e95a8296f9c520ef12d9a3dd88749b51eab8c1b7cc97961608ab9fc241a7e2888a693141962c8fd6d", + "0xabda319119d8a4d089393846830eee19d5d6e65059bf78713b307d0b4aad245673608b0880aa31c27e96c8d02eff39c0", + "0x887f11ae9e488b99cb647506dcaa5e2518b169ee70a55cd49e45882fe5bfb35ffaf11feb2bf460c17d5e0490b7c1c14d", + "0xb36b6e9f95ffff917ca472a38fa7028c38dc650e1e906e384c10fe38a6f55e9b84b56ffa3a429d3b0c3e2cf8169e66a9", + "0xa0450514d20622b7c534f54be3260bab8309632ca21c6093aa0ccc975b8eed33a922cbcc30a730ccc506edf9b188a879", + "0x87cfaf7bcd5d26875ca665ac45f9decd3854701b0443332da0f9b213e69d6f5521ae0217ec375489cd4fad7b4babf724", + "0x842ad67c1baf7a9d4504c10c5c979ce0a4d1b86a263899e2b5757407c2adcdcf7ed58173ad9d156d84075ef8798cb1c4", + "0xac1a05755fe4d3fb2ab5b951bafe65cca7c7842022ca567b32cddf7741782cbf8c4990c1dd4ea05dc087a4712844aebb", + "0xa000c8cecc4fddeb926dc8dd619952bc51d00d7c662e025f973387a3fc8b1ef5c7c10b6a62e963eb785e0ec04cb1ffbe", + "0x8a573c9986dbeb469547dfd09f60078eab252d8ec17351fe373a38068af046b0037967f2b3722fa73ed73512afd038d2", + "0xb8dff15dff931f58ba05b6010716c613631d7dd9562ae5138dbec966630bcdb0e72552e4eefc0351a6a6b7912d785094", + "0x990e81fd459433522e8b475e67e847cb342c4742f0dbf71acc5754244ccd1d9ff75919168588d8f18b8aea17092dd2a4", + "0xb012f8644da2113bef7dd6cdc622a55cfa0734bd267b847d11bba2e257a97a2a465c2bb616c240e197ff7b23e2ce8d8e", + "0xa659bd590fde467766e2091c34a0b070772f79380be069eef1afecc470368a95afd9eed6520d542c09c0d1a9dca23bd0", + "0xb9239f318b849079477d1cf0a60a3d530391adacd95c449373da1c9f83f03c496c42097c3f9aca10c1b9b3dbe5d98923", + "0x851e9a6add6e4a0ee9994962178d06f6d4fbc0def97feef1ba4c86d3bcf027a59bafa0cf25876ca33e515a1e1696e5cc", + "0x803b9c5276eed78092de2f340b2f0d0165349a24d546e495bd275fe16f89a291e4c74c22fdee5185f8fce0c7fbced201", + "0x95915654ca4656d07575168fb7290f50dc5dcbbcdf55a44df9ec25a9754a6571ab8ca8a159bc27d9fa47c35ffd8f7ffd", + "0x88f865919764e8e765948780c4fdd76f79af556cd95e56105d603c257d3bfb28f11efca1dfb2ce77162f9a5b1700bac8", + "0xb1233131f666579b4cc8b37cfa160fc10551b1ec33b784b82685251464d3c095cdde53d0407c73f862520aa8667b1981", + "0xa91115a15cf4a83bda1b46f9b9719cfba14ffb8b6e77add8d5a0b61bea2e4ea8ce208e3d4ed8ca1aab50802b800e763a", + "0x93553b6c92b14546ae6011a34600a46021ce7d5b6fbfcda2a70335c232612205dbe6bfb1cc42db6d49bd4042c8919525", + "0x8c2a498e5d102e80c93786f13ccf3c9cab7f4c538ccf0aee8d8191da0dbca5d07dff4448383e0cf5146f6d7e629d64f8", + "0xa66ab92c0d2c07ea0c36787a86b63ee200499527c93b9048b4180fc77e0bb0aa919f4222c4bec46eeb3f93845ab2f657", + "0x917e4fc34081a400fc413335fdf5a076495ae19705f8542c09db2f55fa913d6958fa6d711f49ad191aec107befc2f967", + "0x940631a5118587291c48ac8576cdc7e4a904dd9272acb79407a7d3549c3742d9b3669338adbc1386724cc17ee0cc1ca3", + "0xae23ae3a531900550671fd10447a35d3653c5f03f65b0fdffe092844c1c95d0e67cab814d36e6388db5f8bd0667cd232", + "0xae545727fca94fd02f43e848f0fbbb1381fd0e568a1a082bf3929434cc73065bfbc9f2c840b270dda8cc2e08cd4d44b0", + "0x8a9bc9b90e98f55007c3a830233c7e5dc3c4760e4e09091ff30ee484b54c5c269e1292ce4e05c303f6462a2a1bd5de33", + "0xa5a2e7515ce5e5c1a05e5f4c42f99835f6fde14d47ecb4a4877b924246038f5bc1b91622e2ff97ed58737ed58319acfa", + "0x8fa9f5edf9153618b72b413586e10aaa6c4b6e5d2d9c3e8693ca6b87804c58dc4bf23a480c0f80cb821ebc3cf20ea4fc", + "0x925134501859a181913aadac9f07f73d82555058d55a7d5aaa305067fbd0c43017178702facc404e952ea5cfd39db59b", + "0x8b5ab1d9b5127cb590d6bddbf698ffe08770b6fc6527023d6c381f39754aecc43f985c47a46be23fe29f6ca170249b44", + "0xaa39c6b9626354c967d93943f4ef09d637e13c505e36352c385b66e996c19c5603b9f0488ad4014bb5fc2e051b2876cc", + "0x8e77399c6e9cb8345002195feb7408eb571e6a81c0418590d2d775af7414fc17e61fe0cd37af8e737b59b89c849d3a28", + "0xa0150aeca2ddc9627c7ea0af0dd4426726583389169bc8174fc1597cc8048299cc594b22d234a4e013dff7232b2d946c", + "0x98659422ef91f193e6104b09ff607d1ed856bb6baed2a6386c9457efbc748bd1bf436573d80465ebc54f8c340b697ea5", + "0x8d6fb015898d3672eb580e1ffdf623fc4b23076664623b66bfb18f450d29522e8cb9c90f00d28ccf00af34f730bff7ac", + "0x996a8538efa9e2937c1caad58dc6564e5c185ada6cdcef07d5ec0056eb1259b0e4cef410252a1b5dbaee0da0b98dac91", + "0xaa0ae2548149d462362a33f96c3ce9b5010ebf202602e81e0ef77e22cfc57ecf03946a3076b6171bea3d3dc9681187d7", + "0xa5ce876b29f6b89050700df46d679bed85690daf7bad5c0df65e6f3bde5673e6055e6c29a4f4dcb82b93ccecf3bad9cc", + "0x81d824bb283c2f55554340c3514e15f7f1db8e9e95dd60a912826b1cccb1096f993a6440834dad3f2a5de70071b4b4b5", + "0x914e7291da286a89dfc923749da8f0bf61a04faa3803d6d10633261a717184065dcc4980114ad852e359f79794877dd9", + "0xae49dc760db497c8e834510fe89419cc81f33fd2a2d33de3e5e680d9a95a0e6a3ccbdf7c0953beeb3d1caf0a08b3e131", + "0xb24f527d83e624d71700a4b238016835a2d06f905f3740f0005105f4b2e49fc62f7e800e33cdc900d805429267e42fc0", + "0xb03471ecaa7a3bf54503347f470a6c611e44a3cee8218ad3fcad61d286cfb7bb6a1113dad18475ec3354a71fcc4ec1e2", + "0x881289b82b30aff4c8f467c2a25fced6064e1eece97c0de083e224b21735da61c51592a60f2913e8c8ba4437801f1a83", + "0xb4ce59c0fc1e0ecad88e79b056c2fd09542d53c40f41dea0f094b7f354ad88db92c560b9aeb3c0ef48137b1a0b1c3f95", + "0xa1ffb30eb8ef0e3ea749b5f300241ebe748ed7cf480e283dfcda7380aa1c15347491be97e65bc96bdf3fe62d8b74b3ae", + "0xb8954a826c59d18c6bfab24719f8730cc901868a95438838cd61dac468a2d79b1d42f77284e86e3382bf4f2a22044927", + "0x818e7e7c59b6b5e22b3c2c19c163f2e787f2ff3758d395a4da02766948935eb44413c3ddd2bf45804a3c19744aa332f3", + "0xa29556e49866e4e6f01d4f042eed803beeda781462884a603927791bd3750331a11bc013138f3270c216ab3aa5d39221", + "0xb40885fa0287dc92859b8b030c7cca4497e96c387dcfe6ed13eb7f596b1eb18fb813e4ae139475d692f196431acb58fe", + "0x89cd634682fd99ee74843ae619832780cf7cd717f230ea30f0b1821caf2f312b41c91f459bdba723f780c7e3eed15676", + "0xb48c550db835750d45a7f3f06c58f8f3bf8766a441265ca80089ead0346f2e17cbb1a5e843557216f5611978235e0f83", + "0x90936ee810039783c09392857164ab732334be3a3b9c6776b8b19f5685379c623b1997fb0cdd43af5061d042247bc72f", + "0xa6258a6bae36525794432f058d4b3b7772ba6a37f74ef1c1106c80a380fc894cbeac4f340674b4e2f7a0f9213b001afd", + "0x8f26943a32cf239c4e2976314e97f2309a1c775777710393c672a4aab042a8c6ee8aa9ac168aed7c408a436965a47aeb", + "0x820f793573ca5cc3084fe5cef86894c5351b6078df9807d4e1b9341f9d5422dd29d19a73b0843a14ad63e8827a75d2da", + "0xa3c4fca786603cd28f2282ba02afe7cf9287529e0e924ca90d6cdfd1a3912478ebb3076b370ee72e00df5517134fe17f", + "0x8f3cdabd0b64a35b9ee9c6384d3a8426cc49ae6063632fb1a56a0ae94affa833955f458976ff309dafd0b2dd540786ae", + "0x945a0630cd8fa111cfd776471075e5d2bbe8eb7512408b5c79c8999bfaeca6c097f988fb1c38fa9c1048bac2bca19f2e", + "0x8a7f6c4e0ba1920c98d0b0235b4dda73b631f511e209b10c05c550f51e91b4ba3893996d1562f04ac7105a141464e0e9", + "0xab3c13d8b78203b4980412edc8a8f579e999bf79569e028993da9138058711d19417cf20b477ef7ed627fa4a234c727a", + "0x82b00d9a3e29ed8d14c366f7bb25b8cfe953b7be275db9590373a7d8a86ea927d56dc3070a09ef7f265f6dd99a7c896e", + "0xb6e48a282de57949821e0c06bc9ba686f79e76fb7cbf50ea8b4651ccd29bc4b6da67efea4662536ba9912d197b78d915", + "0xa749e9edcba6b4f72880d3f84a493f4e8146c845637009f6ff227ff98521dbbe556a3446340483c705a87e40d07364bc", + "0xb9b93c94bd0603ce5922e9c4c29a60066b64a767b3aed81d8f046f48539469f5886f14c09d83b5c4742f1b03f84bb619", + "0xafa70b349988f85ed438faafa982df35f242dd7869bda95ae630b7fd48b5674ef0f2b4d7a1ca8d3a2041eff9523e9333", + "0xa8e7e09b93010982f50bd0930842898c0dcd30cdb9b123923e9d5ef662b31468222fc50f559edc57fcfdc597151ebb6e", + "0x8ce73be5ac29b0c2f5ab17cae32c715a91380288137d7f8474610d2f28d06d458495d42b9cb156fb1b2a7dfdcc437e1c", + "0x85596c1d81f722826d778e62b604eb0867337b0204c9fae636399fa25bb81204b501e5a5912654d215ec28ff48b2cb07", + "0x96ff380229393ea94d9d07e96d15233f76467b43a3e245ca100cbecbdbb6ad8852046ea91b95bb03d8c91750b1dfe6e1", + "0xb7417d9860b09f788eb95ef89deb8e528befcfa24efddbc18deaf0b8b9867b92361662db49db8121aeea85a9396f64fd", + "0x97b07705332a59cdba830cc8490da53624ab938e76869b2ce56452e696dcc18eb63c95da6dffa933fb5ffb7585070e2d", + "0x971f757d08504b154f9fc1c5fd88e01396175b36acf7f7abcfed4fff0e421b859879ed268e2ac13424c043b96fbe99fc", + "0xb9adb5d3605954943a7185bddf847d4dbe7bafe970e55dc0ec84d484967124c26dd60f57800d0a8d38833b91e4da476a", + "0xb4856741667bb45cae466379d9d6e1e4191f319b5001b4f963128b0c4f01819785732d990b2f5db7a3452722a61cd8cc", + "0xa81ec9f2ab890d099fb078a0c430d64e1d06cbbe00b1f140d75fc24c99fe35c13020af22de25bbe3acf6195869429ba5", + "0x99dcea976c093a73c08e574d930d7b2ae49d7fe43064c3c52199307e54db9e048abe3a370b615798b05fe8425a260ba0", + "0xa1f7437c0588f8958b06beb07498e55cd6553429a68cd807082aa4cc031ab2d998d16305a618b3d92221f446e6cd766d", + "0x806e4e0958e0b5217996d6763293f39c4f4f77016b3373b9a88f7b1221728d14227fce01b885a43b916ff6c7a8bc2e06", + "0x8e210b7d1aff606a6fc9e02898168d48ec39bc687086a7fe4be79622dd12284a5991eb53c4adfe848251f20d5bfe9de0", + "0x82810111e10c654a6c07cbfd1aff66727039ebc3226eef8883d570f25117acf259b1683742f916ac287097223afc6343", + "0x92f0e28cca06fd543f2f620cc975303b6e9a3d7c96a760e1d65b740514ccd713dc7a27a356a4be733570ca199edd17ba", + "0x900810aa4f98a0d6e13baf5403761a0aeb6422249361380c52f98b2c79c651e3c72f7807b5b5e3a30d65d6ff7a2a9203", + "0xb0740bfefea7470c4c94e85185dbe6e20685523d870ff3ef4eb2c97735cef41a6ab9d8f074a37a81c35f3f8a7d259f0e", + "0xaf022e98f2f418efbbe2de6fefb2aa133c726174f0f36925a4eafd2c6fd6c744edb91386bafb205ce13561de4294f3a6", + "0x95e4592e21ba97e950abb463e1bc7b0d65f726e84c06a98eb200b1d8bfc75d4b8cff3f55924837009e88272542fd25ec", + "0xb13bd6b18cd8a63f76c9831d547c39bbd553bda66562c3085999c4da5e95b26b74803d7847af86b613a2e80e2f08caae", + "0xa5625658b474a95aba3e4888c57d82fb61c356859a170bc5022077aa6c1245022e94d3a800bf7bd5f2b9ab1348a8834e", + "0xa097ee9e6f1d43e686df800c6ce8cfc1962e5a39bb6de3cf5222b220a41b3d608922dae499bce5c89675c286a98fdabd", + "0x94230ba8e9a5e9749cd476257b3f14a6bf9683e534fb5c33ca21330617533c773cb80e508e96150763699ad6ecd5aee7", + "0xb5fea7e1f4448449c4bc5f9cc01ac32333d05f464d0ed222bf20e113bab0ee7b1b778cd083ceae03fdfd43d73f690728", + "0xa18a41a78a80a7db8860a6352642cdeef8a305714543b857ca53a0ee6bed70a69eeba8cfcf617b11586a5cc66af4fc4f", + "0x85d7f4b3ff9054944ac80a51ef43c04189d491e61a58abed3f0283d041f0855612b714a8a0736d3d25c27239ab08f2ec", + "0xb1da94f1e2aedd357cb35d152e265ccfc43120825d86733fa007fc1e291192e8ff8342306bef0c28183d1df0ccec99d0", + "0x852893687532527d0fbeea7543ac89a37195eadab2f8f0312a77c73bdeed4ad09d0520f008d7611539425f3e1b542cfd", + "0x99e3bd4d26df088fc9019a8c0b82611fd4769003b2a262be6b880651d687257ded4b4d18ccb102cba48c5e53891535e4", + "0x98c407bc3bbc0e8f24bedf7a24510a5d16bce1df22940515a4fbdacd20d06d522ef9405f5f9b9b55964915dd474e2b5c", + "0x80de0a12f917717c6fc9dc3ccc9732c28bae36cff4a9f229d5eaf0d3e43f0581a635ba2e38386442c973f7cb3f0fdfa7", + "0x94f9615f51466ae4bb9c8478200634b9a3d762d63f2a16366849096f9fc57f56b2e68fe0ca5d4d1327a4f737b3c30154", + "0xa3dcbe16499be5ccb822dfcd7c2c8848ba574f73f9912e9aa93d08d7f030b5076ca412ad4bf6225b6c67235e0ab6a748", + "0x98f137bf2e1aea18289750978feb2e379054021e5d574f66ca7b062410dcfe7abb521fab428f5b293bbe2268a9af3aa4", + "0x8f5021c8254ba426f646e2a15b6d96b337a588f4dfb8cbae2d593a4d49652ca2ada438878de5e7c2dbbd69b299506070", + "0x8cc3f67dd0edcdb51dfd0c390586622e4538c7a179512f3a4f84dd7368153a28b1cf343afd848ac167cb3fcaa6aee811", + "0x863690f09ac98484d6189c95bc0d9e8f3b01c489cb3f9f25bf7a13a9b6c1deaf8275ad74a95f519932149d9c2a41db42", + "0x8494e70d629543de6f937b62beca44d10a04875bd782c9a457d510f82c85c52e6d34b9c3d4415dd7a461abbcc916c3c4", + "0x925b5e1e38fbc7f20371b126d76522c0ea1649eb6f8af8efb389764ddcf2653775ef99a58a2dcf1812ce882964909798", + "0x94d0494dcc44893c65152e7d42f4fb0dc46af5dc5674d3c607227160447939a56d9f9ea2b3d3736074eef255f7ec7566", + "0xb0484d33f0ef80ff9b9d693c0721c77e518d0238918498ddf71f14133eb484defb9f9f7b9083d52bc6d6ba2012c7b036", + "0x8979e41e0bb3b501a7ebbd024567ce7f0171acfea8403a530fe9e791e6e859dfbd60b742b3186d7cf5ab264b14d34d04", + "0xaf93185677d39e94a2b5d08867b44be2ba0bb50642edca906066d80facde22df4e6a7a2bd8b2460a22bdf6a6e59c5fdd", + "0x90f0ef0d7e7ab878170a196da1b8523488d33e0fde7481f6351558b312d00fa2b6b725b38539063f035d2a56a0f5e8f1", + "0xa9ca028ccb373f9886574c2d0ea5184bc5b94d519aa07978a4814d649e1b6c93168f77ae9c6aa3872dd0eea17968ec22", + "0x82e7aa6e2b322f9f9c180af585b9213fb9d3ad153281f456a02056f2d31b20d0f1e8807ff0c85e71e7baca8283695403", + "0xaffce186f842c547e9db2dffc0f3567b175be754891f616214e8c341213cbf7345c9ecd2f704bb0f4b6eba8845c8d8a7", + "0xab119eb621fade27536e98c6d1bc596388bb8f5cad65194ea75c893edbe6b4d860006160f1a9053aea2946bd663e5653", + "0x99cd2c1c38ead1676657059dc9b43d104e8bd00ae548600d5fc5094a4d875d5b2c529fac4af601a262045e1af3892b5e", + "0xb531a43b0714cc638123487ef2f03dfb5272ff399ff1aa67e8bc6a307130d996910fb27075cbe53050c0f2902fc32ffe", + "0x923b59ac752c77d16b64a2d0a5f824e718460ef78d732b70c4c776fecc43718ecfaf35f11afbb544016232f445ecab66", + "0xa53439cd05e6e1633cdce4a14f01221efcd3f496ac1a38331365c3cadc30013e5a71600c097965927ee824b9983a79cb", + "0x8af976ffab688d2d3f9e537e2829323dda9abf7f805f973b7e0a01e25c88425b881466dee37b25fda4ea683a0e7b2c03", + "0x92e5f40230a9bfbb078fa965f58912abb753b236f6a5c28676fb35be9b7f525e25428160caeaf0e3645f2be01f1a6599", + "0x8c4e7b04e2f968be527feba16f98428508a157b7b4687399df87666a86583b4446a9f4b86358b153e1660bb80bd92e8b", + "0x97cd622d4d8e94dceb753c7a4d49ea7914f2eb7d70c9f56d1d9a6e5e5cc198a3e3e29809a1d07d563c67c1f8b8a5665a", + "0x967bfa8f411e98bec142c7e379c21f5561f6fd503aaf3af1a0699db04c716c2795d1cb909cccbcb917794916fdb849f1", + "0xb3c18a6caa5ca2be52dd500f083b02a4745e3bcaed47b6a000ce7149cee4ed7a78d2d7012bf3731b1c15c6f04cbd0bd1", + "0xb3f651f1f84026f1936872956a88f39fcfe3e5a767233349123f52af160f6c59f2c908c2b5691255561f0e70620c8998", + "0xae23b59dc2d81cec2aebcaaf607d7d29cf588f0cbf7fa768c422be911985ca1f532bb39405f3653cc5bf0dcba4194298", + "0xa1f4da396f2eec8a9b3252ea0e2d4ca205f7e003695621ae5571f62f5708d51ca3494ac09c824fca4f4d287a18beea9a", + "0xa036fa15e929abed7aac95aa2718e9f912f31e3defd224e5ed379bf6e1b43a3ad75b4b41208c43d7b2c55e8a6fedca72", + "0x80e8372d8a2979ee90afbdb842624ace72ab3803542365a9d1a778219d47f6b01531185f5a573db72213ab69e3ffa318", + "0xaf68b5cdc39e5c4587e491b2e858a728d79ae7e5817a93b1ea39d34aec23dea452687046c8feae4714def4d0ed71da16", + "0xb36658dfb756e7e9eec175918d3fe1f45b398679f296119cd53be6c6792d765ef5c7d5afadc5f3886e3f165042f4667f", + "0xad831da03b759716f51099d7c046c1a8e7bf8bb45a52d2f2bfd769e171c8c6871741ef8474f06e2aca6d2b141cf2971f", + "0x8bae1202dde053c2f59efc1b05cb8268ba9876e4bd3ff1140fa0cc5fa290b13529aede965f5efdff3f72e1a579efc9cc", + "0x86344afbc9fe077021558e43d2a032fcc83b328f72948dba1a074bb1058e8a8faec85b1c019fc9836f0d11d2585d69c8", + "0x831d1fc7aa28f069585d84c46bdc030d6cb12440cfaae28098365577fc911c4b8f566d88f80f3a3381be2ec8088bf119", + "0x899de139797ac1c8f0135f0656f04ad4f9b0fa2c83a264d320eb855a3c0b9a4907fc3dc01521d33c07b5531e6a997064", + "0x855bc752146d3e5b8ba7f382b198d7dc65321b93cdfc76250eabc28dba5bbf0ad1be8ccda1adf2024125107cb52c6a6e", + "0xaf0aeccab48eb35f8986cabf07253c5b876dd103933e1eee0d99dc0105936236b2a6c413228490ed3db4fa69aab51a80", + "0xae62e9d706fbf535319c909855909b3deba3e06eaf560803fa37bce3b5aab5ea6329f7609fea84298b9da48977c00c3b", + "0x823a8d222e8282d653082d55a9508d9eaf9703ce54d0ab7e2b3c661af745a8b6571647ec5bd3809ae6dddae96a220ea7", + "0xa4c87e0ea142fc287092bc994e013c85e884bc7c2dde771df30ca887a07f955325c387b548de3caa9efa97106da8176a", + "0xb55d925e2f614f2495651502cf4c3f17f055041fa305bb20195146d896b7b542b1e45d37fa709ca4bfc6b0d49756af92", + "0xb0ebe8947f8c68dc381d7bd460995340efcbb4a2b89f17077f5fde3a9e76aef4a9a430d1f85b2274993afc0f17fdbead", + "0x8baaa640d654e2652808afd68772f6489df7cad37b7455b9cd9456bdddae80555a3f84b68906cc04185b8462273dcfc9", + "0xadd9aa08f827e7dc292ac80e374c593cd40ac5e34ad4391708b3db2fe89550f293181ea11b5c0a341b5e3f7813512739", + "0x909e31846576c6bdd2c162f0f29eea819b6125098452caad42451491a7cde9fd257689858f815131194200bca54511f4", + "0xabc4b34098db10d71ce7297658ef03edfa7377bd7ed36b2ffbab437f8fd47a60e2bcfbc93ff74c85cfce74ca9f93106c", + "0x857dbecc5879c1b952f847139484ef207cecf80a3d879849080758ef7ac96acfe16a11afffb42daf160dc4b324279d9b", + "0xaab0b49beecbcf3af7c08fbf38a6601c21061bed7c8875d6e3c2b557ecb47fd93e2114a3b09b522a114562467fcd2f7d", + "0x94306dec35e7b93d43ed7f89468b15d3ce7d7723f5179cacc8781f0cf500f66f8c9f4e196607fd14d56257d7df7bf332", + "0x9201784d571da4a96ef5b8764f776a0b86615500d74ec72bc89e49d1e63a3763b867deca07964e2f3914e576e2ca0ded", + "0xaabe1260a638112f4280d3bdea3c84ce3c158b81266d5df480be02942cecf3de1ac1284b9964c93d2db33f3555373dcc", + "0x8ef28607ca2e0075aa07de9af5a0f2d0a97f554897cab8827dfe3623a5e9d007d92755d114b7c390d29e988b40466db9", + "0x87a9b1b097c3a7b5055cd9cb0c35ba6251c50e21c74f6a0bca1e87e6463efc38385d3acc9d839b4698dfa2eb4cb7a2ef", + "0xaee277e90d2ffce9c090295c575e7cd3bafc214d1b5794dd145e6d02d987a015cb807bd89fd6268cd4c59350e7907ee2", + "0x836ad3c9324eaa5e022e9835ff1418c8644a8f4cd8e4378bd4b7be5632b616bb6f6c53399752b96d77472f99ece123cd", + "0x8ffffdb67faa5f56887c834f9d489bb5b4dab613b72eac8abf7e4bcb799ccd0dbd88a2e73077cadf7e761cb159fb5ec5", + "0x9158f6cd4f5e88e6cdb700fddcbc5a99b2d31a7a1b37dce704bd9dd3385cca69607a615483350a2b1153345526c8e05d", + "0xa7ff0958e9f0ccff76742fc6b60d2dd91c552e408c84172c3a736f64acb133633540b2b7f33bc7970220b35ce787cd4e", + "0x8f196938892e2a79f23403e1b1fb4687a62e3a951f69a7874ec0081909eb4627973a7a983f741c65438aff004f03ba6f", + "0x97e3c1981c5cdb0a388f1e4d50b9b5b5f3b86d83417831c27b143698b432bb5dba3f2e590d6d211931ed0f3d80780e77", + "0x903a53430b87a7280d37816946245db03a49e38a789f866fe00469b7613ee7a22d455fb271d42825957282c8a4e159d9", + "0xb78955f686254c3994f610e49f1c089717f5fb030da4f9b66e9a7f82d72381ba77e230764ab593335ff29a1874848a09", + "0x938b6d04356b9d7c8c56be93b0049d0d0c61745af7790edf4ef04e64de2b4740b038069c95be5c91a0ba6a1bb38512a9", + "0xa769073b9648fe21bc66893a9ef3b8848d06f4068805a43f1c180fdd0d37c176b4546f8e5e450f7b09223c2f735b006f", + "0x863c30ebe92427cdd7e72d758f2c645ab422e51ecef6c402eb1a073fd7f715017cd58a2ad1afe7edccdf4ff01309e306", + "0xa617b0213d161964eccfc68a7ad00a3ee4365223b479576e887c41ef658f846f69edf928bd8da8785b6e9887031f6a57", + "0xa699834bf3b20d345082f13f360c5f8a86499e498e459b9e65b5a56ae8a65a9fcb5c1f93c949391b4795ef214c952e08", + "0x9921f1da00130f22e38908dd2e44c5f662ead6c4526ebb50011bc2f2819e8e3fca64c9428b5106fa8924db76b7651f35", + "0x98da928be52eb5b0287912fd1c648f8bbda00f5fd0289baf161b5a7dbda685db6ad6bdc121bc9ffa7ed6ae03a13dbee3", + "0x927b91d95676ff3c99de1312c20f19251e21878bfb47ad9f19c9791bc7fb9d6f5c03e3e61575c0760180d3445be86125", + "0xb8e4977a892100635310dfcb46d8b74931ac59ae687b06469b3cee060888a3b6b52d89de54e173d9e1641234754b32b1", + "0x98f6fd5f81ca6e2184abd7a3a59b764d4953d408cec155b4e5cf87cd1f6245d8bdd58b52e1e024e22903e85ae15273f1", + "0x909aaacbbfe30950cf7587faa190dc36c05e3c8131749cc21a0c92dc4afc4002275762ca7f66f91aa751b630ad3e324d", + "0x91712141592758f0e43398c075aaa7180f245189e5308e6605a6305d01886d2b22d144976b30460d8ce17312bb819e8f", + "0x947d85cb299b189f9116431f1c5449f0f8c3f1a70061aa9ebf962aa159ab76ee2e39b4706365d44a5dbf43120a0ac255", + "0xb39eced3e9a2e293e04d236976e7ee11e2471fe59b43e7b6dd32ab74f51a3d372afee70be1d90af017452ec635574e0e", + "0x8a4ba456491911fc17e1cadcbb3020500587c5b42cf6b538d1cb907f04c65c168add71275fbf21d3875e731404f3f529", + "0x8f6858752363e2a94c295e0448078e9144bf033ccd4d74f4f6b95d582f3a7638b6d3f921e2d89fcd6afd878b12977a9d", + "0xb7f349aa3e8feb844a56a42f82b6b00f2bfe42cab19f5a68579a6e8a57f5cf93e3cdb56cbbb9163ab4d6b599d6c0f6aa", + "0xa4a24dc618a6b4a0857fb96338ac3e10b19336efc26986e801434c8fdde42ca8777420722f45dfe7b67b9ed9d7ce8fb1", + "0xaafe4d415f939e0730512fc2e61e37d65c32e435991fb95fb73017493014e3f8278cd0d213379d2330b06902f21fe4e1", + "0x845cc6f0f0a41cc6a010d5cb938c0ef8183ff5ed623b70f7ea65a8bdbc7b512ea33c0ee8b8f31fdf5f39ec88953f0c1e", + "0x811173b4dd89d761c0bdffe224cd664ef303c4647e6cf5ef0ed665d843ed556b04882c2a4adfc77709e40af1cfdea40b", + "0x93ba1db7c20bfba22da123b6813cb38c12933b680902cef3037f01f03ab003f76260acc12e01e364c0d0cf8d45fca694", + "0xb41694db978b2cf0f4d2aa06fcfc4182d65fb7c9b5e909650705f779b28e47672c47707d0e5308cd680c5746c37e1bc7", + "0xa0e92c4c5be56a4ccf1f94d289e453a5f80e172fc90786e5b03c1c14ce2f3c392c349f76e48a7df02c8ae535326ea8fe", + "0x96cbeb1d0693f4f0b0b71ad30def5ccc7ad9ebe58dbe9d3b077f2ac16256cde10468875e4866d63e88ce82751aaf8ef6", + "0x935b87fd336f0bf366046e10f7c2f7c2a2148fa6f53af5607ad66f91f850894527ecec7d23d81118d3b2ee23351ed6ed", + "0xb7c2c1fa6295735f6b31510777b597bc8a7bfb014e71b4d1b5859be0d8d64f62a1587caafc669dfe865b365eb27bd94f", + "0xb25d93af43d8704ffd53b1e5c16953fd45e57a9a4b7acfcfa6dd4bf30ee2a8e98d2a76f3c8eba8dc7d08d9012b9694c6", + "0xb5a005cd9f891e33882f5884f6662479d5190b7e2aec1aa5a6d15a8cb60c9c983d1e7928e25e4cf43ec804eaea1d97b0", + "0x93f9f0725a06e4a0fb83892102b7375cf5438b5ebc9e7be5a655f3478d18706cf7dbb1cd1adcee7444c575516378aa1b", + "0x900d7cbf43fd6ac64961287fe593c08446874bfc1eb09231fc93de858ac7a8bca496c9c457bced5881f7bf245b6789e0", + "0x90c198526b8b265d75160ef3ed787988e7632d5f3330e8c322b8faf2ac51eef6f0ce5a45f3b3a890b90aecf1244a3436", + "0xb499707399009f9fe7617d8e73939cb1560037ad59ac9f343041201d7cc25379df250219fd73fa012b9ade0b04e92efa", + "0x94415f6c3a0705a9be6a414be19d478181d82752b9af760dda0dbd24a8ff0f873c4d89e61ad2c13ebf01de55892d07fa", + "0x90a9f0b9f1edb87751c696d390e5f253586aae6ebfc31eb3b2125d23877a497b4aa778de8b11ec85efe49969021eaa5a", + "0xa9942c56506e5cd8f9289be8205823b403a2ea233ba211cf72c2b3827064fd34cd9b61ff698a4158e7379891ca4120d8", + "0x83bb2ee8c07be1ab3a488ec06b0c85e10b83a531758a2a6741c17a3ccfa6774b34336926a50e11c8543d30b56a6ac570", + "0x8a08a3e5ebe10353e0b7fff5f887e7e25d09bb65becf7c74a03c60c166132efaada27e5aea242c8b9f43b472561ae3ed", + "0x957c7a24cefaa631fe8a28446bc44b09a3d8274591ade53ba489757b854db54820d98df47c8a0fbee0e094f8ad7a5dc4", + "0xb63556e1f47ed3ee283777ed46b69be8585d5930960d973f8a5a43508fc56000009605662224daec2de54ea52a8dcd82", + "0xabed2b3d16641f0f459113b105f884886d171519b1229758f846a488c7a474a718857323c3e239faa222c1ab24513766", + "0x882d36eed6756d86335de2f7b13d753f91c0a4d42ef50e30195cc3e5e4f1441afa5ff863022434acb66854eda5de8715", + "0xa65ea7f8745bb8a623b44e43f19158fd96e7d6b0a5406290f2c1348fc8674fbfc27beb4f724cc2b217c6042cb82bc178", + "0xa038116a0c76af090a069ca289eb2c3a615b96093efacfe68ea1610890b291a274e26b445d34f414cfec00c333906148", + "0x90294f452f8b80b0a47c3bcb6e30bdd6854e3b01deaf93f5e82a1889a4a1036d17ecb59b48efa7dc41412168d7a523dd", + "0x88faf969c8978a756f48c6114f7f33a1ca3fd7b5865c688aa9cd32578b1f7ba7c06120502f8dc9aee174ecd41597f055", + "0x8883763b2762dfff0d9be9ac19428d9fd00357ac8b805efda213993152b9b7eb7ba3b1b2623015d60778bffda07a724d", + "0xa30a1a5a9213636aa9b0f8623345dc7cf5c563b906e11cc4feb97d530a1480f23211073dcb81105b55193dcde5a381d2", + "0xb45ee93c58139a5f6be82572d6e14e937ef9fcbb6154a2d77cb4bf2e4b63c5aabc3277527ecf4e531fe3c58f521cc5e3", + "0xac5a73e4f686978e06131a333f089932adda6c7614217fcaf0e9423b96e16fd73e913e5e40bf8d7800bed4318b48d4b1", + "0xb6c1e6cdd14a48a7fe27cd370d2e3f7a52a91f3e8d80fb405f142391479f6c6f31aa5c59a4a0fdc9e88247c42688e0cf", + "0xab1760530312380152d05c650826a16c26223960fc8e3bf813161d129c01bac77583eff04ce8678ff52987a69886526b", + "0xa4252dffae7429d4f81dfaeeecc48ab922e60d6a50986cf063964f282e47407b7e9c64cf819da6f93735de000a70f0b2", + "0x94c19f96d5ecf4a15c9c5a24598802d2d21acbbd9ee8780b1bc234b794b8442437c36badc0a24e8d2cff410e892bb1d2", + "0x89fafe1799cf7b48a9ea24f707d912fccb99a8700d7287c6438a8879f3a3ca3e60a0f66640e31744722624139ba30396", + "0xb0108405df25cf421c2f1873b20b28552f4d5d1b4a0bf1c202307673927931cbd59f5781e6b8748ddb1206a5ec332c0b", + "0xaa0f0e7d09f12b48f1e44d55ec3904aa5707e263774126e0b30f912e2f83df9eb933ca073752e6b86876adaf822d14ba", + "0xb0cbe8abb58876d055c8150d9fdbde4fea881a517a2499e7c2ea4d55c518a3c2d00b3494f6a8fd1a660bfca102f86d2a", + "0xb1ef80ec903bac55f58b75933dc00f1751060690fd9dfb54cf448a7a4b779c2a80391f5fda65609274bd9e0d83f36141", + "0x8b52e05b1845498c4879bb12816097be7fc268ce1cf747f83a479c8e08a44159fc7b244cf24d55aca06dccf0b97d11e1", + "0xb632a2fc4fdb178687e983a2876ae23587fd5b7b5e0bb8c0eb4cfe6d921a2c99894762e2aaccdc5da6c48da3c3c72f6c", + "0x953ef80ab5f74274ae70667e41363ae6e2e98ccbd6b7d21f7283f0c1cafb120338b7a8b64e7c189d935a4e5b87651587", + "0xb929cfd311017c9731eed9d08d073f6cf7e9d4cd560cddd3fdcb1149ab20c6610a7674a66a3616785b13500f8f43ee86", + "0x870fb0d02704b6a328e68721fb6a4b0f8647681bfcb0d92ec3e241e94b7a53aecc365ed384e721c747b13fbf251002f1", + "0x979501159833a8ba5422ed9b86f87b5961711f5b474d8b0e891373fe2d0b98ff41a3a7a74a8b154615bb412b662a48be", + "0xb20f9c13cdeceef67f877b3878839ef425f645b16a69c785fe38f687c87a03b9de9ae31ac2edb1e1dd3a9f2c0f09d35d", + "0x8c7705ed93290731b1cf6f3bf87fc4d7159bb2c039d1a9f2246cda462d9cdf2beef62d9f658cfeea2e6aef7869a6fc00", + "0xaa439eb15705ad729b9163daee2598d98a32a8a412777c0d12fd48dc7796d422227a014705e445cc9d66f115c96bbc24", + "0xa32307e16f89749fe98b5df1effef0429801c067e0d8067794e56b01c4fef742ad5e7ab42a1a4cc4741808f47a0b7cb8", + "0xb31e65c549003c1207258a2912a72f5bad9844e18f16b0773ea7af8ff124390eb33b2f715910fc156c104572d4866b91", + "0x85608d918ed7b08a0dc03aee60ea5589713304d85eee7b4c8c762b6b34c9355d9d2e192575af0fd523318ae36e19ae1c", + "0xa6497dbaf0e7035160b7a787150971b19cf5ba272c235b0113542288611ebecefa2b22f08008d3f17db6a70a542c258d", + "0x87862adb1ac0510614ab909457c49f9ec86dc8bdf0e4682f76d2739df11f6ffcfb59975527f279e890d22964a1fba9b6", + "0x8717ac3b483b3094c3b642f3fafe4fbafc52a5d4f2f5d43c29d9cfe02a569daee34c178ee081144494f3a2ca6e67d7b1", + "0x855100ac1ec85c8b437fdd844abaa0ca4ac9830a5bdd065b68dafb37046fcf8625dd482dc0253476926e80a4c438c9ec", + "0xae74821bf265ca3c8702c557cf9ef0732ede7ef6ed658283af669d19c6f6b6055aca807cf2fa1a64785ec91c42b18ae5", + "0x812a745b1419a306f7f20429103d6813cbdea68f82ff635ac59da08630cd61bda6e0fa9a3735bfd4378f58ad179c1332", + "0x867dbbfe0d698f89451c37ca6d0585fd71ee07c3817e362ef6779b7b1d70b27c989cdd5f85ac33a0498db1c4d14521fe", + "0x84db735d3eb4ff7f16502dccc3b604338c3a4a301220ad495991d6f507659db4b9f81bba9c528c5a6114bcdba0160252", + "0xaadc83d1c4e5e32bf786cfb26f2f12a78c8024f1f5271427b086370cdef7a71d8a5bf7cd7690bae40df56c38b1ad2411", + "0xa27860eb0caaea37298095507f54f7729d8930ac1929de3b7a968df9737f4c6da3173bda9d64ff797ed4c6f3a1718092", + "0xa3cdcaa74235c0440a34171506ed03d1f72b150d55904ce60ec7b90fcd9a6f46f0e45feab0f9166708b533836686d909", + "0xb209a30bdac5c62e95924928f9d0d0b4113ebb8b346d7f3a572c024821af7f036222a3bd38bd8efd2ee1dbf9ac9556cd", + "0x83c93987eff8bc56506e7275b6bef0946672621ded641d09b28266657db08f75846dcbde80d8abc9470e1b24db4ca65b", + "0x800c09b3ee5d0251bdaef4a82a7fe8173de997cc1603a2e8df020dd688a0c368ad1ebef016b35136db63e774b266c74c", + "0x93fb52de00d9f799a9bce3e3e31aaf49e0a4fc865473feb728217bd70f1bc8a732ec37ac3582bf30ab60e8c7fdf3cb8d", + "0xa1aff6b4a50d02f079a8895c74443539231bfdf474600910febf52c9151da7b31127242334ac63f3093e83a047769146", + "0x8c4532d8e3abb5f0da851138bfa97599039bcd240d87bbdf4fd6553b2329abb4781074b63caf09bc724ceb4d36cb3952", + "0x8bd9b0ae3da5acda9eb3881172d308b03beec55014cd73b15026299541c42fd38bab4983a85c06894ebb7a2af2a23d4c", + "0x979441e7f5a0e6006812f21b0d236c5f505bb30f7d023cb4eb84ec2aa54a33ac91d87ece704b8069259d237f40901356", + "0xa1c6d2d82e89957d6a3e9fef48deb112eb00519732d66d55aa0f8161e19a01e83b9f7c42ac2b94f337dcc9865f0da837", + "0x97a0b8e04e889d18947d5bf77d06c25bbd62b19ce4be36aaa90ddbeafd93a07353308194199ba138efaadf1b928cd8d2", + "0x822f7fbe9d966b8ec3db0fc8169ab39334e91bf027e35b8cc7e1fe3ead894d8982505c092f15ddfe5d8f726b360ac058", + "0xa6e517eedd216949e3a10bf12c8c8ddbfde43cddcd2c0950565360a38444459191bdbc6c0af0e2e6e98bc6a813601c6d", + "0x858b5f15c46c074adb879b6ba5520966549420cb58721273119f1f8bc335605aeb4aa6dbe64aae9e573ca7cc1c705cdc", + "0xb5191bb105b60deb10466d8114d48fb95c4d72036164dd35939976e41406dff3ee3974c49f00391abfad51b695b3258c", + "0xb1b375353ed33c734f4a366d4afad77168c4809aff1b972a078fd2257036fd6b7a7edad569533abf71bc141144a14d62", + "0xa94c502a9cdd38c0a0e0187de1637178ad4fa0763887f97cc5bdd55cb6a840cb68a60d7dbb7e4e0e51231f7d92addcff", + "0x8fe2082c1b410486a3e24481ae0630f28eb5b488e0bb2546af3492a3d9318c0d4c52db1407e8b9b1d1f23a7ffbaf260a", + "0xb73fe7aa2b73f9cae6001af589bf8a9e73ea2bb3bb01b46743e39390c08d8e1be5e85a3d562857a9c9b802b780c78e6d", + "0x8e347f51330ae62275441ccd60f5ac14e1a925a54ced8a51893d956acc26914df1bb8595385d240aa9b0e5ada7b520ea", + "0x8dc573d6357c0113b026a0191a5807dbe42dcd2e19772d14b2ca735e1e67c70e319ef571db1f2a20e62254ed7fb5bcd6", + "0xa5dacbe51549fe412e64af100b8b5eba5ec2258cc2a7c27a34bc10177d1894baf8707886d2f2ef438f077596a07681e9", + "0x8349153c64961d637a5ff56f49003cb24106de19a5bbcf674016a466bfbe0877f5d1e74ccb7c2920665ef90a437b1b7e", + "0x96ad35429d40a262fdc8f34b379f2e05a411057d7852c3d77b9c6c01359421c71ef8620f23854e0f5d231a1d037e3a0d", + "0xb52385e40af0ed16e31c2154d73d1517e10a01435489fc801fbea65b92b3866ab46dab38d2c25e5fb603b029ae727317", + "0x8e801c7a3e8fa91d9c22ebd3e14a999023a7b5beea13ec0456f7845425d28c92452922ca35ec64012276acb3bbc93515", + "0xa8630870297d415e9b709c7f42aa4a32210b602f03a3015410123f0988aea2688d8bcfc6d07dc3602884abbf6199b23f", + "0x8cd518392e09df2a3771a736f72c05af60efc030d62dbbb9cd68dc6cbbe1fb0854eb78b6ed38337010eb1bb44a5d5d30", + "0x921aa4c66590f6c54bf2fa2b324f08cbe866329cc31f6e3477f97f73e1a1721d5eb50ed4eacc38051fe9eda76ba17632", + "0xa37e595cb63524cb033c5540b6343c3a292569fc115e813979f63fe1a3c384b554cecc2cae76b510b640fe3a18800c81", + "0xb0bb57e4e31ae3ce9f28cef158ed52dabfad5aa612f5fcc75b3f7f344b7cec56b989b5690dacd294e49c922d550ee36b", + "0xa3c618ce4d091e768c7295d37e3f9b11c44c37507ae1f89867441f564bf0108f67bf64b4cf45d73c2afc17a4dc8b2c68", + "0x999e6650eda5455e474c22a8c7a3fd5b547ec2875dc3043077ad70c332f1ccd02135e7b524fcbf3621d386dec9e614fa", + "0xb018f080888dec3c2ca7fcfeb0d3d9984699b8435d8823079fc9e1af4ca44e257fbe8da2f6f641ee6152b5c7110e3e3c", + "0xa2bcd4bcd9b40c341e9bba76b86481842f408166c9a7159205726f0776dcb7f15a033079e7589699e9e94ce24b2a77fd", + "0xb03de48f024a520bb9c54985ca356fd087ca35ac1dd6e95168694d9dae653138c9755e18d5981946a080e32004e238fe", + "0xa6c1a54973c0c32a410092441e20594aa9aa3700513ed90c8854956e98894552944b0b7ee9edf6e62e487dc4565baa2f", + "0x845d7abf577c27c4c1fafc955dcad99a1f2b84b2c978cfe4bd3cd2a6185979491f3f3b0ec693818739ed9184aba52654", + "0x9531bcfc0d3fcd4d7459484d15607d6e6181cee440ba6344b12a21daa62ff1153a4e9a0b5c3c33d373a0a56a7ad18025", + "0xa0bbf49b2dd581be423a23e8939528ceaae7fb8c04b362066fe7d754ca2546304a2a90e6ac25cdf6396bf0096fae9781", + "0xa1ec264c352e34ed2bf49681b4e294ffea7d763846be62b96b234d9a28905cdece4be310a56ec6a00fc0361d615b547c", + "0x87c575e85b5dfbfd215432cb355a86f69256fff5318e8fda457763ac513b53baa90499dc37574bdfad96b117f71cb45e", + "0x9972edfdeec56897bef4123385ee643a1b9dc24e522752b5a197ce6bd2e53d4b6b782b9d529ca50592ee65b60e4c9c3c", + "0xb8bcf8d4ab6ad37bdd6ad9913a1ba0aba160cb83d1d6f33a8524064a27ba74a33984cc64beeee9d834393c2636ff831a", + "0x83082b7ec5b224422d0ff036fbb89dc68918e6fde4077dfc0b8e2ee02595195ecadb60c9ab0ad69deb1bac9be75024fa", + "0x8b061fce6df6a0e5c486fd8d8809f6f3c93bd3378a537ff844970492384fb769d3845d0805edd7f0fcd19efabf32f197", + "0xb9597e717bb53e6afae2278dbc45d98959c7a10c87c1001ed317414803b5f707f3c559be6784119d08f0c06547ec60b1", + "0xb9d990fd7677dd80300714cfd09336e7748bbf26f4bb0597406fcb756d8828c33695743d7a3e3bd6ddf4f508149610ef", + "0xb45f7d2b00ceea3bf6131b230b5b401e13a6c63ba8d583a4795701226bf9eb5c88506f4a93219ac90ccbceef0bfd9d49", + "0xa8ccaa13ca7986bc34e4a4f5e477b11ae91abb45c8f8bf44a1f5e839289681495aba3daa8fb987e321d439bbf00be789", + "0xae0f59f7a94288a0ead9a398fdd088c2f16cccb68624de4e77b70616a17ddf7406ca9dc88769dadeb5673ff9346d6006", + "0xb28e965dcc08c07112ae3817e98f8d8b103a279ad7e1b7c3de59d9dbd14ab5a3e3266775a5b8bbf0868a14ae4ab110f1", + "0x84751c1a945a6db3df997fcbde9d4fe824bc7ba51aa6cb572bb5a8f9561bef144c952198a783b0b5e06f9dd8aa421be8", + "0xa83586db6d90ef7b4fa1cbda1de1df68ee0019f9328aded59b884329b616d888f300abb90e4964021334d6afdea058fd", + "0x8fcea1ce0abf212a56c145f0b8d47376730611e012b443b3d1563498299f55cbcbe8cbd02f10b78224818bb8cbbd9aaa", + "0x8d66c30a40c34f23bae0ea0999754d19c0eb84c6c0aa1b2cf7b0740a96f55dd44b8fee82b625e2dd6c3182c021340ac6", + "0x92c9b35076e2998f1a0f720d5a507a602bd6bd9d44ffc29ede964044b17c710d24ce3c0b4a53c12195de93278f9ec83b", + "0xa37d213913aff0b792ee93da5d7e876f211e10a027883326d582ad7c41deebdfce52f86b57d07868918585908ebd070a", + "0xa03995b4c6863f80dd02ed0169b4f1609dc48174ec736de78be1cdff386648426d031f6d81d1d2a7f2c683b31e7628c0", + "0xb08b628d481302aa68daf0fa31fd909064380d62d8ed23a49037cb38569058e4c16c80e600e84828d37a89a33c323d1f", + "0xa0ee2e2dd8e27661d7b607c61ac36f590909aa97f80bdfd5b42463ca147b610ac31a9f173cbecdd2260f0f9ea9e56033", + "0x967162fba8b69ffce9679aac49214debb691c6d9f604effd6493ce551abacbe4c8cc2b0ccee6c9927c3d3cfbdcb0be11", + "0x8deab0c5ed531ce99dadb98b8d37b3ff017f07438bc6d50840577f0f3b56be3e801181333b4e8a070135f9d82872b7f2", + "0xb1bfa00ec8c9365b3d5b4d77a718cb3a66ed6b6cf1f5cf5c5565d3aa20f63d3c06bb13d47d2524e159debf81325ba623", + "0x90109780e53aeacd540b9fe9fc9b88e83c73eaf3507e2b76edc67f97a656c06a8a9e1ec5bce58bfd98b59a6b9f81b89d", + "0x88a1009a39a40421fdcc0ffc3c78a4fbace96a4e53420b111218091223494e780a998ebecf5a0abd0243e1523df90b28", + "0x90b77146711ee8d91b0346de40eca2823f4e4671a12dad486a8ec104c01ef5ee7ab9bd0398f35b02b8cb62917455f8b3", + "0xb262c5e25f24ae7e0e321b66fdb73b3bf562ded566a2d6a0152cf8bafb56138d87b6a917a82f5ace65efc73cfc177d81", + "0xae65a438c7ea46c82925b5ec5f71314558ca5146f5d90311431d363cfeac0537223c02cbb50fa6535d72fc2d949f4482", + "0x8984208bfc193a6ef4720cc9d40c17f4be2f14595ef887980f2e61fa6927f9d73c00220937013b46290963116cbe66ac", + "0xa8f33a580508f667fac866456dce5d9246562188ad0f568eb1a2f28cf9fd3452dd20dc613adb1d07a5542319a37ecf1a", + "0xaedadd705fc086d8d2b647c62e209e2d499624ab37c8b19af80229f85e64a6e608d9cd414cb95ae38cf147d80ec3f894", + "0xae28077a235cd959f37dc3daedc3706f7a7c2ffe324e695f2e65f454bf5a9fc27b10149a6268ebfaa961ad67bb9b75d7", + "0xa234c7f5a5e0e30f2026d62657bd92d91a9907ec6a2177f91383f86abb919778121ff78afb8f52c473fe6fb731018b52", + "0x816a2ea7826b778f559a815267b6c6eb588558391c0a675d61bb19470d87489ba6c1e2486ea81dd5420a42ee7c35a8de", + "0x9218b61948c14234f549c438105ae98367ef6b727ad185f17ad69a6965c044bb857c585b84d72ef4c5fb46962974eed7", + "0xa628031217a0b1330b497351758cf72d90fb87d8bdf542ea32092e14ff32d5ef4ca700653794bb78514d4b0edfd7a8d7", + "0xab4e977141be639a78eb9ed17366f9642f9335873aca87cce2bae0dddc161621d0e23264a54a7395ae706d748c690ee9", + "0xb1538c4edff59bcf5668557d994bac77d508c757e382512c4368c1ded4242a41f6200b73fe8809fb528a7a0c1fc96feb", + "0x965caabe5590e2ff8c9f1048bbdda2817e7a2847e287944bfab40d94cb48389441ac42ff3a7b559760bfab42ff82e1e0", + "0xa64b7484d22c4b8047c7a8ef54dc88cb8d110c61ef28ba853821b61e87d318b2b4226f7f0d1f3cdf086a0e1666d0212c", + "0x8915ab7e41d974eef9a651b01c2521392e8899e6ab91c22aeee61605c78fb2b052399ba1d03473aa9cfb52d1a8ba4257", + "0x8dd26875d4a1716db2f75a621d01e971983267770e2da92399aecf08f74af1f7e73643ac6f0a9b610eda54e5460f70ed", + "0x83dabcb84c9cbce67e1a24ecbfa4473766b9519588b22288edbaa29aca34cefd9884f7310e7771f8f7a7cbced2e7eea0", + "0x956be00c67987fb4971afca261065a7f6fcef9fb6b1fcb1939f664bbc5b704223253ebfda48565624a68fb249742c2cf", + "0xa374824a24db1ab298bee759cee8d8260e0ac92cd1c196f896600fd57484a9f9be1912ded01203976ac4fab66c0e5091", + "0xa225f2ed0de4e06c500876e68e0c58be49535885378584a1442aae2140c38d3ca35c1bc41936a3baf8a78e7ab516f790", + "0x8e79c8de591a6c70e2ef2de35971888ab0ca6fd926fdb6e845fb4b63eb3831c5839f084201b951984f6d66a214b946b8", + "0x91babc849a9e67ab40192342c3d0d6ce58798101cb85c9bd7fc0ac4509ffc17b5ea19e58045cf1ca09ec0dee0e18c8f9", + "0x8b4897fc2aef5bbe0fa3c3015ca09fc9414fdb2315f54dbecc03b9ae3099be6c0767b636b007a804d8b248c56e670713", + "0x8f63ba42e7459ea191a8ad18de0b90b151d5acbf4751e2c790e7d8328e82c20de518132d6290ff3c23d2601f21c1558e", + "0xa1a035dc9b936587a16665ea25646d0bb2322f81960d9b6468c3234c9137f7c2b1e4f0b9dbe59e290a418007b0e7a138", + "0x81c4904c08f7bb2ac7b6d4ac4577f10dd98c318f35aac92fc31bab05eceb80a0556a7fc82614b8d95357af8a9c85a829", + "0x8c40e44e5e8e65f61e0a01f79057e1cb29966cc5074de790ea9c60454b25d7ea2b04c3e5decb9f27f02a7f3d3cb7014f", + "0xad8709e357094076eb1eb601539b7bcc37247a25fbc6ada5f74bb88b1b371917c2a733522190f076c44e9b8e2ae127fb", + "0x92d43cd82c943fd71b8700977244436c696df808c34d4633f0624700a3445f3ecc15b426c850f9fb60b9aa4708f2c7c0", + "0xb2cb8080697d1524a6dcb640b25e7255ae2e560613dbd27beaa8c5fc5c8d2524b7e6edd6db7ad0bb8a4e2e2735d4a6f7", + "0x971ca6393d9e312bfb5c33955f0325f34946d341ff7077151f0bcafd2e6cbd23e2ad62979454f107edc6a756a443e888", + "0xb6a563f42866afcee0df6c6c2961c800c851aa962d04543541a3cedeb3a6a2a608c1d8391cf405428cd40254e59138f3", + "0x986bd17bad9a8596f372a0185f7f9e0fb8de587cd078ae40f3cd1048305ba00954aff886b18d0d04640b718ea1f0d5a3", + "0xae32dbccfb7be8e9165f4e663b26f57c407f96750e0f3a5e8e27a7c0ca36bc89e925f64ddd116263be90ace4a27872c4", + "0x83725445ec8916c7c2dd46899241a03cf23568ac63ae2d34de3bce6d2db0bc1cfd00055d850b644a059fb26c62ed3585", + "0xa83f7e61c05b1c6797a36ad5ded01bf857a838147f088d33eb19a5f7652b88e55734e8e884d1d1103a50d4393dfcd7a8", + "0xaa010b4ec76260d88855347df9eaf036911d5d178302063d6fd7ecad009e353162177f92240fe5a239acd1704d188a9d", + "0xa88f4ba3cf4aff68ec1e3ded24622d4f1b9812350f6670d2909ea59928eb1d2e8d66935634d218aeac6d1a0fc6cae893", + "0xb819112b310b8372be40b2752c6f08426ef154b53ef2814ae7d67d58586d7023ffa29d6427a044a3b288e0c779866791", + "0xb5d1e728de5daf68e63b0bb1dee5275edae203e53614edeeeefff0f2f7ac4281191a33b7811de83b7f68111361ef42e1", + "0x953fb3ddc6f78045e53eaacfd83c5c769d32608b29391e05612e4e75725e54e82ad4960fbef96da8b2f35ba862968a3e", + "0x936471136fb2c1b3bb986a5207a225a8bf3b206a1a9db54dc3029e408e78c95bfb7539b67006d269c09df6354d7254ac", + "0xac353364b413cae799b13d7dc6fa09c322b47e60b9333e06499155e22d913929b92a45a0ad04ba90b29358f7b792d864", + "0xa0177419ead02ba3f0755a32eee3fd23ec81a13c01eab462f3b0af1e2dba42f81b47b2c8b1a90d8cec5a0afa371b7f11", + "0xb009eeb5db80d4244c130e6e3280af120917bb6fcebac73255c09f3f0c9da3b2aa718cd92d3d40e6b50737dbd23461aa", + "0xb8a43426c3746c1a5445535338c6a10b65474b684a2c81cd2f4b8ebecc91a57e2e0687df4a40add015cd12e351bbb3eb", + "0x94ff3698a6ac6e7df222675a00279c0ea42925dc6b748e3e74a62ea5d1e3fd70d5ab2d0c20b83704d389dd3a6063cf1a", + "0x90e4142e7ce15266144153e21b9893d3e14b3b4d980e5c87ce615ecd27efac87d86fa90354307857f75d7ebaeffe79ef", + "0xa5fd82c3f509ec9a36d72ba204a16f905e1e329f75cfd18aaa14fb00a212d21f3fac17e1a8e3bc5691ab0d07f8ec3cd0", + "0x962e6bfd75ea554f304a5fee1123e5bf2e048ccd3b401716b34c52740384579188ac98bc0d91269fc814de23f4b2dd34", + "0xb50b4e45c180badf9cd842cd769f78f963e077a9a4c016098dc19b18210580ad271ae1ba86de7760dd2e1f299c13f6a0", + "0x84cf08858d08eca6acc86158ffda3fbe920d1d5c04ac6f1fc677760e46e66599df697397373959acf319c31e47db115c", + "0xa697a38ba21caa66b7739ed0e74fe762a3da02144b67971fcad28c1132d7b83e0ac062cc71479f99e2219086d7d23374", + "0xad1f6d01dd7f0de814fe5fbb6f08c1190ff37f4a50754d7b6291fc547c0820506ea629aabacf749fec9c1bbfda22d2d0", + "0xb11fd7f8c120d8a370a223a1adc053a31bef7454b5522b848dec82de5482308fc68fdaf479875b7a4bc3fc94e1ea30eb", + "0x93ecf90ebfc190f30086bcaeee18cda972073a8469cf42a3b19f8c1ec5419dff2d6a5cc8ef412ccd9725b0f0a5f38f88", + "0x911f25aaa5260b56b3009fa5e1346a29f13a085cf8a61b36b2d851791f7bcf8456840eccbfc23797b63ecd312e2d5e12", + "0xa52f17a8b2db66c98291020b1db44ab23827e1790e418e078d1316185df6aa9f78292f43a12cd47131bd4b521d134060", + "0x9646fca10bf7401e91d9a49753c72f3ecb142f5ed13aba2c510a6c5ccb8d07b8e8d1581fc81321ad5e3996b6d81b5538", + "0xaa1da4a5665b91b62dda7f71bb19c8e3f6f49cc079d94fcd07b3604a74547e8334efa5a202822d0078158056bbda2822", + "0xa2432ae5feeaf38252c28aa491e92a68b47d5b4c6f44c1b3d7f3abc2f10b588f64a23c3357e742a0f5e4f216e7ca5827", + "0x83c7b47735cd0ef80658a387f34f259940096ebb9464c67919b278db4109fea294d09ea01a371b79b332cff6777c116d", + "0xa740a2959e86e413c62d6bdd1bc27efe9596ee363c2460535eab89ba1715e808b658bd9581b894b5d5997132b0c9c85c", + "0xb76947237fa9d71c3bece0b4f7119d7f94d2162d0ced52f2eac4de92b41da5b72ad332db9f31ebb2df1c02f400a76481", + "0xa20e1f2b7e9cc1443226d2b1a29696f627c83836116d64d2a5559d08b67e7e4efa9a849f5bb93a0dadb62450f5a9eaab", + "0xb44bff680fba52443a5b3bd25f69c5640006d544fca1d3dc11482ee8e03b4463aae59d1ec9d200aa6711ce72350580fb", + "0xa9490f5643bacec7e5adcda849ab3e7ff1f89026bf7597980b13a09887376f243158d0035e9d24fdee7cb6500e53ef29", + "0x96081010b82c04ad0bfc3605df622db27c10a91494685ef2e6e1839c218b91cbb56e043e9a25c7b18c5ddee7c6769517", + "0xa9522d59bcf887cbbbc130d8de3ff29a86df5d9343a918f5e52c65a28e4c33f6106ac4b48ecd849a33d39eeb2319d85b", + "0xaa5e0cea1a1db2283783788b4d77c09829563b75c503c154fdaa2247c9149918edac7737ef58c079e02dca7d8397b0eb", + "0x8c03f064e777d0c07c4f04c713a86bf581cc85155afe40e9065ead15139b47a50ead5c87ac032f01b142d63ff849758a", + "0xa34d672bf33def02ee7a63e6d6519676c052fa65ca91ed0fe5fdd785c231ba7af19f1e990fc33f5d1d17e75f6af270be", + "0x8680443393e8ac45a0b07c30a82ac18e67dcc8f20254bd5ede7bf99fc03e6123f2fcd64c0ca62f69d240f23acd777482", + "0xa4e00ab43d8ae5b13a6190f8ef5395ec17fbac4aa7dfa25b33e81b7e7bf63a4c28910b3a7dc9204dbc4168b08575a75e", + "0x8249259066ee5672b422c1889ab5ed620bddd1297f70b4197c40bb736afba05d513b91d3a82ee030336c311d952cd60c", + "0xa0651d8cf34fa971bde1ec037158a229e8e9ad4b5ca6c4a41adedb6d306a7772634f703dcfac36f9daf17289f33c23fb", + "0xb02ff6e8abff19969e265395ceaf465f43e7f1c3c9cfc91f1748042d9c352b284e49515a58078c877a37ff6915ee8bf4", + "0x927fb7351ac28254458a1a2ea7388e1fbd831fbc2feedb230818f73cc8c505b7ff61e150898ce1567fcb0d2c40881c7b", + "0xa9d3861f72090bc61382a81286bb71af93cdeefab9a83b3c59537ad21810104e0e054859eeafa13be10f8027b6fc33b8", + "0xa523306656730b1a31b9a370c45224b08baf45773d62952a0bf7d6c4684898ae78914cfafbd3e21406407cc39e12afdc", + "0x947a090e7703a3ea303a4a09b3ab6b6d3fda72912c9f42cc37627557028b4667f5398a6d64b9281fa2efbe16f6c61ed6", + "0xb41d24d40c10239c85d5b9bf1a3886d514a7a06b31ca982ea983e37162293350b12428eabc9f6a460473ad811e61ba40", + "0xb0bb9805724f4ca860e687985c0dc6b8f9017fe71147e5383cfbbbdcb2a42c93c7062ba42acdead9d992b6f48fc1d5ac", + "0xaec775aa97a78851893d3c5c209a91267f1daf4205bfb719c44a9ed2614d71854b95bb523cd04a7f818a4a70aa27d8fc", + "0xb53e52e32ca90b38987610585ad5b77ecd584bd22c55af7d7c9edf5fbcae9c9241b55200b51eaed0fbdb6f7be356368f", + "0xa2c5ac7822c2529f0201717b4922fb30fb037540ab222c97f0cdac341d09ccb1415e7908288fabef60177c0643ed21bf", + "0x92162fda0cbd1dafbed9419ae0837e470451403231ee086b49a21d20de2e3eed7ce64382153272b02cf099106688af70", + "0x8452d5df66682396718a76f219a9333a3559231e5f7f109a1f25c1970eb7c3408a5e32a479357f148af63b7a1d352451", + "0x831ea95d4feb520994bc4904017a557797e7ad455a431d94de03b873a57b24b127fcc9ff5b97c255c6c8d8e18c5c7e12", + "0x93d451d5e0885ccdbb113a267c31701e7c3d9e823d735dc9dfd6cfdcd82767012dc71396af53d3bedd2e0d9210acf57f", + "0xa2126f75a768dcc7ebddf2452aebf20ad790c844442b78e4027c0b511a054c27efb987550fcab877c46f2c7be4883ae0", + "0xaa4d2dcba2ccfc11a002639c30af6beb35e33745ecbab0627cf0f200fdae580e42d5a8569a9c971044405dfdafed4887", + "0xab13616069ef71d308e8bf6724e13737dc98b06a8f2d2631284429787d25d43c04b584793256ed358234e7cd9ad37d1f", + "0x9115ee0edc9f96a10edcafeb9771c74321106e7f74e48652df96e7ca5592a2f448659939291ff613dd41f42170b600ad", + "0x97b10a37243dc897ccc143da8c27e53ccc31f68220bffd344835729942bb5905ae16f71ccaed29ca189432d1c2cc09b1", + "0x875cf9c71ae29c3bde8cdcb9af5c7aca468fbb9243718f2b946e49314221a664959140c1ebc8622e4ed0ba81526302fd", + "0x86b193afbb7ff135ce5fc7eb0ee838a22e04806ceec7e02b3fb010e938fff733fc8e3a1d4b6cba970852d6307018b738", + "0xb3403a94f1483edce5d688e5ed4ab67933430ede39cd57e2cddb4b469479018757d37dd2687f7182b202967da12a6c16", + "0x83edfa0a6f77974c4047b03d7930e10251e939624afa2dcafbd35a9523c6bf684e1bb7915fc2e5b3ded3e6dc78daacf2", + "0x88ff3375fe33942e6d534f76ed0f1dfa35ae1d62c97c84e85f884da76092a83ecd08454096c83c3c67fac4cd966673d7", + "0xaf0726a2a92ee12a9411db66333c347e1a634c0ab8709cc0eab5043a2f4afac08a7ae3a15ce37f5042548c6764ae4cf6", + "0x81cfa33bb702e2f26169a006af0af0dcaa849cec2faf0f4784a06aa3c232d85a85b8123d49a1555cca7498d65e0317e4", + "0x910a16526176b6e01eb8fb2033ffbb8c9b48be6e65f4c52c582909681805b3d9e1c28e3b421be9b9829b32175b8d4d80", + "0x93d23befa411ca1adbdba726f762f2403e1cc740e44c9af3e895962e4047c2782ca7f2f9878512c37afd5a5a0abbd259", + "0x82fcf316027fedfe235905588b7651b41e703836f96cb7ac313b23b4e6c134bff39cd10b3bddb7458d418d2b9b3c471b", + "0x8febc47c5752c513c4e5573428ad0bb40e15a5e12dbfa4c1ef29453f0588f0b75c3591075fef698e5abcf4d50c818a27", + "0x83dab521d58b976dcea1576a8e2808dfaea9fa3e545902d0e0ce184d02dca8245d549134a238ab757950ad8bc11f56eb", + "0x898cfb9bf83c1c424eca817e8d0b99f5e482865070167adab0ecf04f3deeb3c71363b9f155c67b84d5e286c28238bef8", + "0xb845e388cc1a8e8b72a24d48219ac4fd7868ee5e30960f7074b27dada842aa206889122acfce9e28512038547b428225", + "0xb1ce4720e07e6eecc2a652f9edbad6bd5d787fbaff2a72a5ca33fa5a054dd3b4d5952563bc6db6d1ce1757a578bba480", + "0x8db6990dd10741cf5de36e47726d76a12ebe2235fdcb8957ab26dba9466e6707d4a795d4e12ec7400d961bd564bdee7e", + "0xa3ca7afd20e16c2a45f73fc36357763847ed0be11cb05bfd9722f92c7ba3fa708cf10d4e0ae726c3eccae23cc55fd2be", + "0x8701b085c45b36f3afb589207bbf245ef4c5c82aa967ecd0c334daa1f5a54093c5e0fcacd09be540801920f49766aa0f", + "0x84e3736727ba76191d9a6a2a3796f55bb3c3a8bbb6e41f58e892ea282c90530b53ab5490bbf1a066723399bb132160fb", + "0x87c02a01917333c7b8866f6b717b1e727b279894108f70574d1b6e9e8dc978eda8778342baf3c6464d6e0dd507163e76", + "0xb8da532dac81fafaed759e99c3ae011d75f3fda67a8c420c3b9747281fe32e31ac3c81e539940286440704c2c3e3b53e", + "0xa0cc63c3bef75a5c02942977a68a88cd3d103d829b6c0f070f64206da7e3638f10f42452788092de8fbbc626ce17b0d4", + "0xb5c9317b3f6b1d7ee6871506c0430cdf73e28b02c001ba6ca11061c7e121c91152d2b80c4f80e1d8f51ff5653bc0db5b", + "0xb798fb572da977dd3ef2dce64042b012a470d6bd2cb61a16267abe2b8399f74540d7c70462a6b2278d73567447e31994", + "0xb868eda58739effda68c834745cd2cf66a09f0f215607b65685bb5ca3eba71150f43a6e47b81a0c19fb58eeae3da56e8", + "0x9041c93a7e8f2c34812fd6e9744b154e898e1ef69db72bf36242c71e2c251f3db7e86cbd802da603a92cd0b06b62ea63", + "0xa834d648e974230582fc17b3a449f4f65b3297038a3a5401e975b9b60ff79b2006a33e1486d3428106580276993311e1", + "0xa3ce874da6ade9f0f854d7ae7651fc3ff63cec748a847527539fe0d67e6c99eaa3011065a4627c2192af7f9569f7ab57", + "0xae78ad16de150cc0400d3b6b424c608cd2b2d01a7a38ea9c4e504d8463c0af09613774dbefdd5198415b29904e0fbb63", + "0xb966db5a961067e743212d564595ef534e71dcd79b690a5a2c642d787059fc7959b9039b650372461a1f52910f7e857b", + "0x8069904f360af3edfd6cabd9b7f2adf5b61bd7feb0e9a040dc15c2a9d20052c3e5e0158f3065ec3200d19b91db603b71", + "0x9600917dbcd80a47f81c02c3aafecfcef77f031bf612a0f1a8bdef09de9656f4bb0f8e3e95f72ece1c22bd2824f145b6", + "0x834a0767b7b6199496c1faee0e3580c233cc0763e71eebc5d7c112a5a5e5bd95c0cf76a32ea5bb1b74f3cf00fbd2cfb4", + "0x99469a893579ed5da7d34ec228854c4666c58115d3cae86d4fc2d03d38f10d8c5dc8fb693763a96ab6be2045cc8d518b", + "0xa52cc0aecda6594de57d8ca13b146e77212cc55854929c03f2a8a6cdfa46296791c336aebcc2610d98612d5b4c0452df", + "0x97864434d55aa8a7aad0415d36f9558ce6e6c00452923db68a1e738232d0cb2d47e3b0b8f340c709112838adeaee4695", + "0xa4a7f2c45db3661b6af7ec759f9455ba043b0de6fd4787e3372cba215b9f7c641d5d817a0576e7aa28a46349d2fe0ae6", + "0x864e857652d95e1d168c1b9c294777fc9251a4d5b4b00a346b1f1c9c898af9a9b5ec0ac1f3a66f18a370b721dbd77b23", + "0xab8eac458fa8e7eb5539da3964ccd297a216448c3af4e4af0dcfed0ce29e877a85e29b9601dc7508a060b97a05f37e15", + "0xa6fd0782c5629c824fcd89ac80e81d95b97d8374c82010a1c69f30cef16ffc0f19e5da2d0648d2a36a636071cb4b69a7", + "0xad35a75fd8832643989d51d94ee6462d729e15f6444ffdf340dfb222af5d2b6b52e5df86082dbc7728fde7c1f28ac6b4", + "0x8e06831cc8a0c34245732ea610ea6aae6d02950299aa071a1b3df43b474e5baee815648784718b63acfd02a6655e8ea7", + "0x994ac097f913a4ce2a65236339fe523888ee43494499c5abf4ac3bce3e4b090f45d9abd750f4142a9f8f800a0115488c", + "0xa3e6a8e5e924f3a4f93e43f3f5aafb8b5831ce8169cddde7296c319d8964a0b6322a0aa69e1da1778fcc24b7de9d8b93", + "0x81a9bd04f4c6e75517de4b5e2713f746bd7f3f78a81a2d95adc87ba0e266d1f5e89c9cfb04b5159c1ff813f7968a27a4", + "0xb24de8f3a5b480981c6f29607b257ded665ecd8db73e2a69a32fcf44e926fdc7e6610598e10081cf270d2f879414b1ab", + "0xadc1b3f8ed1e7d5a26b0959ffe5afc19e235028b94cb7f364f6e57b6bf7f04742986f923fae9bf3802d163d4d0ebc519", + "0xa9fa5092b6dd0b4e1a338a06900b790abbc25e2f867b9fb319fdcdfb58600315a45a49584c614f0f9f8b844aa59dd785", + "0xb29c06b92b14215e7ef4120562893351ae8bf97cc5c3d64f4ecd0eb365b0e464cf27beec3f3ddac17ed5e725706b6343", + "0xadc0d532ba4c1c033da92ba31aa83c64054de79508d06ee335dcab5cabae204a05e427f6f8c2a556870a8230b4115fd0", + "0x9737150d439e6db2471d51e006891d9687593af4e38ee8e38bfa626abcefa768ca22d39133f865d0a25b8bbf7443d7db", + "0xa10d1e6a760f54d26c923c773b963534e5c2c0826c0a7462db2ea2c34d82890f9c58f0150db00aa2679aa0fdb1afcb08", + "0x816947dc6c08ee779e9c2229d73dbfd42c2b3b6749b98ec76dbad017f4b4d4f77b5916600b576691978287208c025d6f", + "0xa2dc52b6056219d999f07b11869c254e8b3977113fd9ba1a7f322377a5d20e16c2adf46efb7d8149e94989b3f063334a", + "0x8153900aae9cf48ebc7438b75c16f5478960ef9170e251708f0c2457967b7b31521c889b5fe843d2694a07c0e804fa48", + "0xa9e9d8d66c8774972cc1686809ce1fa5f0e16997ef2178b49bcd8654541b5b6e234cb55188f071477ba1cebcf770da45", + "0xb1fa775f9b2a9b05b4b1f0d6ad5635c7d7f4d3af8abaa01e28d32b62684f9921197ba040777711836bc78429bf339977", + "0xb1afbbd522b30e1ae2adf9a22993ab28b72a86a3d68d67b1833115e513632db075d047e21dfe442d6facc7b0a1b856bf", + "0x8779b7d22f42845a06ae31ac434e0044f5f9b4e704847fb93943e118e642a8b21265505ad9d6e418405d0cb529e00691", + "0xab2c6cef1c4e7c410e9e8deb74c84bedeb3c454ae98e3bc228eb13f6b7081b57977b3e849ba66346250e37c86842c10c", + "0x908d6c781d7d96aa2048c83e865896c720a66fdec7b06ab4b172192fe82f9ff6167815ffb66549d72bfb540bb35c36c6", + "0xb790440f205ece489e2703d5d1d01ba8921dd237c8814afb5cb521515ed4c3b0a6df45fd4bd65ba63592c2fe1d008df3", + "0xaec346251f9c78336b388c4e9069a1c6c3afbbb6bfaffdad050a9e70e92fb3cae3609067b4903552936f904c804b0ea6", + "0xa0e528cc2cb84b04cc91b4084e53ead4188682a6050b3857c34280899c8233aa8c1a9c6fa4fd6a7087acf1b36d67734a", + "0xaa8d7632be3e4340712a1461a0ad0ae90ba6d76e2916511c263f484c6c426939fa93ffbb702cd0341eea404d6ddffebb", + "0xa4ea871d8a1d4b925d890aefb9897847599b92e15ce14886b27ce5c879daa9edead26e02ccc33fcf37f40ff0783d4d9e", + "0xab63e4dc0dbdaf2ada03b3733aafe17e719d028b30dc9a7e5783c80933a39935dbe1ef0320bb03f9564cafdf7a4b029b", + "0x8219761bbaa39b96b835f9c2b4cec0bf53801f8e4f4a4498d19638be2fa0a193b2c1fbf94e26c1058d90a9ac145a7a12", + "0xa609ee5561828b0f634640c68a98da47cb872b714df7302ef6b24d253211e770acd0aa888802cd378e7fa036d829cd36", + "0x90793ff0736f3c80b5e0c5098b56cda8b0b2bca5032bb153d7b3aa3def277f2fc6cea60ac03edc82e3a9d06aff7d1c56", + "0x8760085283a479d15a72429971a0a5b885609fd61787a40adb3d3d7c139b97497aa6bcb11b08979e2354f1bc4dbf7a0d", + "0xb168ede8b9a528c60666057f746530fc52327546872dd03c8903f827d02c8313e58c38791fb46e154d4247ea4b859473", + "0x842c1149ca212736ebe7b6b2cb9a7c3b81ae893393c20a2f1a8c8bfef16d0a473ff865a1c130d90cc3626045f9088100", + "0xb41d0e2c7d55108a8526aa0b951a5c8d7e3734e22fe0a6a2dd25361a5d6dea45c4ab4a71440b582a2f9337940238fe20", + "0x8380bd49677e61123506dd482cdf76a8f1877ea54ed023d1deabfc05846103cfd213de2aef331cdf1baf69cfc6767be9", + "0xa026f92030666b723d937f507e5a40e3f3cfd414ad4b2712db0a7a245a31a46002504974ed8ba9d8e714f37353926a4e", + "0xb492e9e9917b29eb04cde0b012df15cbd04f3963d120b63c55dc4369e04f5ac7682b2c7dff8c03410936c26ca73ad34c", + "0x81fd9271b4ee36be0ba8f560d191e1b6616dd53c56d1d8deac8c1be7bc67bbc53d434cf70d04e7fa9de3e63415389693", + "0x835c3711abe85683d2344a3ee5f70e68342fd1aec025ad248efe66aab3e3d5790fad2f45bae0d7a53a80998fde45f0aa", + "0xb46599be80b8f7dbad0b17808dd5ca91d787929c0bef96fbbcf6c767727d07ed6785bad164d733ecb015eb6c8469a16d", + "0xb36bf5c17271d39f5ccb3d82a5e002957207a0cdf9ae7108a4946e6f3ed21a5d353fa940b6fe949c39422b452339bae9", + "0xa12f5444e602d6fb8be51a08b8bc4ec105dfd759d2afe98d51ff4edd673c92e4fc91ff32417ae8070e12169004f8aad3", + "0x892ce3ca0a2961a01f7f0149b8a98fdc0f8871c2d85e76daf7c8aed2a18624b978a4d0a84213f81f9d2a81f7ca4826d0", + "0xb1e6229ebd5b3d85e62d0474d1fed34564f1b5b9c5856fae36164dd0eff378d67d6717dda77536379006fb462bced9da", + "0xac852921dcb81e54e1e315fd6226219932f7b785c2ceb2035710e814899784d7001101f1515d68e3fb74cdbb4baf9e26", + "0x989a42d851123d708a213f3a02cfc926df15af058ec9b5a9df968fe16decbd781b5e65a4c17fbfedd2ac17126084700f", + "0xb1d0fc2f7c948e466445f307da7b64b3070057c79c07c7ebbbe6f8ed300a642b3567aed2e5f28988ac566ba62e0d2a79", + "0x83057263b41775bc29f1d59868a05b0f76d3bdf8a13c1014496feb4c0ee379bfd0d4079785252f51fbeb641e47a89b69", + "0xac9e6a208aa9c557155cf82b389bb4227db5ac4b22a0c7c8d1c3d98946df8b82b0c49d093ba55c8255e024a6d67c14b4", + "0x8294a11cd3f5111b1f8bd135be23b4de337ac45711db9566ebf6e162cd58e7859b1309eba8149b0f0a43e07f62a92411", + "0x8c15f3388b196603c05adec195c1d2cc589e3466da3169e9afd37157fa55cd34bfafbfc5ff10ac0e04aa6a0d0b2ce3db", + "0xb8faf8ba89c3115576ab6b340f6cc09edfea8f7331f5a5e8003960c584e839fcecf401113dfbb9a5c11a13721b35c263", + "0x955c63b1166514c02847402d0e92dccfe3c0dee3bc70d2375669afb061594c85651e6569f471a6969759e5f373277da4", + "0x963bd4f9ae7361d6936d209592a07d9a22cc9ef330cf0c5cb845cb4085d76e114aee66d7599bf5b9f11c6b1c05dade8d", + "0x85509b3c97e06e0db113b8b40022c8989a305cec39acab36ba3a73a4b4719573e5bdb82dc4795699c26d983465cd61b0", + "0xb870cfd7f691f88db8d1dfbe809b7b402eabd3b3299606b7dfdb7ef49415411f01d2a7e4f7ebd919ac82c7094f628166", + "0xa5533e7b58a6a9e5c25589134f501584163551247d36f50666eeb0a0745cf33e65bb8f7a9c2dc7fe7cb392414f1ece4a", + "0xb93d1ade01ff5678fcd5b5b4f06a32b706213748076cae3a375e20a97231133ec37c1c3202cbc4896b66c3410210f446", + "0x86ed3a58000a46fe2c37d4de515430a57d8f54ab4300294685534372fed1d68e192dd43d43ea190accf3dc9b22e1548b", + "0xa8c7d8dc30057bb8ad66b9cfda5e223334407730aeb0f51705922c18e7a07d960c470d463d1781899203e1b1ed1df484", + "0x8d86821d006e957e8544f95a98b110c89941bcc6985562e7a97285f5826b35b690963b2c141ff3f389d92ee18ec76d24", + "0xa4e1108cd3cf01810e74dbbf94340487011b80013b9bfdc04f019188c0d4d077a54b71a3f97a036601aad42a268531e8", + "0xa822cd61db07f64bea00de226102f5fc0adf8fa9f05a6c7478b0ff93e48f6cc3191302d22e1f369b571877d5eb96139c", + "0xb1ad4094d0bb4c325dfe072b17711962247dd7ff7e4bce4612e80a6f3c1bde04880ba1682f60d5f1451318afd4d3ba60", + "0x88e7beb0cfd7361288ea27f6b2cb18870e621152ff47994440c18d45284d21bad80d9806ed7d9d392a5cd791d5150ce2", + "0xaad3724a176cf4476595cdfb9e2c3261c37052324c0b5373a30b6cbeb481bccd303720840c49a84ddca916d470eb6929", + "0xa57983370d159e7078a273746fb22468000a6448b1a31d277272e35c6f548f97928e9015f1daf577511bd9cfee165237", + "0xa54136e9db381cdd6dfb3fff8bdec427d4dc1072f914f6fecfec13d7b8f95bb3b5f30ad7677288c008ce134edfb039a7", + "0xa25dfc4019f165db552f769f9c8e94fa7dbbf5c54a9b7cde76629cc08808c1039ecbd916560c2b6307696dd9db87d030", + "0xa917d25328b0754d70f36e795fe928e71ae77e93166c5e4788716c1ef431115c966f2aad0ce016f4bacc2649f7466647", + "0x842ce5e4ad7d8d4b8c58430e97ff40a9fce1f1c65ecba75fed2e215e101d1b2d7ab32c18df38dab722c329ab724e8866", + "0xa8eb2ed2986ff937a26a72699eb3b87ef88119179719ff1335f53094c690020123f27e44fc6b09f7a3874bf739b97629", + "0x96753c1f9c226f626122dad6981e9810a3cf3bbee15cfc88e617cfd42753e34593610861be147a7b8966bcdec55bba8d", + "0x94119d31606098f5b129931b51b4b42c4e3513a128b9bfb03cfeee78b77b9909b1c2fcf0a292e49d63bc4e5fe823dfef", + "0xa869654f5880d9c21a0af1ff4cfa926e03ec1f2d80fe5524605e04f484e09dc80d6769249f31fd378ff3926ab4cebc69", + "0xb2a539bdd8de4499c5f35cd8824974c2abb1933b3f50d0175dd044563ca829eaa0fc47bdac97eafa98434d1cd05d7c5d", + "0x85f53b2bfcde1986ce7279f3a2f5f841f87d75af5d197c897f261d4874bc6868c575ecf7556a32b7b33f7b2795454591", + "0x964f087ed02228b30f401d8aea35c1a7f76698e4075e1bb343398be74c716884e9ca1a31b81566e1ff7513cf76a2f0cd", + "0xa1c9d9c9bfbc9c4e281a2953d5991e7b22ff1a32ddaace9e8d9a42e080efb802b853d3276973b5189a5745943c9b4389", + "0xb0c45a9852663a427d7f50c608a6419fbd00f90e8452757a45269d25c0386ec29942f48a34aafc0187ef6020e581d290", + "0xaa3ca7b01862d5d2aea714fa06724b7dda7062b6608605cb712588b2c49fc3c7d89a8799e6e7c31e7a9ef28b1ad4d1f7", + "0x88f5e98ae8c5ae7add42f6d358a35667e590aa80e1869593cbf597d7ee466efa35b429f1836ba2199d8280fe7f60ce3a", + "0x8a3bff472e8008f7e50362acc1a0b53c09ac60430942544532722e938470376f0672662261992146765b7c75a380c318", + "0xb9847be7f7aee7532282c279dde928698a892a183ca3047ceda521e9e0a50d96fd3ce59f8e58f31af49508ade6d4ba51", + "0x98065dc23ea3df6d9f8459e81887d88d5752b7e7ba6050ec5c3f0dce93e463e0bf12be3c94ec74c16e2f7ba62e447845", + "0x994aff677b97ee790894dbdb21b1f9210734e008cee2aa2200c8f2579ea650b872f39776a13a8c31e95cc817091bae1c", + "0xb292811674e18912ebe79df1af4a132b04ab702c125c039e0213f735f658fafd36c38e5bbd7cad35842576431f5f3630", + "0x96520d750ec10bb10f75019f8f0e4a93ecbc6b678a710d76cd10aa27a6642ad1461bd58fc2aab8e0391b3f788339ed29", + "0x80d478da7fe246ad0e81a00141229e9d91ffb7fd1b29975c8ec358ed5e864e481bf01b927a9ba002c5ec4aa226d0cb57", + "0xae58049d93a11ae845dc5be2505e95657f83b95d83ff3591a3c565d587157be795ff4481f42d59eda95e6d523444e199", + "0x85f1f5ad988b9f8a7e24b6d6a22b9de9fb3fe408f95711389c444d7ba2243987225b04318aa97a4cde2cb4c30c05508f", + "0x922092d0cb828e764ce62f86cbc55c04dce07233cff041888fae48cfe93818780b4aec9b4ff4718275bb2bfa6bd9e9ba", + "0xa85ba97125feff0590a05fb78f19a7338639ad1748802918af4d59307bc994536c0ad638b97b9acd26a08b6b4370dfbf", + "0x8c46fcaa8d13266d650bd9366180e5ebbfa002c339e4424a030de19ed922e2daa9a353ae54921a42299607ae53feb075", + "0xb8549832230eb1ec6ee3c33c078deb47f556a0907d2a85fde7720391c82d2ed63dd753cf544a6a0a46eed4b8d1ecd9b8", + "0xb7b96f24504c7f8fbed9c1c654a2550feeee068407b809c43f1082c9558c8665806d911d5d244308169d8a531373bf56", + "0x81c483fd9d9ad7af7869d617ac592e7e951e39738da041d8c4110637689108eb29c8acadfc85366c70885cdf77b353c3", + "0xacf33bcfd9080dfdba828727fe36803327a94e8a3ee5b6e445274f0e8267ad3c943994a8dd6d09b8072912b57e1e25b8", + "0xb3475e7456ff96861bc11068198d51b69b899f5ff13022694b501d3adc8bac58a16204b12011d61e880c8459f4badbbb", + "0x8ceb9562026aa96d6e786ec2e5cd49200b5b424349a2214cd3ff5c8f1c2bf1b9872480428f5428e45cc61106cbfbd953", + "0xaf56f7e482c24a1367fd798201a20c464848ece431f2d8a31a6ef4f9bdbaa50991e748dcb4ef0c08fdac0ef8ddda3b80", + "0x896dae8b12549909d512fd5c02a2f72dde4086aef6c8007ddb26bb04dff51a707ae94ff87e45191fc10339967fa28958", + "0x8ed1c606840e07a2ac6ff16ac6e81ed3e1c90872ababfe68d56ed2dc50d9294579b9c3546dc63292874299a3162d59f9", + "0xb4d7a5c0836e419a46942281ce77d0aade8e39eb1bf1190dd274ca5070898a1c02ad9d165855629d6e1c96df1a6bd5f3", + "0xaebad8939ac117deb28b789d9846c2c80359dc260920ac8408dbae0b6228dbf496dac0023a3b4302bb9a53e8ada18e61", + "0x812d07c74a8650dc3f318c9b2dbf265f181041fb432fee989cedabd44b933dc6590e36c71dcf9dbe7b4bbf74ea0d7c50", + "0x87b131dd3489889e090839c392231e0ee198acac65bb2e9e63e7d6da322391d1685cfc8ba60699308054c4b0fd89c90c", + "0x8b12110ece0b99b2e653b4bc840a12bce5b85abf6fb953a2b23483b15b732a0068824f25fcaa100900e742886c7b4a0d", + "0x8765fc9b526a98512e5264c877bdca567e32fdcde95cdbcf4f4c88ce8501e1c7fab755f80b87b9b32d86d18856f1d005", + "0xac806a32a14019337dfdb5f781ecba5cdea8fb69b23e0e57a0f885e0082a9c330ba808621a48e24316604f6c6c550991", + "0xa711970fa40cf067c73e3edee9a111bf00cd927112205e9d36a21897529be9a051be45c336d6b56725dca3aeea0aed15", + "0x908adbc17fc18821f217d46c25656de811d4473779a41eacd70d2a0d7dd3010de4268a562378814e619e13ac594bb0c3", + "0x894251b79be5ae763f44853f6999289b3a9abda64d52797c6c7d6d31ff2a79e9b3906da72f9ebb95b61d6b29479e076f", + "0xaadcf11ea15bcb6d979c3ea320cff8dfcc23c5118ed075f35e77f71459b2141253060e3a90839adbcd3d040ad3bdc5e2", + "0xb4e55d7d2eeaaffb0267448ecce0b75166e4805dc0e261eb5634d4a3f3c08964a597302fd8f6b45ec48178619291dadc", + "0xa8e2a02c93d6bec7f42f9265269660b4b404940c3e3de9515b4d826ea7e71f18c6f90a71ce3fbe452d0713de73cb391e", + "0x8e2467accfe207cb1ba37d60662920f95338ee212927edb706228c25345734217740159310edf17687f58b333754cb65", + "0x90376b88f653381b3bab673c48c2b84fa82a091e18f710a732fef836e0d39043fcd5527aa97a3a385c0a77cf53746993", + "0xb16530e289198c235ab680f86851bcc177f0c16a58483d83a89213077b06d6840600b03834b6b7af0e22b1914f72de43", + "0x8c4fc3854f938ef1c2b5df065e4e75e9f299798afae8205706439491bdf9784c756134922e77af007e349a790afa52b7", + "0xa68aaec4341d29b92b35322f89b1ae3612e7b440c89a86135a07c261dc5799217a651460c92113d099b486817226d8cd", + "0xa653f965feefd2df24156478f0cf3755274ca395afb79e8c72d3b6e1d1f5ba7f3e4f9a4c5ee85355de6f3c81935ff579", + "0xaaf6c8d2717b57f6b14e06c742a11a3bc736bfc0327ca4b8a005b6e924f06871141d231737698a9a59286e44f244a168", + "0x8de32e3c104b4278e27aac695d224f134001c3619f15186466c57c0c46f67e2efe537501d0d9f52f4cdbc724a170b92d", + "0x8e9b5858b6d4ffe811f6498bd80e454f0d6b345d4729c946626c7cdc196c803a349a14515296aadb7258bb7a5b37e930", + "0x82fc711043aaf1d7a9c712d00eafd816a710f82eb10818ba6af09f591447f36814dbff6e6a1cb2b5c7f16c73930dbbca", + "0xb2f0205327fc8ff687f751e7b97788732afaef4fcf51bb17fd7579ed07501915790b70fc36624371fe4fb87a0179d850", + "0xadd87d5b1288d30f3449d3ccfa11cba4dc7756d85cee1cb6171b493680a625a01f273d0bb8e6332d0410250036b3acdd", + "0xa411f75ef7dd8de8062331ea40929db989e4d65ae8f33d3fa6cc19c98fa8a8ec2b7c7534a5c5eee9e5051626a6a2e47c", + "0x89d40a647781e7f2e8ab3a0f7dc7133669944c0cf627376433687a2ea15c137be26f582a6b07ff94b266ac0910009f7c", + "0xb2b5f808c26b40ed507922ed119b0fb95e0d6d8b084bbbba58ca456b4354d03110c99989b93207998334ea5d1b70fe49", + "0x8c8db028671969a1e80e595283ce5e678ee955d785043bb5fd39fdb68a00e4c15b462600a7ab1f41486b6883e725894e", + "0x958087ce0c75fe77b71770c2f645ef3360c1a9c98637693b988c5f6ce731f72b24ab8b734e8eb6258ee8b23914451f0d", + "0xaad6c00df131c1eec6c556bae642e6dcc031e70f63eee18682f711c7b2fcd9afbf1f18cf8a4af562759130add67bd4a3", + "0xb6d23c567291f019cd9008e727704e7e6679b274feb29abba0d92e036f349b1f0fa8c5271ec7384e8d70a2c3977b1f8a", + "0xa942c770e903d4150b5684e4b94bb72d0e171df2c7cae6f46e002c41c6b04d774ac6e2753ba8dccdbba3ad1e297a9ae5", + "0xaa542d1849390f86d797408ed7f6a31504aa65d583481a00e475028af20f8b69248a87a8ffab1dace0377db77fe5f9b2", + "0xa1ed3f9564a97f7cabe7c67e018eaeaa42db73a2f3d2332041ca9a7bea57436d848784d6dc402862c22a47f0692b1286", + "0x925c757750c91db8b1b3c220fcbdd80742b4a060abfb0a402071d215c780ef6b420132ec5a43043b9fd7a06bf1b323db", + "0x94e575daa7fa0bbb35b4386f510fc3877c9df57bcf15349c5923f30ad6a8df95372835cc078216b41a7192921c1e8973", + "0x9346a41174865d9ab31c7fb9a5329f322bfce06002386d3f5a2e2193de9bfff12bd0bd93307928f7b85e1097b2aaddff", + "0xa6e54c9324baa1bff7e9bf39c94fdd308ec6f210aad937112ec727565f8a6141375c04196831873bf506294854f6a20e", + "0x98d47b662504f400f1a0e14e24b43829490d022ade02a56288aaf148d466b45d89b5fc146cef67c9ba548cd37ad5e354", + "0xab690dd59a69904b6b3a4d5a42d17ea4898d9b00c6753aec216d5d4ea564f9a1642697df44d5a62f2c2ab19aaabf1532", + "0x8d0aa8d3c5ec944af49beb99e403cc0d6d1adc6003b960075358a4ff1cbfa02a83d6cb4d848d9e83b34882446a330883", + "0xaf9334b7300780c752f32eaa68f3dcecd07dc50d265083f37f9800b02c2595ba24dab89f5fc27c1ecfdbf5291b4d77bc", + "0x81c4a6aaf7d4ccee9925c512dae5da6d916a6dd59f7a4cc79d216a91201b4d300114a309e3ddb3291bb95f85bec2a8ea", + "0x8c804e810c0785789de26e12b1beff56a163769733be7a31f34f81093782d6410293768a166c9191ef8636fc8724a31e", + "0xa91222b48de238f6dfe79c84080cee618611bd0bdca15cfe44474829e42481f8511a82589e69964e19f8cba04e3f5f3f", + "0xb26a8885aa594b0c8ad4a1711d80bcf687df996442075dd1497db1b446d16c74e28bc6f0e92b2ecea9c3e15c9c7e828a", + "0x85940f45d324ad1d335bd1d7d6f81758f52213e63d5770d9fe0c0c9507d5550795e538b6a2dd463f73d789b5ce377aed", + "0x931a277c78082f416880620df3aeb6d0bff2103d19679dd092ea981f5323e438c50a0d094908034ff8a2cb47b1a44108", + "0x88dd85e4e2aa349a757b98661fc00d4538ec1d3f53daf44b16ffcf7f943dd4f2bba5b8ba3b05c529251dfeed73f6f1e9", + "0xb7fd7182cd33639710b8216c54a11bb02e199bbc54fe33492a809dbe17771a685d6238ea3ebcfc75e3b0d4ea5369bc9f", + "0x85d77194d910f8cdad7330e1bca9087529a40fece17492f1d17cc4790833891b6d01d24f036b6422175c732b438faeb5", + "0x9845265892d672d9517fbd22f88be4f225711b4abafa8327cc059f000656e4737188506051565d97912a0c19c3d063c0", + "0x90a81987aa841c7f640c298b816643a0ae00cd3609c3a31d0b01245283cc785d9bb27763131b31a4f21aeda4e50073e8", + "0x8b1256eb41a600bda8a06ac08b98a220ebfd52f89a0e4fdce32425db7a0481e9b7873ba3b7a24ad9fb782ee217dfdbf6", + "0x870548998deed85c59507cec7e69cc001c279bb2a99c45a4d030a35c107e69feb76afecb9e435e67965051d6d7a88220", + "0xb1504d194a0dd8df48d431ce991f89d7a0f72f573d21bd5bb46474c5005e43820877a44e62db555f194427ac8a4b9168", + "0xa00d7423ec2cf0c9e9da07f3dae092d09e1ff4be852e07e531aa54d62ad937bfb52c8bf44683ac3a70f6dfc125575da1", + "0x8019625ad3d218018803aacc2efcedba3a41c24aca8c5aab2005556e58fdf2ed614831277df7937aa594e97a2fc65e7d", + "0x8595596284f3add0155ecfee3fc0b66a6b6fc7923d82ca8302952e2ed906d119a1c053aed1123b51f73e1d30d93aba57", + "0xa8ba033f5e7d06177e9ae2d99c40ed4e99e14e1c1b61795997f62e21ed8af1531c4720f23d6a39b0f75c6cd91c58c700", + "0xa94f4167c0f6ae214bae75dd92c63299dd954b00b0d8b0416b8af929fe5aec6a259e44f83a183412d7ba4eb3a49728c0", + "0xa73ee3c3a0fd2a369e0a279c3e214fb662d0378eea3c95cfb91412d7213a1f05958bd0de8f2a4f80f9f80d7eef943b41", + "0x8ef6f3e241f6a761c9ab412629a49648c08b70b837c2cd8bea620bc93056ec73754e3e11f0df50f8e9fa67a9867501a9", + "0x80b473ac4ba8cb82b4ae684206cde124d10fcf619f55a6c90d035981e1b08b9e141b4e5fa9a9af0b7f0c281b355dd593", + "0xa566e2be0b41f01978dfffbb32f442b5e6706f5b9901110e645cf390f6a82869e3ca16887ffa35782a004d251d29c26e", + "0xa74e01eefa03546d00afdd24bf17015eee95d36de28c03c9b055e062cd5e8d8f20473c6d7ad21c94f9058fc5e84f9628", + "0xacefc74de146911275dfd19bbe43d72729e89e96da04aff58e5fcb90962856c0b24eb13f43e30329f5477a1b65ae9400", + "0xb5f113ef36e75de6d6d44130f38e460ad3ffc65cb9a5606828c4f7617981fecf76f5e862d7626ccb117aa757cc3c3e52", + "0x96d3aeb1d3a66b136244062b891fc7f93ce745b776478d361a375ae57bdba9b4fcb257becbae228c1a3aff4a1c4fb5e2", + "0xab26c4a110877e5495b674569a32025dad599637b5dafedcfe32f205dfa68cd46f3ddf4f132a8e5765883b5c83214a07", + "0x922a7a738066692193af32ccbab74edef067668ce3253e18a3275afcd5a6df7168deb2f5175c5fb413dc08fdaef63b17", + "0xa47542f8e4a3a35ef6049280d1a9442c920887d5f1a1483149e143ca412318495a36decb804f81c9f5a7672a14965a4c", + "0x8fde57991e72a2aebd3376b4d9fdd795943ba3833431e52b136683567e6ee2cc1c1847dc49dc9534983060c54bf22f7e", + "0xaddb041f01a99e7238ab2f9f2f94579861d0470b93b91cfb29f3a2e4c82386c868b2cfb6f3778b8a9cf908788acafe58", + "0xa8c4e1df726431c43703739776e2cc51f5ebac57051244991baf53582538120133a44ca603d0722a4b5193e1be3c5ec0", + "0x846379125968d1154376c5dc63100bdcd99b9403d182e3566fe48d79099099f51523cd81d21f0d1dcd622b715bdd851a", + "0xb828bf0d936d275abb40e3d73ef57fcd7ce97e9af35e194ae61463317bac6c1b0c3e4b40afe08a1061037bb7149108fc", + "0xabd07c71754973e698fa26c5019afd9551548f8369e2249b9902513f19a097057ee7065a1d88912e8f52e6e0fbfa6d82", + "0xa9e36b6fcc9a3cc98e76d5751c76c50e1f92b7670f8076ab6ca8a30de4ec14c34669e049fd39bd293cde8789b1ca67f0", + "0x8c060835496a04c7b51790790035862b20547e62fa8bb4e8857fb36891ec6309520af5c0f45d5ea46e3d228747d710a4", + "0x8cc472ec62b8dce244373f40a821db585628989b6a7c4d394edffbc6346c8be455f4528d528fff41f91f2c875bd9fc0f", + "0xb4a75571f84f93451f15b3a86479063d7324d2789b6d2f2f4f8af68c66fac32743dc09b51df29608d62aaba78f6904af", + "0x916484984743b5ac16d40d0544faf9184819d92f779254b7fb892eb68cefbe59e75be8a6336a585e120f6ccae0a1eeac", + "0xb906ae585a73119764024e9eb87d92e53ee0c673474fec43fec4d344a3bbf471ce3976d25e37d197604689bbc944f1ab", + "0x8552708487305f16f95db3e01fbbfb969398f5b6d116844cbb000c9befd03f15c767584bf9541a42141949a4dc787a3a", + "0xa6025a2773f78c247f78c0d895ade8a6baa76e5499085f6175935d98a05fc41c1359f7843e0c6c323f1be256c45f45e6", + "0x96dac695dd9288aeb6e32dce50e51ddf1fbd41de6146e3605c7a81f2253b17babf2bfda4f5a9d0c28352b9746c0dfa2c", + "0xa215b21f8eb2290f9d308278f2859a999eb3a31f4888f84a65f9ed05e1151c17777f91054d4d0de759ac5c3547d91929", + "0x8fd7c9a279e9b619acf927d501b35dc551979731a89eab91d38b2356c0d73569baddacb9d1096d20a75c917ecaedadd6", + "0xb985e8baa5195e2f1ea1091122d55aa321178d597f87b732b23eccb12b891638be1a992305a1ffcf5233af34339fa02c", + "0xae1a9604b7f569aa48d2daa1889e76d3d103065fc8c3deb9ae127a6d94145695cab3bef640fa781612e8082c6d616c47", + "0xa8fc67f9069f753360349eb874fa4dcadb2ec48d97c61abe568faee5f370ec3c87786c7faf0f73fc0ae7181a36eb89ca", + "0xa506d13acc3a9f80509fac936aef848cd30698631fff6130ed6217512ed9527d075f653cf6ef91f68e48a24c903eeb3a", + "0xa415093755cc012863043bf586b970bafdd87653ad14d1929672e04949bae4a753d16aa3eb5bd1afe3df3691b80f240f", + "0xace3b792a1960580348b6fae8513149242378a18382741bbc2fb2f785cb8bf87550da4b5e0df2955970ab3a31f99f5d7", + "0xa47d7fa7522664c8f9c404c18102f6f13a1db33ba8b0a56faa31a78a3decba3168c68f410115c5d9f240b3dc046dc9b4", + "0xa9c930db3ea948cd2dd6ea9d0f9a465a5018bbaf6e9958013f151f89a3040cc03ae0b8eaf74b0ff96b4e7a6cd8aa5b4f", + "0x88abd235e3e760166cdedff4be82cf6ba02d68f51c6d53b1de326769f1f635215890f9a4c35b06dd16a9b93f30f3a471", + "0x8f8d7b2fcdb70bfedde1ffd7f0b94108f0fa432f6ae81097988521dd2c4da928c10c5da3c7f33f11bd5331f2da8ec219", + "0xb7abdbd48cece30d8f795a58a94913d76842cb006892485a9382a0502826538ca4ff951cc1ef4493e45de8571360d20d", + "0xb3e7b125f350c52695f7c5ec4a30916ea6c11744f1151a18ea0510e6cf6ed6f6dba4beaa4ca56988d306bd80ec360056", + "0x9a004423c95e1f1714f98fb97ab798d6ab16cb5f6d6cad860635585d4d4b43ffcda63d8e931351189275e5a2cef28c2f", + "0xa8eab6ef917cacdc9b1932eb312309e1f85298d63e55ed9c89ab79da99d3eb60f1643d16be920e82d9285f60c7f7cab3", + "0x934df955485113d10c4dde476ec14a98771145aadf3c8b61af26b09b9948757fa1abcc945ac91466a18c18c2fdce40d0", + "0x99ed9146561597cff8add2196ff3a0f161dd5302685ceb846afca6efb5225f642e8f4a0970eecb01cdf18694fa697095", + "0xb37062dd12a81267bbbf89bc9d6e30784c0e11e713cc49c6c96440f800f2a6a2a7e7f6c7f6c9eed4bc3c8890f2787342", + "0x83a3d70055b6044e0207b3ece4da849755ab5798317b36b20c3555a392c27982f811e1c5007697554eeedc737b37f3ef", + "0xa85392c07ff8658935fbc52acec7221cd916c5fde8537a8444eefd507220e76f600350ae8f5dc3353911087b88b91045", + "0xb1ea23558ad805dde9cc1eade995cd8e7f46d9afa230908b5fbaaa09f48547f49c2bd277bff8ab176f1c240beedd2b09", + "0x8a16a48b9105d94700e8e5706b8d8a1ed14cffda5558a596974ea3191c5c3449da6e7efe2059e7baf4530a15f175ce16", + "0xac5fa54381fc565842417558e131df26e9505027759416165035357816a7e1859a7c14c228c79b4e5ba2ef6758e12ad8", + "0x8475e290c399cc9322c05264a516cf766bf5fdb6b9dec7283961da0b99012d499b244b33fc0eaf94b461ab777f2a9537", + "0xa7922f3c70e6857652805af7d435646c66d94eec174be997c4fe973d8f019990c4f757eeb730b2cfdf8154e6e97f7d5b", + "0xb90deb797fba3150cf265a23ea6bd49a382855cd4efe171cbcb1664683a9f1687cfcadfdca4e39cd971ec13aa5cdc296", + "0x91ca761dd9659007d2fe8970bbd336c19ed0d2845d0d8aaab397116affcc793de2da73d89e6625cf4dae5983cceffa56", + "0x9121ae9b60323ab1301e97555bcc74ddba0f5b1e62bfe9eaa2c239e1d685c4a614d397b32a59febed4db9968db44f38a", + "0x8477b07da4bbfe9087975f30d2c2333fccfcd7149f90e0e6fabecee627eee3ea324df31cf6a680393f5dedf68a35c9de", + "0x946a9c0f02fa6bf9f9d4933e7fc691749f4ac2f82a9b880666b5185189d4f3432da9096d0ea4d6baacbc079e19c887ce", + "0xb24663332914ea519435874d4c42d11842ea84dd3dc55292d5b0f27f64587848d095bacaec235a37003bdb5185daa6f2", + "0xb980f46f84ac21dea75b4650f9412f6123325842758589a9b47caa68545905061f03fcad23cc102e2ce8ffeb1ae634a8", + "0x90e9ebb060182d3043ea4210a2d934858559522a19eab9f0ff81a367484a05ec7cce78ee6a91dfff96145869db6a4e80", + "0xb04228a009c91847693eab29c9ea71d1d6ba07060bc2b0b3bb81c46a125baecb3e1412f6ce4305076a97d316d14e4665", + "0x8d3268370dbf38d378c7228c7b54e91f90f43cbfddc0d8468de11a4312616ca6372619209b89114152b16f334f4d2780", + "0x964a63ffae653e0249685e227d937937b079ec3da9c977dad2b2e052af5eb560ce7d175941f2ae0df90e3d0a20b77e75", + "0x855604c2910be885b14b27896e16d8dc339236b975398c771d29ac74e4278a2305fcf85203050a8faffddf64ea19cf78", + "0x8e0b1d61a4349411eec77cf3490555843187a25a93e1f45bf66ad3982b9cc141b07805f8cb252b0fcc125e0052a7c450", + "0xa03bc9588f971a1257cd0cfd2ca406c76aaeb634001864b0e4dda91e009d3361b33fc39f34922835031a423a13619a82", + "0xb703fa855c2c4e1641d2687717fe8c5061acab71cd2dab55cdb069a6865464c3080f7936ddfd320516b6791b36c64b8c", + "0xaad1cfa7295e463fc3d5374ea4b952020010d67a77c7a86fe2c351a5959cd50df6a0045ad588257567a99bfd0e9400b3", + "0x97906fb82abf5c1d9be8f72add8e6f175a6a5a4300b40295cb5ec8527cc7ec700fa03a7a494122d9605d212457452e41", + "0xa83366cf93ad9a07f617e4002a10b624270f60083559b045ab5a805aaa592ac37b90c1e8b5437158f3bd942cf33bb633", + "0xa585168e157e111bfa329d0ed6651a96509b20b30f6bb0691c6a5875d134d4a284867ab52511cdc19e360d10638e58a1", + "0xb17d480a0b39f2487b7f3878714658fda82f2147c5ecbccd4004eb92d267c4663b42c93bafb95ce24e2f2f0a9ea14b8f", + "0x9362297a1a3951d92db4fd8ea6b48c403d6d8d2f7e7b6310b9cf9b4e4ba9e84cfe1ae025830aab9466c32fd659144474", + "0xb1a62fbadfd4ea4909d8d0714c1e3ee9f95237fde20720f88d5ad25c274a6792158b99966d7b93151f769c832b6a132b", + "0x8d9af736949a33fe929548abe72384281365385862821a584f5198eed63bc5388f89fc574cda35a9eaabed0d336b86b6", + "0x90ee2235f4ec2c6089b5cb7b8a41c9bc39e4a57935022ef28bed490e2ab12680922af7395bda4f708809e2bfc62192c9", + "0x91f3a123d420bca34d3d751119bbebc435630c6605fb59a8d80d16a4895972e56cfe4cf1998e0a527c18ee38c2796617", + "0xa2c4fbb20e7fbaae103b86ca9d8dbc2828e6bf33d1d7ce153bd98e8880fe7ac62abbf7059194b1eee64f4526a36c63a9", + "0x91a7f93310ac74f385f11509f4bea9a4d74f2ce91cf2024fee32a4a44d5e636a73339c6b4027ee4d014a24b90de41ecb", + "0x914a6d405fee0a15e99704efb93fd240105572335f418d95e1f2de9afeb97f5f4b80aaf20bd5bf150b9da9abc2b6d6a5", + "0x9462cf2c7e57e224389269b9fdddc593b31e1b72ab5389346aa9759fad5d218039a4a5bc496f4bf7982481bc0086292a", + "0xb7596132d972e15dc24f2cd0cf55ee4a6cc3f5a0e66dff33021a95e5a742889e811afd1dc0cd465cee6336ad96f25162", + "0x99409bba2548f4ece04751308f815ecee71222869d8548fa142788fb19df5366d093a5131e57560237471bbd5279bbe5", + "0x8e7560988a844b5b844ad460b19c452a5a04346d8c51ca20d3b144a3670ecc60c064b2415c2eeebf140d6ae4ba5c5360", + "0x8cd9e18d311e178e00eb81ca839cfaa8e64e50a197de8461f07135fca28c1d895dd9c2401b923a4175ff711853497317", + "0x91ebf99c95e8f653402b3079ecbd533ed7cd3b6c857a710142354ce8330cebdee7cf0fd0400417883b66055bec9d0552", + "0xa9d0cf8cc6bbdc44426dcb716df667826426b4559056d73738bf3eaa6df373403861b6bbd6fa0454b1d2730e3b0015c4", + "0x928320b452ef21d2443dee360110550f531d7a4275b2cb227814150f3e9e360e05a884d6e3bc4415f202120ea5ac333e", + "0xb9551f2b2e7bb984618f2e7467e33b5b5303b8707f503f2e696e49c2990ea760c31e0944d52257c7a38b553a67cf621c", + "0xb2ec34126fe61345e5c6361fe55b8fb3218cdcc9103bba5b200252d50b758153cd549226b7aabedd265906401e755190", + "0xa8cf814926082a96a921d471036a9919a58e68d02ee671c215ea304759cd92a7c2c9ccebdd5e9ec5572164ad2abb22ad", + "0x8c0563c28c261bbe9a1ec4986f8b277324bf05b4fe5e2b79a862168e646bbea50ce7c4622b2aa7ca899c1a728c226d24", + "0xb558cdc334ea894d3a13347ea9e30f78a0a20621903d6c009c54feceba3ba81d2445a43572e088ae691f65489702e963", + "0xa62ba0b20f46c367cfd409beb300e39f1a6cd5be95e63457b6ad3cb66374aed754fd037b8e4215d651a7d8e1a442f762", + "0x8543e2c6135df471bd7a5c09f1313674c7f6847cb88f15eabf40b2bc9535d0ec606725b97103334a0c162a20d9f5bb53", + "0x8c0367d7058d63b425450f8ee9252e64234c0c2e61878c7c2d4b17bab22a72f40c75ac3bf8b64f264c00d9c5963af041", + "0xacb7207445993d563f1b6e7b179bbd6e87044399f80e6d15980acf7aaccb9d85071fecb22250afb3aba850712fbda240", + "0xb93725e66184bb03f0ab4078c737a7fb2b10294a3a09995958de3dcf5316b476ce9b5cd8d180017196d9482abdfcab88", + "0xafcb52bb7b8f45a945299da6fc6a877ba9f69f7f23d5f94b5f5d9a04c3cf3089333bbd50fc305e3907825003da73b9f6", + "0x961de781cb238cef52d43bc0dc7d8e3a75bca4c27ab37a2e9353137a9aa9403444a5841b595adeca75a3de5485ab97f6", + "0x9408c828d3ed6df40cc167d72ca9882a9c9cf8e765d6f9125e02e0d66ee0ac94f449803afb50bf1b92176feae92473d6", + "0xa85480591e7e033b9087fd0efe5cf3c88c10a75de4a5d7da4443df1cc1fa1aa59b6cde3ce7453fcabe555495e49ef6f7", + "0xa2611bd82344bc5d70d7e6cf3f0d25866b9f709ac4bf6f75d1006da2a11e2cd07a4c0ac71505e5062a04f71db7a3063b", + "0xac466aaa96febb5b810ba350c7a874797ce4bd6c9585f6b9d114d646894a67c9af9526ade4f7ec834d3a69e18ab643af", + "0xb73fc98a79fe77cdbc524c76a09cb9f2d5f8b0a5508846bed1ba5ea9ae3bb62120e01d3b8fb544d90ac9ae0c3d4ccefe", + "0xaed333c3403adc899a870082f70aadc770c9f880dc057f05a46d7400be9d893354121a0a31e5475898f437bf722eefcf", + "0x97f02133c72187178a8c48db26031f0b2c0317a6648d2be5f7450f00c37391cec935bea46b8144ec9fea5327ee959f27", + "0x940b582b41f1d0f09f0c5f51bab471e4eb143e91b1e96dde83e94650421d51f9c9baec10cc802fb83cd63b56d0b907c0", + "0xb1286a55a74a88a75da47671994916be428be1ca3f42783e497d6478eaa6aca69d50a421b210e9ed3283d578b651b8cf", + "0x97cd4e87e21c71d11f1df1c0b6518c00e1610661be4b13cdbdbb026d60fc3f4a2b8549326a648b3fdecb7de8f6aa9fb7", + "0x8f36bbcccee986c35328633bf6ee8f70b5dbf42d0f677c0f4e009d2289976e512af6af91a6ddcd87dc0df93bc4ecd02d", + "0x9253ad44ad182e67ab574d718733a69c05cd5bcc43e6292ef0519a9430460aa6a233fe26269da7298ea88cf406e733c0", + "0xb616b5ea74db0dcf8f10a2db79df6ec3566c06410f68a933eff150194608c591b2b175908d4b4ccaef1018b0fefc5693", + "0x80a712ba89394381cbb83fedcaae914cc4f21ab024b8da8a7bbad7762a22f82940451427b1a3f5d84c246d5ba0c7ccc7", + "0xa806909a5517a970879143ad789c6cb6256b82553b649f6865cdafbbc050b1f86528241b3cb600e784186e1a672b588f", + "0xb6ae801d1f0e4adf3ce57659d7c61f94abd3c8d1635ad28133a79eff0586fc48bdc195615335449e9bfee39e8a955eb2", + "0xb8a000561211844bef72adf3413f3b438a8789fcddf6676402ca6a1c2c63b9deed322030de2ae3a0aeb3cedbb89406c3", + "0x8bc3615b28e33fc24a7c989f8b4f719c914c4c65b35ad3d4cf15e2196e37c62e42ca34e8b1275e0f32589b969bdfc21b", + "0xb2f9637f370a79e7591e5056dac004f56b375f33645ae9f5a192cc6b7b6b3d8a1105cc00f10d8bc8ef250ecc2ac63c39", + "0xb51899978b9c5b737999fee1935a5b0944261e7005bea411b5903d2c16ea045a3b0bcd69395b6733752caed43bc4e343", + "0x873c71a01009dddb9885c48658f83aa6320e74bc152e09de8b631c763c2b4e2e8cbac921418a0d9085ff5c53a2b52d39", + "0x96470f48efd7d2ac2daea8753ef097c09c6fc128a54cc7ef758ff07e32c0b0ac7d122f97b53e88a29cc26874dfee5e0d", + "0x8dd2decbd3504b7961d65edb8d51b96377f4edd2e0d2cd8a4d98333f373c79a8d7ca8f8408718d0e7b5e48255857c339", + "0xb536ae387bdd0f6e40850c71fcaecb1051b2c8f7bf5cf92c6bda030de72a03e9212d00390c53a72a08e9fb2bff1249c0", + "0xb1566076f59064e3545adef74fd1acadc1bee0ae23543c30caf9e1ad1fc20ebe84ee25004c612525b26857253f5345b7", + "0xafd180e25444cb720342923b8897d38a6537bc33a0ca1fc9c6e4d524b280193618f19e2bcfbd07606b78b734fe6114ed", + "0x89b2a6c8811e5a6d07aa74c79dd854bdfc292cc104b525bc37e4c7c1f9485e19d759c8e27cd7cd73c46346f56ce3b189", + "0x8234196e196898b2501b79d0dc016f6df3d5878952cdb8a93735e4ce2ecf77d07924c701e084533a20f0c50a7d1ee376", + "0xadea7ce2efc77711f50138691ef1a2b946aaba08e7e3b21378708dd5a10bae933ed121e71834b43b14e2ea30a7b306e8", + "0xa566d406a35fae703b3d1ea1791d9207116002e5ee008d01e053a1ea4fe5af2feb63605b011ae6a14414028aa054b861", + "0xb83bbb063682386456719179b6f6bbc8cf6f791229600b7d402167737492f99437b45886695b26a28731e952e56f1ee1", + "0xa8f5fffc2c335d3ad5c7593e81f0862351413cc348392afa86d50921dabb929a5a1de20d604666af9e17a13bbc30bc3b", + "0x8d5dcdc1335f01847f6ef650ff64b26e7c4cecb934a7bbce11254e8ced9fa9e4fc87eec55248f69bf499180101c63f5a", + "0x83fec30b8bc62f9fc28301a03ef18158d6364738f1c42de311bbfba2e62b25d4c9ea9d6097698b24c84fff956a6748b9", + "0x96394fbe0c2d03cdaa56e13326aeb62344238ad3043ee2fb4f18ebf0a6f7f090f410032a2d15bfbeca9449202d59f2a0", + "0x94880f5928fe71a797362a37d05849d23e118742697f75bc87173a777e7b9d4383b8796a8a2bbee27fb781f363301dfe", + "0xaf229535896ab86fdf6d2ae676a0dbf44f868f6c7f17bd9a65567631c7aa2e29758f41de050ca5311bd1528bcc811532", + "0x8d4fa4968575b483b3ac16345e7f1ea3f81e8dad72c945a48b7b982054fe1030584be2f89b2f53af84d2490cda551b84", + "0x8052aeb115e4d242078c8726d376a13156cc832705243f14adaa3ef3889e1f2fcdfd46e087acab6fa85a74afde5f5eef", + "0xa1349c8a22788a1937a837fceecfaada9e93a63e582a09c56b53da52c9db1600254dc85f63f5eadfa30b89b31dcbdb30", + "0xa10178cdb263ff1a5e0cc034b6deaa160d00c3c3fe1fd1ff0c55fdf1ecb83d771070c10930f88832b75fef39a10024ea", + "0x938b17e4405934ea5ef29c2187d6787c5ff5d8c9a02665efb453117d462dbc50ef2c202cbc884305cd807a70b5cc177b", + "0x84f01f0da6b58c71788616be71fb3c259ceea7f8bd131a5661c5c03d0205feaff6dac2915919347b0559c381477b3d89", + "0x98787f0a2fac2b04bb7aa247ac77236bbe690aae64203e553be328a2c3bffb772e7a0244e585d27558cc64b089a5ee11", + "0xa14501d8b6b3a84b13b9006d521667e8d168f642ebf154c4e90ec8c75d11985fd0c9d86fc2efa6c7077dafecfdf0ab13", + "0x8215dee75eed04de83a3e910129bee8c48ce01cf1317ea477ff35c09a6f9e9771a8b05aa79e6b0f3e71b9874695e7a2a", + "0x85763c3072c7400a2c5668ef5cc53e6f4b8dff474146028a8be370ca9d8af9bf9ee10cd7d23d33eb6d6e257dd3af38d6", + "0x91bf62245c5a59d514d39bfb74db7f72ca7160c1c5d5be3844fff37e53e99d451e18a6747c65e33f98f48a55f38962c6", + "0x8c68817c6a6ea348d9aedce99929371c440fbad72718c2d239ffcaebb26ecc8a4e8c38c2819d945fdb7f02ffda70a5e0", + "0xa96ce2745866a22267a49faa7ea00ebf009ea8d0b0ca2c233c62759b9d5514306b5822dd2eee0124c9e28380e2f97aa4", + "0x8b18d5757c73843dcd55f0f0dc894bcd17e0ecf4c9fd901eacd38480844a15b4ce5e9598ccee039f9d93185137630cdb", + "0xa5b45c403b6735aaae14389bcee23ca10571f5437f1f5ab0c2b4e573dfd3341c638fff2cc780166af96b118d47ff2299", + "0xac849a0ccd354dd46bf55ea837d509b4ae3eefcbd5b8eb2582d301fd56c27b89950c6eefdd4e98e608ef4a6b75251311", + "0x89f13ac14bb064e9c6b49a482831ecea6344faec490bd18bb44028b83a0f22e21145861558029bd172ba7c5247c2cba7", + "0xaa57b057a2ac32c101e442c33831630c81b2e061a542e3e1d6897b2b7ca8a7241ef717a548b3f751d60d89be384ba5da", + "0x8a43db4e12682b98230364f25c75b49002f5002bd72a1674cf2a9d53197b5ef1b95e48429af98af503b0d5c3e0e017b2", + "0xa10cd7b8e1574d78c4e917cf833d3d845b878e8e8b60312e6a994bd4f391a5e8c38dcd774087b93c9241238f43f80937", + "0x8b61ccb949088286216cd628811df1a362a7f5c333654ce823e63ebd04b069d5b0f627fb6c96d54c7b853de8aab05472", + "0x887b902020ad45f70f2d5bcfa7324fcbe7be09fd2b1bd40f9ae43a89d487986e89867aee0945ea6a0fe8dfd051ffec56", + "0x822fcd260a7876cad31f54987053aab06108de336878b91b7a15d35013d6d4d6de2d4b30397bb6f1d5c1a7b48e9d1ced", + "0x80b89ff95d725858b50e84d825ea99fb6a8866f10b91a5d364671ccbb89cb292bada9537c30dbde56b989c8bdc355baa", + "0xb53cab156006c3a1766a57dd8013f4563a2e8250995dbeda99c5286a447618e8ac33ebf25704b9245266e009a0712dc5", + "0xb6e2da9c1156e68c15861a05cd572976b21773e60fc5f2f58c93f3e19c73ad6c2ee3239e6cb4654040c8e15df75a505d", + "0x8b7e187d473a0bd0b493adcdb91ca07c9310fd915dec46c2c9f36a5144eb7425dd35dfa50feb0e9ef747caed9f199944", + "0x9743ec3917e953e0a420406b53f4daa433adf4ad686207e9f296e7c83d1ffdbf81191b920ba635c85416e580178c16ff", + "0x98d1476fd4504a347c5261012298ca69c8593fec91919d37ddfdf84155b6f1c600cd8dbb92b93f3262da16cf40a0b3c6", + "0x94f50d52982a3c81ac47a7b3032dad505b4e556804f8606d63d821f2c1a4830917614630d943642ba375b30409546385", + "0xb5c0eb5f4cf3f719be1a9ad0103349269e8b798dbffe1b5b132370b9de1188a6d71dcbc3635dfdb4b888400f790b6ea4", + "0xb47fb45ec73392598866d27994c2feb0b0f3d7fc54303a2090757a64b6426d183ae41af16794ced349ede98b9b3fd48c", + "0xb5f45fd0aee6194dd207e11881694191e7538b830bfe10a9666493ae8b971d65bc72214a4d483de17c2530d24687d666", + "0xa50c149ea189387740d717290064a776e2af277deafcf5f0115bbbdc73c0840d630965a4e0214b738d1cb0d75737e822", + "0xb941afc772043928c62e5dbe5aa563fa29882bff9b5811673f72286ac04fddf9a9ed0f9faf348268fa593a57bc00ba6b", + "0x839051a7838937270bdf2f8990fd9aa7d72bfc86cffe0b057aa8eca7393abf16b70d71a6470d877f8ec6771efa5a8f26", + "0x835bc9d049418ab24dd1cbf76ed5811381e2f0b04035f15943327771f574f723b07c2b61a67a6f9ddc1a6a20b01f990d", + "0x8935cf5634d6ae7b21c797a7d56675e50f9d50240cb2461056632420f7f466fdcd944a777437dcb3342841ad4c3834bf", + "0xb5698fe3da1f9d1e176c9919fddd0d4d7376106774aa23a7a699f631566318d59b74ae8c033eba04d06f8cdcb4edbbed", + "0xad11421ba75d74c600e220f4bce2ca7eacb28e082b993b4368d91218e7b96029acfbdf15a2ab0b8133b7c8027b3c785b", + "0x886ef813644599051dafdaa65363795cf34a3009933c469bd66a676fdd47fc0d590c401cc2686d1ba61fce0f693426d4", + "0x8858fdf3e98e36d644257ab6076f7956f2e7eacc8530ec1da7f3e9001036cba7a0855fb5011925cdc95a69600de58b2d", + "0xb59eca7085a2f6dfeaa6a414b5216ff0160fbea28c0e2ad4f4ffd3d388e1cc2c23a32dbe517648221b75a92500af85e3", + "0xabec62d259bcd65b31892badad4ac8d2088366d9591cd0dab408a9b70ad517db39c2ef5df52348ba4334dce06a4e3ba5", + "0xa9acfe8f5a310779509621ed2946166ffb6168e68ecf6d5a3b2f6008df1728c8fceb811636c50d2e419b642a848a9ca9", + "0x9929bb1a3537362848fac3f1bcb7cfb503dac0a0b1bebbfd6ddf14c9a73731e2248cbaf0fbb16c7d9c40cc6737c3a555", + "0x981d06c7431e6f4654e32f1c5b27e7be89e7c38d59c4e2a872a0f0934cb852c6aeff2d2eaee8302131795590b8913f5e", + "0xa6ba9dd43354320f65fd5cdd5446cfa40080bcf3ef4a083a76ad4e6a609b0b088bcf26c4957bfab829dca6064410ca5f", + "0x9367ef28def311c79adfd87e617651fcc41ad8caf047d73ce9a1f327e8871e9b35d5b203fd0c0138e32e2ef91e20ba62", + "0x855d1bb508a9036f42116c8bbb830c576189798baee27c7c3477ef1b1fc5d7b0c2c7203457f1eb48d4b029dd6f646be2", + "0x8539a5d0528d3d601083e162b34cb33b5bf6736b4feeeab4941f10eea127c56b7e0b8d57f34b72f8f674d89c10bf302c", + "0xa3b71a9a9ac2dfcd681bfd8f6a5d9abf5df6950821705bdfb19db25f80d9b8a89fac7a922541cc681325679c629743d2", + "0x8e95929dfd4e5b56e5a8882aad6b7e783337e39055a228b36022646a13a853d574603de5fed12b6c1f2585621ead7afd", + "0x8b05c885575d6894cb67ba737db5915639a6f281bf249480df444ff9f02724e28ed7371ee7ec26d50d25f3966010f763", + "0x90f1a45de0cc0641181d54ee86630b5d182d24e7c30c2615803f16de90ec7c982a00b21f250ccebc2e94ef53a13e77e6", + "0x90f0e97a132092e51a4521c2ecaaa47e4e4f319e67a3cdbd00ed85c2f10dfb69c339bc9498e2abbffcd54b1fdc509a20", + "0xa9995234520cab9d1bdec1897b0b67571b718d5021c0fcf913140206b50ab515273b5f8a77e88fe96f718c80dd9be048", + "0xaebc6495d54d0e45a3c74388891dbcfab767f574fed0581566415af872dc5b3bd5d808c44f6e1fbdde7aa9ffd260b035", + "0xae757f8f4b1000a623a7d8e337a50c3681544520683207e09d05e08a6f39384b7aaadf72018e88b401e4a7bb636f6483", + "0xa626a28d5ce144cc0c6a30b90ec2c1412cbbc464ee96ac49035e5b3a37bb3e4ed74e8934c489b4563f2f7db1caf8b2ad", + "0x8c994e81dfd7a5c2f9d4425636611d5dd72d0b091a5862f8bec609d0cdd3c423eb95b0c999c48faa5dbb31e510c22b61", + "0xa1c0e59e076b908de760d9becff24883c6eb9f968eac356e719c75cce481f2f7bcb1a41ed983a00c1a3b9369a7ff18f9", + "0x8d7e199044fe2e552bc514668fe8171c3416515f7a5019f239c0384f0ade349e88df26cd30f6b67d02b83bf005d85de8", + "0x80190f2255199be690fb502d02ed159aa568c390a684f7840512efc3d2a62f28a49d5d1928ad99a5f975ad81a245acd5", + "0x889d84cefef33f5714e14d558f41d406072ba66b427bf27918b669c5be46261c3de0139610a2c2eadef8e6508e937bcb", + "0xa480a686d5085b854ccf9e261e7f1f2d40d978fc30b62b1a8fa9561127745529405820df21a680ee2258b8cefa5f0201", + "0xae6243400d416a8c13b80b6637726959ef07b8d9b6aff2bd3bb23aaaf97337c7a6b466c5db617bf2798e01d4ccc68e4d", + "0x85e0ff143657e465f3d934ee781de5cbd2bfd24f2fbbe6d65c698cdd93204a845f6ef1fa8941c2578463a06a8a418481", + "0x8f4f8b45f1a9f6c2a711776db70f20149dd6d0e28d125906ba9893c5e74e31c195b0906f04c922c8b556ced7cd3d611d", + "0x877b852c33483b25c4cd8da74b6b589d8aa96e217c3c4d813466c77ef83af95a94a47364aa8421f0396ce631ad87d543", + "0x852cb06bc4222ce125287a7a55a79ad0bf55596f26830dd6d79da3c60f80e3ba7b9a9b42b126dcb99d2cb9ce142783ef", + "0x810cd64c1dfce85d509eeb57a5c84efafe1d671454ef601a040de8d46fb33bc419577f6a6c404e28ffdfe315ffec558a", + "0xb60ff8bc804d101a32079b8ed52285fdbb47fd60c3c15cef17cfe7f6b0567de6b50128b9dbc49a1d9811b62b22c99143", + "0xa9df7068b26a6a58f7a499e67b17d34f2a2e8e5029c6e51e2b4c0d19324fb5cd9734c4c4d5034e1bfc274cd0c74a82d0", + "0xad93c50802ded1e21217a58b874c074ea52322492d589820691572084d8edaede8c2ce8021c6df8c0060f395f3c25ee8", + "0xa17b98e090f7ef5800477132b436c1fccc1802f34956711bfc176e36890c7df95a108e03f34659142434cbd8aee9dccd", + "0xacb14aea5575c293dc0a2b58c5350390801d57e9bcda876d87c56565043ddde1a544a88b48ad0d8ec3d41f690aef801e", + "0x88b8e26cbc83faa053fa247e26c95d1bbb77955b336e1b0e41d080633248238de8adc9b98688c98fdfc67e7286bc5be4", + "0x899f69823cf1b2204c8da91bb4f943c04d943137b08b1c46e160919e3378bd22a666a079a66e63d81c05336c742efdd2", + "0x8d7ffbc0b47a32408c9e88676ac4f87683cf37c37d214163ca630aec2d3cc014d88caff35022ff3b6d036eb8343d52a3", + "0xb7760f27db0704a6742855998a0c31333bb34d60ddebc95588e25b72445ae2030427aab088ec023f94563118980f3b74", + "0xad06ecc0f3745861c266bf93f00b30d41ed89d41e99ab63fedd795c970d3ad40560e57ab7333883a72e5575a059df39c", + "0x8687d28b1cbc8aa34a0e5dbdb540a517da9bda36160daaa7801fce99754f5d16eda3bc8e1df6b0722cfb49e177e9bcb6", + "0xa38332c3ebbd7f734c8e6ab23ae9756f47afbf7d1786fe45daebc8d7d005d6d8fd22f5dbd0fa8741e1bfb2014d3f9df7", + "0xb86f84426dee88188be9c5cc10a41599e53b7733ba6f2402392b0ea985effc7525756ca1b7b92041ae323337618b238f", + "0x958731a6f1881f652d340832728bc7fadd1acebd8daebd772b5acea634e9f7b7254b76d38a7065ea1b2cdea83b18a54f", + "0xadb90bff1f0d7d45b8ba28b536c0e0f7f4dc4b9a0354692ecf29539631d7a57d308db3e438e0f907810234c490b42153", + "0xa5188c775ad76617d3bb6e7f1f3b2449f48b7bb7a84035c316284396529564a227e3b9762a89c7114fa47b3ca7ba418a", + "0xa3826ef63c98793a5c8c5d5159e2e00cc85fb5e5124f06421b165de68c9495e93c2f23cd446adf6e6528967aa3ed3909", + "0x80eab97de89f3824ace5565b540b229adcc6ef9d2940e90de185af309234cd8aa4ae9c7ce1b409b3898c8fd10c8c2896", + "0x8824f5acd4c2330c459fdb9ece9313263a8b20419f50f8d49958dc21754c21a77bcf7fbf3e0041f78d8fb667a3342188", + "0x95091cf06911a997a09b643326c2fadbbe302555ab2521db806a762a5f4492636507ca71d7a093840236ac3c096614f7", + "0xa392c81a546196d7e78b61f3ceaadfb2771d09fe43f862c0af65f5e55ce490a0293b9ab754cb5ab03ff642a9a8213a23", + "0xafd76cce1dfa2c9e4af4f840376674f090af37d8c6541824963373f97b9dd1f405c50b2ff56165e1d4dde760e590738a", + "0x8fc4f513d3b40c10872603e1c29a4b2cf4c99320962644ce89f69ffb57f844344e1d472b2d43559119bdfb5a2c21749a", + "0x9951ca8e13b9a2b4a789e851c04c4f030470772da62f101074ef304612e9653b43b37d2c081b5d0a09196b3a167f5871", + "0xb4f16fc2a113403ab5fc1b6a9afddec77be7406413b70ee126f0e84796168a572940550d61e443e5635591d4b6c46ca9", + "0x8d71452cf39e7345c7298d514b9638a5cbe78af7652f0286d42632c5c6d7953ed284551fb40c77569a7721413cdbf79c", + "0x953625b58d52a308cb00ad87c44a3fd936786ada44000d45bb609ea9db6b156a0d0f9475e13ee5e053eaded19a09990a", + "0xa0983a3baa278ad5f5de734eb1b65a04f668408994e396fb0b054991ad2e56e27ac522b04fe37c9583b754e344f795b3", + "0x8eaa454257f77a6754b2c1c5ff0036fa5b03e214576fabc657902c737fcbf298b1795b43c5006e18894f951f5f7cd203", + "0x90183fdeae2ce2a295a567fa61b997b1f975d1be7b03d0101728cd707bb2a7111c222588ab22e573518fa1ef03719f54", + "0x8abec7f31f6b897a1d497368a42733a6bd14ffbb8b21d3e49fc4cd3c802da70e8886827c1aea0b18d1b44635f81ec461", + "0xa6d1e6fd24b0878ff264b725662e489451c590b2aadaf357d64210a3701fe763f529826fa6e0555267c1f5ecc2c52c05", + "0x8fe6d2a4ea0d91702cb2a8a1d802f5598f26d892f1a929ff056d2b928821e4b172c1c1c0505aa245813fe67074cf9834", + "0x82a026a408003583036f16268113ca6067ce13e89c6e9af0a760f4b2481851c62fadeeef0d361f51dcd9fa5674ec5750", + "0xa489a574b862d4056091ef630e089c163c16c2f104d95eb79a27ae1e898b26d6c1adc23edc1490f73bb545d3a6e3b348", + "0x939d85148547fc7b9894497841bd4430bc670bb670f0efeac424b529a9aebf2c02ac18a9d1402a12e4e590d623de09f0", + "0xa3ab52cf911a2ba7fb0cd242d7778ec0d4fa382960c9bd5b476bb1cd44ff1430a3871bbbcea0a0db2630c39ee639fd1e", + "0xb7629509d8c3a3b88b31f1af137a25c38f536284f11a5bbbe0d05b86a86bc92ebbf70f17c256dc8b0d48374e1985e6f3", + "0x8a8647ff33e0747dd6c6ceddcf7938a542656174a08a31b08337ea49b08d814e75f8363fb51676a2cd2746569e3bc14e", + "0xa7a7f8d94d32b7cee00b3ff272d644b8dca86b8da38c726f632c2bcdfa0afb13fd0a9a5685ddaeb6073df4d9cfa3d878", + "0xb7136eea8d05bfee2265b0e9addb4bdf060270894de30d593627891584b9446b363973de334b6105e0495cf8cb98e8f7", + "0xa9fcd33ea59315ad7611a3e87e8d1fd6730c8cbeeaebd254e4d59ed7d92c97670303a2d22e881ab16c58779331837529", + "0x965fd41741a0d898c2f2048945b2aefc49c735228c25deaf17fed82c4d52cf3f8e93b3fb8825ade632dc4940311b1542", + "0xb9f400a2c7ca7da8b36470ee5d26c672b529b98e6582012cbfc2a3c24b72e73f5633de4265c417c0d47c474155a603c6", + "0x85f333b0b1630a688a385f48bf0175cd13ecdd92fa5499494f4ad5aea0ef1b9d180fad8f936018538d842630ff72884c", + "0x8da95a735a1a98ed8e563099bd87d13a237dd7ec6880cfac56c6416b001e983a56f3d72dda7f68684bb33e4f64cadd30", + "0xa29b66a2095e1acce751f6aec8dfeae1e5b24187dfedb5d1635ca8deae19b580ef09329a18b3385ebb117cd71671f4dd", + "0xb001deeeaf5eaf99ac558c60677b667b9f3d57cf43a2c4d57fd74b125a6da72ea6c9dc81b110655e0df01ca7b8a7a7ed", + "0x912e11dfff77c778969836d5029747b494dd81d9f965f8be2c9db9e8b08f53858eface81862c3ee6a9aa10993d0d23f3", + "0xac166a00e9793cf86753aa002ca274cb6f62328869fe920f5632a69a5d30d8d3ce3f0c5487cb354165763ca41d83495a", + "0xb74df519ae1a8faeff2ccd29892886b327c7434360ab5c5355752667069a77d466a48cb57b1950d10b6c47c88b2a8538", + "0x8751679aeffa39da55f2c2a668f7b26fb8258f70c5454b13e2483e3ad452f3ac7cc4fa075783e72b4a121cd69936c176", + "0xae0cc16848b8bf8fffbb44047d6f1d32b52b19d3551d443a39fb25976a89d1a5d2909a4fc42ee81a98ad09d896bd90a9", + "0xa0c8acd6a2f0d4ab0e0a680fa4a67b076bbbf42b9ec512eb04be05fb2625f6d2ed7b4349eebe61eb9f7bd4f85e9de7fa", + "0x85c629ce0deeb75c18a3b1b4e14577b5666cf25453a89d27f1029a2984133a2b8e7766597e2ff9ee26a65649b816b650", + "0x938dbb477840d3ed27f903d09fd9959f6fec443fbc93324bc28300dd29e602bd3861fd29508da0dfdbb0fff7f09c5a6c", + "0xa7c76cd4a42ab7904d036fe6637471d9836ad15d0d26a07b1803b7fb8988b8c9edf522e0d337a1852131d0f658565ae7", + "0x838a30260cf341ae0cd7a9df84cbc36354c6bc7b8f50c95d154453c9e8ec5435d5f9b23de2a5d91b55adde3dbdb755b9", + "0x8f870b1f798c0516b679273c583c266c2020b8dea7e68be4b0628b85059d49e5a680709c3d6caabe767a0f03975c4626", + "0x89bad0b6499d671b362ae898fee34ad285aa8c77d33ca1d66e8f85b5d637bbd7ae2145caae7d9f47e94c25e9d16b8c4f", + "0xaf963d3dd3d983864c54b0ed1429c52b466383f07a1504215bbf998c071a099a3a1deb08d94b54630ac76d1d40cfc3da", + "0xb5686de207c3d60d4dcfe6a109c0b2f343ed1eb785941301b827b8c07a8f1311e481a56a4baab88edb3ddc4dace6a66a", + "0x95e5978739a3e875e76d927f7c68bdf7ab20966db9fa8859f46a837760dfe529afa9a371a184dfb89d2962c95d5fcf3b", + "0x96d2855e20c37ed7bd7f736e11cfba5f61bb78a68303a7ced418c4c29a889a4798c5680be721a46d548d63525637e6b0", + "0xb134bceb776cd5866e911f8e96016704c9a3caeadcabd7c0f37204497d789bc949e41b93e4c2d597e4c924853f1b21e3", + "0xa1949ff397013acde0303e5d64432bf6dd7f01caa03c5fc38e7c8ae705b9d5c2646b4b02d013004e5eb58e344703260c", + "0x8036a5f79d8aeb6df4810974cf8dbd0ac778906d2f82b969ac9dcfbe7ece832a7e8aad08a4dc520f7abeb24b1610ae84", + "0x982b6b0af8602a992c389232b525d4239edc3ae6ceea77d7729d1fffc829664dd647ff91c4cb9c7f7c25cea507f03167", + "0xb34c7d24fa56ab6acdb8af5b4fa694a1985a1741cc53a2b0c5833611e8ed6fb3b663a4d9a126bb4a1a469f2072199d66", + "0x8166366fec4ee2b3eda097dc200cdfa0533a742dfbe7082dfa14c1c1ecafc9d9fa71f518476634f29d06430869bd5e02", + "0x86c0251ac00b8200618c8b7ce696d1e88c587f91e38580b2d6ae48a3ef904e0ba1b20b7f432719ca40e7995f2281a696", + "0xafd89f3bc7843a1e45ac961e49c1971114c5238d9e21647804b1852b8f476a89c12d1edfb97fff71445e879d6bfd3b70", + "0x911d8bec4d4c3e73a2c35469b2167569f59705404425bd95440408fb788e122f96e9b1bd695f35c6b090f10135b20cd3", + "0xb3f6350ff7afaa0660f9dddd9559db7f164e89351a743fc695d987c88f89fc29136e3c5eb81963edabf2b6f2057120be", + "0xa371229680d1468777862e9c0e864156f9cd7c12ce7313a8de67b7bd34e3d1b6fa45ce891a81f8316f4afcbdecf3b6ca", + "0xa6a9a875ef9efe8ba72523e645b5773aa62c4fb41efd23da3fa38105472308b8d293be766342ee0a2f00758825bd3b6a", + "0xa840d495a184f4499b944ee08f07193a1e1bb8ab21f8ce7aa51d03bd8643f2bc2616c17b68d3fe7c0fb364136926a166", + "0xb55200ae7d6ebb0b04b748051c5907293184b126cf8a1c2f357e024f1a63220b573e2875df83d9b5e0c6e2ace9300c40", + "0xb1e0870f2e3719f42a48256ee58cc27f613308680f2d3645c0f6db0187042dddcfed0cb545423a1a0b851b3a16146d70", + "0xb43a22ff3f838ad43786dc120b7f89a399ed432c7d3aa4e2062ad4152021b6fa01d41b7698da596d6452570c49a62062", + "0x88b1dc50873564560affaa277b1c9d955aebdcdd4117dab1973306893b0e3f090899210102e7e1eef6f7cdf2f4e0e5db", + "0x9223c6246aa320b1b36eb1e28b5f9ccc2977e847850964f9762c7559da9546e508503050e5566ccb67262d570162b7a3", + "0xaeeed21b932752709f43dc0c2c7d27d20263b96a54175dd675677a40a093f02bba80e2e65afe3eb22732a7617bf4ff9d", + "0xb47cae580ae84f4e4303db8f684f559382f075ef6e95698b9a629e92b67bf004f64e7cf47e401768fa170c4259efbda1", + "0x849821e1ead81fe2dc49cd59f2bba305578c4ea0e8f4b8ae8fc275a1c4a6192f8819d5b6d7da786c94dfc16aacf3e236", + "0x8c60d9a8baefc72a3d3f9dd2e24cca40fb5ce36b19d075122391d9b371c904a0a15d2196c0f2ac9da3acf188d15b0fe8", + "0x946edfe168bbe5ddb0fa6c2890bb227d8418bfbebe2bafab84909825484f799407b610d8aab6a900c5ff9eb796cdc4bf", + "0xae7bf8ae71de5d7ea644d9541e49da1ec31eca6ff4c3fbec5480d30e07ef2c2046cc0a486af7b3615a6a908846341e99", + "0xb4d31a6f578463c9a5ccde0ea526c95b1981eb79468665395c0e550829abfdfa86689699d57830856e324092a423f231", + "0x93415ad3a732417cca9771b056ed42db7ce50879aca7c6f71883ad297eaf5a37fd4641d44a0b7e28b90c168834141340", + "0x98960617a413a3ba86d8257a7386355a69258943aa71834166bd624ea93b0af06178e86538e237f88fd039eacf7cb04a", + "0x881335200a487545e38d5b1ffda3080caf5729e1b980603bcdf9ea652cea7848335b83aeeaa321d3476ae4a8d9073582", + "0xb39e84c14666d51895b7a8341fd8319f9e0a58b2a50fc3d7925cce3037f7c75367b5fb5bf25ff4720c9992cab7b8b9f4", + "0x8ea4bab42ee3f0772d6bd24dff3643d8b61147b46ada374414d8d35c0c340e458e449d31023d96e66decf9c58e30cc34", + "0xa5198f6759a045b6a4ba28e4bc3bb638fad44c5a139064327580e285adf38ea82a7570acebf925e81a39d9025f3a6f2e", + "0x80267097e2d27c1b19ecf95d184dcff822d34e03326b9fc139a4f8b75b3f80777bb97a9dd284d9b755f14dd401d63c0e", + "0x946f346220bd3b6f733e94b61a1ad0b44e45c356fa6036dde5882d93b5613c98e23b20e91eddc6b3c5acea38085705af", + "0xa5f559e110cad99bbcae2d9362434aee7db0f3b6d72311291649dbda3f84c10e9760b66b988db3d30067bf18ae2e5238", + "0x8433b38e5c7b293ef532f8c70cef1ed9be7f31f60d5b532e65df7d2885203be78b7ad78ab3011bc54cd9f64c789bf837", + "0xa5a4c0a9b0e0b6bb912cf6ecd30738b0acc0146d77442449b486c3f32d7e60244f643a5cf9cc6da2de5408d0c5f17691", + "0xa81feb329fb51b72464bddcfcf4e02149d995b548d88c64ba143144ce16b652c9913c8ee948ee837596ec97cc43d8cc9", + "0x88e5a7e93a738d61330425bc21ade88d33d7160d124bf174eb3e12a00283654431036977c4f1a47a1bbbf2ef8449ac89", + "0xac75ad7c099383069e662bfd3624b92b64b5838246902e167fc31b9411efda89b2c6bbd1d61b9eb7d304faacf438d70b", + "0x8583bcd1c7cb9bb4bb6bcff803b0a991912b8403a63c0d997761ff77295ccc357d0292318601a8c61329ab28fed7bb83", + "0xa1f9aa0523f1dff00023a44a6c3a9e4e123be0f6722a1c6682ac3c6047efe9e62f4773daf4767e854e1fcbf8ee7339e2", + "0x85f65ebcf5c7e574174b7c4c4166a9a5368e7986b8c0ef846c2e13b75dea7311a87483503149ebfb3cb839b3ef35c82d", + "0xabc55eeb72699031a367b9675a2b91a8434e1f01467660903ced43a0b2a11a85ebdf48f95c13ff67e4e2958065a50ff3", + "0xa4ff77c9b86939a15647499b9412417b984bfb051e5bf27b35392a258a5dac297bbdbcf753a4be6729ffb16be924a2ff", + "0xaf0d41c15b5172efa801cc85ed101b76844dcd06712d0d21160893235a2dbedd15d187a9b31cf0d0ca6c14de6ab2b707", + "0x92661339199f18e5dd9a210783c1d173a26dfa315bd99a33d6f04bf506c871a2b47745c1909faa209d5e6c5c645124a4", + "0xb35813dafb52df709dfa47982bfb44e1bf704f9f46085b2a0e92511dff90e5597110f614f8915830821fc5ed69ae0083", + "0x934a05aa713fa276a4d47f1a28ef06591e5a9a69293c1651c223174df0af4927fc9cd43d374d89c1b4f7c8dc91abe44b", + "0x8f83a0ef05202c0b7170ac96f880135e2256fdf8964dae5aed5dd0f6452a6d8e123321e8c182b3aa6f1f8ab767caa735", + "0xb92db10c21c321cf1349fd34129d7180e5088daf2bbe570de6427299aab68992c011c2e2939a44247396f5427c1d914a", + "0x95ce1892d1ce25ef2bc88a23880055a4d829a3b31f3806635fd49bec32cca4e965b129b6dd3e90f7e3a2eb293ffc548d", + "0x970cf816ee7501ade36b0b59f87c7e352957f67f1f75bbacd8ed52893f9fc40572c76f49c23db44866af7e34a63cd3f9", + "0xa2fcd08581d3569fff699fd7ed1ede5f98f2b95956ecdf975a29af053d9f4f42600b3616ad6161e958c3ce60139c20a4", + "0xb032688b6cc8a7e63dcb82694f71f087b1ee74c4d5fa27323b1ead3ba21722d7fc49eda765725b5553db5260005049c3", + "0xb0b79e4329f1ad25ef6a603390baf889757cab5af10bfa6953a61f89aaace0442b9ef08e57ba778f1e97bf22f16f0ace", + "0xa2e6ac06f8973266cd0df447f82cec16614df65174c756e07f513e2c19aa82c10d8670047860960cfba3c5e4c42768c8", + "0x811e66df0f3721a1ae0293549a0e3cd789f93fb6be2cab8e16015a6d52482af9057b1b75e9456322a5a9e87235e024cd", + "0x8744a80b3d9e37da4c50c536007981a4958d7e531cb93916dbf985cdc22f4ff482a5cc4fe50915c049d2de66530f1881", + "0xb20b6e8c7be654c23c8ca440be2c37cf9cc9f4e81feedfd0cd7c56f37eda8f295fe5d415e9bac93d5f0a237edd8bc465", + "0xb33fd84377f31f7819150d464b5eb3ef66e06cb8712665cf0587d61e1b1c121d11cc647f3753bbc18604941c77edbc1f", + "0x83acb8a3ec5f477b6d44cd49f9e091bc2bf7c9dfee876cde12075a7db9262314cb66ad2e7557114e0c19373e31c6eff1", + "0xacfe4172327832ee207eb07da9cd37da3b009c776f7a8290529f0249f58da213254baddc7c3074fbaa1d226ba1e52b7c", + "0x81911b4dea863424b9d77a981987732382702e0294d8c8e1ec48e89678ecb0e64836b45205a120885fa8f8a3a4b9d4b0", + "0xb11f61b1302579a11077bb2f1f0db371ab943573b261be288dc76172eee8a5102b992a5b526092d160ffd20aac2d4856", + "0xab491f7f1e002a44944c02537f365e525ebb6d5614bba8e5e8e8bd12064c702a1759571ddbeee592a0ba8b73cfce8810", + "0x89211da3d92aed6b111de001b8b5a9231a1c2d09fb1cd2618ec457b635a6c8590fe119acca42fce76dce791c35b889c7", + "0xa5f076c8f7164bcab8af59021ef97a0afa93d0877e52241c3ff5a9a9f81227a55c119ed6a84d34b196e94ec851ca5ca0", + "0x80d91417d0d6c1adb5a3708165da1d54a83caaff482a4f65abf3fb335cbbc738c74ed19a8c451ca98befdf9b2d8b5f90", + "0xaecba33a67f66401614eec5fa945e763da284edb9dc713bad4ac03972630781a09a3e2a291aac0605a9560c5f3444de5", + "0x8a0aa1320bf5217a049b02ad02a4f892bfd6a3f5b48f472041d12f3aaab8dd197307f144f9de5f9e762c6b4971a121b4", + "0xa4120a569e446fe4129f998e51f09c1cc7b29dc2b353d6f6f05daad1a4ef99acfcbaa4950a58aacf7ee1b3fde0af33d0", + "0xaff71370d58b145758a5f24cf3c0c6667d22a1f950b8137c369fa845a5265cd645b422f24fa95e1cd7db1d68686120b6", + "0xa839f075a8a702809a51fbc94595eab4f269a2e7a027aa1f4fc472e77f586138bf5aa4e5570a560e139eb6cda4cca161", + "0x9484f1caa3e35cda0e3d36e43aff3dd8cf45a5a51fc34aafa3a63ed3543047ba9d6af2a9bc7c201c028499e6b4c41b28", + "0x84ddb374c5c9170903bb3e1054fad071b0a147a9ca2ebe2fdb491ebb2431d53b398872a39cc385f973e38579d8e60158", + "0xacaad8babaeaeb52c5b5a16ae689fa5ae15846f2d1f3596a52371bd8681819603822ee8d32ab8cda1bd5290d601e483f", + "0x946b69ca5361b60c3dc31db13669b05e5c0452f3c80e7e185f9667a36f351e9ed83bcb5c6dd2439ecd4490e3a87d260a", + "0x99f457221ac40df86f9b4bef0bf8812720b2f7218273a0aab08c4d4d4fb18a0fb0ef6ba9bf7fa53c116cc6f16742e44f", + "0x8bc0e812d8b718dbe48ead74a6bc7bac68897d01d097422be04110a25589bacd50d336d2c8b70d0dfde6c1b8bc372dc3", + "0x895d118dae2fb35a4b0de22be0d000ec0f0f317b9494db7c12f10d7db81b6f3eaf6d6f3fdfe952f86ec4143d7469368d", + "0x893bf3d7e579e800526bc317438a69590d33759931830daf965cec721baa793ea335e9624a86b84b8fed5effc3e2bbac", + "0xa112d30dda88c749ca15d6dc65bcbc7fe838b2d25329d44410a9a96db195c7ce6a6921196a61ba7c9d40efdb101a164d", + "0xb88b5340af052fc3b8e1a8cf7532206801e79d878f1fb02b32ac4f8e91b64e0ec9252d808b87c4579de15886a20aaef1", + "0x865f76475bb5da18c6a078c720c7b718e55d310876c98017c30ac31882ae347258b508ec34001918324250241d2df5b7", + "0xb6d8a15913eb1714061d5cacbd0bb05edd83ecdb848a89b864e7411598e9f7814d0c039ebe4735437c8370d2ff183751", + "0xa95fedce8351ae9c24d7fa06ebc5cd4e3aef87afaf04a7150e561a6a7f2347bdcec1e56b82d6e5f597fe7124f6cc503b", + "0x8526004ca0c802b073d50b0902ea69975949e7567b2e59ca2cf420bc53d91951d26096f2abb07a2955a51506e86488dd", + "0x99ccecaab68b6e5adadb9c848cb577de7e7ff4afc48d3b6b73bc0872730245b8a1c68cebf467074af6756d6226f4f4a7", + "0xb5497d5c0cd79b7e6022e295642e1f2161254379eb78ef45e47f02c84ef5a3f6b6297718e4fac8093bf017287e456917", + "0xb6943f30012b2093c351413c2b1b648afc14a5c4c0c338179d497e908451d2779919fe806181452ed386c1e8f8e8c25c", + "0xafdb56ce89bcd3247876c918cad68aad8da65d03c7c73ccbee0c4c39f3ad615aab87ffa0db5b3b63b4cc915d0b66deb7", + "0xa44659d7be2f11d4d4949571d7bf84a6f27f874d3281edc34ef1098d321a4dcad9a42632b39633f8f9d20a39f54a2464", + "0xa3e489b4db5832280dd58c62120262471b6fb4355c2ad307bd17c5c246b3f1e1b00f925930f5f5f6987de234fcbb7d16", + "0x87a4e3a190340ed4949597703083d338e9c17263ba8a39b67100589f0dddbc420d9557f9522c17c71ae04b76876f8db0", + "0xa35a3978e928eaac8c182a0a613c611ae7b4827c5e999f938eed06921c0294befdc21d02e68d035a2fc8d03c82641126", + "0xa6898d90265dcf0fb215629f04b07c7918e022667583efe0bfe02f258b446954876c6ca9e369ffe1bb079e2314ebda32", + "0x922fc52e648b6b2b6768c079c67ab425da72907a46add801715f8a2537280869d7071d527b833aa63ef562ce059a392b", + "0x8acbb7c4297196d8d1c131040c34cc7064656a148c2110b19c672abb094b1d084fafe967f7122ba9dd1523a4eaec3b42", + "0x82dbf2cdd581fe3b81b156792228eae2485710e6c21dd5fd14614dc341bb0afbebbc0f32340eda9f094b630afcfc17e8", + "0x907a095dca885da219e4558e9251ec765cf616e995c61546bc010963bf26f2d8adbd9b2ef61f2036e1740a627c20fbed", + "0xa7a83f849691d04640137989a2d0c90a7ed42a42b0ad328435d7e1fba557a27a58eec9170ab3d0099ec97da0c950765a", + "0xb7d435a801c2a5652cb479027f2c172eafa3df8ca0d896bbb9d49a42c42660fb382a8439bfed09ddf7e0214cb6066761", + "0x8bc6b5e79af5512589f90de8e69bc858277055cf7243f592cc4edd193f03f71d16c9300097ddafb79752c63f135c884c", + "0x913264fca800467bee58a429e1f245ef303f5dbeea90f0ce6bb3c7ae6d1bd0f99ea75d3d309634684d2178642c81b5d8", + "0x83ba558f9c23b785a123027c52924a1d7334c853a6165d4f5afd093b0b41951a36860ba0a20fa68f73d7db9df0e3ef38", + "0x875b2df7cb54ecdf7ba31181b9dc7dbe02761ab8ffb61757d42a735c8e20d44bad5b904e76dcec6bb44883fdb9f4ad84", + "0xaf3dc5d2dd29565de8f4c700d5f1ab71dadb4351f06e9ee2eb5ee7a9b5da827d0c6726c6dc780748a26aa3b4d10e6c2d", + "0xa113ff09296b25f550f6d0d3f37dd4517b14cf6d5517293bd3068aa3aea765a8640fcd4bf0ba96db5c00167267fbd574", + "0xa138c5cca485b9180ef091c9e327982bea203c165cb83564f416c36e813bea1ef1f6345f57c8a591df360541b7b758f5", + "0x85793441e917ed520d41dda6e762269fb9f9702e5ef83cee3e90652d324536bf4233425cd05b54a383609076ab84ea13", + "0xb422ac9de53d329e6321a8544c264d63cffc37965d627d7e180a999c3332644e21fedf10cd2f43cf6ba4fc542db91155", + "0xa85d31d4bfa583a493681e57bfccca677ec5b85870a53de37f7be7833b573f8c8dcf029cea4ae548d83048030d77d56d", + "0xab8a0702a371db496715a4ee8fcb6d430641b0f666d7fe3ef80c09df0bf570293cec1aa1675381c6bbd9ecc1f7cdccf9", + "0xb308ef2b87438d35957191294782e9f5014a3394fadad3e2ccaf6ebf20fd889a36dbb8ddb3634baa8e2e131618aa4e70", + "0x919e972e5b67cd65f377e937d67c27b4dd6fd42cfe394a34a70e8c253a1922f62ff36b9dcc7fbbc29b0960ad6a7fde88", + "0xa0e4d4be28301af38a910971c8391ef3ec822ce35757226a7fd96955cd79afa14accba484ef4e7073e46b4b240a5863f", + "0x9422f6d424c1736b4b9bb9762aa62944085e8662c4460319dac4877b1e705aa5cd8b6b3a91268363ec3857c185685f4b", + "0xb7cf9f2053119d284a37df4e4489b632594df64e5dc846652ee26b4715e352e6333118b125021481138e4ec3e9f9987b", + "0xaea983e81c823472df8652654be8a60a8bf40147d599f87e323397f06bf88c98e9c6db0f28414f6ea4091f3eb0f6a96d", + "0xaa20bf03cd8b6ffda09fe0ef693fc0aaa3bb372603e786700e52063a4f7ee742771c41cf5e67e6248f99b7fc73f68dbf", + "0x8748a4978198071d7d5ddc08f8c8f0675d895dc19df0889e70bd86d44c469c719b93f6526c7e7e916c7bfeb9a1379aaf", + "0xb8fcd863d55dab2f7b1c93844306e00056ba17338ddfa3f02689a0b58b30239beb687b64c79b8420ecea8d0d082d9ffa", + "0xabb1a35952dc8a74dd1cdbc8ae7294c6bfd1910edab6f05c879e9ed06c636a949fe0017ec67f8f6f73effcb5817cccae", + "0x8bef43422b1c59e354b7f46c08a8eb78e26c4d01c236a4fe781cefb7465293a4444f2bdc68c6a221cd585a2494d9a1d7", + "0x93527258940feff61befa18fcd6626fcff019d34a3ac8c6886599cbef75b15c15d689e8c1bd2177cc93c4c1792dee8d7", + "0xb7f114eea99c8278841180ec8886ad2bab1826554a1657b9eeb17aa815f31b59c3931913ddec40aa9923bc92f8975635", + "0x91a96446158b194a0a6ada2e37c8a45f3017c34034f757245f6f3b98c65d39d084e74d2a9dc271e5918faa53990ec63f", + "0xaea4ada0a853753db03f9790e20bab80d106f9b09e950f09aeaba5d869f0173bed673b866a96d6b0dd8123a539caac9a", + "0xb8e3e98ff0d3e512441e008a4a6783233045a4639e0c215c81984846b43ff98de99d7925cf717b1ca644f6229b6d16a2", + "0x8987ef81a75213894e11e0310e8ba60fe06e2b264cc61655e5b51bf41cc8c3d6c10696642ea3517770f93be360207621", + "0x8d4eff7335252f74af4a619c78625fd245df640f2086338dbb6c26b059f83fe70f3e81f5b6c12d62c0f784e572d56865", + "0xa56f6389b0bac338f20c615d7d11e16045a76cbea23ced0a9d9067f538421c378200bfd4523b7c96094ab67f47f98d42", + "0x83f5ab0727fd6ce8b3370ce3fac1f3a9c1930ea7ebbd16be61cc26f34aa1291ba4b5f16729d7d4f5924eaa4a1e31a04e", + "0x8cc62366874bf8751067a526ea32927584cef41174e2ec5a53079ee557067bc282f372b831cb2547c5e21a2f178c91b4", + "0xb609e141006dc8d8649457efc03f8710d49abb34bc26a33ed4e173e51b85d7acdf18d74aed161b074f679d88f5aa2bf3", + "0x873c7aa784c17b678443320950e494250baff8766db42619b9fc7ec4c3afa4eee290cd1f822b925d5b9e55c9cdd1af2f", + "0x859ba787f052d3665481c3dd58159ec8c238d918fb6d2787ebe275ef9acd377cb7aaa03a69820c78247bf51afee3d5bf", + "0x8eb1e6d2b0f51a3275b4a8be96957cb2d518b32c815dc0dfd5f75340c7dee73e5edc45db7c7d375c4ffaf8c59767d0c1", + "0x85f3876ff5edbb826a9592e68db3dcc975725bfdda4fcac197758a8b27e4f493e6c531b1342ba0f5a75f965273720345", + "0x8a1272f2678d4ba57e76c8758818965e6849971e8296b60ff85a522feeaaa3d23d3696c040d8bdaf1b380db392e988aa", + "0x85002b31ce31be7cc8757141a59a7cf9228b83144993d325b2241f5bfac09a02aca0c336307257f1a978c0bbf79fa4fe", + "0xb96bd26a6bbbc705c640285fd561943ef659fca73f25e8bf28cfcd21195752b40359d0edca0adc252d6e1784da267197", + "0x936cfe367b83a798ab495b220f19cfe2e5bde1b879c8a130f84516ac07e3e3addcc791dc0e83a69c3afc225bed008542", + "0xb1302f36190e204efd9b1d720bfaec162fcbba1b30400669dbcdd6e302c8c28f8b58b8bbde10f4512467dd78ed70d5e0", + "0x8291b49f56259c8d6b4fd71525725dd1f35b87858606fc3fe7e048ac48b8a23ba3f0b1907b7c0d0c5ef6fa76cddc23f0", + "0x97aca69d8e88ed8d468d538f863e624f6aed86424c6b7a861e3f45c8bf47c03e7b15d35e01f7add0a4157af171d9360c", + "0xb590d896e6b6f2e4dcffebfa67fc087fa518a9c8cb0834a5668cabe44e5c2b6f248f309b9cd74779030e172dba5d9e29", + "0x97e7099bff654bcb37b051a3e8a5a7672d6ab7e93747a97b062fc7ae00c95deef51f5ced2966499217147058e00da4be", + "0x83435b739426f1b57f54ebad423939a68ad3d520db8ca5b7e28d1142ebfb4df93f418b180a6c226c0ca28fa0651163a0", + "0x946c9144d982837c4dbc0b59544bdbc9f57e7c9ef0c82a7ad8cfddea78dedc379dbc97af54ba3ac751d844842a2990a4", + "0x90ba1eff9c25adba8c3e6ef5b0d46c13de304632fec0646ee3a7bee69da2bc29e162dd3fb98a37ed1184ae5da359cf0a", + "0xb17b7a5c0a48eb9784efb5ff8499230b45efeb801cf68e13fe16d0d308511af5aa60e3b9a5610f96d7c2242ae57d455b", + "0x9991245e5617c4ea71575e5b2efe444f09cbbed13b130da08f8e9809d62512e8298a88d41f6aa3dbf3bcbc90654ceb18", + "0xa1190c4cbccf2898a7fe025afd03f8652973a11cef59775fb47d69a6b4dcb9a5a0c554070421a5e10a75e43b63d37b79", + "0x857c0a5f291eb35a76be11543a8c3d798187bd0717e2cdee50d390b66322d0d9529520fd3377136cdc93cfee99b6403f", + "0x944d11e5f9a3493c67786df94f129352d892fbdc43e98206b8dbf83cce240f65305e1768b38e5576048a31dca5c18f31", + "0x818f361c5dae709e067a82b81beffbd9674de8df2bc1bfc3a27ddf326260e124e46b1e36697fb8de539b7736db093e9e", + "0xb07f5b737735a0d628e7ac2d335080b769bdb3acea38ad121e247a6e4307916ba1d029da5d341f079ea61eeaf7d8554e", + "0xa69e338803f3ee0fbbddc7ee481a13f6b64d25d71bae0d76f4b5145b54923cf1616c77ba0fd9ca37a3ae47208f490423", + "0xacaee66b94e226622e28a144f93f6b1b442b9c79d7a8a1740c4d53044d0675a661e7453509b9e716e469fe11ce45ee31", + "0x9402ca799d2e1cce0317ed49453ee0b2669b05e68ff101b89306db215c3941b3786ad3402d00369cb1dee020b56d3142", + "0x849440c539fc0df3c8d06e23e271e6faa50234d5c057b8561e9376415f4396e548351cc677b0abeafe4f51b855a3dc83", + "0x865b99587eb3dbc17e412647673f22b2e89185d1df1ec8ea04515585ad2edfb731be458123118dcd7b41b475026477b9", + "0x9390618833b5adbaf24bd38cf9fc6f25104717f314259bb4da5c7a1f6963ecdc04d07bed391d8cd765c3d53567b2b6b1", + "0x95383e8b1d0a629cec238b5ae2bda236a027f4e3b5f99ceace05f1d5a781ec1e7a43058f44ef0a5aee6b0db5697a0d89", + "0x91739b8946d90db3a5244f7485295cc58143ba0449c9e539df1ba3c166ecf85ff914c9941192963c32d35033ae2f0980", + "0xb5d88848d856d882db5947b9182025f0abf2bc4335b650fa0a48a578e2c87f32cc86d42d3b665ee2eab46d072bf1eccd", + "0x91f4c754549f5a53b1902ef84274ce9acf0bfd2e824e62eb127d67e3214ce05fc2430c05ea51e94dc6e8978f5d076bab", + "0x91fff8c75f8ad86afe78ec301de05e4ca71421d731419a17c747a9a0bf81129422c9499e4749107b168d1695dc90292f", + "0x99fbd7bede9cc1e2974c2a21c70788960c2dbf45a89552da8d73bb1d398b8399590707f2f4ba4b43cb356e703eb01b5e", + "0x80a51cd83e3d748c07b9ac82de1a697b09031e3edc7bf585f06cd0ffa8ea319517fcc2b735614b656677b54b4910814e", + "0x886b27de1f93311d1a31b6d698aa28b54fbd800decd8e25243d89e352ee38cb252d5648b5134a3e1ed021bae46e9da48", + "0x976e70c94db905f83b4ef72188d840874bf005814c0c772f3832aa65b1f21927403125eea7a07b6d3305b1a781b36ab7", + "0xb4adb9d1c49eb31462583580e3ffa625bea4f8b2a7d4927e4ff925c1759d4b3c1e43283d635b54fb0eabfbe1f4c12992", + "0xb66b466bd48485ebeedd47e749d86cbaa3deffbbee2e69cfaa5e9f3bd28b143d7c1c0255a7a1393a2cc1490b2c485571", + "0x8bded5bc0794513947ddb00ff6b780c5cc63a74e2a0b0284153c346a31c82e1eff07c073939da39e6f87a06c14ff1a80", + "0xaceea8c6f799589f6b7070abf69fec724e6679514e60f1eaf9a52c37e9cebb72abcc833a81d8da1a4f5194c1a7eeff63", + "0x89a9f76d053379687fd221ebcaf02c15c2c241bb673ef5298e32640a115d9e0f2331c3e185572cd65946dd6c5bd42412", + "0xa57b6f1e3fdd92eadc6220760f22d0685a82cada1c7a1bda96d36e48e2852f74f3a83c757dd8857e0aee59e978da4919", + "0x9106cf0891bb39ce87433c5f06a5c97a071d08ad44a7cbcd6918c0729c66bb317fbbee8aa45591cee332ad1234c7257d", + "0x96c18cca4a0f0299e0027ff697798085f9f698a7237052c5f191b1dba914e5a015ae356b80c17f0fdd31d08c5a939ebb", + "0xa892103c93df126c024825c07d8769bdac5f1d26ea9509ee26530dc594384b2a5095cc34e0b41ab3db0392a29792c9e8", + "0xb7c2dbc95edb6fc25802ea051803b7bea682f87a99f8a9fdcc3091c81d914b9493dfb18a8894c964805298a6c22b07f2", + "0x8e40948927d560a6840d7fb99802989ce72b43693e9dc7ed9dcda4bca7daedf75271cf656bcc22b3f999a550faad8648", + "0xb354de1c6f0603df3ed9036c610281e55b51a48950ee3ce57a00b4692232de7ca57d19722700e15cbe67a91fcec2f786", + "0xadf987b90737b933436d8036c1d3f0c9104f26c540052e22e703964f72739ac1261e4289b8f27dec47281a0f3f51378a", + "0x8ed5248e9c836fffa7c924178db593e1aaeb54bcf2e93c1983c1f3899cad538deeb2b836430fddc9b2f283e0797ea11e", + "0x907e5410e3bd5d7f55340e2f497bd1ca10bfcb4abed2c66a3cdf94dc40bbd7c43ac98754e0b4b223ea4c61eebf2f27f5", + "0x8e81b441ea0397db28840fb4b3c3bfe6d8e31418816f7bda36f9c1cfe4556daee30c43639d90a2dc9b02a3d65e5f4ab2", + "0x897085c477f5030f9fed06e181b05953a8cd2001d959dd6139738d40f1d673b2c7120b5348f678547acfdc90ffc9fcc6", + "0xb0bf2784c4b3808a04be5a00a0593035ce162b3886e1500247b48365eac8ec3d27c7e5e6372e030c779c75fb79772d0d", + "0xaf3fe6c75f2a1241ac885d5091ff3882cf01695d957d882e940f0c31f7a5b5e269c1a2bae7336e9a7cda2b1d23c03bd1", + "0xa6d94e065f85736d77080a4f775885ccb0dd5efdbe747e4595280bca0ebe12450257c1beadcbec77566ef57508c5d4df", + "0xa5c50fe56b5532bf391da639a2f2b6cbb2634fc6637416fea7c29a522dea024d4adaaa29b6d472b4d2cc3e3b85c72e2a", + "0xafc35f5a03b245a6286318ef489db05d397bbd16c17b4e92eeb56509f875246c0176c01804139eb67dc4247c2a36ff9e", + "0x99ba14ab5a9612c078f9bbaa0e68fd1d52ecceb2ed19bd9abf8f98dd4ed1f9c4fa6e4d41bcef69be2ff020b291749ca8", + "0x8018cdd3d96f331b4c470a4c3904bed44cadecbeec2544ca10e4352cf4ae1a856cf55f6383d666bf997ad3e16816006e", + "0xa9964790c318bb07b8fe61d230dd2161dd3160e186004647a925cfec4c583b4e33530bf5d93d8a14338b090055085b05", + "0xab89d8401df722101c2785cb3ef833017f58376ee82cedd3e9405b2534f259bb76063434a247652c7615a6de5194de65", + "0xa72c3d320a0d40936dee8edfb36703be633aefbb8f89530df04eb6aebe0305ef4f4b6709436f8036d417272a7e47e22a", + "0xb3457661ad62634cc25e2918921a97b0bf5c59ccc7063bc8eb53194783f07659f42f8978c589228af5b12696588d8b2f", + "0x926fa35cd3ed4c8ad78af6284b87ae53b2e25a1ff50398034142a2bbed5b989ba3181ff116838931742c0fbcd8b8a56c", + "0xae57fe506626432f27ae4f8791421c2df9efd9aaabe4b840ccf65fc3d0dd2f83e19eb63ae87bfa6898d37b5da869ddb2", + "0x99c0a26ac74211db77918156d7ae9bea6ecf48da3ce9e53829a9ad5ed41321227c94fbd7449ae2e44aae801811552b1b", + "0xabdd2635b61cb948e51b762a256cf9d159b9fcb39b2fb11ba2fed1cb53475a03fc6e024a6a824a67a689396119a36a7b", + "0xa5ca98b98da8bb8eb07b1e5e3c85a854db42addefacd141771a0c63a8e198421dccc55ef1d94662ca99a7d83b9173fc3", + "0xa821bb5cf1eb3aeae6318c8d554e2ea3137d73bb29d2e4450c9a33f441355ea77bb0e0e0ce7c819abc3ed119110a3a92", + "0x95cdfb19b3f7196c26d60586e2c1efaa93352a712f8c8ef6209f6f318cecd52d7bebdfbfee4be1f5903a1595f73bc985", + "0xaef6e6a400106e217f9888afcef0a1e1299b59017e77dc5453317dec0c32ae96873608bef3f1b504a7e4f45b06edc9c6", + "0x96399ad093299ba26dc09ae85dbec9a1801dea4a338dd5d578bcdcb91246db0059e54098ba8a56cbb24600a40095cf79", + "0xad8b018ac99857ad4b38bdf6d110bbef64029a4d9f08df85a278c6ddc362a5f64e1f3a919f798ccb2f85a7f4ca1260b4", + "0xb211f3b5dd91941d119c4fe05e2b4c7bb0ce0a8d7ef05932a96e850f549a78cd20cded0b3adb3f9f8b7058889ae2cb4e", + "0xab780dd363671765c9c9ab0f4e7096aacf5894e042b75f40a92df8eb272a6229078cd6eadcc500eead3650860aa82177", + "0xa4d96b16ab3abe77ead9b4477c81957e66a028f95557e390352743da53d1a7ba0c81d928a7ea8bc03b9900135ac36a6a", + "0xb4d4e028099bf0f28ac32141cd8de4ee7c3d62d4f519fad6abbb4ba39592750812220a4167d1da4c4f46df965f7cf43d", + "0xaa929c5f0bd8cb44a861bfb3d18340a58c61d82afa642447b71b1470a7b99fe3d5796bdd016b121838cb3594f5a92967", + "0xa038e66f0a28aba19d7079643788db3eed8e412fb9ab4c0f6cacf438af4657cc386a7c22ae97ccc8c33f19a572d6431c", + "0x89c1ff879faa80428910e00b632d31c0cebb0c67e8f5ded333d41f918032282fb59fbcbe26d3156592f9692213667560", + "0x8d899072c9d30e27065d73c79ce3130a09b6a4a4c7d9c4e4488fda4d52ad72bd5f1fd80f3a8936ef79cf362a60817453", + "0x8ffb84a897df9031f9a8e7af06855180562f7ca796489b51bb7cca8d0ca1d9766a4de197a3eb7e298b1dfb39bc6e9778", + "0x836ebd0b37e7ef4ff7b4fc5af157b75fa07a2244045c3852702eaafa119ca1260c654a872f1b3708b65671a2ece66ad2", + "0x9292dfd6d5bfc95f043f4eb9855c10cbcf90fbd03e7a256c163749b23a307b46a331bdbd202236dca0e8ea29e24906de", + "0x8bc37eaa720e293e32b7986061d2ffcbd654d8143e661aabe5602adc832ab535cffbe12a7b571d423675636a74b956e4", + "0x887455f368515340eb6f9b535f16a1cf3e22f0ceda2ead08c5caefccef4087e9f4b5d61c5b110ff3e28e4ab2ad9e97c5", + "0xa6e5ec36e7712056fec00de15b8696952b17891e48ebe2fa90c6f782c7d927b430917b36b4a25b3d8466da3ca2a4985d", + "0x895cae36ba786104ec45740c5dc4f2416b2adce6e806815e3994e98d9e1be372eaec50094fbb7089015684874631ab7e", + "0x9687444fe6250c246b1711a8f73992f15c3cac801e79c54ffd5e243ad539fdd98727043e4f62d36daf866750de1ba926", + "0xb17f75044c8e9ce311bb421a5427006b6fa1428706d04613bd31328f4549decd133e62f4b1917016e36eb02ea316a0ca", + "0x8538a84d2f9079dd272a7383ff03b7674f50b9c220e0399c794a2bcb825d643d0fc8095d972d5186b6f0fe9db0f7084f", + "0xaf07b37644cc216e7083bac1c4e6095fa898f3417699df172c1f6e55d6c13c11f5279edd4c7714d65360b5e4c3c6731e", + "0x87eed8fe7486c0794884c344c07d3964f8fc065aebb0bb3426506ab879b2e0dfaefa5cece213ec16c7b20e6f946c0bd2", + "0x8a4bf42f141d8bc47c9702779d692a72752510ef38e290d36f529f545a2295082a936c8420f59d74b200a8fff55167c4", + "0xa7170e5e00a504a3b37cb19facf399c227497a0b1e9c8a161d541cb553eb8211449c6ac26fe79a7ff7b1c17f33591d74", + "0xa9a2cc7232f07ef9f6d451680648f6b4985ecab5db0125787ac37280e4c07c8210bab254d0b758fd5e8c6bcf2ee2b9ff", + "0x8908d82ebfa78a3de5c56e052d9b5d442af67a510e88a76ba89e4919ae1620c5d15655f663810cfc0ee56c256a420737", + "0xa9d47f3d14047ca86c5db9b71f99568768eaa8a6eb327981203fdb594bdb0a8df2a4a307f22dcea19d74801f4648ea89", + "0xa7c287e0e202ebfc5be261c1279af71f7a2096614ee6526cd8b70e38bb5b0b7aca21a17140d0eddea2f2b849c251656a", + "0x97807451e61557d122f638c3f736ab4dab603538396dca0fcdf99f434a6e1f9def0521816b819b1c57ecdfa93bd077eb", + "0xa8486d60742446396c9d8bc0d4bed868171de4127e9a5a227f24cbf4efbbe5689bbd38f2105498706a6179340b00aed5", + "0xa03b97c2a543dfefa1deb316db9316191ab14e3dd58255ce1027b4e65060d02fb5cb0d6ac1a2bf45bfeac72537b26429", + "0xa7d25060f6861873410c296a4959a058174e9a1681ac41770788191df67fc1391545dab09de06b56cd73a811b676aa1b", + "0x96bb9c9aa85d205e085434d44f5021d8bbafc52cd2727b44e2a66094a4e5467b6294d24146b54c0d964c711e74a258d4", + "0xb07b17f11267e577191e920fa5966880f85ff7089ac59d5d550e46f3a5cdadd94f438a547cd1ec66f20a447e421f96c6", + "0x964e33e1571c97088fe7c8ca3430db60a8119f743a47aa0827e6e2fb9bae5ff3bf6cecd17b11dd34628546b6eb938372", + "0x82a0513a05870b96509a559164e6ff26988ea8a2227ac6da9adc96fe793485a9eb6bdcab09afac7be4aef9a5ae358199", + "0xb1185bc679623e7a37a873d90a2a6393fb5ccc86e74ba4ba6f71277df3623cde632feae4414d6429db6b4babde16dee0", + "0xb3d77504b7032b5593a674d3c0cd2efbf56b2b44ed7fe8669f752828045e4e68202a37bf441f674b9c134886d4cee1df", + "0x95ab31749ff1f7b3f165ce45af943c6ed1f1071448c37009643a5f0281875695c16c28fc8d8011a71a108a2d8758e57d", + "0xb234dee9c56c582084af6546d1853f58e158549b28670b6783b4b5d7d52f00e805e73044a8b8bd44f3d5e10816c57ecc", + "0x86da5d2343f652715c1df58a4581e4010cf4cbe27a8c72bb92e322152000d14e44cc36e37ff6a55db890b29096c599b9", + "0x8b7be904c50f36453eff8c6267edcb4086a2f4803777d4414c5c70c45b97541753def16833e691d6b68d9ef19a15cb23", + "0xb1f4e81b2cdb08bd73404a4095255fa5d28bcd1992a5fd7e5d929cfd5f35645793462805a092ec621946aaf5607ef471", + "0xa7f2ca8dacb03825ef537669baff512baf1ea39a1a0333f6af93505f37ed2e4bbd56cb9c3b246810feee7bacdf4c2759", + "0x996d0c6c0530c44c1599ffdf7042c42698e5e9efee4feb92f2674431bbddf8cf26d109f5d54208071079dfa801e01052", + "0xb99647e7d428f3baa450841f10e2dc704ce8125634cc5e7e72a8aa149bf1b6035adce8979a116a97c58c93e5774f72b7", + "0x95960a7f95ad47b4a917920f1a82fbbecd17a4050e443f7f85b325929c1e1f803cf3d812d2cedeab724d11b135dde7a3", + "0x8f9cd1efdf176b80e961c54090e114324616b2764a147a0d7538efe6b0c406ec09fd6f04a011ff40e0fa0b774dd98888", + "0xb99431d2e946ac4be383b38a49b26e92139b17e6e0f0b0dc0481b59f1ff029fb73a0fc7e6fff3e28d7c3678d6479f5a3", + "0xa888887a4241ce156bedf74f5e72bfa2c6d580a438e206932aefc020678d3d0eb7df4c9fe8142a7c27191837f46a6af6", + "0xab62224ea33b9a66722eb73cfd1434b85b63c121d92e3eebb1dff8b80dd861238acf2003f80f9341bfea6bde0bfcd38c", + "0x9115df3026971dd3efe7e33618449ff94e8fd8c165de0b08d4a9593a906bbed67ec3ed925b921752700f9e54cd00b983", + "0x95de78c37e354decd2b80f8f5a817d153309a6a8e2f0c82a9586a32051a9af03e437a1fb03d1b147f0be489ef76b578b", + "0xa7b8a6e383de7739063f24772460e36209be9e1d367fe42153ffe1bccb788a699e1c8b27336435cd7bf85d51ba6bfdd6", + "0x937a8af7ed18d1a55bf3bbe21e24363ae2cb4c8f000418047bf696501aaeec41f2ddf952fd80ef3373f61566faa276a9", + "0xab5e4931771aeb41c10fa1796d6002b06e512620e9d1c1649c282f296853c913f44e06e377a02f57192b8f09937282eb", + "0x893d88009754c84ec1c523a381d2a443cb6d3879e98a1965e41759420a088a7582e4d0456067b2f90d9d56af4ea94bba", + "0x91b2388a4146ebaaa977fec28ffbfb88ac2a1089a8a258f0451c4152877065f50402a9397ba045b896997208b46f3ebf", + "0x8ce0523192e4cc8348cd0c79354a4930137f6f08063de4a940ea66c0b31d5ea315ce9d9c5c2ec4fa6ee79d4df83840dd", + "0xb72f75c4ab77aca8df1a1b691b6ef1a3ff1c343dd9ed48212542e447d2ed3af3017c9ad6826991e9ef472348c21b72a4", + "0xaf0fa5a960f185326877daf735ad96c6bd8f8f99ab0ab22e0119c22a0939976ece5c6a878c40380497570dc397844dba", + "0xadf9f41393e1196e59b39499623da81be9f76df047ae2472ce5a45f83871bb2a0233e00233b52c5c2fa97a6870fbab0a", + "0x8d9fc3aecd8b9a9fca8951753eea8b3e6b9eb8819a31cca8c85a9606ce1bd3885edb4d8cdbc6f0c54449c12927285996", + "0x901969c1d6cac2adcdc83818d91b41dc29ef39c3d84a6f68740b262657ec9bd7871e09b0a9b156b39fa62065c61dacb1", + "0x9536a48ccd2c98f2dcbff3d81578bbb8f828bf94d8d846d985f575059cd7fb28dfa138b481d305a07b42fcb92bacfa11", + "0x8d336654833833558e01b7213dc0217d7943544d36d25b46ecc1e31a2992439679205b5b3ab36a8410311109daa5aa00", + "0x95113547163e969240701e7414bf38212140db073f90a65708c5970a6aaf3aba029590a94839618fc3f7dd4f23306734", + "0xa959d77a159b07b0d3d41a107c24a39f7514f8ce24efa046cfcf6ace852a1d948747f59c80eb06277dce1a2ba2ec8ea9", + "0x8d2cb52dd7f5c56ef479c0937b83b8519fa49eb19b13ea2ec67266a7b3d227fb8d0c2454c4618d63da1c8e5d4171ac7b", + "0x9941698c5078936d2c402d7db6756cc60c542682977f7e0497906a45df6b8d0ffe540f09a023c9593188ba1b8ce6dfcb", + "0x9631d9b7ec0fc2de8051c0a7b68c831ba5271c17644b815e8428e81bad056abb51b9ca2424d41819e09125baf7aaf2d4", + "0xa0f3d27b29a63f9626e1925eec38047c92c9ab3f72504bf1d45700a612682ad4bf4a4de41d2432e27b745b1613ff22f9", + "0x80e3701acfd01fc5b16ecfa0c6c6fd4c50fe60643c77de513f0ad7a1a2201e49479aa59056fd6c331e44292f820a6a2c", + "0xa758c81743ab68b8895db3d75030c5dd4b2ccc9f4a26e69eb54635378a2abfc21cba6ca431afb3f00be66cffba6ab616", + "0xa397acb2e119d667f1ab5f13796fd611e1813f98f554112c4c478956c6a0ebaceef3afae7ee71f279277df19e8e4543a", + "0xa95df7d52b535044a7c3cf3b95a03bafd4466bdb905f9b5f5290a6e5c2ac0f0e295136da2625df6161ab49abcdacb40f", + "0x8639fc0c48211135909d9e999459568dbdbbc7439933bab43d503e07e796a1f008930e8a8450e8346ab110ec558bcbb9", + "0xa837bcc0524614af9e7b677532fabfb48a50d8bec662578ba22f72462caabda93c35750eed6d77b936636bf165c6f14e", + "0x97d51535c469c867666e0e0d9ed8c2472aa27916370e6c3de7d6b2351a022e2a5330de6d23c112880b0dc5a4e90f2438", + "0xaadb093c06bd86bd450e3eb5aa20f542d450f9f62b4510e196f2659f2e3667b0fe026517c33e268af75a9c1b2bc45619", + "0x860cef2e0310d1a49a9dd6bc18d1ca3841ed1121d96a4f51008799b6e99eb65f48838cd1e0c134f7358a3346332f3c73", + "0xb11c4f9e7ef56db46636474a91d6416bcb4954e34b93abf509f8c3f790b98f04bd0853104ec4a1ff5401a66f27475fce", + "0x87cb52e90a96c5ee581dc8ab241e2fd5df976fe57cc08d9ffda3925a04398e7cffaf5a74c90a7319927f27c8a1f3cef5", + "0xb03831449f658a418a27fd91da32024fdf2b904baf1ba3b17bbf9400eaddc16c3d09ad62cc18a92b780c10b0543c9013", + "0x94e228af11cb38532e7256fa4a293a39ffa8f3920ed1c5ad6f39ce532e789bb262b354273af062add4ca04841f99d3aa", + "0x99eb3aeb61ec15f3719145cf80501f1336f357cc79fca6981ea14320faed1d04ebe0dbce91d710d25c4e4dc5b6461ebf", + "0x920a3c4b0d0fbe379a675e8938047ea3ec8d47b94430399b69dd4f46315ee44bd62089c9a25e7fa5a13a989612fe3d09", + "0xb6414a9a9650100a4c0960c129fa67e765fe42489e50868dd94e315e68d5471e11bfbc86faffb90670e0bec6f4542869", + "0x94b85e0b06580a85d45e57dae1cfd9d967d35bdfcd84169ef48b333c9321f2902278c2594c2e51fecd8dbcd221951e29", + "0xb2c0a0dd75e04a85def2a886ee1fda51f530e33b56f3c2cf61d1605d40217aa549eef3361d05975d565519c6079cc2ac", + "0xabb0ea261116c3f395360d5ac731a7514a3c290f29346dc82bacb024d5455d61c442fefe99cc94dddcae47e30c0e031f", + "0xa32d95ae590baa7956497eddf4c56bff5dfdc08c5817168196c794516610fcc4dbcd82cf9061716d880e151b455b01e0", + "0x8bd589fb6e3041f3ef9b8c50d29aed1a39e90719681f61b75a27489256a73c78c50c09dd9d994c83f0e75dfe40b4de84", + "0x82d01cdaf949d2c7f4db7bfadbf47e80ff9d9374c91512b5a77762488308e013689416c684528a1b16423c6b48406baf", + "0xb23e20deb7e1bbbc328cbe6e11874d6bdbb675704a55af1039b630a2866b53d4b48419db834a89b31ebed2cfc41278dd", + "0xa371559d29262abd4b13df5a6a5c23adab5a483f9a33a8d043163fcb659263322ee94f872f55b67447b0a488f88672d6", + "0x85b33ddf4a6472cacc0ed9b5ec75ed54b3157e73a2d88986c9afa8cb542e662a74797a9a4fec9111c67e5a81c54c82b3", + "0xaf1248bc47a6426c69011694f369dc0ec445f1810b3914a2ff7b830b69c7e4eaa4bafec8b10ed00b5372b0c78655a59b", + "0x94b261ed52d5637fd4c81187000bd0e5c5398ce25797b91c61b30d7b18d614ab9a2ca83d66a51faf4c3f98714e5b0ea5", + "0x953d4571c1b83279f6c5958727aaf9285d8b8cbdbfbaff51527b4a8cfdd73d3439ba862cdb0e2356e74987ff66d2c4d9", + "0xb765dae55d0651aca3b3eaef4ca477f0b0fda8d25c89dccd53a5573dd0c4be7faaadaa4e90029cdd7c09a76d4ce51b91", + "0xb6d7b7c41556c85c3894d0d350510b512a0e22089d3d1dd240ad14c2c2b0ce1f003388100f3154ad80ec50892a033294", + "0xa64561dc4b42289c2edf121f934bc6a6e283d7dce128a703f9a9555e0df7dda2825525dbd3679cd6ba7716de230a3142", + "0xa46c574721e8be4a3b10d41c71057270cca42eec94ca2268ee4ab5426c7ce894efa9fa525623252a6a1b97bcf855a0a5", + "0xa66d37f1999c9c6e071d2a961074c3d9fdcf9c94bf3e6c6ed82693095538dd445f45496e4c83b5333b9c8e0e64233adc", + "0xab13814b227a0043e7d1ff6365360e292aca65d39602d8e0a574d22d25d99ccb94417c9b73095632ff302e3d9a09d067", + "0xb2c445b69cff70d913143b722440d2564a05558d418c8ef847483b5196d7e581c094bae1dbb91c4499501cfa2c027759", + "0x87cbde089962d5f093324b71e2976edbe6ad54fb8834dd6e73da9585b8935fca1c597b4d525949699fdfa79686721616", + "0xa2c7e60966acb09c56cf9ad5bdcc820dcabf21ef7784970d10353048cf3b7df7790a40395561d1064e03109eaac0df98", + "0x8ea7b8af208678178553946b2ee9e68c0e751b34f3652409a5e66c40d3aee3a40ba6ffe2175ce16c6a81b78ecc597d02", + "0x960234239e1e3ea262e53d256ad41b2fe73f506b3d130732d0ee48819eb8a9c85bb5106a304874d8625afae682c34015", + "0x858459694c4e8fdafa6cdaee1184e1305ca6e102222b99b8e283dd9bb3ebf80e55d6c4d8831a072b813c8eceb8124d95", + "0xa30a8ce0f44aeb5590dc618c81c7cac441470ce79fd7881a8f2ea4ca5f9d848ebde762fcaee985cbd3d5990367403351", + "0xa83867643672248b07d3705813b56489453e7bc546cdba570468152d9a1bd04f0656034e7d03736ea156fc97c88dc37f", + "0xa7bb52e0fc58b940dc47ea4d0a583012ee41fad285aba1a60a6c54fa32cfe819146888c5d63222c93f90de15745efb2b", + "0x8627bcc853bdeaad37f1d0f7d6b30ada9b481ccdf79b618803673de8a142e8a4ce3e7e16caed1170a7332119bcdc10a9", + "0x8903d9dc3716b59e8e99e469bd9fde6f4bca857ce24f3a23db817012f1ea415c2b4656c7aeca31d810582bb3e1c08cc6", + "0x875169863a325b16f892ad8a7385be94d35e398408138bd0a8468923c05123d53dba4ce0e572ea48fcdadd9bd9faa47a", + "0xb255b98d46d6cc44235e6ce794cc0c1d3bd074c51d58436a7796ce6dc0ae69f4edaa3771b35d3b8a2a9acd2f6736fab3", + "0x9740c4d0ee40e79715a70890efda3455633ce3a715cbfc26a53e314ebbe61937b0346b4859df5b72eb20bcba96983870", + "0xa44ce22ab5ddc23953b02ec187a0f419db134522306a9078e1e13d5bf45d536450d48016a5e1885a346997003d024db0", + "0x90af81c08afdccd83a33f21d0dc0305898347f8bd77cc29385b9de9d2408434857044aec3b74cb72585338c122e83bb4", + "0x80e162a7656c9ae38efa91ae93e5bd6cb903f921f9f50874694b9a9e0e2d2595411963d0e3f0c2d536b86f83b6e4d6ef", + "0x8b49fa6babe47291f9d290df35e94e83be1946784b9c7867efd8bc97a12be453013939667164b24aeb53d8950288a442", + "0xa1df6435d718915df3da6dda61da1532a86e196dc7632703508679630f5f14d4cb44ce89eff489d7ff3fe599cc193940", + "0xafd44c143dbb94c71acc2a309c9c88b8847ef45d98479fccce9920db9b268e8e36f8db9f02ff4ee3cff01e548f719627", + "0xb2cf33d65d205e944b691292c2d9b0b124c9de546076dd80630742989f1ffd07102813c64d69ba2a902a928a08bce801", + "0xb9f295e9f9eca432b2d5c77d6316186027caca40a6d6713f41356497a507b6e8716fb471faf973aaa4e856983183c269", + "0xb3bd50c4b034473edce4b9be1171376a522899cb0c1a1ae7dc22dd2b52d20537cf4129797235084648ac4a3afc1fa854", + "0x8ef37683d7ca37c950ba4df72564888bedaf681931d942d0ea88ead5cc90f4cbef07985a3c55686a225f76f7d90e137d", + "0x82107855b330bc9d644129cebecf2efbfab90f81792c3928279f110250e727ce12790fd5117501c895057fa76a484fc0", + "0x816a5474c3b545fb0b58d3118cc3088a6d83aad790dbf93025ad8b94a2659cceba4fa6a6b994cb66603cc9aef683a5e3", + "0x8f633f9b31f3bb9b0b01ea1a8830f897ecd79c28f257a6417af6a5f64e6c78b66c586cf8d26586830bd007fb6279cd35", + "0xacb69d55a732b51693d4b11f7d14d21258d3a3af0936385a7ce61e9d7028a8fe0dd902bda09b33fb728bc8a1bc542035", + "0x8d099582ac1f46768c17bf5a39c13015cfe145958d7fc6ddfd2876ad3b1a55a383fbe940e797db2b2b3dc8a232f545dc", + "0x97a4dd488b70bf772348ececaca4cf87bc2875d3846f29fe6ef01190c5b030219b9e4f8137d49ea0cc50ca418024c488", + "0xb4d81148f93fa8ec0656bbfb5f9d96bbf5879fa533004a960faac9fd9f0fe541481935fdf1f9b5dd08dff38469ef81c5", + "0x8e9b2ae4fc57b817f9465610a77966caaff013229018f6c90fa695bd734cb713b78a345b2e9254b1aff87df58c1cd512", + "0x99eb7126e347c636e9a906e6bfdc7c8ca0c1d08580c08e6609889a5d515848c7ca0f32ab3a90c0e346f976a7883611f7", + "0x8ca87944aa3e398492b268bda0d97917f598bc0b28584aa629dfec1c3f5729d2874db422727d82219880577267641baa", + "0x88ab0e290dc9a6878d6b4e98891ff6bfc090e8f621d966493fcbe1336cc6848fcbb958d15abcfa77091d337da4e70e74", + "0x8956a2e1dc3ec5eb21f4f93a5e8f0600a06e409bb5ec54e062a1290dff9ce339b53fbbfc4d42b4eed21accea07b724d6", + "0x8d22220da9dc477af2bddb85c7073c742c4d43b7afee4761eba9346cadbcd522106ed8294281a7ef2e69883c28da0685", + "0x90dafd9a96db7e1d6bde424245305c94251d5d07e682198ae129cd77bd2907a86d34722cbde06683cc2ca67cebe54033", + "0xb5202e62cf8ea8e145b12394bd52fd09bda9145a5f78285b52fda4628c4e2ccfc2c208ecde4951bd0a59ac03fa8bc202", + "0x8959856793ba4acf680fb36438c9722da74d835a9fe25a08cf9e32d7800c890a8299c7d350141d2e6b9feceb2ebb636f", + "0xab0aa23c1cd2d095825a3456861871d298043b615ae03fcd9283f388f0deef3cc76899e7fde15899e3edf362b4b4657f", + "0x9603b333cc48fe39bea8d9824cfee6ac6c4e21668c162c196ecd1ff08ef4052ace96a785c36b8f7906fdcb6bc8802ddd", + "0x93bfecbc3c7cc03c563240e109850a74948f9fa078eb903b322368cda0b50888663a17953579578ba060b14dbf053024", + "0xb01f843b808cf7939a474de155a45462e159eb5044f00c6d77e0f7ec812720a3153209e971a971ccbf5ebee76ec4074f", + "0xb009e0567c3c75ed767247d06fa39049a4d95df3392d35a9808cb114accf934e78f765cd18a2290efef016f1918c7aeb", + "0xad35631df8331da3a12f059813dfa343d831225a392f9c7e641c7d23a6c1ad8df8e021201c9f6afb27c1575948d6bf68", + "0xa89c2a631d84128471c8ef3d24b6c35c97b4b9b5dad905c1a092fb9396ae0370e215a82308e13e90e7bb6ebcc455eb2a", + "0xb59c7f5fbfeb02f8f69e6cedef7ff104982551f842c890a14834f5e834b32de1148cf4b414a11809d53dd3f002b15d6a", + "0xaa6f267305b55fede2f3547bc751ba844ce189d0b4852022712b0aee474de54a257d4abcd95efe7854e33a912c774eba", + "0xafddd668f30cce70904577f49071432c49386ec27389f30a8223b5273b37e6de9db243aceb461a7dc8f1f231517463a9", + "0xb902a09da9157b3efa1d98f644371904397019d0c84915880628a646a3ad464a9d130fdc651315098179e11da643ad2e", + "0xb05f31957364b016c6f299ae4c62eede54cab8ea3871d49534828c8bdc6adbc6a04a708df268f50107d81d1384d983ae", + "0xb4c3f7284802e614ddf1f51640f29e7139aae891467d5f62778310372071793e56fbd770837b97d501191edd0da06572", + "0xb4eddb7c3775fb14fac7f63bb73b3cde0efa2f9a3b70e6a65d200765f6c4b466d3d76fcd4d329baee88e2aba183b8e69", + "0xa83e7dbae5a279f0cfd1c94e9849c58a3d4cecc6d6d44bb9b17508576ca347fca52c2c81371d946b11a09d4ed76ec846", + "0x8018ea17e2381c0233867670f9e04c8a47ace1207fdcf72dce61b6c280ba42d0a65f4b4e0b1070cc19c7bb00734974d9", + "0xaf90b541dfed22e181ff3ef4cf11f5e385fd215c1e99d988e4d247bc9dcee9f04f2182b961797c0bcc5f2aaa05c901a9", + "0xa37046e44cf35944e8b66df80c985b8a1aa7004a2fd0b81ac251638977d2ff1465f23f93ac0ce56296f88fdc591bbdd7", + "0xa735bd94d3be9d41fcd764ec0d8d7e732c9fc5038463f7728fd9d59321277e2c73a45990223bd571dab831545d46e7aa", + "0x94b32dcb86f5d7e83d70a5b48fe42c50f419be2f848f2d3d32ee78bf4181ab18077a7666eedb08607eece4de90f51a46", + "0xa7f0804cafbf513293485afc1b53117f0cbfaea10919e96d9e4eb06f0c96535e87065d93f3def1bbc42044dbb00eb523", + "0xaaaad1166d7f19f08583dd713275a71a856ab89312f84ca8078957664924bb31994b5c9a1210d0c41b085be4058ed52e", + "0xa1757aac9f64f953e68e680985a8d97c5aac8688b7d90f4db860166dd3d6119e8fca7d700a9530a2b9ba3932c5e74e33", + "0x98cada5db4a1430c272bfc1065fb685872e664ed200d84060ee9f797d0a00864f23943e0fb84ba122a961996a73dfb14", + "0xa5e609f716dc7729d1247f40f9368a2e4a15067e1dd6a231fece85eeefb7e7d4a5ac8918fb376debd79d95088750b2ca", + "0xb5365eb8caab8b1118619a626ff18ce6b2e717763f04f6fa8158cdca530c5779204efa440d088083f1a3685454aa0555", + "0xa6e01b8da5f008b3d09e51a5375d3c87c1da82dff337a212223e4d0cdb2d02576d59f4eef0652d6b5f2fc806d8c8149c", + "0xae310f613d81477d413d19084f117248ad756572c22a85b9e4c86b432e6c602c4a6db5edf2976e11f7353743d679e82a", + "0xa1f219c0b8e8bb8a9df2c6c030acbb9bbfa17ba3db0366f547da925a6abb74e1d7eb852bd5a34bae6ac61d033c37e9dc", + "0xa2087fa121c0cdd5ea495e911b4bc0e29f1d5c725aadfb497d84434d2291c350cdaa3dc8c85285f65a7d91b163789b7a", + "0x929c63c266da73d726435fa89d47041cfe39d4efa0edce7fc6eca43638740fbc82532fd44d24c7e7dd3a208536025027", + "0x91c1051dcc5f52ad89720a368dddd2621f470e184e746f5985908ba34e1d3e8078a32e47ab7132be780bea5277afecb0", + "0xae089b90ba99894d5a21016b1ea0b72a6e303d87e59fb0223f12e4bb92262e4d7e64bfdbdb71055d23344bc76e7794b2", + "0x8b69aa29a6970f9e66243494223bad07ac8f7a12845f60c19b1963e55a337171a67bdc27622153016fce9828473a3056", + "0x95ca6b08680f951f6f05fd0d180d5805d25caf7e5bda21c218c1344e661d0c723a4dfc2493642be153793c1b3b2caaa4", + "0xa4789dc0f2a07c794dab7708510d3c893d82ddbd1d7e7e4bbbeca7684d9e6f4520fb019b923a06c7efab0735f94aa471", + "0x93c4f57a3cf75085f5656b08040f4cd49c40f1aab6384a1def4c5c48a9fe4c03514f8e61aabe2cfa399ff1ccac06f869", + "0xb6c37f92c76a96b852cd41445aa46a9c371836dd40176cc92d06666f767695d2284a2780fdfd5efc34cf6b18bcfb5430", + "0x9113e4575e4b363479daa7203be662c13d7de2debcda1c142137228aeead2c1c9bc2d06d93a226302fa63cc75b7353ec", + "0xb70addeb5b842ac78c70272137f6a1cef6b1d3a551d3dd906d9a0e023c8f49f9b6a13029010f3309d0b4c8623a329faf", + "0xb976a5132b7eb42d5b759c2d06f87927ef66ecd6c94b1a08e4c9e02a4ce7feca3ac91f9479daa1f18da3d4a168c2ba77", + "0x8fdab795af64b16a7ddf3fad11ab7a85d10f4057cf7716784184960013baa54e7ba2050b0e036dc978ff8c9a25dc5832", + "0xb2c982ad13be67d5cdc1b8fac555d4d1ec5d25f84e58b0553a9836f8f9e1c37582d69ad52c086a880a08b4efcccd552e", + "0x810661d9075ae6942735215f2ab46d60763412e1f6334e4e00564b6e5f479fc48cf37225512abbccf249c0ca225fc935", + "0xa0c4bf00a20f19feff4004004f08231b4c6c86ac4ed57921eea28d7dea32034f3f4ab5b7ded7184f6c7ffbf5847232ad", + "0xb2bb5a9eea80bf067f3686a488529d9c2abd63fc9e1d4d921b1247ef86d40cd99e0a8b74f750e85c962af84e84e163a6", + "0x887ee493c96d50f619ba190ce23acddc5f31913e7a8f1895e6339d03794ecefd29da5f177d1d25bc8df8337ae963fc7b", + "0xb7966fb07029d040f2228efa2cfcd04341e4666c4cf0b653e6e5708631aa2dd0e8c2ac1a62b50c5a1219a2737b82f4f7", + "0x92234cfd6b07f210b82db868f585953aafbcbc9b07b02ded73ff57295104c6f44a16e2775ca7d7d8ee79babb20160626", + "0x8d3cd7f09c6fd1072bc326ff329e19d856e552ac2a9f20274bc9752527cd3274142aa2e32b65f285fb84bc3adaaea3cc", + "0x8caed1cb90d8cd61e7f66edc132672172f4fa315e594273bb0a7f58a75c30647ec7d52eda0394c86e6477fbc352f4fe8", + "0xae192194b09e9e17f35d8537f947b56f905766c31224e41c632c11cd73764d22496827859c72f4c1ab5fd73e26175a5d", + "0x8b7be56aac76d053969e46882d80a254e89f55c5ab434883cbafc634a2c882375898074a57bc24be3c7b2c56401a7842", + "0x98bc4a7a9b05ba19f6b85f3ee82b08bed0640fd7d24d4542eb7a7f7fde443e880bdb6f5499bd8cb64e1ddd7c5f529b19", + "0xa5a41eaa5e9c1d52b00d64ab72bc9def6b9d41972d80703e9bfe080199d4e476e8833a51079c6b0155b78c3ab195a2a7", + "0xa0823f6f66465fd9be3769c164183f8470c74e56af617f8afd99b742909d1a51f2e0f96a84397597afbd8eeaabb51996", + "0x801da41d47207bdd280cc4c4c9753a0f0e9d655e09e0be5f89aeed4ce875a904f3da952464399bf8efc2398940d5fba2", + "0xa719314085fd8c9beac4706c24875833d59a9a59b55bca5da339037c0a5fc03df46dbecb2b4efcfed67830942e3c4ea1", + "0xa75dde0a56070bb7e9237b144ea79f578d413a1cbbd1821cee04f14f533638b24f46d88a7001e92831843b37ed7a709f", + "0xa6b4ef8847a4b980146e1849e1d8ab38695635e0394ca074589f900ce41fa1bb255938dc5f37027523bac6a291779bef", + "0xb26d84dfd0b7bd60bcfdbea667350462a93dca8ff5a53d6fc226214dcb765fada0f39e446a1a87f18e4e4f4a7133155f", + "0xae7bd66cc0b72f14ac631ff329a5ca4958a80ba7597d6da049b4eb16ac3decde919ca5f6f9083e6e541b303fb336dc2f", + "0xa69306e6bfbbc10de0621cffb13c586e2fcfd1a80935e07c746c95651289aec99066126a6c33cb8eb93e87d843fc631f", + "0xa47e4815585865218d73c68ba47139568ea7ae23bfa863cb914a68454242dd79beaec760616b48eea74ceab6df2298dd", + "0xb2da3cfb07d0721cd226c9513e5f3ace98ed2bc0b198f6626b8d8582268e441fa839f5834f650e2db797655ca2afa013", + "0xb615d0819554f1a301a704d3fc4742bd259d04ad75d50bccee3a949b6226655f7d623301703506253cca464208a56232", + "0x85e06ed5797207f0e7ae85909e31776eb9dae8af2ec39cc7f6a42843d94ea1de8be2a3cdadfcbe779da59394d4ffeb45", + "0x8c3529475b5fdbc636ee21d763f5ec11b8cb040a592116fb609f8e89ca9f032b4fa158dd6e9ceab9aceb28e067419544", + "0xaccddb9c341f32be82b6fa2ef258802c9ae77cd8085c16ec6a5a83db4ab88255231b73a0e100c75b7369a330bfc82e78", + "0x93b8e4c6e7480948fa17444b59545a5b28538b8484a75ad6bc6044a1d2dbd76e7c44970757ca53188d951dc7347d6a37", + "0x90111721d68b29209f4dc4cfb2f75ab31d15c55701922e50a5d786fb01707ab53fcec08567cd366362c898df2d6e0e93", + "0xb60a349767df04bd15881c60be2e5cc5864d00075150d0be3ef8f6b778715bebca8be3be2aa9dbdc49f1a485aeb76cda", + "0xb8d5a967fdd3a9bcf89a774077db39ef72ca9316242f3e5f2a350202102d494b2952e4c22badecd56b72ba1eea25e64b", + "0x8499ebd860f31f44167183b29574447b37a7ee11efcc9e086d56e107b826b64646b1454f40f748ccac93883918c89a91", + "0x99c35e529782db30f7ccab7f31c225858cf2393571690b229ece838ec421a628f678854a1ddbd83fa57103ccebd92c7f", + "0x99817660d8b00cbe03ec363bcdc5a77885586c9e8da9e01a862aca0fc69bf900c09b4e929171bc6681681eae10450541", + "0x8055e130964c3c2ebd980d3dc327a40a416bcdbf29f480480a89a087677a1fb51c823b57392c1db72f4093597100b8d3", + "0x877eaddef845215f8e6f9ed24060c87e3ab6b1b8fbb8037d1a57e6a1e8ed34d00e64abb98d4bf75edb5c9788cbdccbef", + "0xb5432bbff60aeae47f2438b68b123196dfb4a65cc875b8e080501a4a44f834b739e121bec58d39ac36f908881e4aa8ab", + "0xb3c3f859b7d03ff269228c0f9a023b12e1231c73aba71ad1e6d86700b92adc28dfa3757c052bbc0ba2a1d11b7fda4643", + "0xab8a29f7519a465f394ef4a5b3d4924d5419ca1489e4c89455b66a63ac430c8c9d121d9d2e2ed8aa1964e02cd4ebac8c", + "0x866ae1f5c2a6e159f2e9106221402d84c059f40d166fab355d970773189241cd5ee996540d7c6fc4faf6f7bcff967dce", + "0x973a63939e8f1142a82b95e699853c1e78d6e05536782b9bb178c799b884f1bc60177163a79a9d200b5ff4628beeb9e7", + "0xa5fc84798d3e2d7632e91673e89e968f5a67b7c8bb557ea467650d6e05e7fe370e18d9f2bdd44c244978295cf312dc27", + "0xb328fe036bcd0645b0e6a15e79d1dd8a4e2eda128401a4e0a213d9f92d07c88201416fc76193bb5b1fe4cb4203bab194", + "0x99239606b3725695a570ae9b6fb0fb0a34ad2f468460031cfa87aa09a0d555ff606ff204be42c1596c4b3b9e124b8bd6", + "0xaf3432337ca9d6cce3574e23e5b7e4aa8eda11d306dc612918e970cc7e5c756836605a3391f090a630bac0e2c6c42e61", + "0x8a545b3cb962ce5f494f2de3301de99286c4d551eaa93a9a1d6fef86647321834c95bf754c62ec6c77116a21494f380d", + "0x8f9b8ea4c25469c93556f1d91be583a5f0531ac828449b793ba03c0a841c9c73f251f49dd05cbb415f5d26e6f6802c99", + "0xa87199e33628eeffd3aff114e81f53dd54fba61ba9a9a4d7efdbff64503f25bc418969ab76ef1cf9016dd344d556bb29", + "0xa2fda05a566480602274d7ffcaefdd9e94171286e307581142974f57e1db1fa21c30be9e3c1ac4c9f2b167f92e7c7768", + "0xa6235d6a23304b5c797efb2b476ed02cb0f93b6021a719ae5389eb1e1d032944ae4d69aec2f29fcd6cbc71a6d789a3ba", + "0xa7f4a73215f7e99e2182c6157dd0f22e71b288e696a8cff2450689a3998f540cfb82f16b143e90add01b386cb60d8a33", + "0x922d8f9cd55423f5f6a60d26de2f8a396ac4070a6e2dc956e50c2a911906aa364d4718aea29c5b61c12603534e331e7e", + "0x96d7fdf5465f028fc28f21fbfe14c2db2061197baf26849e6a0989a4ea7d5e09ab49a15ba43a5377b9354d01e30ce860", + "0x8f94c4255a0fc1bd0fa60e8178c17f2a8e927cac7941c5547d2f8f539e7c6ed0653cab07e9fb1f2c56cdd03bb876512a", + "0x95984c10a2917bfa6647ebce69bf5252d9e72d9d15921f79b2c6d7c15ee61342b4fb8a6d34838e07132b904f024ded04", + "0x93e65e765a574277d3a4d1d08ca2f2ff46e9921a7806ca8ca3d8055f22d6507744a649db7c78117d9168a1cbdb3bbc61", + "0x8d453b7364662dc6f36faf099aa7cbbe61151d79da7e432deba7c3ed8775cfe51eaf1ba7789779713829dde6828e189a", + "0xacffa3ee6c75160286090162df0a32a123afb1f9b21e17fd8b808c2c4d51a4270cab18fba06c91ef9d22e98a8dc26cdd", + "0xa5597cc458186efa1b3545a3926f6ecaaa6664784190e50eed1feac8de56631bee645c3bac1589fa9d0e85feb2be79d4", + "0x87ba9a898df9dfa7dabc4ab7b28450e4daf6013340e329408d1a305de959415ab7315251bad40511f917dfc43974e5f0", + "0xa598778cf01d6eef2c6aabc2678e1b5194ee8a284ebd18a2a51a3c28a64110d5117bcbf68869147934e600572a9e4c8a", + "0x84c69a4ad95861d48709f93ade5ac3800f811b177feb852ebcd056e35f5af5201f1d8a34ab318da8fe214812d0a7d964", + "0x9638a237e4aed623d80980d91eda45e24ebf48c57a25e389c57bd5f62fa6ffa7ca3fb7ae9887faf46d3e1288af2c153b", + "0x800f975721a942a4b259d913f25404d5b7b4c5bf14d1d7e30eee106a49cb833b92058dab851a32ee41faf4ef9cb0dea4", + "0xb9127a34a59fed9b5b56b6d912a29b0c7d3cb9581afc9bd174fc308b86fdb076f7d436f2abc8f61cef04c4e80cd47f59", + "0x8004eda83f3263a1ccfc8617bc4f76305325c405160fb4f8efeff0662d605e98ba2510155c74840b6fe4323704e903c4", + "0xaa857b771660d6799ff03ccad1ab8479e7f585a1624260418fc66dc3e2b8730cfa491d9e249505141103f9c52f935463", + "0x98b21083942400f34cde9adbe1977dee45ba52743dc54d99404ad9da5d48691ddea4946f08470a2faad347e9535690c7", + "0xa4b766b2faec600a6305d9b2f7317b46f425442da0dc407321fc5a63d4571c26336d2bccedf61097f0172ec90fb01f5f", + "0xb9736619578276f43583de1e4ed8632322ea8a351f3e1506c5977b5031d1c8ad0646fb464010e97c4ddb30499ddc3fb0", + "0x973444ffaff75f84c17f9a4f294a13affd10e2bceed6b4b327e4a32c07595ff891b887a9f1af34d19766d8e6cb42bfd1", + "0xb09ce4964278eff81a976fbc552488cb84fc4a102f004c87179cb912f49904d1e785ecaf5d184522a58e9035875440ef", + "0xb80c2aa3d0e52b4d8b02c0b706e54b70c3dbca80e5e5c6a354976721166ea0ca9f59c490b3e74272ef669179f53cb50d", + "0x8e52fa5096ff960c0d7da1aa4bce80e89527cdc3883eba0c21cb9a531088b9d027aa22e210d58cf7cbc82f1ec71eb44f", + "0x969f85db95f455b03114e4d3dc1f62a58996d19036513e56bee795d57bf4ed18da555722cd77a4f6e6c1a8e5efe2f5d7", + "0xab84b29b04a117e53caea394a9b452338364c45a0c4444e72c44132a71820b96a6754828e7c8b52282ad8dca612d7b6a", + "0x83e97e9ab3d9e453a139c9e856392f4cef3ec1c43bce0a879b49b27a0ce16f9c69063fd8e0debbe8fabafc0621bc200c", + "0x8c138ebdf3914a50be41be8aa8e2530088fb38af087fa5e873b58b4df8e8fd560e8090c7a337a5e36ef65566409ad8f3", + "0xa56da9db2f053516a2141c1a8ed368ae278ab33a572122450249056857376d1dffc76d1b34daf89c86b6fe1ead812a0c", + "0xa3233ea249f07531f5bc6e94e08cea085fd2b2765636d75ff5851f224f41a63085510db26f3419b031eb6b5143735914", + "0xb034bb6767ce818371c719b84066d3583087979ba405d8fbb2090b824633241e1c001b0cb0a7856b1af7a70e9a7b397e", + "0x8722803fe88877d14a4716e59b070dd2c5956bb66b7038f6b331b650e0c31230c8639c0d87ddc3c21efc005d74a4b5cc", + "0x8afe664cb202aacf3bd4810ebf820c2179c11c997f8c396692a93656aa249a0df01207c680157e851a30330a73e386b9", + "0xa999e86319395351d2b73ff3820f49c6516285e459224f82174df57deb3c4d11822fd92cbbed4fc5a0a977d01d241b19", + "0x9619408e1b58b6610d746b058d7b336d178e850065ba73906e08e748651e852f5e3aab17dcadcb47cc21ff61d1f02fcf", + "0x947cf9c2ed3417cd53ea498d3f8ae891efe1f1b5cd777e64cec05aba3d97526b8322b4558749f2d8a8f17836fb6e07aa", + "0xaec2fdae2009fda6852decb6f2ff24e4f8d8ca67c59f92f4b0cf7184be72602f23753ed781cf04495c3c72c5d1056ffe", + "0x8dba3d8c09df49fbfc9506f7a71579348c51c6024430121d1c181cad7c9f7e5e9313c1d151d46d4aa85fb0f68dd45573", + "0xb6334cb2580ae33720ebf91bb616294532a1d1640568745dcda756a3a096786e004c6375728a9c2c0fb320441e7d297a", + "0x9429224c1205d5ecd115c052b701c84c390f4e3915275bb8ce6504e08c2e9b4dd67b764dd2ea99f317b4c714f345b6ff", + "0xabe421db293f0e425cfd1b806686bdfd8fdbac67a33f4490a2dc601e0ddbf69899aa9a119360dad75de78c8c688ca08b", + "0x95c78bffed9ae3fff0f12754e2bd66eb6a9b6d66a9b7faaeb7a1c112015347374c9fe6ce14bf588f8b06a78e9a98f44c", + "0xac08f8b96b52c77d6b48999a32b337c5ad377adf197cda18dbdf6e2a50260b4ee23ca6b983f95e33f639363e11229ee4", + "0x911a0e85815b3b9f3ba417da064f760e84af94712184faeb9957ddd2991dee71c3f17e82a1a8fbeec192b0d73f0ebce7", + "0xaa640bd5cb9f050568a0ad37168f53b2f2b13a91e12b6980ca47ae40289cf14b5b89ddd0b4ca452ce9b1629da0ce4b5d", + "0x907486f31b4ecea0125c1827007ea0ecb1c55cadb638e65adc9810ca331e82bb2fd87e3064045f8d2c5d93dc6c2f5368", + "0x8cbfaf4ce0bbbf89208c980ff8b7bc8f3cfef90f0fe910f463cb1c0f8e17cce18db120142d267045a00ba6b5368f0dd3", + "0x9286f08f4e315df470d4759dec6c9f8eacef345fc0c0b533ad487bb6cfefa8c6c3821a22265c9e77d34170e0bc0d078b", + "0x94a3c088bc1a7301579a092b8ece2cefc9633671bc941904488115cd5cb01bd0e1d2deef7bdccb44553fd123201a7a53", + "0x8f3d0114fbf85e4828f34abb6d6fddfa12789d7029d9f1bb5e28bc161c37509afdab16c32c90ec346bc6a64a0b75726f", + "0xa8ed2d774414e590ec49cb9a3a726fafd674e9595dd8a1678484f2897d6ea0eea1a2ee8525afac097b1f35e5f8b16077", + "0x9878789ff33b11527355a317343f34f70c7c1aa9dc1eca16ca4a21e2e15960be8a050ec616ffb97c76d756ce4bce2e90", + "0x854e47719dae1fe5673cacf583935122139cf71a1e7936cf23e4384fbf546d48e9a7f6b65c3b7bf60028e5aa1234ba85", + "0xaf74bdda2c6772fe9a02d1b95e437787effad834c91c8174720cc6e2ea1f1f6c32a9d73094fc494c0d03eef60b1a0f05", + "0x80a3e22139029b8be32cb167d3bc9e62d16ca446a588b644e53b5846d9d8b7ab1ad921057d99179e41515df22470fb26", + "0x86c393afd9bd3c7f42008bba5fe433ec66c790ebd7aa15d4aeaf9bb39a42af3cfaf8c677f3580932bbd7ada47f406c8c", + "0x90433c95c9bb86a2c2ddcf10adccb521532ebd93db9e072671a4220f00df014e20cd9ce70c4397567a439b24893808dc", + "0x95b2c170f08c51d187270ddc4f619300b5f079bbc89dbca0656eae23eecc6339bf27fa5bf5fd0f5565d4021105e967d2", + "0x8e5eced897e2535199951d4cff8383be81703bca3818837333dd41a130aa8760156af60426ceadb436f5dea32af2814c", + "0xa254a460ebefbe91d6e32394e1c8f9075f3e7a2bb078430ac6922ab14d795b7f2df1397cb8062e667d809b506b0e28d4", + "0xac2062e8ca7b1c6afb68af0ebab31aebd56fc0a0f949ef4ea3e36baf148681619b7a908facf962441905782d26ecbdb5", + "0x8b96af45b283b3d7ffeec0a7585fc6b077ea5fd9e208e18e9f8997221b303ab0ce3b5bafa516666591f412109ce71aa5", + "0xafd73baada5a27e4fa3659f70083bf728d4dc5c882540638f85ea53bf2b1a45ddf50abc2458c79f91fb36d13998c7604", + "0xa5d2fff226e80cb2e9f456099812293333d6be31dd1899546e3ad0cd72b2a8bcb45ec5986e20faa77c2564b93983210c", + "0xa8c9b8de303328fbdaccf60f4de439cf28f5360cf4104581dc2d126bc2e706f49b7281723487ff0eaf92b4cc684bc167", + "0xa5d0d5849102bf1451f40e8261cb71fc57a49e032773cb6cd7b137f71ee32438d9e958077ffafce080a116ccc788a2d4", + "0x80716596f502d1c727d5d2f1469ce35f15e2dbd048d2713aa4975ee757d09c38d20665326bd63303cfe7e820b6de393d", + "0x97baf29b20f3719323cc1d5de23eaa4899dc4f4e58f6c356ec4c3ad3896a89317c612d74e0d3ab623fe73370c5972e2f", + "0xb58bdc9aa5061bf6e5add99a7443d7a8c7ba8f6875b8667d1acbe96fc3ecafbdcc2b4010cb6970a3b849fff84660e588", + "0xb6be68728776d30c8541d743b05a9affc191ad64918fdbd991d2ddd4b32b975c4d3377f9242defef3805c0bfb80fbac7", + "0xb0cddace33333b8a358acad84b9c83382f0569d3854b4b34450fd6f757d63c5bdab090e330b0f86e578f22c934d09c36", + "0x854bd205d6051b87f9914c8c2494075d7620e3d61421cc80f06b13cea64fd1e16c62c01f107a5987d10b8a95a8416ad9", + "0x80351254a353132300ba73a3d23a966f4d10ce9bf6eae82aedb6cdc30d71f9d08a9dd73cb6441e02a7b2ad93ad43159c", + "0x937aae24fb1b636929453fc308f23326b74c810f5755d9a0290652c9c2932ad52cc272b1c83bd3d758ef7da257897eae", + "0xb84d51ef758058d5694ffeac6d8ce70cef8d680a7902f867269c33717f55dd2e57b25347841d3c0872ae5f0d64f64281", + "0xa4b31bb7c878d5585193535b51f04135108134eff860f4eac941053155f053d8f85ff47f16268a986b2853480a6e75e6", + "0x93543f0828835186a4af1c27bdf97b5dd72b6dfa91b4bf5e759ff5327eaf93b0cb55d9797149e465a6b842c02635ffe5", + "0xafdac9e07652bf1668183664f1dd6818ef5109ee9b91827b3d7d5970f6a03e716adcc191e3e78b0c474442a18ad3fc65", + "0x9314077b965aa2977636ae914d4a2d3ce192641a976ffa1624c116828668edbfbe5a09e3a81cb3eed0694566c62a9757", + "0xb395ddcf5082de6e3536825a1c352802c557b3a5118b25c29f4c4e3565ecaaf4bdd543a3794d05156f91fc4ceadc0a11", + "0xb71f774aad394c36609b8730e5be244aaebfff22e0e849acc7ee9d33bedc3ec2e787e0b8b2ffe535560fcd9e15a0897e", + "0x92e9409fa430f943a49bce3371b35ac2efb5bc09c88f70ff7120f5e7da3258a4387dfc45c8b127f2ef2668679aeb314e", + "0x8ef55bef7b71952f05e20864b10f62be45c46e2dca0ef880a092d11069b8a4aa05f2e0251726aca1d5933d7dea98f3f8", + "0xaad3fba9e09fae885cdeef45dfafa901419f5156fb673818f92a4acc59d0e2e9870b025e711de590a63fd481164f3aa8", + "0xb444d52af545dd3a2d3dd94e6613816b154afea0c42b96468aceb0c721395de89e53e81a25db857ca2e692dcb24ba971", + "0x88b279fe173007e64fe58f2c4adba68a1f538dbd3d32d175aa0d026bbb05b72a0c9f5d02b8201a94adb75fe01f6aa8b2", + "0x88494cea4260741c198640a079e584cabfea9fcfb8bcf2520c9becd2419cde469b79021e5578a00d0f7dbc25844d2683", + "0x94f3cce58837c76584b26426b9abdb45f05fee34dd9e5914b6eae08e78b7262ed51c4317031dab1ad716f28b287f9fc2", + "0xb8c7ed564f54df01c0fbd5a0c741beed8183ce0d7842dc3a862a1b335de518810077314aa9d6054bb939663362f496da", + "0x81c153320d85210394d48340619d5eb41304daea65e927266f0262c8a7598321aba82ad6c3f78e5104db2afd2823baca", + "0xab6695a8d48a179e9cd32f205608359cf8f6a9aead016252a35b74287836aa395e76572f21a3839bec6a244aa49573e5", + "0x920ed571539b3002a9cd358095b8360400e7304e9a0717cc8c85ab4a0514a8ad3b9bf5c30cb997647066f93a7e683da9", + "0xa7ec7c194d1e5103bc976e072bf1732d9cb995984d9a8c70a8ee55ce23007f21b8549ad693f118aa974f693ed6da0291", + "0x87a042d6e40c2951a68afc3ccf9646baf031286377f37f6ac47e37a0ec04d5ac69043757d7dff7959e7cd57742017a8d", + "0xb9f054dd8117dd41b6e5b9d3af32ee4a9eebef8e4a5c6daa9b99c30a9024eabeae850ab90dbdb188ca32fd31fd071445", + "0xa8386da875799a84dc519af010eaf47cdbc4a511fe7e0808da844a95a3569ce94054efd32a4d3a371f6aba72c5993902", + "0x8b3343a7cf4ffb261d5f2dbd217fb43590e00feac82510bdf73b34595b10ee51acae878a09efebc5a597465777ef4c05", + "0x8312a5f1ea4f9e93578e0f50169286e97884a5ed17f1780275ab2b36f0a8aa1ab2e45c1de4c8bce87e99e3896af1fa45", + "0xb461198cb7572ac04c484a9454954e157bdd4db457816698b7290f93a10268d75a7e1211e757c6190df6144bbb605d91", + "0x9139764a099580d6f1d462c8bf7d339c537167be92c780e76acb6e638f94d3c54b40ed0892843f6532366861e85a515a", + "0x8bb70acb3c9e041b4fc20e92ba0f3f28f0d5c677bcb017af26f9171e07d28c3c0729bef72457231e3512f909455a13a2", + "0x93301a18e5064c55fcfe8e860fab72da1b89a824ca77c8932023b7c79e4a51df93a89665d308a8d3aa145e46ebe6a0ad", + "0xae3bca496fbd70ce44f916e2db875b2ce2e1ded84edd2cebc0503bdfdec40ec30e1d9afb4eb58c8fa23f7b44e71d88f8", + "0x93cb3a918c95c5d973c0cb7621b66081ed81fba109b09a5e71e81ca01ec6a8bb5657410fdec453585309ef5bf10d6263", + "0x95a50b9b85bb0fc8ff6d5f800d683f0f645e7c2404f7f63228a15b95ce85a1f8100e2e56c0acee19c36ed3346f190e87", + "0x816cc4d9337461caca888809b746ab3713054f5b0eac823b795a1a9de9417c58e32a9f020fef807908fa530cbf35dee8", + "0xa9c2890c2dd0d5d7aedc4cca7f92764086c50f92f0efd2642c59920d807086031bfe2d3ba574318db236c61a8f5f69c2", + "0xad0d5c8c80bddfe14bdaf507da96dc01dc9941aecc8ad3b64513d0a00d67c3f4b4659defb6839b8b18d8775e5344c107", + "0x9047c9fad6ef452e0219e58e52c686b620e2eb769571021e3524bd7eac504f03b84834b16b849d42b3d75c601fd36bb7", + "0xa04dd988fed91fb09cb747a3ac84efe639d7d355524cd7dee5477ecbcdec44d8ac1cec2c181755dcfdb77e9594fb3c5b", + "0xb0ea0c725debd1cec496ced9ce48f456f19af36e8b027094bf38fa37de9b9b2d10282363ea211a93a34a0a5387cace5d", + "0xb5fc46e2bb3e4653ea5e6884dcb3c14e401a6005685ee5a3983644b5b92300b7066289159923118df4332aac52045b8c", + "0x841fc5b26b23226e725e29802da86b35e4f5e3babc8b394f74e30fd5dec6d3840b19a9a096625ce79a4f1edae6369700", + "0x8fd2bbbeea452451def3659bbe0ceb396120ebe8f81eee1ea848691614422c81d7c3e6a7a38032b4120b25c5ffa8f0c2", + "0x9131ce3d25c3d418f50c0ab99e229d4190027ee162b8ba7c6670420ea821831dec1294ac00d66c50fac61c275a9e2c71", + "0x99ec6eafe0eb869d128158cee97b984fb589e1af07699247946e4a85db772289dff3084d224a6f208005c342f32bbd73", + "0xac100fbbe7c2bf00cc56fcd5aa1f27181f82c150c53bbb1e15d2c18a51ed13dcfa7bccab85821b8ddddf493603e38809", + "0xaffd73a458d70c0d9d221e0c2da4348fed731f6b34c0b3e2d5711ba432e85a1ec92e40b83b246a9031b61f5bc824be47", + "0x8ed30ed817816a817e9e07374ef1f94405a7e22dd0096aeaae54504382fc50e7d07b4f1186c1792fc25ea442cd7edc6b", + "0xa52370cfe99a35fa1405aeca9f922ad8d31905e41f390e514ea8d22ee66469637d6c2d4d3a7ee350d59af019ae5a10a4", + "0x8d0b439741c57b82c8e4b994cf3956b5aeaee048b17e0a1edb98253a8d7256f436d8b2f36b7e12504132dbf91f3376b1", + "0x8caac7e1a4486c35109cff63557a0f77d0e4ca94de0817e100678098a72b3787a1c5afc7244991cebcd1f468e18d91d4", + "0xa729a8e64b7405db5ebfb478bb83b51741569331b88de80680e9e283cc8299ba0de07fcf252127750f507e273dc4c576", + "0xa30545a050dad030db5583c768a6e593a7d832145b669ad6c01235813da749d38094a46ac3b965700230b8deacd91f82", + "0x9207e059a9d696c46fa95bd0925983cd8e42aefd6b3fb9d5f05420a413cbc9e7c91213648554228f76f2dd757bde0492", + "0xa83fa862ae3a8d98c1e854a8b17181c1025f4f445fbc3af265dc99e44bbd74cfa5cc25497fb63ee9a7e1f4a624c3202c", + "0x84cdfc490343b3f26b5ad9e1d4dcf2a2d373e05eb9e9c36b6b7b5de1ce29fda51383761a47dbd96deca593a441ccb28e", + "0x881a1aa0c60bb0284a58b0a44d3f9ca914d6d8fa1437315b9ad2a4351c4da3ee3e01068aa128284a8926787ea2a618d1", + "0xaace78e497b32fbff4df81b1b2de69dbc650645e790953d543282cb8d004a59caf17d9d385673a146a9be70bf08a2279", + "0xaa2da4760f1261615bffd1c3771c506965c17e6c8270c0f7c636d90428c0054e092247c3373eca2fb858211fdb17f143", + "0xacb79f291b19e0aa8edb4c4476a172834009c57e0dcc544c7ce95084488c3ad0c63ffd51c2b48855e429b6e1a9555433", + "0x814b58773a18d50a716c40317f8b80362b6c746a531776a9251c831d34fb63e9473197c899c0277838668babc4aa0ecb", + "0xb1f69522b0f7657d78bd1ee3020bcce3447116bf62c146d20684537d36cafb5a7a1531b86932b51a70e6d3ce0808a17e", + "0x8549712c251ef382f7abe5798534f8c8394aa8bcecdca9e7aa1a688dc19dc689dcd017a78b118f3bd585673514832fe4", + "0x912a04463e3240e0293cfc5234842a88513ff930c47bd6b60f22d6bc2d8404e10270d46bf6900fee338d8ac873ebb771", + "0xa327cb7c3fada842e5dd05c2eeedd6fcd8cf2bfb2f90c71c6a8819fb5783c97dd01bd2169018312d33078b2bc57e19f7", + "0xb4794f71d3eceed331024a4cee246cc427a31859c257e0287f5a3507bfbd4d3486cb7781c5c9c5537af3488d389fe03e", + "0x82ffcb418d354ed01688e2e8373a8db07197a2de702272a9f589aed08468eab0c8f14e6d0b3146e2eb8908e40e8389c5", + "0x910b73421298f1315257f19d0dfd47e79d7d2a98310fb293f704e387a4dc84909657f0f236b70b309910271b2f2b5d46", + "0xa15466397302ea22f240eb7316e14d88376677b060c0b0ae9a1c936eb8c62af8530732fc2359cfd64a339a1c564f749b", + "0xa8091975a0d94cdc82fbaff8091d5230a70d6ea461532050abbdfee324c0743d14445cfe6efe6959c89a7c844feaa435", + "0xa677d1af454c7b7731840326589a22c9e81efbbf2baf3fdeaf8ea3f263a522584fbca4405032c4cdf4a2a6109344dfc8", + "0x894e6ffa897b6e0b37237e6587a42bbc7f2dd34fb09c2e8ac79e2b25b18180e158c6dc2dd26761dba0cfed1fb4eb4080", + "0x928d31b87f4fe8fe599d2c9889b0ff837910427ba9132d2fba311685635458041321ae178a6331ed0c398efe9d7912f0", + "0xafc1c4a31f0db24b53ee71946c3c1e1a0884bd46f66b063a238e6b65f4e8a675faa844e4270892035ef0dae1b1442aa0", + "0xa294fcb23d87cf5b1e4237d478cac82ba570649d425b43b1e4feead6da1f031e3af0e4df115ca46689b9315268c92336", + "0x85d12fd4a8fcfd0d61cbf09b22a9325f0b3f41fb5eb4285b327384c9056b05422d535f74d7dc804fb4bab8fb53d556bd", + "0x91b107d9b0ea65c48128e09072acd7c5949a02dd2a68a42ff1d63cf528666966f221005c2e5ca0a4f85df28459cdede6", + "0x89aa5dc255c910f439732fcd4e21341707e8dd6689c67c60551a8b6685bd3547e3f47db4df9dfadd212405f644c4440b", + "0x8c307d6b827fa1adcf0843537f12121d68087d686e9cc283a3907b9f9f36b7b4d05625c33dab2b8e206c7f5aabd0c1e5", + "0x843f48dadf8523d2b4b0db4e01f3c0ea721a54d821098b578fcaa6433e8557cadfea50d16e85133fa78f044a3e8c1e5b", + "0x9942eb8bd88a8afa9c0e3154b3c16554428309624169f66606bfb2814e8bac1c93825780cf68607f3e7cffe7bf9be737", + "0xb7edb0c7637a5beb2332f2ae242ba4732837f9da0a83f00f9e9a77cf35516e6236eb013133ddc2f958ea09218fe260d3", + "0x9655fe4910bc1e0208afbcf0ff977a2e23faded393671218fba0d9927a70d76514a0c45d473a97ecb00cf9031b9d527c", + "0x8434bc8b4c5839d9e4404ff17865ded8dd76af56ef2a24ea194c579d41b40ed3450c4e7d52219807db93e8e6f001f8da", + "0xb6c6d844860353dab49818bed2c80536dbc932425fdaa29915405324a6368277cf94d5f4ab45ea074072fc593318edff", + "0xb2887e04047660aa5c83aad3fa29b79c5555dd4d0628832c84ba7bf1f8619df4c9591fcde122c174de16ca7e5a95d5e3", + "0x953ba5221360444b32911c8b24689078df3fbf58b53f3eec90923f53a22c0fc934db04dd9294e9ec724056076229cf42", + "0x926917529157063e4aade647990577394c34075d1cb682da1acf600639d53a350b33df6a569d5ebb753687374b86b227", + "0xb37894a918d6354dd28f850d723c1c5b839f2456e2a220f64ecadac88ae5c9e9cf9ab64b53aac7d77bf3c6dfa09632dc", + "0xb9d28148c2c15d50d1d13153071d1f6e83c7bb5cb5614adf3eb9edede6f707a36c0fa0eadb6a6135ead3c605dfb75bd1", + "0x9738d73ea0b9154ed38da9e6bd3a741be789ea882d909af93e58aa097edf0df534849f3b1ba03099a61ceb6a11f34c4d", + "0xafabbecbbf73705851382902ec5f1da88b84a06b3abfb4df8d33df6a60993867f853d0d9bd324d49a808503615c7858a", + "0xa9e395ddd855b12c87ba8fdb0ea93c5bd045e4f6f57611b27a2ee1b8129efe111e484abc27cb256ed9dcace58975d311", + "0xb501c2f3d8898934e45e456d36a8a5b0258aeea6ff7ac46f951f36da1ec01bd6d0914c4d83305eb517545f1f35e033cc", + "0x86f79688315241fe619b727b7f426dbd27bcc8f33aef043438c95c0751ada6f4cd0831b25ae3d53bcf61324d69ea01eb", + "0x83237e42fa773a4ccaa811489964f3fab100b9eea48c98bdef05fa119a61bde9efe7d0399369f87c775f4488120b4f2e", + "0xb89f437552cab77d0cd5f87aca52dd827fb6648c033351c00ab6d40ac0b1829b4fcdf8a7dad467d4408c691223987fbe", + "0x8e21061698cb1a233792976c2d8ab2eeb6e84925d59bb34434fff688be2b5b2973d737d9dda164bd407be852d48ef43f", + "0xb17a9e43aa4580f542e00c3212fbf974f1363f433c5502f034dfd5ed8c05ac88b901729d3b822bec391cca24cc9f5348", + "0xaac6d6cda3e207006c042a4d0823770632fc677e312255b4aff5ad1598dc1022cab871234ad3aa40b61dc033a5b0930b", + "0xb25e69f17b36a30dada96a39bc75c0d5b79d63e5088da62be9fcbddfd1230d11654890caa8206711d59836d6abbc3e03", + "0xaf59fe667dd9e7e4a9863c994fc4212de4714d01149a2072e97197f311be1f39e7ad3d472e446dcc439786bf21359ede", + "0x957952988f8c777516527b63e0c717fc637d89b0fd590bcb8c72d0e8a40901598930c5b2506ff7fea371c73a1b12a9be", + "0xa46becd9b541fc37d0857811062ca1c42c96181c7d285291aa48dc2f6d115fcff5f3dfdf4490d8c619da9b5ce7878440", + "0x87168fbd32c01a4e0be2b46fe58b74d6e6586e66bbb4a74ad94d5975ac09aa6fa48fd9d87f1919bd0d37b8ebe02c180c", + "0x895c4aa29de9601fc01298d54cfb62dd7b137e6f4f6c69b15dc3769778bfba5fc9cbd2fc57fd3fad78d6c5a3087f6576", + "0xb9cf19416228230319265557285f8da5b3ca503de586180f68cf055407d1588ecec2e13fc38817064425134f1c92b4d5", + "0x9302aaef005b22f7b41a0527b36d60801ff6e8aa26fe8be74685b5f3545f902012fcade71edca7aaa0560296dac5fca5", + "0xa0ccda9883027f6b29da1aaa359d8f2890ce1063492c875d34ff6bf2e7efea917e7369d0a2b35716e5afd68278e1a93a", + "0xa086ac36beeba9c0e5921f5a8afea87167f59670e72f98e788f72f4546af1e1b581b29fbdd9a83f24f44bd3ec14aee91", + "0x8be471bf799cab98edf179d0718c66bbc2507d3a4dac4b271c2799113ce65645082dc49b3a02a8c490e0ef69d7edbcb1", + "0x8a7f5b50a18baf9e9121e952b65979bda5f1c32e779117e21238fb9e7f49e15008d5c878581ac9660f6f79c73358934a", + "0xb3520a194d42b45cbab66388bee79aad895a7c2503b8d65e6483867036497d3e2e905d4d51f76871d0114ec13280d82f", + "0x8e6ca8342ec64f6dbe6523dc6d87c48065cd044ea45fa74b05fff548539fd2868eb6dd038d38d19c09d81d5a96364053", + "0xb126a0e8263a948ba8813bf5fb95d786ae7d1aa0069a63f3e847957822b5fe79a3a1afa0ce2318b9ba1025f229a92eb7", + "0x8e4461d6708cac53441a3d23ac4b5ff2b9a835b05008c26d7d9c0562a29403847cf760b7e9d0bcb24a6f498d2a8a9dd2", + "0xb280a761bab256dfe7a8d617863999e3b4255ddbdc11fe7fe5b3bb9633fc8f0cb4f28e594d3b5b0b649c8e7082c4666a", + "0xa3e3043bfd7461e38088ee6a165d2ca015de98350f1cb0efc8e39ed4fcdb12a717f0ede7fbf9dadb90496c47652cc0ce", + "0xa4c1f5b1b88ae3c397d171e64395afe0cd13c717677775a01dd0461d44a04ee30ec3da58a54c89a3ca77b19b5e51062c", + "0xa268638e0655b6d5a037061808619b9ae276bb883999d60c33a9f7f872c46d83d795d1f302b4820030c57604fa3686e7", + "0xac20176111c5c6db065668987227658c00a1572ce21fe15f25e62d816b56472c5d847dd9c781fb293c6d49cc33b1f98f", + "0xacc0e22d9b6b45c968c22fd16b4ece85e82a1b0ab72369bdd467857fee1a12b9635f5b339a9236cbd1acc791811d0e29", + "0xb56066e522bee1f31480ff8450f4d469ace8eb32730c55b7c9e8fa160070bdec618454e665b8cbc5483bc30b6cebbfb9", + "0x8c1772bdfacff85f174d35c36f2d2182ae7897ad5e06097511968bbb136b626c0c7e462b08a21aca70f8e456b0204bf8", + "0xb4de3cf4a064bf589be92513b8727df58f2da4cd891580ef79635ac8c195f15a6199327bb41864e2f614c8589b24f67e", + "0x8f3c534125613f2d17bf3e5b667c203cb3eab0dbca0638e222fe552fddf24783965aa111de844e8c3595304bfc41c33b", + "0x8e445b2711987fe0bf260521cb21a5b71db41f19396822059912743bf6ca146100c755c8b6e0e74f1bf2e34c03b19db9", + "0x87ff9adf319adb78c9393003b5bdda08421f95551d81b37520b413fe439e42acf82d47fa3b61476b53166bf4f8544f0e", + "0x83f3c00c55632e1937dcdc1857de4eccd072efa319b3953d737e1d37382b3cf8343d54a435588eb75aa05bf413b4caa0", + "0xb4d8ee1004bac0307030b8605a2e949ca2f8d237e9c1dcf1553bd1eb9b4156e2deb8c79331e84d2936ec5f1224b8b655", + "0x93b2812b6377622e67bf9a624898227b56ebe3c7a1d917487fc9e4941f735f83679f7ac137065eb4098ad1a4cfbc3892", + "0x81943d9eab6dcea8a120dde5356a0a665b1466709ebb18d1cbfa5f213a31819cb3cf2634e6d293b5b13caa158a9bb30b", + "0xa9042aae02efd4535681119e67a60211fc46851319eb389b42ebadcab1229c94199091fb1652beba3434f7b98c90785f", + "0x91db52b27fd9b1715df202106b373c4e63ce8ec7db8c818c9016ace5b08ef5f8c27e67f093395937ba4ce2f16edf9aef", + "0x83cb9b7b94bd6ead3ff2a7d40394f54612c9cb80c4e0adadffea39e301d1052305eb1fe0f7467268b5aba3b423a87246", + "0x8720fd6712a99d92dd3fdaae922743ab53fad50d183e119a59dae47cdac6fbea6064c732d02cb341eaea10723db048fa", + "0x8d40022c1254462a2ac2380a85381c370b1221e5a202d95c75bccba6d1e52972dd5585a1294a1e487bf6ae6651867167", + "0xb7bc06e08d8c72daba143627582f4b4f34cc2234b5cb5cd83536f2ef2e058631a3920468ea4d550aea01cad221d6a8a6", + "0xa6e1a6f70fba42d3b9ce5f04ffdcfca46fc94041840c0066a204030cf75ea9f9856113fea3a9f69ea0037d9a68e3a9d4", + "0x8b064c350083fce9a52da2e2e17bf44c4c9643d2d83667cbd9ad650bbeba55e2c408e746ccf693e56d08826e8a6d57fc", + "0x8d304a5405a0c0696917fcddc6795dd654567ca427f007d9b16be5de98febbf8692374e93f40822f63cf6f143c4d9499", + "0xb968db239efec353a44f20a7cf4c0d0fca4c4c2dc21e6cbb5d669e4fe624356a8341e1eec0955b70afb893f55e9a9e32", + "0x98971f745ce4ce5f1f398b1cd25d1697ada0cc7b329cee11d34b2d171e384b07aeb06ac7896c8283664a06d6dd82ec6b", + "0x881f5a20a80f728354fad9d0a32a79ffe0ba9bed644ed9d6a2d85444cda9821018159a3fa3d3d6b4fadbf6ea97e6aff6", + "0xb7c76cbb82919ec08cf0bd7430b868a74cb4021e43b5e291caa0495ca579798fab1b64855e2d301f3461dd4d153adeb6", + "0xb44c8c69b3df9b4e933fe6550982a6f76e18046e050229bd2456337e02efb75efa0dfe1b297ed9f5d7fa37fec69c8374", + "0xa5bd7781820ba857aee07e38406538b07ab5180317689a58676f77514747672dd525ea64512a0e4958896f8df85e9d4d", + "0xa8443d1dc91b4faa20a2626505b5b4ad49cc5c1fd7a240a0e65d12f52d31df1585ba52c21e604dcec65ec00b81ae21fe", + "0xa157ae42fc6302c54bcdd774e8b8bafc4f5d221717f7bf49668c620e47051b930dce262d55668e546272dd07ca7c8d3f", + "0x8732c10448b63e907ff95f53cd746f970c946fd84fcbfe4cf9ede63afbbfc66b293bbc7c470d691bbd149bb3c78bb351", + "0xa82192f4fd9a0c33489a0486b79d0f6c797c7eccb45f91f7f1e8e1dd1924ca9944b983951025b99ab5861d31841451fe", + "0x839efc6d199ddd43f34f6729b6b63f9ee05f18859bf8fd3f181fa71f4399a48bff7dde89b36e9dc1c572f1b9b6127cca", + "0x992ef084abe57adfd5eb65f880b411d5f4ed34c1aeb0d2cfac84fff4f92a9a855c521a965ba81b5eef2268e9a9e73048", + "0xa2518ab712fa652e6e0bd0840307ef3831094e9a18723fb8ec052adacbb87f488d33778c6ec3fd845003af62e75125d1", + "0xb630ac3c9e71b85dd9e9f2984bb5b762e8491d8edb99cad82c541faf5a22dd96f0fddb49d9a837b1955dea2d91284f28", + "0x8d886d1b7f818391b473deba4a9a01acce1fe2abe9152955e17ba39adc55400590c61582c4fef37a286e2151566576ed", + "0x884f100dc437639247f85e5d638fcc7583d21bf37a66ce11e05bfc12f5dbe78685b0e51b4594e10549c92bb980512e12", + "0x806d7bac2d24cfff6090ba9513698292d411cdea02976daa3c91c352b09f5a80a092cfa31304dcfcd9356eaf5164c81b", + "0x934ed65f8579ee458b9959295f69e4c7333775eb77084db69ad7096f07ad50ad88f65e31818b1942380f5b89e8d12f1b", + "0xaaf50ca5df249f0a7caf493334b6dca1700f34bd0c33fe8844fadd4afedbb87a09673426741ac7cbbb3bf4ab73f2d0f3", + "0xb2868642cfa0a4a8a2553691c2bef41dab9dff87a94d100eaa41645614ab4d0e839ec2f465cc998c50cd203f0c65df22", + "0xa326513112e0b46600d52be9aa04d8e47fe84e57b3b7263e2f3cf1a2c0e73269acb9636a99eb84417f3ae374c56e99b0", + "0x97b93efc047896ddf381e8a3003b9e1229c438cc93a6dbef174bb74be30fac47c2d7e7dc250830459bed61d950e9c924", + "0xb45e4f0a9806e44db75dbb80edc369be45f6e305352293bcae086f2193e3f55e6a75068de08d751151fdf9ebc6094fa1", + "0x87f2161c130e57e8b4bb15616e63fa1f20a1b44d3e1683967a285f0d4f0b810f9202e75af2efa9fc472687c007a163f7", + "0x8f6400a45666142752580a2dce55ef974f59235a209d32d2036c229c33a6189d51435b7ea184db36f765b0db574a9c52", + "0xa0ee079462805f91b2200417da4900227acde0d48c98e92c8011a05b01c9db78fc5c0157d15cb084b947a68588f146f4", + "0xab0612d9bb228b30366b48e8d6ae11026230695f6f0607c7fa7a6e427e520121ff0edea55d1f0880a7478c4a8060872d", + "0xad65dfde48f914de69f255bb58fa095a75afe9624fc8b7b586d23eb6cf34a4905e61186bc978e71ccb2b26b0381778a6", + "0x8c8a4847d138d221c0b6d3194879fd462fb42ed5bd99f34ebe5f5b1e1d7902903ec55e4b52c90217b8b6e65379f005a4", + "0xa41dca4449584353337aef1496b70e751502aeed9d51202de6d9723e155ca13be2d0db059748704653685a98eaa72a07", + "0xae40e5450fd994d1be245a7cd176a98dd26332b78da080159295f38802a7e7c9c17cc95da78d56558d84948cf48242cd", + "0x863878fda80ad64244b7493e3578908d4a804887ad1ad2c26f84404dcad69ea2851846ad2c6f2080e1ed64fe93bbec31", + "0xb262fb990535f162dc2b039057a1d744409a3f41dd4b70f93ff29ba41c264c11cb78a3579aad82f3fa2163b33a8ce0e1", + "0xa7f6eb552b9a1bb7c9cb50bc93d0dda4c7ecf2d4805535f10de0b6f2b3316688c5e19199d5c9ec2968e2d9e2bd0c6205", + "0xa50aa5869412dc7081c8d827299237910ecec3154587692548da73e71fa398ff035656972777950ba84e472f267ba475", + "0x924c3af750afc5dfad99d5f3ed3d6bdd359492cff81abcb6505696bb4c2b4664926cb1078a55851809f630e199955eb3", + "0xa1acffa31323ce6b9c2135fb9b5705664de8949f8235b4889803fbd1b27eb80eb3f6a81e5b7cc44e3a67b288b747cf2f", + "0x8dec9fd48db028c33c03d4d96c5eecea2b27201f2b33d22e08529e1ae06da89449fe260703ac7bb6d794be4c0c6ea432", + "0xaa6642922ccf912d60d678612fffe22ef4f77368a3c53a206c072ed07c024aa9dcde2df068c9821b4c12e5606cfe9be2", + "0xa16ddf02609038fcb9655031b1cb94afe30b801739e02a5743c6cd2f79b04b2524c2085ca32ec3a39df53de0280f555d", + "0xb067d48589e9d3428c6d6129e104c681e4af376a351f502840bbea6c3e11fcbfdf54dadf6f1729621720a75ff89786c3", + "0xb14a24079de311c729750bb4dd318590df1cd7ffc544a0a4b79432c9a2903d36a0d50ecd452b923730ade6d76a75c02c", + "0x97437bac649f70464ace93e9bec49659a7f01651bba762c4e626b5b6aa5746a3f0a8c55b555b1d0dc356d1e81f84c503", + "0xa6f4cb2ffc83564b1170e7a9a34460a58a4d6129bd514ff23371a9e38b7da6a214ac47f23181df104c1619c57dff8fe2", + "0x896d0f31dfc440cc6c8fde8831a2181f7257ffb73e1057fd39f1b7583ea35edf942ad67502cd895a1ad6091991eabc5e", + "0x9838007f920559af0de9c07e348939dfd9afe661b3c42053b4d9f11d79768cba268a2ee83bb07a655f8c970c0ee6844b", + "0xb41b8a47e3a19cadec18bff250068e1b543434ce94a414750852709cd603fc2e57cd9e840609890c8ff69217ea1f7593", + "0xa0fb4396646c0a2272059b5aeb95b513e84265b89e58c87d6103229f489e2e900f4414133ed2458ddf9528461cfa8342", + "0xae026cfa49babc1006a3e8905d6f237a56a3db9ddf7559b0e4de8d47d08c3f172bde117cdf28dfdfd7627bd47d6a3c85", + "0xa6a3f3e7006bc67290c0c40c1680bf9367982eb8aaf17ecb484a58c8e9c2a7c24932e2caa9aacc9b4fbf4c0abd087a46", + "0x9093e05bd814177a01a3b8d7b733db66294e1c688c56def6e1827c0f2d9a97cf202721641bf81fb837f8581ae68cb5ce", + "0x87feef4de24942044f47d193d4efc44e39a8c0f4042fba582f2491a063e3a4640cb81f69579b6f353b9208884a4f7ce6", + "0x975f9b94e78aac55bd4755f475e171e04f6fbddb6fd3d20a89a64a6346754a3ff64ecff8c04b612a1250e1d8d8a9e048", + "0x87cde4d0164922d654cf2dc08df009e923c62f1a2e3b905dfde30f958e9e4dd6070d9f889712acd6c658804f48f3edb1", + "0xae8e22e158dda90a185eec92602831b5d826e5a19aab8c6400dba38b024c7d31c4cf265eb7b206dd45834f020b3f53cd", + "0xa4475807adc28aa086e977b65bbd7c8512119318c89d2619ea03a6739a72c3fb90c9622451896c7113ad4d12a3004de6", + "0x97f1ae1e0d258a94532c7b73fa8ebdbbd53349a4d2d0a217fe56dfdd084dd879960bc6ff45ebb61b5dbf2054642800a4", + "0xb3c832bd3691332a658b0caaa7717db13f5b5df2b5776b38131ac334b5fd80d0b90b6993701e5d74d2b7f6b2fd1f6b9d", + "0xa4b6af590187eb1b2cb5ae2b8cffa45c5e76abdb37cec56fc9b07a457730f5af0706d9ce0a17da792bbece5056d05670", + "0x97b99a73a0e3145bf91f9dd611a67f894d608c954e9b8f5a4c77e07574064b3db47353eba8038062cebaad06a2500bab", + "0x8e5ca5a675de6e6d3916bd9ce5898bb379372afe3f310e70ff031bc8cc8fabfb7f3bfb784f409bb7eb06fdb4511ee477", + "0xaabbbee4da1f16b5bbe001c19debe04745932d36dfbbf023fbf1010a2b1d54eb92fa5e266ac1e9337e26e2ddba752f40", + "0xb13447c77496825f48e35c14f9b501c5056e6d5519f397a2580cea9a383a56a96994d88926aa681142fe2f1589c03185", + "0xb89c55db39ff0e73dde7435b61e8a4d3e10f51dd8096cbc7f678661962e6de3d16f2f17a0e729cc699234cb847f55378", + "0x82c36b7de53698a1bafbb311fefc6007fcefa47a806ebe33a4e7e0fc1c7b6b92a40a1860702cf9295a16c6b1433e3323", + "0x8daeec8c88543d09c494a15cc9a83c0b918d544311fd2a7d09e06cf39cdebfa0cfc0e8fc0e3b5954960b92332f98697c", + "0xb18e55a1a7ae16be3a453d2bfa7659a7ec2d283dd46bdc82decef6d3751eeafc4f86f2416a22955c7e750c0582d4f3eb", + "0xb50c743462e2915bf773848669e50a3bcdb5a9ac5f664e97eaccf568c7d64a6493d321be0225de16142ce82ce1e24f66", + "0xaf69c9643805fb860434424b1608aababc593aaebc6a75fc017f7f62bb2b1da932b0b9bd5e6dcbba328422dafc06efd8", + "0xb5947db4f809fd0d27af838b82eef8ab4fe78687a23ebc61c09c67eb7e8d0e6a310ecb907fd257859d5a2759a07c21cc", + "0x92c7960e163ca5bdf9196c7215102f8e9d88efc718843321c6e2a6170137b8ecec4ea5d5a5ce4c28012b6cdbd777dd01", + "0xb63f9509ed5e798add4db43b562e8f57df50d5844af6e5c7acf6c3b71637c0a2d2433f4a0627b944f0af584892208bb8", + "0x8ef28304a9bfe5220af6a9a6a942d2589606f5dc970d708ef18bc7ed08e433161020d36fb327c525398cd8ecb57002f9", + "0xb722e0410f896c4462d630a84a5a14e94289fc38ed6d513ca88a09005935cec334c480028efa1943c7a5e202ae8c8379", + "0xb56b6672b488e64d4dde43571f9ceaa7e61e336b0fd55bb769a57cd894a6300e724e5f88bad39a68bc307eb7406cb832", + "0x8bf493da411fd41502b61a47827731193652e6ce3810709e70869d9aae49e4b17a40437a7a0dcc0547dbac21f355c0da", + "0x9613b60a144c01f6a0e7d46ddde07402e2133a1fe005c049a56415ff90401765040b2fc55971d24b94c5fd69fec58941", + "0x85e2f02b291563d8eea3768cf6a4602c0ca36568ffcf3d93795d642044196ca6b0b28991ea5898e7974ee02831a0ec70", + "0xb08ef66703dd9ac46e0208487566fbf8d8654d08c00f03e46f112c204782ccc02a880a3f9dffd849088693cee33b7b6d", + "0xa0b19eeda6c71b0e83b1f95dffef4d370318bdea6ea31d0845695e6b48d5c428c3dbba1a0ded80964992c4a0695f12ee", + "0xb052642e5772d2ef6f49dd35c5e765c5f305006b2add3b4bee5909ca572161edf0e9c2bc3bc3bc7f56fd596360ef2201", + "0x8261af164c768fec80d63fca6cd07d1c0449e9ca665fe60c29babdbd8a2b20cf1f556a4b24cd7341712468a731c21b32", + "0x8a17016a1b2fc0fa0d9e3610ea80548fcf514e0a35e327f6b5f8069b425c0f0829af7e206013eab552be92b241be5ac5", + "0x8eea25c680172696f5600271761d27ef4c8cec9ab22f01f72b2c7c313a142fafaec39e6920b96fcace858883e02eff7a", + "0xb8e0c590106e125c5bca7e7a071cc408b93629da0d8d6381f1b73fbdf17024a0cf13f679f5203a99bbbcb664b4a94e88", + "0xb9943b29395258b7afdf1781cfaf131297a4f325540755df73401b2ec4a549f962952e9907413c39a95585c4aff38157", + "0x8286eab4a04f8113fb3f738a9bc9c2deaf3a22bf247151515568703da4efe6450ab3970f5c74e978a2db7e8d795331b7", + "0xa10cf383c8a7e3f0a0a5556b57532170ff46dabdcbb6a31c4617271634b99540aa575786c636d3809207cbf1d2f364d3", + "0xa5af7eb998140d01ba24baa0e8c71625aee6bd37db4c5ff607518f907892219ba8c9a03c326b273bfd7068232809b73c", + "0xaed5f461e38fccc8b3936f1328a9747efcbceb66312f6d6eddce57c59570852767159f1a7d9998f63342515fef4ba9bf", + "0xaec3e94b029aa692bfe2b8dbc6c3b0d132b504242e5ebe0cad79c065085e2fc05550e5cdaa2353892a40ff1a062dd9eb", + "0x87c23703960129396018d0347f5dd034abdbd57232b74195b6a29af34b6197b3cd63c60ac774d525add96ae54d5c0fb4", + "0x97964a7768216e1c84dece71ce9202cc64b6d483650aa6f6d67215f655f66cda14df0a0f251db55832c77bfd9b6316e2", + "0x8167aaf24c8a023d0aea16b8c24d993618b9d0c63619e11a28feab8f14952bafcb0918ed322cbc0ae1b2e1786071819b", + "0xb58318bd62852ffb712fc58f368c21b641dde7b3fa7d7269974c7a7b5b3e1641569fc7b5f32ca49de22f4f993506d92d", + "0xb172e7911d5cd3f53af388af847b928947c711185aebd3328f8e6ed1106c161ae0c1b67d3d9eb237e9e66eb0672edec0", + "0xa6834cf69b2c4433cf6e779bfbb736b12e73e71e149c38101d13dbacf6c5048db53994a6a039381df40bbd67de40fcd0", + "0x882604aa3bb19fffd6db744b5cf4a2431b157dac06d0617e0703684a118ca90b2d22a7758a1de7732a7144e68b11b7f7", + "0xaddc128ba52bf7553b9ba49eff42004d388a02c6b6e9809abe1c0d88f467e5ff6cb0c82a8fd901b80dfc9a001f7b9997", + "0xabf19604a3f0cffefa7a9ced81627f6aacb8d7267b52b825f25d813d9afa24af6d70da21450ed93eaff8b4d2a9b905a9", + "0xa3c67e7bf02dbca183d86924611a7149556ee17cb3469793624da496b6c25617a9071925dd02aab9cb028739cb79043d", + "0xb1cea4284a3ac4d5b1c6f0947c6ec8365b3281ed15495bf328a907a9a02cdd186e7cb1ef080385b3399df786855985a9", + "0xa6edb126314559e6129caf1111dc3c82ff914efce658b11f2c9b48081be1cf3f46bde482469d493379025a158d95ab1b", + "0x9843fd7dd424da1acc6f92f87fac364a8b0d4097d74b6b451386384966c85145d43fc6ecedf04271b0f963ac731fd93f", + "0x83852bedca03a97a2e63053cb102387866cbefe6707ebb6dae2d32a59c343079f1a863f299fd64d0ecbe024d0a1247d5", + "0xa570e645a0679ebc6f0ca03cc8f7367b03c3886f3d9c787992de7f3e93360a170d3ac9ae7720999c727a887b1dc762bb", + "0xad644c40555238f28844eed632c8972b63d2602098031d53b5599d1a874903e0d0c428e0ab12a209ea3fb31225578f1c", + "0xb64e9f92a14812ed31075f9fdd3324659a036ef2f293ef9ca6f6feb87d0c138e1ba74bc36a910afd22ff9b3c8ec7cfa5", + "0x8f2d75a86d517dafac09b65596f4b89c4a9c0a7003632407504153fa297c9e3228e236948a5d5224b8df49a087c8e0e3", + "0xb02d6ab9292ae336c8a74115f33765af2c9f62c331d70c087cf4c2979792bb3c2666f6699c017f8d4c6b378fd4bda86a", + "0xa923d660d2e55228b8bc74f87d966069bd77c34a776fa96f37b48539c85634482e514e2cb76cb8eb20efd85eb9c83fae", + "0x81d7ffb53090a6d512055ecfd582ca92805525a05654e39bb12653a6a8902a16e651ba7b687b36b8bea7186632c7e9e3", + "0x83e9b33e29b57ae53d9f72bd4622ff388252333b4fa32ad360a5b00f3ffc8813b9cb8a1361454d3bb7156c01b94b6a08", + "0xad7d6bffe4d67eb53b58daa3fc8a5a60790c54fa42226ae12847e94c6de3b4365b3be39855a4f6a5f12e4803cdaed96b", + "0xa7709fed85abbee5a2fa49c5238582ec565da08c132d4912821491985bf83b681eb4823634bfe826abd63a6c41a64ea7", + "0xb8fb6ed55741132a1053b6ca77bdf892e96b048488373ba4aa2f2225fae6d578724124eb6975e7518e2bf3d25d215763", + "0x85e0c53089529a09b5bce50f5760af6aeafef9395388aa4b6144ca59953169101783347ee46264ec0163713a25fe7c63", + "0x8f9e47a9c37b678e56c92b38d5b4dab05defc6b9c35b05e28431d54b1d69ac31878c82c1357d016f3e57ca07d82d9c16", + "0xa81f508136ee6ec9122c48584df51637f768ccfe8a0b812af02b122a0fafa9abcc24778bf54143abb79eccebbdde2aac", + "0x931a96d2257a4714d1ef20ac0704438481632647b993467e806b1acc4a381cc5a9dec257e63239ba285deb79f92122dd", + "0x99fb0ff747bcd44b512bf8a963b3183ce3f0e825a7b92ddd179253e65942a79494a515c0c0bc9345db136b774b0a76b0", + "0xa9dbb940b5f8ab92f2d85fc5999e982e3d990fe9df247cfc6f3a3f8934fb7b70e2d0362ba3a71edc5d0b039db2a5f705", + "0x99011a1e2670b1b142ec68b276ff6b38c1687eed310a79e2b902065bc798618c0cdee7b2009ad49623ed7ae0aa2b5219", + "0x9361e9f3aa859c07924c49f3d6e9b5d39a3df2fc1c10769202ec812955d7d3814c9e6982f4df3a8f3bdbfb4550cd1819", + "0xa8aa23f177ddc1e7a7856da3eac559791d8b3f188c0b3ae7021bcb35dfb72b0f043c3699597a9188200408bc3daf6ab7", + "0xa5a502ff673f6dab7ae4591a7b550c04ede22a45a960c6b5499644f721c62b12b9e08248e7f8b8a59a740b058d2a67e6", + "0xad374f80f0b52bc5a9491f79a547ce5e4a3ce4468a35d7dbca8a64083af35ab38eff9aa774ccba2e2e1e006e45cb0b85", + "0xab6851827125e3f869e2b7671a80e2dff3d2d01ce5bfbeb36cbaf30c3d974a2d36fd9f7c3d331bb96d24b33dbd21f307", + "0x96658f6a2d225a82f7ccee7f7a7e476967e31a0cd6c62859d3b13ee89702bb821547f70ffd31cb46a6a0d26a93158883", + "0x878f59ff2590bc3d44fdc674717589800748b78d543d3c0dbb50125b1d6011d6a083f10ab396e36b79f2d89b7cf51cdd", + "0xb8bdfb97829c5d973a15172bfe4cb39620af148d496900969bd7ca35de9b0e98eec87af4e20bef1022e5fb6c73952aa0", + "0xa292a78b452743998aee099f5a0b075e88762222da7a10398761030ffcc01128138d0f32fccf3296fcbea4f07b398b5f", + "0x85da44fdd7b852a766f66ba8804ed53e1fc54d282f9a6410106c45626df5a4380cbea2b76677fdfde32446a4d313742a", + "0x84bebf036073d121e11abc6180cba440465c6eaadc9a0c0853a5f1418f534d21cccf0cfc62533eaeae4653c7b4988046", + "0x923dec006a6af04ef675f5351afffffd2c62a17a98f4144221927c69f4553dd105e4fcc2227b5f493653d758cd7d0352", + "0xa51eda64f4a4410a1cfa080d1f8598e23b59856436eb20a241e11106989fbbb48f14c2251f608cbf9531c7c442b30bf7", + "0xac6d26ae7bab22d49b7fba7fe4b8cf6d70617977008c8290787c9da1a4759c17c5e441efb3dee706d5d64d9d2ace1de5", + "0xab5138b94d23c1bf920b2fb54039e8a3c41960a0fe6173261a5503da11ff7b3afdb43204f84a99e99888618a017aac1b", + "0x8c85647a91e652190eee4e98a1eec13a09a33f6532926427bf09e038f487e483f7930fbe6ff7a2126ccde989690dc668", + "0xa6026ab87cffec3e47b4c9673957d670cb48c9b968d2ad0e3d624d81c1082dcebbc70d0815cbd0325e0a900d703a6909", + "0xac4f6ff6baf8374a3c62bdd5a8d207d184ff993f6055bcee1e6dcc54173d756c37c24570d6462395add6f7871d60b1ae", + "0xa0dd6bc93930d0016557588f2598b7462ca48cbed637c8190be0fb4811e4576217ca9fc3c669c2a4db82e3f8bb24acaf", + "0xa67c1d79f7e7193a23e42928a5cc6a6e8e0c48b6b286607dbcfaaa0f10a7ba29ad62d1d57ca28c486794f0908bece29c", + "0x822f411bab4882202ed24e67c84e0c9a8da5b3389804ed9dfba0f672e3e1457ea76cad0cb935dbb3d7a39500fba5fe12", + "0x8a1198572323689300a9d7db2e2bcb7c519392e5d3d33e83cd64bcf1517a7dde52318a98203727b186597702c0eed258", + "0x8a84141b02f1d037c68d92567d71cda3a0b805d1e200b1d3fff3caf9902457cbfbaac33157b87ab0bb9e4fe3bac882c3", + "0x8070ace16d9eef8658fdcf21bed0d6938f948f31ca9d40b8bdb97fc20432cd2a7ef78eeefc991a87eae7f8c81adf9b19", + "0x9522e7123b733ce9ca58ab364509f308a1ead0915421ccede48071a983fd102e81e1634ffa07a9e03766f167f5c7cb5e", + "0x82cbdf97a755e952304f5a933fd4d74a3038009f242dac149595439130a815e9cc0065597c0b362130183a4c4a444173", + "0x81e904f9b65cd7049c75f64c7261e0cbb0cc15961ffcac063d09399d0d2b0553b19e7c233aca0f209f90cf50c7f5e0b2", + "0x8f5f6ea87429542ea04ad3eb5fc7eeb28fcf69c01c1a5d29b0de219524f6fba90c26069bfc9092379fe18cb46274393a", + "0xa4e5815481eb33b7990d2de1a3a591c1ab545b64fbeb4cff8c71b6bcb04d28940097899062bf43b27c5a8f899616703e", + "0xa7afe6066681e312882b3b181f462a1af2139d9bd2aefffae7976f3fc357bfd8fbd6ddd4e5e321412f107736e77f0cb6", + "0xb8ab102d7ff8d46b055095d8fb0ec2f658c9e18eee523c295b148b37f8342c120798113553b8bfebf2a11f27bc704cc4", + "0x862175ecc7e0e294c304a0352cd0f1d11b2603d326bb0e54e02b6cc8d04d01ac31c8864e9395aa1f3b90b76bc4397f5b", + "0xa4ea51ef3d82509f0e4eb6af705fa7530921cf9512cb5bf030571e69f4504a299297219a0a7e40db1b45165a5ea3a3f2", + "0xa6fb8b573e2ba6db0e8aba53a489e99bebe533c0fcd947dbfa732e00594f03f4e8609ccc44d8215986d38bc3d4e55d48", + "0x93fe8e0bdd5d66df2bd18be5963e864bddfcdcd3298590e7c3b11d99a070a4948fecef46453f19960bbfeada37979613", + "0xacbc45bc55c7080b45c69a3db80cbfc0267006dcf49c47330975aeff2a8ac07b206e1b1c3a515e50866ff510739b92c0", + "0x94a577df0983e4ee3d6b80c73d7e8e3bb78bd8390ff56fea350e51bdf5e0176b8494e7e81dc7b1d842ada961089cd1eb", + "0x81eb1fbe9e9c89f5818d0ef98e694da86e88625f0a37cfe88e6de69f90e58297e67f1d5c9d71263b523b63e42685975a", + "0xa81a2391ea4d0f65ab4325196559d67e2648b3f1e464509430b40d9948d5b0fc01c337d9b51048a93c4d62e6b73e1e8c", + "0x849a026e55ed77135138836c9df67883763e4602357d8566da2ee2505d135d44061de0c070cf333ffb9ac2e55a0894b2", + "0x8e272cc5734374c003c7b2e6ba833eb99b6be608da04e576df471c24705b6b2a790549c53e7971df2d9f0b88d0f570c6", + "0xb0f9e6d985064aa311d4a147f41007fdc576b7b9194aa4b8712bf59a76a71543fec2ee3db21bd3d30d4096f25babc543", + "0x96331837f0d74e2ba6cb1bfaddf4b1fb359bf46cb6c3c664938eb030e56bc85a5ce17bcd60b7fa7b72cb0ba1f3af0b5b", + "0xa0eaab6de4b5a551896e7d26153fb5df4bc22a37833ec864090b57b5115b0f8f1279e855cea456bb844802b294b0dbb7", + "0x955e87d3b966edff34f28137f871881c59bbbc6d69986b739867807680ca22b5e3272ced1d25854ed9700d87f133848b", + "0x9270a6db157a8ce78a1af6bfe2b5bbe7b621d56cc8f9940a03b5a5f600848b87b05d83595b2a3a315d4b7f4687c46085", + "0x9043328f2dd4dd85e14c91237a3478dc1eed239164924b53d1de9364d76c81315afa9639b58eedb1ab2122e2ae2e7cfb", + "0x857fe9f7d00b03bce367de7f789d755911a5f85d78044f18311ecd9b955e821b4a50228347260ba1205aef61219001fe", + "0xa0f878050367a7103fddf380908da66058ef4430eae1758335c46c24f5c22fefb0753991b3a47dba5c7eaafa4d598178", + "0xab5959296b1af14d2878816c7da9926484cbf8896b7eeac8a99dc255013319a67a0209025e1f8266ffd8cd7d960bdc87", + "0xabe53abc57ea46419dbe0ac1f39eee39a4feae265e58b50928eb0695e25938a16a8b00e65c1313837dc3367297e2c258", + "0x93e3e42ed6ba9c45d4e7a4bf21c1e469efafded1f3be9931a683dbb780db2494742fd76c9ad29fd7d12da2b778ede543", + "0xab3e64035c488a6e63496ddb2de9648cc63a670c5d4b610c187d8ceb144fcc50b016046f50b10e93b82937ebe932ac08", + "0xa3a8fa898f489b313d31838ad9f0c7ffe62ef7155de5da9ffe6ecd49a984fac3c6763e8cb64e675e1c4a0e45e7daf078", + "0x8356b26aa7c9fc9734b511480dad07b164cfec1324ad98eec9839a7943f2889d37c188d465515ad4e47c23df641c18c3", + "0x83c4476f829e0fe91da2353d5b58091e9335157941e89ca60ccab1d7fdd014bcf21bd55249805780ddc655c5c8c2536e", + "0x814f6e66505b2cb36de92c0de8004d6d094476522e66b9537787beff8f71a1381ed9f2b7d86778979ad016a7dae6cbac", + "0xb1cd7f6da4a625b82bea475442f65d1caa881b0f7ce0d37d4b12134d3f1beb3ad4c2f25f352811e618c446185486adb6", + "0xa71b918481b9bda667de0533292d81396853a3b7e2504edd63904400511f1a29891564d0091409f1de61276d2aebc12a", + "0xa2cd3d4104ec5fb6d75f5f34762d5e7d2ff0b261bea5f40a00deec08fbdab730721231a214e4df9b47685d5bacfe37c6", + "0x807f2d9de1399093bf284814bc4093f448f56a9bde0169407cdc0e7d2a34ff45052aef18bcb92f0ac7a0a5e54bd843e9", + "0xabeb03010c3ac38587be2547890a8476dd166ac7b2a92c50d442f031eaf273ad97114c38e57fe76d662c3e615334ac0b", + "0xb90a688da4b0bf65ff01bcf8699f0cba995b3397fcbe472e876ae1091a294463e4b94350ae8bd5c63b8441089e0884fd", + "0xad88db4afb177931788fb08eff187e15ad739edc7e1a14c8b777b6bf668aec69ca4749773f94250c1fdda3b59f705f7c", + "0x9886809f9ae952797c6527c6db297d2aa3d5209b360efe6a19970575a9f78aee3c21daadb8e8dfcbeeea5290238d16d9", + "0x930f486e95d7c053c9742e6f0b31e6d4fa2187e41229e46a074b469aafb87880aa8e972719b363049fc9fe2db8f03ce2", + "0x8d229af4fa08bd8aeb5fd9acfee47571eb03fcd2f19073b94cd27e2a6735029d31f123249d557f8d20c32ac881eae3aa", + "0x84576ed5aebe3a9c3449243a25247628993fdb2cc327072418ea2f1d11342756e56e9a82449bc3ea6e8eaecabc62e9b5", + "0xb775cb86cbec9c46a4a93d426379c62872c85dd08bccda39b21cb471222b85b93afd34a53337b6d258f4891c6458e502", + "0x8be1540e6b535b416b8d21e3ecf67dfb27a10fd4010f9f19426422edaeb0a4961d43ff3afd1db0994170056ce4d77aec", + "0xb9c7438e90a5501a4d05bbb8ab68d6db7e9baa8927231a5c58715ee2ab76ca1da0e94910a076958654869148d813d0e9", + "0xaa9bed1c4d2e7cbc2e1a884c8998773f7cc6fa9d6493c8abe8b425114a48305c3a43a1abda2292177ffd39ef02db4163", + "0x897b395356047cd86f576cfc050f7e4546ecd4df30b2c31ed8945797b81dd4ed9b9106cfbe6d7dd8bf91882e3cf1f42e", + "0x949a37e1037d9464b2ccd3ad23eda7089570d6b5ffa18025d2548a9df8829de8d62960f04a603f21eecbca5893d45284", + "0xb8a0642f68ff169ffbcd8cd684fae75d96f9bd76949472775bf155edc55a3d9c3e6f0299ee73a6cfb96289361fdbe9ee", + "0xa1273141510fcddd89b9b92c19a268dadd1528ad85744b8174684c9b56668e6b35dabb05f2b4cc6ef5611eaea6052f27", + "0x97c7415c82de83ecc066eb922268b8205ad7266c65b2b8f7e0aadac87f076c738cea72f9b0f069b8d28cf9d5438b8287", + "0xb32c7005380c848f71092a74297555dc6022369fc2a4f285e586ac8f53f6bd354fbe4b1f8a4cfb406a101103bf87bb64", + "0x91b48eeba52f02d04f536d32112038f8ba70bb34284fbb39e0f7bae2e08b3f45ad32e2f55d1beae94b949c15652d06a1", + "0x99e24f5ea378cb816a4436af2ee7891ac78a2e37c72590be0abd619244a190fee51fc701b6c1c073611b412cb76332c9", + "0x9465d1e73a1a0a5f7b1cd85f4fa4f5dee008b622b14d228d5cd5baeec174451e7ae93c5de688393d37cc24ce15df4139", + "0xa6ac3986ee01debdacb5ddc1e2550cb4f039156df15c7d5752b79f333175b840bdca89c4959a523e58cf97bbd6b2039e", + "0xb7f7a5cc1b1b6145988170d619c170c130231abbe0b5143a9bccaaebeef9ceb1c16e26749bc9dc5650fe91f92fa1b79b", + "0x854cb04f1557457383a401d79a655adfd0a4b706ea2bbc6262949c8d657efcfdc9c7960cbe1a50b5eebb361c5e378f80", + "0x8dd199dccbdc85aeca9ddcb5a78dd741a452f7a0d3ceb6546d76624bad2fce0e7e6c47ee30d60bf773f18d98503e7f9c", + "0x889e1ca9f0582be9bf5f1aede6a7312b30ea9bed45ab02d87182a013430f16007ae477ee6a823ae86c7fef7da016a0ec", + "0x892a60e63edfb3e7a6cf2d0be184413d214401fc1e6c004ca2902c3f1423728bf759a136e6e715d26d5bb229c75cc20a", + "0xa2287cd092261b39d22dcb1fa19512590b244771bb69fb62eda72f12be37d48e408b3e37a47608f68d743834edee7f15", + "0xb3b6afb950bbec0ff631bdf18af433e68adc63d02cb479704f24329ca6b6edd9a3d1d606563dbdce6038b676b85130b9", + "0x847da90f37b294509de51ab6521fdff12d5a1ec3cccaf730aa744da7e54b85fd9c70618787e87c0ba9947ce6c81387fb", + "0xad872153c00bccac75bdb30d1ab7044d814f4f8655ff26421d48fea04fb21d4dc82c1900620a57d13adc45c1062a1817", + "0x90fa5ee98fd7ec719f2a8543bbd0ff45ac69296c2416fc8666d05de3deea1017079a68aba55540a19585925803c8335d", + "0x962ba6d029e9176d0e8c80a21f2413f7322f22a9e9a32c933697a8b0e995ce25bea5264736a75718b3d330e215a58a05", + "0xa446f9530db30c5e9c1b3844d635e5c2cd311cc4537ff277fe83dd1a0382bcfa73beb07aaa0cf5a97d24c67e688086a4", + "0x8766b2053f16c72db387abe18b43d7b357a542916c9b8d530ee264e921c999494d6eb1e491352ecdf53758640c7a246d", + "0x83f32f511f7b0233662acfc14f30df345af99d2d6c777ce0b4bcdc4dd110533f30b45071df17230aaec392cc482355e1", + "0x82e3521bc9519b36f0cc020225586b263e4feb57b533b38d8e89ccf8d03f301d94da90efb4902002732fbf3876697f38", + "0xb5d1ea69c97ceaa34a720bb67af3fcf0c24293df37a5f6d06268b1eabe441531606954ac2598a1513f64231af722b3a3", + "0x956842696b411e6221c5064e6f16739e731497e074326ef9517b095671f52a19e792d93fe1b99b5a99a5dc29782a5deb", + "0xb19b5658e55c279eb4b0c19a0807865858cbec1255acd621f6d60c7e9c50e5d3ee57da76b133580899a97c09f1dd8dac", + "0x89e6a8b916d3fcc8607790e5da7e391f6bc9eae44cc7665eb326a230b02bc4eb4ef66e608ccc6031048fc682529833d0", + "0xb1a210bc8070ed68b79debd0ec8f24ec5241457b2d79fd651e5d12ceb7920e0136c3e0260bc75c7ff23a470da90d8de9", + "0x85b1954278e2c69007ad3ab9be663ad23ae37c8e7fa9bc8bd64143184d51aea913a25b954471b8badc9e49078146f5ac", + "0x98bf63c7a4b200f3ce6bf99e98543925bc02659dc76dfedebe91ec5c8877d1271973a6e75dad1d56c54d5844617313e1", + "0xb7404b6e0f320889e2a0a9c3c8238b918b5eb37bcdab6925c9c8865e22192ba9be2b7d408e1ea921a71af3f4d46806d0", + "0xb73cbbebf1d89801aa838475be27c15b901f27d1052072d8317dcae630ab2af0986e56e755431f1c93f96cd249f2c564", + "0x95b2027302f7f536e009f8a63018da6c91ec2b2733c07f526cc34cbcfa2f895ccfd3cc70be89f4e92c63c7ddc2a93370", + "0x9201d9ff5d0b1222bfa2345394f88ddf4fe9282acf51bee9b18b96bb724fdf8e736d7101acc2795a34e72f9e0545c9a8", + "0xacbff7eb160f427d8de6f29feeddfa8994674e033a0ccdc8e8c73f9243968f1a6379da670a7340f422892d50c97113c7", + "0x97ae8d03352c3729e1623e680dd9664f303b3bcfb844ef80d21e9c773a247967d27b86c9326af29db5eefd0bd3d4fac8", + "0x8e53ae5c22f5bfa5fe4c414dad6a10b28a3e5b82a22e24a94e50ce3b2bf41af31e7ba017d2968811c179017b78741ef0", + "0xb5ac7dd150247eb63dfb7dd28f64b1bf14426dc3c95c941e8e92750c206c4c7f4ad1a6b89e777cfe26ecb680dbf0acb6", + "0x99ae2e4652ea1c1c695e7ea2022fd35bd72b1a0d145c0b050da1be48ad781a413dc20fbda1b0b538881d4421e7609286", + "0xb8abe1fb3a7443f19cd8b687a45e68364842fc8c23d5af5ec85da41d73afb6840ef4b160d022b2dad1a75456d809e80b", + "0x842619c3547e44db805127c462f5964551f296a270ed2b922e271f9dc1074fdf1c5e45bb31686cec55cb816d77853c01", + "0x902dff769391de4e241a98c3ed759436e018e82b2c50b57147552bb94baddd1f66530915555e45404df9e7101b20e607", + "0x82e4f2ee7c7ca1ee8f38afa295d884e0629a509c909a5464eb9ea6b2d089205478120eed7b6049b077b2df685ec8ba48", + "0xaa21a68b0888e4a98b919002a7e71e6876b4eb42227858bf48c82daf664c3870df49e4d5f6363c05878a9a00a0bcf178", + "0xa8420cd71b1d8edd11ebc6a52ba7fc82da87dd0a1af386d5471b8b5362c4f42718338bcbc302d53794204a0a06b0671d", + "0x98c686bd3a994668fbbd80c472eed8aedd3ab5aa730c8d3ce72e63fb70742e58525437be1f260b7ecc6d9d18a43356a0", + "0xaca0b2df9ec8ede0b72f03b121cded5387d9f472b8c1f3a5f1badd5879fb2d5d0bbb6af1a2dd6bdebf758cfceadbe61d", + "0x93b1abd9cb41da1422d171b4dbf6fbcb5421189c48e85c9b8492d0597838f5845198494c13032e631c32456054598e1d", + "0xa246ab3a47f7dc5caedc26c6c2f0f3f303ed24188844ab67a3da1e793d64c7c7fe3e5cc46efafbd791b751e71de0614c", + "0xb9b52095ca98f1f07f3b0f568dd8462b4056c7350c449aa6ce10e5e8e313c2516ac4b303a4fc521fe51faf9bf7766ce9", + "0x8e2e9d26036e847c2a2e4ba25706a465ac9fbb27804a243e3f1da15dd4084f184e37808661ec929479d3c735555085ee", + "0x8b8c4f4ad5c8e57e6a7c55d70ef643083d4b8dac02716ea476d02dbbb16c702a2f2d5dd5efe3aec7704d2b8cdafe3959", + "0xa800afea30d0df333805d295bac25419b7049d70044be00c7c85a92a0503ca471001bc1e6552323f1a719eb96616fc20", + "0x868bced4560e1495b8527058ebc82a538b7cf806f8d8fe8eeed6981aba771de4d5e9f03cbfc7157d38b9f99cdea87b96", + "0x86b86258b0c1feb988cc79f6c4d4b458ff39428eda292f9608a5fc4c3765782c8c23c66f82d7538e78e092cd81d69a56", + "0x9370eac15de2555824c7d48520a678316a7bb672e66f8115ad7dbc7c7b1f35a7718e8fa0c35f37e3ef2df32dfa7ca8d1", + "0xae200bc5be0c1c8c6ec8e9fd28b4d256c6f806c0f270766099e191e256d67b9cceda2cc2fed46dfa2d410971a7408993", + "0xaf2428c77b2b9887ecde1ea835ed53c04891547fb79fe92e92f9c6009cdfffa0cb14de390532ad0ef81348b91798bd47", + "0xa9069eef0316a5d13d1aa4cef0cf9431518f99b916c8d734bd27b789828ae03e5870837163ea6ad0be67c69184b31e8d", + "0xb1b1ce6d529f5a8f80728173b2f873c8357f29644b00f619c15111224377ae31a2efb98f7e0c06f5f868030aab78ed52", + "0xb89c98beef19ee7f300e1c332a91569618ef8bf2c1d3de284fc393d45f036e2335d54917c762f7c2874a03fe4f0f6926", + "0x8264f993dceb202f8426339183157e9e0e026d4e935efe4cf957eb14cd53edcdc866305fb1334cdf0e819b69eafbaccf", + "0xaebd113f73210b11f5ac75b474f70a2005e5c349345003989175dffa19f168abd7f0e28125b18907502fff6fcc6f769b", + "0x9993ad061066ca6c2bb29fe258a645089184c5a5a2ef22c811352749a199be3a3af3a0d5ce963febf20b7d9e63508139", + "0x97952105000c6fc6c2dcae1ebdb2feae64f578d26a5523807d88e6caf1fe944b8185e49222d06a4553b3bdb48c3267a2", + "0x82dd955f208957d74693bed78d479c9663f7d911f68ff033929418eb4a5c5dc467589ca210c1ba3c2e37d18f04afe887", + "0xb816fc4763d4c8a1d64a549c4ef22918e045ea25fa394272c7e8a46dcb0c84d843d323a68cc3b2ef47a5bbb11b3913bc", + "0xa7a87ba4d12a60ee459aad306309b66b935d0c6115a5d62a8738482f89e4f80d533c7bba8503e0d53e9e11a7fd5fe72b", + "0x92b36d8fa2fdee71b7eea62a5cc739be518d0ecf5056f93e30b8169c3729a6a7ed3aa44c329aa1990809142e0e5e2b15", + "0x8835b6cf207b4499529a9034997d2d3bc2054e35937038deb9c3e2f729ebd97125f111c12816d30b716b397016133c52", + "0xacf14cd6d978ba905cf33b9839b386958b7a262b41cbd15e0d3a9d4ef191fcc598c5ab5681cf63bc722fe8acfda25ce6", + "0xb31302881969c5b283c6df90971f4fb2cc8b9a5da8073662da4029f7977fbb4aaa57dd95b003a9e509c817b739f964e7", + "0xb74669e1c3fa7f435e15b5e81f40de6cfb4ad252fcdfb29862724b0a540f373d6e26c3d600471c7421b60a1d43dbeb0f", + "0x861d01615cba6ca4e4ef86b8b90f37fa9a4cc65cef25d12370f7e3313b33bb75de0953c8e69972b3c2a54fe110f2a520", + "0xa58a56820efaf9572fd0f487542aaff37171d5db4a5d25bfb1a5c36ca975eb5df3cb3f427589e1101494abb96b5e4031", + "0xaf13d0a6869ef95cb8025367c0a12350800c6bc4ae5b5856dcb0a3ca495211d4139f30a8682d848cb7c05c14ae9f48cb", + "0x8c385767d49ba85b25a3a00026dd6a3052e09cd28809d5a1374edf4f02dc1beed367055b0dee09102c85985492b90333", + "0xb5129fc2fec76711449f0fcb057f9cf65add01b254900c425e89b593b8d395fc53bb0a83ddbd3166acc6d2c17f7fc2a4", + "0x86bd01b3417d192341518ad4abf1b59190d9c1829041e6f621068bce0bef77ec3b86875b7803cf84ff93c053c2e9aad1", + "0xa74fc276f6af05348b5fabccb03179540858e55594eb8d42417788438c574784919fb6297460f698bd0da31ce84cebfc", + "0x967ed3ec9f1fc51f76f07b956e1568d597f59840ef899472a3138f8af4b4c90861e23690c56b7db536f4dd477f23add6", + "0xb9e678206de4fc1437c62d63814d65f3496be25a7a452e53d719981d09c7e3cae75e6475f00474e7c8a589e2e0c6bfa3", + "0xb028eaffaa4ff2b1b508886ff13c522d0b6881998e60e06b83abe2ac1b69f036eece3ded0f95e9ae721aea02efff17b6", + "0x935f82de9be578c12de99707af6905c04c30a993a70e20c7e9dd2088c05660e361942fa3099db14f55a73097bfd32a44", + "0x96a1cc133997d6420a45555611af8bcd09a4c7dbddf11dbe65aab7688cc5a397485596c21d67d1c60aae9d840f2d8e48", + "0x80d117b25aa1a78e5d92ea50e8f1e932d632d8b37bebf444dcc76cc409322fb8eface74a5dddab101e793ff0a31f0a53", + "0x893229136d5ab555dc3217fb4e8c6d785b5e97a306cdaa62f98c95bad7b5558ed43e9a62a87af39630a1563abd56ec54", + "0xb7ec1973ec60bd61d34201a7f8f7d89d2bc468c8edc772a0ba4b886785f4dadc979e23d37b9f7ef3ff7d2101d3aa8947", + "0xb6080ca201d99205a90953b50fc0d1bd5efd5eadbfe5014db2aeb2e1874d645ab152fb4b0ff836f691b013b98ce7c010", + "0xb546e66ec0c39037bbaa66b2b3f4704a6a72cf1924a561550564b6fcf41fbc2930e708cd5cac1d05e12a4b8ec93ff7eb", + "0x8abeed90a01477260f4b09fff8fa00e93afe727e8eed6f111d225c872a67e6ab61d0472ab6add3fe987744e16f7c5268", + "0x8e02342d5cc1836ed21834b9ef81686172cc730f0412479db5f590b0ff7a729a0e986ffed16d6ecafd6b83d65922ca5e", + "0xb05660605cf8e8a10c8d3c77cccbe4e7179fa27cc829571f6b722a58e65e4e44d7fe977446118e9da2d2f40af146cc2d", + "0x942a00e006baba6d025cbd99297bdb0cbf3d84cddf849b1b5a9fe9ef1745352fad81313cce5d7622d6652096a8fa065c", + "0xaace8212b3d8dbe44ac97460a5938a3b803aca9bd00d8a643a859351daf391b22d1fd2a6b3e0ff83cc9ee272a1ad7686", + "0x965a9885a5259197a75a19707a2f040e0fd62505e00e35ebe5041d8467596752aedf0b7ec12111689eceb3e2e01ecfc8", + "0x81d58270a4e7ee0137cb2bf559c78c4fd5b3a613468a8157b6a9c5c0b6ca20a071b87c127d59cecc3d0359237a66d890", + "0xaf92b6354fbf35674abf005cb109edc5d95845e3d84b968e6001c4b83d548715dffc6723ac754c45a5ace8cd7dd30a24", + "0xb112caa707f9be48fdde27f1649149d9456857f928ea73e05b64bb62d597801daac0b89165fea76074f8b5770043f673", + "0xb6e7380746da358fc429f676b3d800341e7ab3f9072c271310626ae7f67b62562ff76c63bc9f5a1dbc0e0af87752408a", + "0xa45e9e8d0931207ebc75199aa0c983134aa97f771ff546a94a3367bcedf14486f761e7f572cf112e8c412018995fdaf4", + "0x854381128de5bfb79c67b3820f3005555f3ee6f1200046ebbfaee4b61b3b80a9cebf059c363a76b601ff574b8dbf0e6b", + "0xaa1b828a8b015d7c879669d5b729709f20a2614be6af6ff43b9c09b031f725f15b30cde63521edda6cd4cf9e4ab4b840", + "0x8f28f6b62c744084eeddcb756eced786c33725f0f255e5999af32b81d6c6506a3f83b99a46c68fc822643339fe1b91c5", + "0xac584e76a74cafe4298ca4954c5189ccc0cc92840c42f557c40e65a173ea2a5cd4ae9d9f9b4211c9e3dfd6471fc03a1b", + "0xa413365df01db91e6a9933d52ab3e5ed22d7f36a5585ad6054e96753b832e363484fb388c82d808d1e4dfb77f836eab9", + "0x8a68c51006d45bf1454a6c48a2923a6dbeb04bd78b720bb6921a3ca64c007043937498557f0a157262aac906f84f9bf8", + "0xb93ff8b6c8c569cc90ee00cfe2fc3c23cccea2d69cbca98a4007554878311635cb3b6582f91636006c47b97e989fe53d", + "0xb9a8a44d54592511d74c92f6a64d4a8c539a1d8949916ef3773e544f6f72c19a79577de9878433bd35bb5f14d92f411d", + "0x94f066a7e49ae88d497893e4ce6d34edc2dc0b42fe03934da5d4ed264d1620d506fcc0661faa90a6cf5083e1720beaaf", + "0xb42b102adef8f42c1059b5ca90fe3524dcd633cf49893b04b4a97a1b932ca4c7f305cebd89f466d5c79e246bad9c5ced", + "0x86b560d78d3c5fb24a81317c32912b92f6ea644e9bedfdea224a2f0e069f87d59e6680b36c18b3b955c43c52f0a9d040", + "0xa3829fa7e017c934fa999779c50618c6fb5eafb5e6dec0183f7254708a275c94ba6d2226c5ca0c0c357b2f2b053eea93", + "0x9337dda730076da88798fd50faed1efa062f7936a8879ea4658c41d4fcf18cee7120366100d574536e71f2f11271b574", + "0x853d09a30f4342f5a84c4758e4f55517a9c878b9b3f8f19e1362be9ae85ca0d79c2d4a1c0c14f5eff86010ad21476a7a", + "0xb0bc74cb69bdd8fdffca647979e693ad5cbf12a9f4ead139162fa3263bfebef3d085aab424ed8c6220b655228c63c6b1", + "0x88d8dc8faf3aab12ba7180550e6a047f00d63798775b038e4a43a3b40a421a3f5f152a7e09f28ccd7198bb8cefc40c07", + "0x88db2e3b8746415d0c3e9f5706eda69a29d0b9ee5135ad006060be7787f4f1f7069e2e2e693c5e10b7c3d5a949085ae0", + "0xb5bd830d2f1c722188dba2690d21b7b84b92cbdd873a55aaa966f1d08d217bfc8cffe8caea68868f3850b90b4ab68439", + "0xb5ad4be0c9626a33fce6c8501297bdde21b07b88531451912ed41971a4c48fdd1036d8a4994a99a7fbba4a5901a7095e", + "0xb0e1337a2a1772191faa91302f1e562e7cdc69ba5b25139e7728ce778a68a7fa9817f852ec8e04a159122cff62992ec6", + "0xb4fd4a4c1be8bc7e4e2bfd45404c35d65b75f45fb19ce55c213a8035b41f1ccbce9766f3df687c0d7cd6cdfc1abb00a5", + "0x814bf565ece6e9e2a094ffbd101f0b9fea7f315a2f4917abe2bf7d070ed8c64a2987bd288385a42fd336ed0a70a9d132", + "0xaf860af861dc80894ed69f29c8601d986917ec4add3d3f7c933a5e9d540bc8ff8e4e79d0bb01bbc08fa19ef062f2890c", + "0xb66d33fcf3cd28f15111960ffc6ed032c3b33d4bb53d035ab460cc5fa7ce78872f0476d0bb13f1d38f2672347d2d6c4d", + "0x89603ae1a5dd7c526936b86a3b69b7b1d0bdf79ba3cc9cc2e542ec801a6126d1514c075d6ad119fe6b6e95544ffe7fbe", + "0x8a1b097f46a62d85cff354d1e38df19a9619875aad055cc6313fdb17e2866d8f837a369a9ee56d4f57995e2b0a94310e", + "0x8dc165d86c7f80b0fcd4b6f90d96cd11dc62e61d4aae27594e661d5b08ef6c91156c749de8948adfaf3265b1d13e21cf", + "0x98e3173772c3b083b728040b8e0ee01dc717b74c48b79669dd9d2f7da207af64ccd7e9244bc21438a5d4ac79b88e9822", + "0x924d168099b6952d6fe615355851f2b474f6edfcd6a4bd3ad2972e6e45c31bf0a7fb6f7fca5879a0de3ea99830cfb5bc", + "0x95452f0b7efda93c9e7a99348e13f356bad4350f60fcd246a8f2aa5f595a9505d05ec9f88b1fe01b90ecd781027b9856", + "0xb95e8af516bb0941fc0767ecd651ada2bc64cc3e5c67a1f70048c634260c0f2c0e55ed22948e1870c54590b36683a977", + "0x82f7feb71e746d5ca24455e3f3e57e4eade92669ab043e877b836612efd3de82009f0555e5d8811bff9f2b75fc57a01d", + "0x87623c02caf590ea84cf4a84d1be501f89262e26eb463f2f94a2d3042889c051b058823c3367a989498e46ff25edab16", + "0xb88da847b1ef74c66f923773ce8c920ca89751335fde17b3a98c0603862069a2afbf35b1552b43ad64dccea69f040ff8", + "0x96b734758c823e5ce5b44625c252957e16fa09f87f869baac195956052dc92f933f377b288c7f63b8028751cbbdca609", + "0xa23cc5fbbe5cb7c1d33d433cec4e502f6548412e2374e285d307f75e98280b0c0af4f46bba18015be88cdf7db8b1239c", + "0x8bd5bbe04bc929ca8f546e673803ec79602f66ec24298d3e3b6bf6f2c25180fc0032ea6f86c38a6e0ec20ff4eaafc7a1", + "0xb95768ca113e5d57ad887a1cb5ef84ce89007ce34c3156cd80b9aa891f3ebaa52b74c0cb42919cfbcf0cb8bafa8085f9", + "0xa117f99045f65e88acc5a14fc944f8363f466e4a64057eb8fc64569da5dd022a01f2860c8e21b16aff98aebdf89461b7", + "0x895cda6503907c98c43477eaf71dfd26759032523691659f13662ca3a967d93bbc5be342d168223cef7e8a333987d6a0", + "0xa084d77d913d3ec0586ad5df2647610c7ed1f592e06a4993a5914f41994a29c4a8492d9dce2e14d8130c872d20722920", + "0x84a328b73c64137bb97a0a289b56b12060fa186ce178f46fe96648402f1b6a97d1c6c7b75321e4b546046c726add5a08", + "0xb7c35087b2c95127ce1470d97bceb8d873a7ad11a8034cc1cba7b60d56f7e882fc06796048435a9586eab25880787804", + "0xab05e3394375ee617c39c25c0ec76e8a7f2381954650c94fbcd11063ea6772c1823c693d2d9dd18bd540a130d7b92855", + "0x82ba5907051d84b37fd9d28f8b9abebc41fc4aaa334570516ca2e848846644016356d40fa9314543017d4f710d193901", + "0x9170517b6e23ee2b87ff7c930cb02b3e6bd8e2ae446107b5b19e269bf88f08de5ded3d81a2ff71b632ca8b8f933253a0", + "0x93dc0e3f6234b756cdbb3fe473b9214e970972e6bf70803f4e2bf25b195b60075177a1a16382f1dee612a4758aa076ee", + "0xb4b49fac49cdfccda33db991994a8e26ab97366545166cc7140aef3d965529f96a5dac14d038191af4fb9beb020ff6d5", + "0xb826537670acdf7a8a45ef4a422d5ae5a1b5416ad0b938307518d103cc7ba78e495ea200adc5941414a70158a366e8a2", + "0x8ae3588b1fbecbc769c761f0390d888e34773cf521d976ee335f6c813bf06dad38850871ac8a8e16528684f1e093d0c1", + "0xad9c00b8dccdb545315fbf26849135699c6aa3735f89581244281154c906aba80d20c1e7f18f41acc61e0565f8015a33", + "0x954ce68146c05fc1c9e536add3d4f702335d93c1650b8c1fad893722a81f915eee2d38275dad00ce87f3f5bc90ef7341", + "0x8243feaeff9a12f5aeb782e3dd68609ce04ecde897c90fd8a19c9c5dace3cf43bd5bc0f1624bf7fd2607ca0d71adbba8", + "0xa8a1be55259cd27898d9d60a61998d8da2bf2d439ba6eedb61d6d16dacc4a81ec706b9196dfa080ba20701d2cd9fa1f4", + "0xb0eac6212c7a62ef6062c30875fbe24b8e1a9d88854c035686f849a9eed4d17fbc9af27429eb7c3fd60b47a5e29f6783", + "0x878561a88412e95f19f1cb8894be9d0ea4a2cdd44f343387f87dd37445e5777bceb643cebc68c910acb5e588c509cd2e", + "0xa57b6c347955d8b0057a87494223148ff9ff12b88e79dbd9d0aae352fe55e15ea57fcfb9add3d5d269ee0001d8660f20", + "0xa07fa66340d4082585e4d72c77510c59b272e7a3345f4b1de6be7ff4a11ea95d712d035a7355fc8d2e571fa65fe8236f", + "0xb9d84a627462438e8ede6c453e3367bfaf81cff199d3e5157ef2bc582d358b28b5ccc3bc27bb73af98ef45179ea79caf", + "0xb14f26ea7ca558761cb19508e5940fbf5dcf2ad8555c5a03e8ff92481994072f523b1ab6b7176f698e2cfd83d4f8caad", + "0x800cca1cbb14e1fc230c7b420ff06864a934b082321bbf5b71f37340383923f23183d4fdc8fa2913928722b8892db28e", + "0x94790c950b92e971ec39e9396c3f32dee32a8275d78e6ea28a47130651bddc86a189ef404c5e8c210bd291186dee0df4", + "0xad7b3b3e377df64023b8726d43a7b6ec81e5a5e8c0943c5bebe5ab5ddd6597255f434a205c14ba90e9e5e3c462a1fe0c", + "0x86ff8156cc857a416e735009cf656b89da59b766b4c4e5a0c0165282b530c10657cc28cf5cb847696725c37ac48b69d7", + "0x89cb64cf9294f68f01533660a2af2aec0ec34cc0b4a0cc36a128f2e0efb3da244981f69aede962f50590faeeb9a5da01", + "0xa2ea5a94a524bb8e6f767017246cd1af9d87c9abb9894e91c4e90c34c5161be6179b49dafcab9cff877a522c76beb145", + "0xb5d9abf29ed6030a1e0f9dc19be416c45ba8cb5ed21aff5492233e114035715d77405d574cd62f2716285e49f79b9c99", + "0xac441cf6104473420babdfb74c76459cbea901f56938723de7ad3c2d3fadb0c47f19c8d9cb15a3ff374e01480b78a813", + "0xabea34bd2d36c5c15f6f1cdd906eb887f0dd89726279925dbe20546609178afd7c37676c1db9687bc7c7ea794516af03", + "0x8140abfd0ec5ca60ef21ad1f9aabbb41c4198bac0198cb4d220e8d26864eedb77af438349a89ca4c3ff0f732709d41a9", + "0xa5a25abf69f3acd7745facb275d85df23e0f1f4104e7a3d2d533c0b98af80477a26ac3cf5a73117db8954d08f9c67222", + "0xb45ac8d221a7e726ad2233ba66f46e83ed7d84dbe68182a00a0cf10020b6d4872f3707d90a6da85f6440c093914c4efa", + "0x80f586dfd0ceaa8844441c3337195ba5392c1c655403a1d6375f441e89d86ce678b207be5698c120166999576611b157", + "0xb8ce52089e687d77408d69f2d1e4f160a640778466489d93b0ec4281db68564b544ec1228b5ab03e518a12a365915e49", + "0x8990f80bae5f61542cc07cb625d988800954aa6d3b2af1997415f35bd12d3602071503b9483c27db4197f0f1f84a97ac", + "0x8329858a37285249d37225b44b68e4e70efeef45f889d2d62de4e60bd89dde32e98e40e2422f7908e244f5bd4ffc9fe2", + "0x8d70c66ea780c68735283ed8832dc10b99d3daeb18329c8a44a99611a3f49542e215bf4066ff4232d36ad72f1a17ccc3", + "0xa3b2676cc8cdf4cc9e38c6cb8482c088e5e422163357da3b7586a3768030f851ad2a138eeb31584845be9ffb8067fc00", + "0x95b1fa74e9f429c26d84a8e3c500c943c585ad8df3ce3aea1f6ab3d6c5d0ed8bb8fa5c2e50dd395fa8d4d40e30f26947", + "0xb1185f2ac7ada67b63a06d2aa42c4970ca8ef4233d4f87c8ffa14a712a211b1ffde0752916bfafdfa739be30e39af15d", + "0x8705a8f86db7c4ecd3fd8cc42dd8c9844eab06b27d66809dc1e893ece07186c57b615eab957a623a7cf3283ddc880107", + "0xaf6356b372f0280658744c355051f38ff086f5563491fc1b3b1c22cfec41d5c42b47762baeb9ee6c2d9be59efd21d2b7", + "0x86bdd4527b6fe79872740d399bc2ebf6c92c423f629cdfcd5ece58e8ed86e797378a2485ead87cbb5e2f91ba7b3fbda1", + "0xa900f0be1785b7f1fda90b8aedd17172d389c55907f01c2dfb9da07c4dc4743cb385e94f1b0fc907dd0fedb6c52e0979", + "0xa9f59f79829a9e3d9a591e4408eaec68782c30bc148d16eb6ae2efccb0e5478830bbdaa4ae6eac1f1088e7de2a60f542", + "0x99cf54a69ad5e8c8ec2c67880900e0202bcc90c9815531d66de8866c0a06489ea750745cc3e3aa1c4d5cb55dcd1e88f7", + "0x8676246a4710d6d73066f23078e09b3fa19411af067258e0b8790456525c02081727b585d6f428c8be285da4aa775a4b", + "0xb596c7014fe9214529c8e6b7602f501f796b545b8c70dbf3d47acc88e2f5afd65dccef2ef01010df31f03653566b16df", + "0xa12205c6c1780fc8aebdd98611e12180005b57750d40210b9eff0396d06023bd4ff7e45f36777123ff8bed7c5f52e7a3", + "0xae7dbd435bba81685d5eab9abc806e620253da83e56b4170952852d442648a5d8743f494a4b0fc9d606574f87895b0d6", + "0x9786257b1726b7cdc85219ca9eec415f98f5a11e78027c67c7b38f36f29fe7a56443570fdfedc1d9293a50e4c89d89f6", + "0xaaf0515070d1ca92aacdf5fac84193d98473d8eb2592381f391b8599bcd7503dbf23055324399d84f75b4278a601c8b2", + "0xb31654dbf62fbbe24db4055f750f43b47f199a2f03c4d5b7155645276b2e456a218ca133743fb29d6f1a711977323f6e", + "0x8f4d39106ecdca55c1122346bdaaac7f3589d0cf0897a6b4b69e14b4d60550fd017876399401ce7c5d35f27da95f50be", + "0x8a7bfdb48cd47afe94aff705fac65f260b3a3359223cff159b4135565c04b544dd889f6c9a6686f417e6081ad01e0685", + "0x967ba91111e5e08f9befcbaad031c4fb193776320989f8ede4018254be0e94586254432d3dbae1455014f3a2f2549d01", + "0xa9db52352feeb76715a35c8bed49fb3a8774c9c8e58838febf800285fd6c4938ec162eb8457029e6984d8397dc79ea19", + "0x811794e6bfe2539e8f6d5397c6058876e9e30763ad20dad942bb5dbcab2f16d51718ce52bfb4de17889ba91da1b85bcd", + "0xa6db0f65a6dc8b8cc2312a3e0146d8daf520255bb12f74874c05693914e64e92be0cd53d479c72cb2591e7725dfaf8b0", + "0x918d21bfa06d166e9eb5b7875c600663a0f19cc88c8e14412319d7aa982e3365f2dff79c09c915fc45013f6b3a21200d", + "0x9894852b7d5d7f8d335dd5f0f3d455b98f1525ad896fdd54c020eeaf52824cc0277ecbfa242001070dc83368e219b76d", + "0xad00acc47080c31fcc17566b29b9f1f19ccaae9e85a312a8dcc0340965c4db17e6c8bd085b327eaf867f72966bf61452", + "0x965e74649e35696744ecc8bed1589700bae9ca83978966f602cf4d9518074a9aa7c29bc81d36e868a0161293f5a96e95", + "0x961e29a239c2e0e0999b834e430b8edfe481eb024cc54ffaffd14edaf4b8522e6350dc32039465badfff90dcb2ba31cc", + "0x943dda8fa8237418a07e311efde8353c56dd8ec0bfa04889ccdd7faa3dee527e316fdc60d433a3b75a3e36ca2aa9d441", + "0xa0ed4c102e3f1d6ebf52e85a2bc863c1af2f55dc48eb94e40066f96964e4d37fff86db2cff55a8d43d517e47d49b5bd7", + "0x9045770ad4e81345bc6d9a10853ee131232bf5634ef4931b0e4ba56161585b4286876bc8a49b7b1f458d768718cb8ebf", + "0xb0dd430295ff28f81895fde7e96809630d1360009bbe555e3ac10962de217d93ead55a99fd4f84d8cadd1e8d86d7b7ef", + "0x95ced48419b870ea4d478a2c8db699b94292f03303f1bf4560b5b1e49ca9b47e7008514fe0a9cf785717f3824567e1b2", + "0xa7986e0e389e8aef6aac4a7a95e2440a9af877ae2bc5ad4c5f29d198ec66aa0db1d58c451e76ae70275a2e44c3d3fa68", + "0x85a8490faf32d15de12d6794c47cc48e02428af1e32205e0742f8299ea96b64bcd6d3b4655272afa595eec74ecbb047c", + "0xb790d7fb1307aacc2d303d9b6753a9773252b66c6b67763cf8841c690cbccc4866ffb5fec1c068b97601a7953fe0f7e8", + "0xafcc4011f8c53f10d63c29b74d9779cd75c861e01974c28a4ec2cbb909b67a1b2287ead175231343c936ad75dfa416ff", + "0x918058bffdecc1ae8779dccf1d874bb9e28edbe34c8b5954a8da64a848858d2f0776437b423baf4e731f3f5fa05a2841", + "0xab554db549aa36dfa9f966a5ed6be8267e3aa9ced348695f3dafc96333c6dbb48ef031693aafd59d1b746ecd11a89c51", + "0xac4ecf746b46b26a7af49cc9cc1d381e1e49b538dbd7fb773ce6b1df63ae31c916693cca8a90fb89f1e7ec5e0e8dd467", + "0xa8de66d48f16b016f780a25ba25bd6338fd8895a1909aabcfb6e70f04ff66f9866e6e2a339bcbfa4bfba4070a6a8db26", + "0xb4b49374eff6dac622e49b0e9c0e334ecbec513a96297f6369696ad39e5ec0de81a1417f6544be866c9f60957a9ba09a", + "0xb8023968549ebab6c1e7a8e82954a5b213bec50bbf35b36697a8d4fd75f9e12d510b365962aace4c9978c5b04da974a7", + "0x8d4bc016026dd19e4059d1c5784897cefa47f7ae2ed6dfa2b3c14a852fff2b64abc09549d106584e0daed861a2d6d6c2", + "0x85e26f433d0b657a53da4c1353485e0c2efa092484c5b8adb3f63dc72ee00be79197ebef7937b37a6a006571641cd6af", + "0xabb37a917301e68328032ff4715abc0fee32e5f5be68232ca8bf7ffb8732bc47504e75b40bcc0a7c7720b71496fa80af", + "0x9837c8d2660522c0357f5222777559d40321a1377f89ca1717215195bad4a348a14764bd87fa75f08e1f6263e9d08982", + "0x97e06f971b4c56408ed5f1de621d233e6a91c797f96ec912737be29352760a58831aaf1f64e377c3ed9f2f4dc8ad1adb", + "0xa12d211304da7b91101513d57a557b2504069b4383db8ecb88aa91e9e66e46e8139dadc1270620c0982103bc89666215", + "0xaab74ba48991c728ba65213e8c769e6824c594a31a9b73804e53d0fda9429403ff3d9f6ea5ef60884585d46356c87390", + "0x92f19be2b7adf031f73611282ad33e462852f778c5e072f689dd0e9458fa6ebccfae02f2b2dc021802c9225035862468", + "0x953bb843c48d722604576cef297123755cef8daa648c30c3a678eada8718dfdb16e71cc3e042a51fedc80577235c2563", + "0x86f509e3c1b9ee9a3b95e6da8516b47feb8c8a83403984228f4903c7ee1ee4f03addcb8fe86283af1196a54b36b9470c", + "0x903d793a377e98e2562c49de33e3fbf84bf99211925e7002a4f688470db655884e1efe92782bf970ffa55d9c418ef3b5", + "0xa41b65681ed7f10987a7bfdf9e56b010d53683819d845d880fc21b2d525540605c5823e75c434f17b5a0d08a091c1564", + "0x971be802de51cfc0d10a96be7977c037873f19334ed4ed4904b7675aec8bfa1f8956cd0150b07064caf18229ffd1ccd9", + "0xb253ebe4f82cdbefbc3ef816d40c497fe426a9f0f0f170e783fa4a05ae6dabdfa8c448817a24e723a314b43e76a7c422", + "0x86f397c95025489929ce9230b1466b5c330ec7c58a3c7e3153d6d05bcb8348a13398908e192590b8812f5c5ff09c133a", + "0xa0713983a3dc9f10b3833687cd2575de2fc63c4ad8d2f54ff85c6db23dd308daefef1bd1e51eec26732f77c1f37ba793", + "0x8249a1d53ec92f311f4fa77e777800d777f3e9d4d452df740fc767fa7b0f36c8dce603d6e6e25f464c0399b8d0b93c30", + "0xa73d0a206a62922f07b928501940d415e5a95716ee23bf6625b01ff2cd303f777adfa373d70279ba8a30fbb4c99a6f1f", + "0xb1106b407ecf234e73b95ff58ac9fdf6709ad2e763b58f0aacc5d41790226d441b5d41405ac03a0641f577848a4f5e8e", + "0xb009963ccc7b2d42792f09ab7cb0e929503dd1438f33b953104b4de43274ca3ce051554d10d7b37041b6f47d7a2dab6f", + "0xb744512a1b3c7ef9180b095c6a0c5bc16086a50020cf20dc2216bbff24d91ca99b95cb73070444dafc3ab45c3598960d", + "0xa0209669ffeddc074d35cc6aa2dac53acac8e870f8a8a5118e734482245b70c3175f760652e792118fdddac028642259", + "0x8ddd3e0d313da17292fdcc1bbc6e9d81189bb1d768411c6fe99801975eddb48dbf76699dcf785cac20ab2d48e392c8fd", + "0x8392aa285b8b734aa7a6e0f5a1850b631ddf6315922e39314916e627e7078065d705ff63adbc85e281d214ec7567863e", + "0xb655a1fff4dba544a068bf944e9de35eaaa6c9a0672d193c23926776c82bebed8aa6c07c074b352882136b17abdab04b", + "0xaf5095f40d1e345b3d37bebee3eb48c5d7b0547f12c030d5bfe8c0285943e0a7a53a186f33f791decba6a416cba0c5c9", + "0x8223527f9eb3c8ff52708613cd2ee47e64c0da039cea3a0189b211dc25e9bfa3d5367a137f024abe94f98722e5c14b67", + "0xafdb106d279273edc1ee43b4eead697f73cb0d291388f7e3fc70f0dd06513e20cc88b32056567dcc9d05364cb9ca8c58", + "0x9319eac79ff22a2d538dcd451d69bca8aa8e639979b0d1b60d494809dbd184a60e92ad03b889037a1ac29a5547423070", + "0xb79191ce22dbd356044e1777b6373b2d9d55d02b2cc23167642bc26d5f29fd9e2fb67dce5bd5cf81a602c3243bedd55c", + "0x988e0da1e96188ffd7c5460ecdf2321f07bc539d61c74a3292c34cb8c56dbafbca23eb4471a61e8e64e9a771a49fd967", + "0xb0792b6cf4b10f8af89d3401c91c9833736616bb9fe1367b5f561c09d8911fb5a43b7a4fd808927b33ab06e82dd37a28", + "0x862f68ea55206023ca470dbd08b69f0f785fcbabb575a1306ff3453c98ffcad5fd6ead42e8a1f9edf14c6fd165ffd63a", + "0x815ff0898b1330ac70610180c0f909561877888ff10def749a1e65edf9f4f7cea710a757c85241dfb13d0031efb5e54b", + "0xaa6e6ce21776ea4507d452ccdaf43a161a63687aae1cb009d340c9200e5646e9c2de4104dfd66b8e55dfa6de6ee83e4a", + "0x8e8f3d3403e0256ecc254b9b1464edca199cad3f3348002d744721c345a1a3c7f257c3587d2229774cd395e26693d1ba", + "0x90483e28985e4a0f7a3cb4bc5e865b9d408b94cd2146c04aed00b48a7ab80a28deb05efec320817d63578d4f953bd137", + "0x84fb2a762ba29193b07f1dd84b3f69153cedb679b66ad04f8a4adf01c14f115163a107e6db23aaf0f0c9687824ded197", + "0xb4a23922bf4302cc9a6583f252a1afa026c87c132b9ae44cc1f75a972cb6ae473447c500827906f9b677617ddd6fb473", + "0x809bb9edbbe3a2769165f029f2a48b6e10e833eb55d8f9107c4a09ca71f0986dc28f3bf4ead9cab498086eb54c626bbf", + "0xa0459dbb08db4155d16301933ec03df77c4f835db2aa3f9697eeb2bb6fcd03337fab45fa43372a469fecc9a8be2e3119", + "0xa638eaace7f21854de49f4db6e4ea83d2983751645e0fb200c5e56561f599fd37dac70bdbd36566fdd10d4114fbb9c2f", + "0xa3a27bc2728390643a524521bf8ef3b6437cfba6febfd8bb54f2b6ecbafafb96196d3dea279ce782efd97b212f364ef5", + "0xb86693b3ea23ea6b2c4d52554f61ef39c0ef57e514ff6da80c6e54395df8376e2e96b9d50e4ec301c59e022c5c5610db", + "0xaf4d7cd678d79e67ae19789d43331dff99346cd18efff7bab68f6170c111598d32837372e3afe3e881fd1e984648483e", + "0xb8735a555ba7fe294e7adc471145276b6525de31cda8c75aae39182915129025fb572ed10c51392e93c114f3a71bd0be", + "0xb1dfb6dbda4e0faaa90fe0154f4ddaf68ee7da19b03daad1356a8550fca78a7354a58e00adeecb364e2fd475f8242c24", + "0x9044b73c1bd19cd8bb46d778214d047f5dd89b99b42466431b661279220af5c50c0cffecebd2b64c3d0847a9c7a8b1ec", + "0x891f0d162651a0aa0d68fb1cc39fa8d77fd9f41ff98b5d6c056c969c4bac05ba8c52cbfa7fbb6ef9adfe44543a6ec416", + "0x8920ae1d5ac05bf4be6aba843e9fc1bc5b109817381cdd9aa13df53cabea319a34ee122dcb32086d880b20900ff28239", + "0xabb14023142876cbc9301336dced18c7878daa830070b5515ff4ac87b7bf358aa7ff129ebbf6fb78e827570a4142661f", + "0xa74b15e178cf91cde56eab0332e62d5ff84c05fcc849b86f45f94d7978bf9c0fc72a04f24d092a9d795ca3d976467f46", + "0x806829621a908ca9b6433f04557a305814a95d91c13152dca221e4c56bfaa3473d8bb1bacd66e5095a53070f85954278", + "0xb09a3c185e93869aa266a0593456a5d70587712bca81983dbc9eebbb0bd4b9108a38ae1643020ecf60c39c55bb3ac062", + "0xb2bbe8f5361a3ecdb19598dd02e85a4c4c87e009f66fee980b4819a75d61f0a5c5e0bdc882830606cb89554ef1f90ead", + "0x825e16cb54fc2e378187aedae84a037e32903467ac022deb302cf4142da3eda3ead5b9f3e188d44f004824a3b5d94fbe", + "0x8b39d4a11d9b8ba885d36bcdb6446b41da12cfd66cb22705be05ab86936464716954360cc403f8a0fd3db6d8b301cb59", + "0xac19d453106c9121b856c4b327ddb3e3112b3af04793df13f02d760842b93d1b1fbdff5734edc38e53103a6e429a1d1f", + "0xb1cacbb965ec563f9e07d669ffc5e84d4149f1fb9fcfbc505788c073578c8f67956fb8f603e0b9a9d65e2d41803038ce", + "0xb7612d9e7dc930bff29191d1503feb2d6451b368b69fa8ecb06353c959967daccdc262a963f01c7fb95496f1bd50d92e", + "0x93f8fceb65ea9ef2052fa8113fb6720c94f0fed3432d89014ee5ad16260aeb428aadea0d1f1e002d2f670612ba565da3", + "0xb3eb9213752156ed1fced3bca151fd0c630554215c808b9a0938b55fed42b6b89f9b76bc698f3e37c3c348d2395dbed1", + "0xb46ab3553ef172ae40fc21c51d1d7eab8599a67f2f89a32a971aa52c2f031664e268b976dd2f7dc2195458fcf4bf3860", + "0x8fb66f2c67ca5b6fb371c7d04592385a15df0c343857ba8037fe2aa9f2a5d4abc1058323ff9652653261b1c7db0edc24", + "0xa7dfdbbf0b14e4af70fdb017875cdc36ad2108f90deb30bfca49301c92cbf821645a00ade1d1ee59a1a55a346675c904", + "0x856199cad25ec80ee0327869077f272e33d59bf2af66c972e4a5839ec3b2a689e16f7fd0a03a3138bec458fcff8edbea", + "0xa2842ac5a715c2f48394988c6f84a6644c567673806feaa575838e906138c1b25d699e1b6ffdfc9be850b15da34077e4", + "0x814b448ada88f769de33054c3c19f988226317797acacdbe55ed2485b52cd259ac5bcbee13f9de057eee33930a7fa0c0", + "0xb49de8dd90da916ed374ca42665464b6abe89ff4453168921f5a7e5ddd3dcfa69422782e389e586e531fd78a1f236a8b", + "0x851f9d942b4c8ffc020c02c7fbee0f65ef42b1ab210ab4668a3db6aa0f8ab9eedb16f6fd739a542cc7e3cc03172b565b", + "0xa5128c155b8062d7fa0117412f43a6fdc2de98fa5628e1f5fc1175de0fa49fc52d015ec0aff228f060628268359e299c", + "0xb0765849127cc4ce1a1668011556367d22ce46027aa3056f741c7869287abcaccf0da726a5781a03964a9ded1febf67d", + "0x984562c64f3338ffe82f840c6a98a3dc958113f7ed28ee085af6890bbc0cd025723543a126df86f379e9c4771bb69c17", + "0x8087fe60a9a22a4333f6fbe7d070b372c428d8c5df3804bb874b6035e5602c0693757fb30a9cd5a86684b5bca6737106", + "0xa15e195b5850f7d45674cdc3bd74f972768b46fe9473182498263edc401745a8716fc532df8fc8c1375e39e391019226", + "0x858ec10208c14a67c4156ea9c147f36d36c4fa0a232195b647e976ba82c8e16262b2b68d31e3b4702070c3dc701bccb5", + "0x84bf3fb83c003380ee1158e2d6b1dca75cd14c7b2a32aec89d901f0d79e1475aa0827cb07cba1784a6bb0d37f6ca5cd4", + "0x91e69f5392648e7f7c698059a0fc4b8478ab8af166d3842fb382ec5c396daa082ee3b2cb0192da3c9d90f6523c4c039d", + "0x8f7299f451c5e641d6fd961946b7a6ba4755685b2a40164e6276c25aefc66715b92492097a191813d39bb4405dc5da36", + "0xade2cf04ff6c94c1019bfa1e0e8f580696230fa6ee9695c4772e5a44501b2fffdd765ec7cc71ba14b83559ad62cc0fc5", + "0x85fc98ecf469d6f98c8b3e441680816f764de39001a249bc7162f990c5a5354683e849164d4fc9287ee516780cdcd436", + "0x928d118188120d038c37abdbe66c05adaa87f1cf9957dee2783b09fa91c4c43a7b0d0b2b6c5f4dea57e3ec8af230e84f", + "0x8025f71cf8d3085d6ea5104dddea8fa66cdb8527e40db01472469be021632daf22721f4acf1a8698a53439fe2f82596c", + "0x83266fffb12b3c795a6b551ac2aa7d9a29c183f861e78768c11286a04e22bd423bba05a68775bd77273e3ca316a4318e", + "0x95fd0c69c2d9df4e795c7ba71ed71a9d9f2878cd7e3a64be7b671d9611649fd41d29f8bdab642ba19cbd3db660d6a7e7", + "0x92a912cb4d5ef4b639876daf4289500c4ebdbd80aff07fd93dc3eea645f084f910e5c02c10492a37f16acaa7e646d073", + "0xb3d2622c987189a0873932aaea8b92ebb6e9e67ff46e91a96bf733c3b84175fffe950f8f4622cc4fa50f116321c5537f", + "0xa98f9a40054b31023a8f7549a44cae853b379bbfe673c815b8726e43ecd11a96db40b20369d712cbf72ffab064ecfac5", + "0xb4e9a38e371fc21f4b8a3d7ad173c9ffad0554530dc053365d9555ddb60f5c9063c72ff4c65d78b091af631a9e1ee430", + "0x875a31aee4ba19e09f8c2754fab0b5530ec283c7861a4858b239a12432f09ef155a35fedb0bc33eac2117c7e62f1c7ee", + "0x95edd0d1a6e94af718590756b5c5f5492f1c3441ecc7fa22f4e37f4ec256b9fffd2fda4c11fc1a7c220daee096eb1ff8", + "0xb35fdc435adc73e15c5aaf4e2eea795f9e590d3e3ee4066cafa9c489ee5917466c2a4c897a186b2d27b848c8a65fa8a8", + "0x94a5ce56f8d72ec4d0f480cb8f03e52b22f7d43f949a4b50d4a688a928ffd2c9074ecbab37733c0c30759204a54f9a6a", + "0x987562d78ef42228c56074193f80de1b5a9ed625dd7c4c7df3bf5096e7d7b08e2ee864bd12d2ea563e24fa20ad4d30ef", + "0x95a8218405038c991ace2f45980dbb1efa9e4ad0d8153486b0213a89e4d7e3cac6d607100660784627c74f90a8e55482", + "0xb6a29d566f5a924355b7f7912f55140e1b5f99f983c614b8a92814ce261f2750e8db178866651ea3b461fb8f92890b14", + "0xafdacc0a13da0446a92455f57a42b3ba27ba707f24171727aa974d05143fae219de9e2eb7c857235dd9c7568f43be5a8", + "0x862a7dc25f7cfa4a09aeca0ed2c9c5ee66189e119e226720b19344e231981504e37bca179aa7cad238ee3ab1386aa722", + "0xa336364e76635f188e544613a47a85978073f1686e4ee7a8987f54da91c4193540ac448b91d07d1fc5c7a8538b1f1688", + "0x8f1ddca9638decd8247c1ce49c1e6cf494d03d91c4f33e48a84452d12b6736e8bd18c157068dfeff3a90977af19e5b1e", + "0x96ae91b9aaf00e437c18ddfc1aef2113ee278153ba090aedeb3f48f1e66feb8897bb1ac7f5ffeffc3be29376dd51e498", + "0x8230b5bd9067efb6089e50213f1cc84da892e6faf0b79d5e4768c29303a80b1b754cb09d17a21933aba4c5f32070878a", + "0xa79dfe217faec7b4d3cf97d8363949efbc6f3d2c6bbc25df2c7bb8b7fd2521e6d3fa76672bfc06de6f426290d0b3cc45", + "0x8290bd36552609d6b3ac9ccb57ff8668fc8290548eecdcee9a231f1125298c20bd8e60f033214dfbd42cd3c8642c699b", + "0x8945db9e8ec437c5145add028d25936ee8823ceb300a959402d262232ae0cbd9a64c1f0a1be6aed15ff152202ea9a70c", + "0x949e232b48adeaf57bd38eacb035267d3e78333c6b4524cab86651a428a730baf9c27ff42cb172526d925de863132e82", + "0x98917e7a5073a9c93a526399bb74af71c76958a74619caccf47949f8fd25962810a19e399b4efcba0c550c371bea3676", + "0xb5b144e0707aefc853ea5570bd78dedc4e690cf29edc9413080f28335ac78022139bfe7f7d6986eb1f76872bb91e82ad", + "0x949945072a08de6fd5838e9d2c3dc3200d048b5d21183020240fa13e71a1a8d30e6bfee4e6895e91d87b92f1444d0589", + "0xb351a03c7c98506ee92d7fb9476065839baa8ed8ac1dc250f5a095c0d4c8abcfab62690d29d001f0862672da29721f16", + "0xa82d81c136bc5e418d1fba614cb40a11f39dc526e66a8b1d7609f42fea4c02b63196315014400084f31f62c24b177cbd", + "0x87d51c907fdcdf528d01291b28adfee1e5b6221c6da68fd92ab66126247cd8086a6bcffff0ea17e7b57b0ba8d01bb95d", + "0xa2a9a1a91dfd918f36c1bfeeca705ea8e926ee012f8c18d633e50ec6e50f68f3380ef2ee839e5a43cf80fbb75bfb5304", + "0x86f22616caed13c9e9cd5568175b6b0a6a463f9a15c301b8766feca593efa6e5ee4c7066e1cd61b407c0be12b3d8236a", + "0xb57e0a2c42790d2fd0207ef6476a433fca0cf213d70840c4af1ad45833f23fca082d21a484f78af447a19a0b068ea55c", + "0x8ae9bda5d85e6e3600dde26379b7270abd088678098506b72196ac8f9ce5b0173bc9c7ff245c95cbab5b5b967bcb043b", + "0x95c7d11f6c874f59ba632b63ce07a7a9d917a74d0b89cefa043f52aa1a7fe2e81c38dea0b20378264b5b4f64039932bc", + "0xac7dee7479f50722526ea1c9d4e2f1a4578d1b5cce2092a07722069c96bb4da295de1c4f16e21005276e3b3f1624ac5a", + "0x89b8aaa49bd18b09f78fc5a1f3dd85d69b5dfcff28fc6d5a92b1520bc54107b8b71bb71fd6e0bde10e0a5809c633e5d2", + "0x8982cb43fe4d3488c55e8c08b935e6c8d31bb57e4f2aeb76d6319470cce99ebf7dc2f116ac15b9d845ab1bc16aa6a583", + "0xa12c63f48e27b1a1c83a32992642f37fb5b89851a35e80f6d1f9bc483cb25acd0e12b1dcf68781ae0cc861f002368bcb", + "0xaa6da92a4b4fa229afc8007abca257ce0ff5fad3b1ccfe5d836b9b52ff6b72575a0b915a759403b993733b16a47fdb15", + "0x8bf706a92fe54f15d633b9463926b874dd43e28aaeca3fe2353fb58ad7753c8a293c56b0e94176070e8a9ec7401073a1", + "0xb81e86de4bb5c1046e40cca79585c5b98c8673626fd3a28e563c5a3296256c2f7086522ae95cbabfaa8f1a8f7eae6272", + "0xad10f895b05d35cb251f78cc042d3f0969a8b6b3f289ddb4b016e0b8e06bfffc3a3e1afa9b0cc548f8c092832bb766bc", + "0xad993aceb68d5217cfb07f862956cde83d05dec5060fc7a8fbfd37c6bfd5429ba69bdaf478b6cd01c323a06793dcd9fa", + "0x83da9c9a8fcb2775df0777aceabe90642a2df1c6abc646566e954f42d6e43455b00b101ec5ef58850c8d4b3100222ca1", + "0xb55484f339fe7c7d107e70432601f4a34e1cc02ae4de5d18b99e5aa995f7b3710fc745769b85c1af803d457491dd8ce3", + "0x8009d80593e82f3e751cec9e7e495fd29ad6f45f8d3ae513bec998b43c49fed74c44229c6f27c421e80c65413b897644", + "0x9868081bbcc71192f7ff8dcf99a91dcd40f96556fbd6f285bdbfdfc785f604d8bf75c368c59db5ac8cdcc663087db53a", + "0xa04b1e91af025b4387ee0a2d790a1afb842e46f4c3717e355578efd1f84fea78782c6f7944b4961268de7f1ac71fb92b", + "0xa7b6301ddb9738b89b28a36d29d5323264a78d93d369f57ddab4cea399c36018a1fcc2cc1bfadf956a775124ae2925bd", + "0xa6cdb469014b33c590a07a728ce48f15f17c027eb92055e1858a1f9805c8deb58491a471aaa765de86a6bda62a18aef4", + "0x828a23280ec67384a8846376378896037bd0cb5a6927ff9422fca266ee10a6fde5b95d963a4acfa92efbb0309cdb17b4", + "0xb498ec16bcdb50091647ae02d199d70c783d7c91348a1354661b1c42bc1266e5a5309b542ef5fdf5281d426819a671cb", + "0x806533fb603e78b63598ff390375eebe5b68380640f5e020e89a5430037db2e519ab8ae5d0d0ad3fa041921c098448e1", + "0x9104ad119681c54cdee19f0db92ebfe1da2fa6bef4177f5a383df84512d1b0af5cbe7baf6a93ad4b89138cd51c7c5838", + "0xac695cde30d021d9f4f295109890c4013f7e213d2150c9d5c85a36d4abfdca4cdc88faee9891e927a82fc204b988dcd9", + "0xa311c244df546d5dc76eccb91fe4c47055fc9d222d310b974d4c067923a29e7a7f6d5a88bfef72fd6d317471f80d5c82", + "0x89e4518335240479ad041a0915fc4f1afaab660bd4033c5d09c6707f0cc963eb2e6872cabc4a02169893943be7f847d4", + "0xa8ad395b784c83aacf133de50d6b23bd63b4f245bb9e180c11f568faca4c897f8dbda73335ef0f80a8cb548a0c3c48fc" + ] +} \ No newline at end of file diff --git a/go.mod b/go.mod index c3e4ee0b49..68929fb8af 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,14 @@ require ( github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.14.0 github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 - github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c + github.com/consensys/gnark-crypto v0.10.0 + github.com/crate-crypto/go-kzg-4844 v0.2.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 github.com/docker/docker v1.6.2 github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 github.com/edsrzf/mmap-go v1.0.0 + github.com/ethereum/c-kzg-4844 v0.1.0 github.com/fatih/color v1.7.0 github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 @@ -53,15 +55,15 @@ require ( github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.2.0 - github.com/stretchr/testify v1.8.0 - github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 + github.com/stretchr/testify v1.8.1 + github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa golang.org/x/crypto v0.1.0 golang.org/x/exp v0.0.0-20230206171751-46f607a40771 golang.org/x/sync v0.1.0 - golang.org/x/sys v0.6.0 + golang.org/x/sys v0.7.0 golang.org/x/text v0.8.0 golang.org/x/time v0.0.0-20220922220347-f3bd1da661af golang.org/x/tools v0.7.0 @@ -80,6 +82,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect github.com/aws/smithy-go v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bits-and-blooms/bitset v1.7.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect diff --git a/go.sum b/go.sum index 1022db1e43..7f463184be 100644 --- a/go.sum +++ b/go.sum @@ -43,6 +43,10 @@ github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8= +github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= +github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= @@ -70,8 +74,8 @@ github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c h1:llSLg4o9EgH3SrXky+Q5BqEYqV76NGKo07K5Ps2pIKo= -github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= +github.com/consensys/gnark-crypto v0.10.0 h1:zRh22SR7o4K35SoNqouS9J/TKHTyU2QWaj5ldehyXtA= +github.com/consensys/gnark-crypto v0.10.0/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -81,6 +85,10 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 h1:6IrxszG5G+O7zhtkWxq6+unVvnrm1fqV2Pe+T95DUzw= github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= +github.com/crate-crypto/go-kzg-4844 v0.1.0 h1:2PXr2wKBNTmSsoYLCmaNg5Z6uQUf7LiUAsnDbTfq+0M= +github.com/crate-crypto/go-kzg-4844 v0.1.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= +github.com/crate-crypto/go-kzg-4844 v0.2.0 h1:UVuHOE+5tIWrim4zf/Xaa43+MIsDCPyW76QhUpiMGj4= +github.com/crate-crypto/go-kzg-4844 v0.2.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -120,6 +128,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/ethereum/c-kzg-4844 v0.1.0 h1:BR9kUo6zAaFphuoNj39NquE3Sl0sD/oT0+idKZ4mkiI= +github.com/ethereum/c-kzg-4844 v0.1.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -399,16 +409,18 @@ github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobt github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCAy1QjzINvKe/pYtLjo2dl59x2w9YSEJxuY= -github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b h1:u49mjRnygnB34h8OKbnNJFVUtWSKIKb1KukdV8bILUM= +github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= @@ -544,6 +556,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/internal/build/gotool.go b/internal/build/gotool.go index 08c8b2ef05..b5452f80cc 100644 --- a/internal/build/gotool.go +++ b/internal/build/gotool.go @@ -53,31 +53,10 @@ func (g *GoToolchain) Go(command string, args ...string) *exec.Cmd { } else if os.Getenv("CC") != "" { tool.Env = append(tool.Env, "CC="+os.Getenv("CC")) } - return tool -} - -// Install creates an invocation of 'go install'. The command is configured to output -// executables to the given 'gobin' directory. -// -// This can be used to install auxiliary build tools without modifying the local go.mod and -// go.sum files. To install tools which are not required by go.mod, ensure that all module -// paths in 'args' contain a module version suffix (e.g. "...@latest"). -func (g *GoToolchain) Install(gobin string, args ...string) *exec.Cmd { - if !filepath.IsAbs(gobin) { - panic("GOBIN must be an absolute path") - } - tool := g.goTool("install") - tool.Env = append(tool.Env, "GOBIN="+gobin) - tool.Args = append(tool.Args, "-mod=readonly") - tool.Args = append(tool.Args, args...) + // CKZG by default is not portable, append the necessary build flags to make + // it not rely on modern CPU instructions and enable linking against + tool.Env = append(tool.Env, "CGO_CFLAGS=-D__BLST_PORTABLE__") - // Ensure GOPATH is set because go install seems to absolutely require it. This uses - // 'go env' because it resolves the default value when GOPATH is not set in the - // environment. Ignore errors running go env and leave any complaining about GOPATH to - // the install command. - pathTool := g.goTool("env", "GOPATH") - output, _ := pathTool.Output() - tool.Env = append(tool.Env, "GOPATH="+string(output)) return tool } From c8b0afb2c449580b45171a6343ce8cc4226587e2 Mon Sep 17 00:00:00 2001 From: Delweng Date: Thu, 11 May 2023 15:09:16 +0800 Subject: [PATCH 106/988] ethclient: acquire the rpc.Client (#27246) Signed-off-by: jsvisa --- ethclient/ethclient.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 47beaf63cc..09d3f37d1e 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -41,6 +41,7 @@ func Dial(rawurl string) (*Client, error) { return DialContext(context.Background(), rawurl) } +// DialContext connects a client to the given URL with context. func DialContext(ctx context.Context, rawurl string) (*Client, error) { c, err := rpc.DialContext(ctx, rawurl) if err != nil { @@ -54,10 +55,16 @@ func NewClient(c *rpc.Client) *Client { return &Client{c} } +// Close closes the underlying RPC connection. func (ec *Client) Close() { ec.c.Close() } +// Client gets the underlying RPC client. +func (ec *Client) Client() *rpc.Client { + return ec.c +} + // Blockchain Access // ChainID retrieves the current chain ID for transaction replay protection. From d17ec0ea66e733062ac4a02122a1ddd81bc75631 Mon Sep 17 00:00:00 2001 From: ucwong Date: Thu, 11 May 2023 01:13:25 -0600 Subject: [PATCH 107/988] ethdb/memorydb: init map with known size (#27241) ethdb:init map with known size --- ethdb/memorydb/memorydb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index 7e4fd7e5e7..6ca7ce7d91 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -342,7 +342,7 @@ func newSnapshot(db *Database) *snapshot { db.lock.RLock() defer db.lock.RUnlock() - copied := make(map[string][]byte) + copied := make(map[string][]byte, len(db.db)) for key, val := range db.db { copied[key] = common.CopyBytes(val) } From 7577b9c28faeaf4ddea6bfb88396a0068ba4f1e6 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 11 May 2023 09:15:44 +0200 Subject: [PATCH 108/988] core/state: unexport NodeIterator (#27239) --- core/state/iterator.go | 16 ++++++++-------- core/state/iterator_test.go | 2 +- core/state/sync_test.go | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/state/iterator.go b/core/state/iterator.go index 29c4abfc21..79bb650abc 100644 --- a/core/state/iterator.go +++ b/core/state/iterator.go @@ -26,9 +26,9 @@ import ( "github.com/ethereum/go-ethereum/trie" ) -// NodeIterator is an iterator to traverse the entire state trie post-order, +// nodeIterator is an iterator to traverse the entire state trie post-order, // including all of the contract code and contract state tries. -type NodeIterator struct { +type nodeIterator struct { state *StateDB // State being iterated stateIt trie.NodeIterator // Primary iterator for the global state trie @@ -44,9 +44,9 @@ type NodeIterator struct { Error error // Failure set in case of an internal error in the iterator } -// NewNodeIterator creates an post-order state node iterator. -func NewNodeIterator(state *StateDB) *NodeIterator { - return &NodeIterator{ +// newNodeIterator creates an post-order state node iterator. +func newNodeIterator(state *StateDB) *nodeIterator { + return &nodeIterator{ state: state, } } @@ -54,7 +54,7 @@ func NewNodeIterator(state *StateDB) *NodeIterator { // Next moves the iterator to the next node, returning whether there are any // further nodes. In case of an internal error this method returns false and // sets the Error field to the encountered failure. -func (it *NodeIterator) Next() bool { +func (it *nodeIterator) Next() bool { // If the iterator failed previously, don't do anything if it.Error != nil { return false @@ -68,7 +68,7 @@ func (it *NodeIterator) Next() bool { } // step moves the iterator to the next entry of the state trie. -func (it *NodeIterator) step() error { +func (it *nodeIterator) step() error { // Abort if we reached the end of the iteration if it.state == nil { return nil @@ -131,7 +131,7 @@ func (it *NodeIterator) step() error { // retrieve pulls and caches the current state entry the iterator is traversing. // The method returns whether there are any more data left for inspection. -func (it *NodeIterator) retrieve() bool { +func (it *nodeIterator) retrieve() bool { // Clear out any previously set values it.Hash = common.Hash{} diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go index 24b192c26c..c8e1a181eb 100644 --- a/core/state/iterator_test.go +++ b/core/state/iterator_test.go @@ -36,7 +36,7 @@ func TestNodeIteratorCoverage(t *testing.T) { } // Gather all the node hashes found by the iterator hashes := make(map[common.Hash]struct{}) - for it := NewNodeIterator(state); it.Next(); { + for it := newNodeIterator(state); it.Next(); { if it.Hash != (common.Hash{}) { hashes[it.Hash] = struct{}{} } diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 87621f49c1..8f8430559b 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -125,7 +125,7 @@ func checkStateConsistency(db ethdb.Database, root common.Hash) error { if err != nil { return err } - it := NewNodeIterator(state) + it := newNodeIterator(state) for it.Next() { } return it.Error From a14301823ea4da3004f05584ca1093d1d626819d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 11 May 2023 15:19:42 +0800 Subject: [PATCH 109/988] all: new empty trie with types.EmptyRootHash instead of null (#27230) --- cmd/evm/internal/t8ntool/execution.go | 2 +- cmd/evm/runner.go | 3 +- core/genesis.go | 4 +- core/state/snapshot/generate_test.go | 82 +++++++++++++-------------- core/state/state_test.go | 7 ++- core/state/statedb_test.go | 28 ++++----- core/state/sync_test.go | 2 +- core/state/trie_prefetcher_test.go | 3 +- core/txpool/txpool2_test.go | 8 +-- core/txpool/txpool_test.go | 38 ++++++------- core/vm/gas_table_test.go | 5 +- core/vm/instructions_test.go | 3 +- core/vm/interpreter_test.go | 3 +- core/vm/runtime/runtime.go | 5 +- core/vm/runtime/runtime_test.go | 10 ++-- eth/api_test.go | 7 ++- eth/fetcher/block_fetcher_test.go | 2 +- eth/protocols/snap/sync_test.go | 4 +- les/fetcher/block_fetcher_test.go | 2 +- light/postprocess.go | 4 +- miner/miner_test.go | 2 +- tests/state_test_util.go | 2 +- trie/iterator_test.go | 2 +- trie/secure_trie_test.go | 4 +- trie/sync_test.go | 2 +- 25 files changed, 121 insertions(+), 113 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 5295f3203c..5633198d39 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -293,7 +293,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB { sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) - statedb, _ := state.New(common.Hash{}, sdb, nil) + statedb, _ := state.New(types.EmptyRootHash, sdb, nil) for addr, a := range accounts { statedb.SetCode(addr, a.Code) statedb.SetNonce(addr, a.Nonce) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 18ec3330c4..52d7c3fa30 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm/runtime" "github.com/ethereum/go-ethereum/eth/tracers/logger" @@ -146,7 +147,7 @@ func runCmd(ctx *cli.Context) error { chainConfig = gen.Config } else { sdb := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: preimages}) - statedb, _ = state.New(common.Hash{}, sdb, nil) + statedb, _ = state.New(types.EmptyRootHash, sdb, nil) genesisConfig = new(core.Genesis) } if ctx.String(SenderFlag.Name) != "" { diff --git a/core/genesis.go b/core/genesis.go index 1a9ee24dff..26f31c0863 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -120,7 +120,7 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) { // Create an ephemeral in-memory database for computing hash, // all the derived states will be discarded to not pollute disk. db := state.NewDatabase(rawdb.NewMemoryDatabase()) - statedb, err := state.New(common.Hash{}, db, nil) + statedb, err := state.New(types.EmptyRootHash, db, nil) if err != nil { return common.Hash{}, err } @@ -139,7 +139,7 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) { // all the generated states will be persisted into the given database. // Also, the genesis state specification will be flushed as well. func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error { - statedb, err := state.New(common.Hash{}, state.NewDatabaseWithNodeDB(db, triedb), nil) + statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil) if err != nil { return err } diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 265515a9cf..a17ae05e5c 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -49,14 +49,14 @@ func TestGeneration(t *testing.T) { // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. var helper = newHelper() - stRoot := helper.makeStorageTrie(common.Hash{}, common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, false) + stRoot := helper.makeStorageTrie(common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, false) helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) root, snap := helper.CommitAndGenerate() if have, want := root, common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"); have != want { @@ -84,7 +84,7 @@ func TestGenerateExistentState(t *testing.T) { // two of which also has the same 3-slot storage trie attached. var helper = newHelper() - stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) @@ -92,7 +92,7 @@ func TestGenerateExistentState(t *testing.T) { helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) - stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) @@ -151,7 +151,7 @@ type testHelper struct { func newHelper() *testHelper { diskdb := rawdb.NewMemoryDatabase() triedb := trie.NewDatabase(diskdb) - accTrie, _ := trie.NewStateTrie(trie.StateTrieID(common.Hash{}), triedb) + accTrie, _ := trie.NewStateTrie(trie.StateTrieID(types.EmptyRootHash), triedb) return &testHelper{ diskdb: diskdb, triedb: triedb, @@ -183,8 +183,8 @@ func (t *testHelper) addSnapStorage(accKey string, keys []string, vals []string) } } -func (t *testHelper) makeStorageTrie(stateRoot, owner common.Hash, keys []string, vals []string, commit bool) []byte { - id := trie.StorageTrieID(stateRoot, owner, common.Hash{}) +func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []string, commit bool) []byte { + id := trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash) stTrie, _ := trie.NewStateTrie(id, t.triedb) for i, k := range keys { stTrie.MustUpdate([]byte(k), []byte(vals[i])) @@ -241,23 +241,23 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) // Account two, non empty root but empty database - stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + stRoot := helper.makeStorageTrie(hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Miss slots { // Account three, non empty root but misses slots in the beginning - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-3", []string{"key-2", "key-3"}, []string{"val-2", "val-3"}) // Account four, non empty root but misses slots in the middle - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-4")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-4")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-4", []string{"key-1", "key-3"}, []string{"val-1", "val-3"}) // Account five, non empty root but misses slots in the end - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-5")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-5")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-5", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-5", []string{"key-1", "key-2"}, []string{"val-1", "val-2"}) } @@ -265,22 +265,22 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { // Wrong storage slots { // Account six, non empty root but wrong slots in the beginning - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-6")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-6")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"badval-1", "val-2", "val-3"}) // Account seven, non empty root but wrong slots in the middle - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-7")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-7")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-7", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-7", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "badval-2", "val-3"}) // Account eight, non empty root but wrong slots in the end - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-8")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-8")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-8", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-8", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "badval-3"}) // Account 9, non empty root but rotated slots - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-9")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-9")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-9", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-3", "val-2"}) } @@ -288,17 +288,17 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { // Extra storage slots { // Account 10, non empty root but extra slots in the beginning - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-10")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-10")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-10", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-10", []string{"key-0", "key-1", "key-2", "key-3"}, []string{"val-0", "val-1", "val-2", "val-3"}) // Account 11, non empty root but extra slots in the middle - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-11")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-11")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-11", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-11", []string{"key-1", "key-2", "key-2-1", "key-3"}, []string{"val-1", "val-2", "val-2-1", "val-3"}) // Account 12, non empty root but extra slots in the end - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-12")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-12")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-12", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-12", []string{"key-1", "key-2", "key-3", "key-4"}, []string{"val-1", "val-2", "val-3", "val-4"}) } @@ -328,11 +328,11 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { func TestGenerateExistentStateWithWrongAccounts(t *testing.T) { helper := newHelper() - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-4")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-6")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-4")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + stRoot := helper.makeStorageTrie(hashData([]byte("acc-6")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // Trie accounts [acc-1, acc-2, acc-3, acc-4, acc-6] // Extra accounts [acc-0, acc-5, acc-7] @@ -420,10 +420,10 @@ func TestGenerateMissingStorageTrie(t *testing.T) { // two of which also has the same 3-slot storage trie attached. helper := newHelper() - stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 - stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 root := helper.Commit() @@ -454,10 +454,10 @@ func TestGenerateCorruptStorageTrie(t *testing.T) { // two of which also has the same 3-slot storage trie attached. helper := newHelper() - stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 - stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 root := helper.Commit() @@ -485,7 +485,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) { helper := newHelper() { // Account one in the trie - stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), + stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3", "key-4", "key-5"}, []string{"val-1", "val-2", "val-3", "val-4", "val-5"}, true, @@ -505,7 +505,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) { } { // Account two exists only in the snapshot - stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-2")), + stRoot := helper.makeStorageTrie(hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3", "key-4", "key-5"}, []string{"val-1", "val-2", "val-3", "val-4", "val-5"}, true, @@ -556,7 +556,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) { helper := newHelper() { // Account one in the trie - stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), + stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true, @@ -686,7 +686,7 @@ func TestGenerateFromEmptySnap(t *testing.T) { helper := newHelper() // Add 1K accounts to the trie for i := 0; i < 400; i++ { - stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte(fmt.Sprintf("acc-%d", i))), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + stRoot := helper.makeStorageTrie(hashData([]byte(fmt.Sprintf("acc-%d", i))), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount(fmt.Sprintf("acc-%d", i), &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) } @@ -724,7 +724,7 @@ func TestGenerateWithIncompleteStorage(t *testing.T) { // on the sensitive spots at the boundaries for i := 0; i < 8; i++ { accKey := fmt.Sprintf("acc-%d", i) - stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte(accKey)), stKeys, stVals, true) + stRoot := helper.makeStorageTrie(hashData([]byte(accKey)), stKeys, stVals, true) helper.addAccount(accKey, &Account{Balance: big.NewInt(int64(i)), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) var moddedKeys []string var moddedVals []string @@ -816,11 +816,11 @@ func populateDangling(disk ethdb.KeyValueStore) { func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) { var helper = newHelper() - stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) @@ -851,11 +851,11 @@ func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) { func TestGenerateBrokenSnapshotWithDanglingStorage(t *testing.T) { var helper = newHelper() - stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) - helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) populateDangling(helper.diskdb) diff --git a/core/state/state_test.go b/core/state/state_test.go index b6b46e446f..ada1e801ee 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/trie" @@ -35,13 +36,13 @@ type stateTest struct { func newStateTest() *stateTest { db := rawdb.NewMemoryDatabase() - sdb, _ := New(common.Hash{}, NewDatabase(db), nil) + sdb, _ := New(types.EmptyRootHash, NewDatabase(db), nil) return &stateTest{db: db, state: sdb} } func TestDump(t *testing.T) { db := rawdb.NewMemoryDatabase() - sdb, _ := New(common.Hash{}, NewDatabaseWithConfig(db, &trie.Config{Preimages: true}), nil) + sdb, _ := New(types.EmptyRootHash, NewDatabaseWithConfig(db, &trie.Config{Preimages: true}), nil) s := &stateTest{db: db, state: sdb} // generate a few entries @@ -150,7 +151,7 @@ func TestSnapshotEmpty(t *testing.T) { } func TestSnapshot2(t *testing.T) { - state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) stateobjaddr0 := common.BytesToAddress([]byte("so0")) stateobjaddr1 := common.BytesToAddress([]byte("so1")) diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 8aa59e3ee5..e73b1b8c6e 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -39,7 +39,7 @@ import ( func TestUpdateLeaks(t *testing.T) { // Create an empty state database db := rawdb.NewMemoryDatabase() - state, _ := New(common.Hash{}, NewDatabase(db), nil) + state, _ := New(types.EmptyRootHash, NewDatabase(db), nil) // Update it with some accounts for i := byte(0); i < 255; i++ { @@ -73,8 +73,8 @@ func TestIntermediateLeaks(t *testing.T) { // Create two state databases, one transitioning to the final state, the other final from the beginning transDb := rawdb.NewMemoryDatabase() finalDb := rawdb.NewMemoryDatabase() - transState, _ := New(common.Hash{}, NewDatabase(transDb), nil) - finalState, _ := New(common.Hash{}, NewDatabase(finalDb), nil) + transState, _ := New(types.EmptyRootHash, NewDatabase(transDb), nil) + finalState, _ := New(types.EmptyRootHash, NewDatabase(finalDb), nil) modify := func(state *StateDB, addr common.Address, i, tweak byte) { state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) @@ -149,7 +149,7 @@ func TestIntermediateLeaks(t *testing.T) { // https://github.com/ethereum/go-ethereum/pull/15549. func TestCopy(t *testing.T) { // Create a random state test to copy and modify "independently" - orig, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) + orig, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) for i := byte(0); i < 255; i++ { obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) @@ -409,7 +409,7 @@ func (test *snapshotTest) String() string { func (test *snapshotTest) run() bool { // Run all actions and create snapshots. var ( - state, _ = New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ = New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) snapshotRevs = make([]int, len(test.snapshots)) sindex = 0 ) @@ -423,7 +423,7 @@ func (test *snapshotTest) run() bool { // Revert all snapshots in reverse order. Each revert must yield a state // that is equivalent to fresh state with all actions up the snapshot applied. for sindex--; sindex >= 0; sindex-- { - checkstate, _ := New(common.Hash{}, state.Database(), nil) + checkstate, _ := New(types.EmptyRootHash, state.Database(), nil) for _, action := range test.actions[:test.snapshots[sindex]] { action.fn(action, checkstate) } @@ -501,7 +501,7 @@ func TestTouchDelete(t *testing.T) { // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. // See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512 func TestCopyOfCopy(t *testing.T) { - state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) addr := common.HexToAddress("aaaa") state.SetBalance(addr, big.NewInt(42)) @@ -518,7 +518,7 @@ func TestCopyOfCopy(t *testing.T) { // // See https://github.com/ethereum/go-ethereum/issues/20106. func TestCopyCommitCopy(t *testing.T) { - state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) // Create an account and check if the retrieved balance is correct addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") @@ -590,7 +590,7 @@ func TestCopyCommitCopy(t *testing.T) { // // See https://github.com/ethereum/go-ethereum/issues/20106. func TestCopyCopyCommitCopy(t *testing.T) { - state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) // Create an account and check if the retrieved balance is correct addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") @@ -680,7 +680,7 @@ func TestCopyCopyCommitCopy(t *testing.T) { // first, but the journal wiped the entire state object on create-revert. func TestDeleteCreateRevert(t *testing.T) { // Create an initial state with a single contract - state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) addr := common.BytesToAddress([]byte("so")) state.SetBalance(addr, big.NewInt(1)) @@ -713,7 +713,7 @@ func TestMissingTrieNodes(t *testing.T) { memDb := rawdb.NewMemoryDatabase() db := NewDatabase(memDb) var root common.Hash - state, _ := New(common.Hash{}, db, nil) + state, _ := New(types.EmptyRootHash, db, nil) addr := common.BytesToAddress([]byte("so")) { state.SetBalance(addr, big.NewInt(1)) @@ -762,7 +762,7 @@ func TestStateDBAccessList(t *testing.T) { memDb := rawdb.NewMemoryDatabase() db := NewDatabase(memDb) - state, _ := New(common.Hash{}, db, nil) + state, _ := New(types.EmptyRootHash, db, nil) state.accessList = newAccessList() verifyAddrs := func(astrings ...string) { @@ -932,7 +932,7 @@ func TestFlushOrderDataLoss(t *testing.T) { var ( memdb = rawdb.NewMemoryDatabase() statedb = NewDatabase(memdb) - state, _ = New(common.Hash{}, statedb, nil) + state, _ = New(types.EmptyRootHash, statedb, nil) ) for a := byte(0); a < 10; a++ { state.CreateAccount(common.Address{a}) @@ -968,7 +968,7 @@ func TestFlushOrderDataLoss(t *testing.T) { func TestStateDBTransientStorage(t *testing.T) { memDb := rawdb.NewMemoryDatabase() db := NewDatabase(memDb) - state, _ := New(common.Hash{}, db, nil) + state, _ := New(types.EmptyRootHash, db, nil) key := common.Hash{0x01} value := common.Hash{0x02} diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 8f8430559b..6e9d9342ee 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -43,7 +43,7 @@ func makeTestState() (ethdb.Database, Database, common.Hash, []*testAccount) { // Create an empty state db := rawdb.NewMemoryDatabase() sdb := NewDatabase(db) - state, _ := New(common.Hash{}, sdb, nil) + state, _ := New(types.EmptyRootHash, sdb, nil) // Fill it with some arbitrary data var accounts []*testAccount diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index 501bb70840..b190567e92 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -23,10 +23,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" ) func filledStateDB() *StateDB { - state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) // Create an account and check if the retrieved balance is correct addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") diff --git a/core/txpool/txpool2_test.go b/core/txpool/txpool2_test.go index 7e2a9eb908..d7ae3bdb1b 100644 --- a/core/txpool/txpool2_test.go +++ b/core/txpool/txpool2_test.go @@ -78,7 +78,7 @@ func TestTransactionFutureAttack(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalQueue = 100 @@ -114,7 +114,7 @@ func TestTransactionFutureAttack(t *testing.T) { func TestTransactionFuture1559(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain) defer pool.Stop() @@ -146,7 +146,7 @@ func TestTransactionFuture1559(t *testing.T) { func TestTransactionZAttack(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain) defer pool.Stop() @@ -213,7 +213,7 @@ func TestTransactionZAttack(t *testing.T) { func BenchmarkFutureAttack(b *testing.B) { // Create the pool to test the limit enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalQueue = 100 diff --git a/core/txpool/txpool_test.go b/core/txpool/txpool_test.go index a4889fa62f..22e106aaf8 100644 --- a/core/txpool/txpool_test.go +++ b/core/txpool/txpool_test.go @@ -126,7 +126,7 @@ func setupPool() (*TxPool, *ecdsa.PrivateKey) { } func setupPoolWithConfig(config *params.ChainConfig) (*TxPool, *ecdsa.PrivateKey) { - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(10000000, statedb, new(event.Feed)) key, _ := crypto.GenerateKey() @@ -218,7 +218,7 @@ func (c *testChain) State() (*state.StateDB, error) { // a state change between those fetches. stdb := c.statedb if *c.trigger { - c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) // simulate that the new head block included tx0 and tx1 c.statedb.SetNonce(c.address, 2) c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether)) @@ -236,7 +236,7 @@ func TestStateChangeDuringReset(t *testing.T) { var ( key, _ = crypto.GenerateKey() address = crypto.PubkeyToAddress(key.PublicKey) - statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) trigger = false ) @@ -434,7 +434,7 @@ func TestChainFork(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb.AddBalance(addr, big.NewInt(100000000000000)) pool.chain = newTestBlockChain(1000000, statedb, new(event.Feed)) @@ -463,7 +463,7 @@ func TestDoubleNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb.AddBalance(addr, big.NewInt(100000000000000)) pool.chain = newTestBlockChain(1000000, statedb, new(event.Feed)) @@ -663,7 +663,7 @@ func TestPostponing(t *testing.T) { t.Parallel() // Create the pool to test the postponing with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) @@ -875,7 +875,7 @@ func testQueueGlobalLimiting(t *testing.T, nolocals bool) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -967,7 +967,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { evictionInterval = time.Millisecond * 100 // Create the pool to test the non-expiration enforcement - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1152,7 +1152,7 @@ func TestPendingGlobalLimiting(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1254,7 +1254,7 @@ func TestCapClearsFromAll(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1288,7 +1288,7 @@ func TestPendingMinimumAllowance(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1336,7 +1336,7 @@ func TestRepricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) @@ -1584,7 +1584,7 @@ func TestRepricingKeepsLocals(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain) @@ -1657,7 +1657,7 @@ func TestUnderpricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1771,7 +1771,7 @@ func TestStableUnderpricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -2003,7 +2003,7 @@ func TestDeduplication(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) @@ -2069,7 +2069,7 @@ func TestReplacement(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) @@ -2274,7 +2274,7 @@ func testJournaling(t *testing.T, nolocals bool) { os.Remove(journal) // Create the original pool to inject transaction into the journal - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -2372,7 +2372,7 @@ func TestStatusCheck(t *testing.T) { t.Parallel() // Create the pool to test the status retrievals with - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index c3d06e515b..4a5259a262 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) @@ -83,7 +84,7 @@ func TestEIP2200(t *testing.T) { for i, tt := range eip2200Tests { address := common.BytesToAddress([]byte("contract")) - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb.CreateAccount(address) statedb.SetCode(address, hexutil.MustDecode(tt.input)) statedb.SetState(address, common.Hash{}, common.BytesToHash([]byte{tt.original})) @@ -135,7 +136,7 @@ func TestCreateGas(t *testing.T) { var gasUsed = uint64(0) doCheck := func(testGas int) bool { address := common.BytesToAddress([]byte("contract")) - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb.CreateAccount(address) statedb.SetCode(address, hexutil.MustDecode(tt.code)) statedb.Finalise(true) diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 61f001a692..2a66f8163e 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -579,7 +580,7 @@ func BenchmarkOpMstore(bench *testing.B) { func TestOpTstore(t *testing.T) { var ( - statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) env = NewEVM(BlockContext{}, TxContext{}, statedb, params.TestChainConfig, Config{}) stack = newstack() mem = NewMemory() diff --git a/core/vm/interpreter_test.go b/core/vm/interpreter_test.go index 31ee9922db..96e681fccd 100644 --- a/core/vm/interpreter_test.go +++ b/core/vm/interpreter_test.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) @@ -42,7 +43,7 @@ func TestLoopInterrupt(t *testing.T) { } for i, tt := range loopInterruptTests { - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb.CreateAccount(address) statedb.SetCode(address, common.Hex2Bytes(tt)) statedb.Finalise(true) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 005ef0c754..951a472e42 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" @@ -106,7 +107,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { setDefaults(cfg) if cfg.State == nil { - cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) } var ( address = common.BytesToAddress([]byte("contract")) @@ -140,7 +141,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { setDefaults(cfg) if cfg.State == nil { - cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) } var ( vmenv = NewEnv(cfg) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 62953a4365..7b521a2ead 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -103,7 +103,7 @@ func TestExecute(t *testing.T) { } func TestCall(t *testing.T) { - state, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) address := common.HexToAddress("0x0a") state.SetCode(address, []byte{ byte(vm.PUSH1), 10, @@ -159,7 +159,7 @@ func BenchmarkCall(b *testing.B) { } func benchmarkEVM_Create(bench *testing.B, code string) { var ( - statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) sender = common.BytesToAddress([]byte("sender")) receiver = common.BytesToAddress([]byte("receiver")) ) @@ -327,7 +327,7 @@ func TestBlockhash(t *testing.T) { func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode string, b *testing.B) { cfg := new(Config) setDefaults(cfg) - cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) cfg.GasLimit = gas if len(tracerCode) > 0 { tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil) @@ -818,7 +818,7 @@ func TestRuntimeJSTracer(t *testing.T) { main := common.HexToAddress("0xaa") for i, jsTracer := range jsTracers { for j, tc := range tests { - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb.SetCode(main, tc.code) statedb.SetCode(common.HexToAddress("0xbb"), calleeCode) statedb.SetCode(common.HexToAddress("0xcc"), calleeCode) @@ -860,7 +860,7 @@ func TestJSTracerCreateTx(t *testing.T) { exit: function(res) { this.exits++ }}` code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)} - statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil) if err != nil { t.Fatal(err) diff --git a/eth/api_test.go b/eth/api_test.go index fca17f1217..dec1b34ddc 100644 --- a/eth/api_test.go +++ b/eth/api_test.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/trie" ) @@ -68,7 +69,7 @@ func TestAccountRange(t *testing.T) { var ( statedb = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: true}) - state, _ = state.New(common.Hash{}, statedb, nil) + state, _ = state.New(types.EmptyRootHash, statedb, nil) addrs = [AccountRangeMaxResults * 2]common.Address{} m = map[common.Address]bool{} ) @@ -139,7 +140,7 @@ func TestEmptyAccountRange(t *testing.T) { var ( statedb = state.NewDatabase(rawdb.NewMemoryDatabase()) - st, _ = state.New(common.Hash{}, statedb, nil) + st, _ = state.New(types.EmptyRootHash, statedb, nil) ) st.Commit(true) st.IntermediateRoot(true) @@ -162,7 +163,7 @@ func TestStorageRangeAt(t *testing.T) { // Create a state where account 0x010000... has a few storage entries. var ( - state, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) addr = common.Address{0x01} keys = []common.Hash{ // hashes of Keys of storage common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"), diff --git a/eth/fetcher/block_fetcher_test.go b/eth/fetcher/block_fetcher_test.go index 520fc9c7b7..6d8516fa6a 100644 --- a/eth/fetcher/block_fetcher_test.go +++ b/eth/fetcher/block_fetcher_test.go @@ -45,7 +45,7 @@ var ( BaseFee: big.NewInt(params.InitialBaseFee), } genesis = gspec.MustCommit(testdb) - unknownBlock = types.NewBlock(&types.Header{GasLimit: params.GenesisGasLimit, BaseFee: big.NewInt(params.InitialBaseFee)}, nil, nil, nil, trie.NewStackTrie(nil)) + unknownBlock = types.NewBlock(&types.Header{Root: types.EmptyRootHash, GasLimit: params.GenesisGasLimit, BaseFee: big.NewInt(params.InitialBaseFee)}, nil, nil, nil, trie.NewStackTrie(nil)) ) // makeChain creates a chain of n blocks starting at and including parent. diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index ee2ef95810..58cde8d1eb 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -1589,7 +1589,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin // not-yet-committed trie and the sorted entries. The seeds can be used to ensure // that tries are unique. func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (common.Hash, *trienode.NodeSet, entrySlice) { - trie, _ := trie.New(trie.StorageTrieID(common.Hash{}, owner, common.Hash{}), db) + trie, _ := trie.New(trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash), db) var entries entrySlice for i := uint64(1); i <= n; i++ { // store 'x' at slot 'x' @@ -1615,7 +1615,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo var ( entries entrySlice boundaries []common.Hash - trie, _ = trie.New(trie.StorageTrieID(common.Hash{}, owner, common.Hash{}), db) + trie, _ = trie.New(trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash), db) ) // Initialize boundaries var next common.Hash diff --git a/les/fetcher/block_fetcher_test.go b/les/fetcher/block_fetcher_test.go index 95ca65916d..f29cf58805 100644 --- a/les/fetcher/block_fetcher_test.go +++ b/les/fetcher/block_fetcher_test.go @@ -44,7 +44,7 @@ var ( BaseFee: big.NewInt(params.InitialBaseFee), } genesis = gspec.MustCommit(testdb) - unknownBlock = types.NewBlock(&types.Header{GasLimit: params.GenesisGasLimit, BaseFee: big.NewInt(params.InitialBaseFee)}, nil, nil, nil, trie.NewStackTrie(nil)) + unknownBlock = types.NewBlock(&types.Header{Root: types.EmptyRootHash, GasLimit: params.GenesisGasLimit, BaseFee: big.NewInt(params.InitialBaseFee)}, nil, nil, nil, trie.NewStackTrie(nil)) ) // makeChain creates a chain of n blocks starting at and including parent. diff --git a/light/postprocess.go b/light/postprocess.go index 38f4995268..001df209b7 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -179,7 +179,7 @@ func (c *ChtIndexerBackend) fetchMissingNodes(ctx context.Context, section uint6 // Reset implements core.ChainIndexerBackend func (c *ChtIndexerBackend) Reset(ctx context.Context, section uint64, lastSectionHead common.Hash) error { - var root common.Hash + root := types.EmptyRootHash if section > 0 { root = GetChtRoot(c.diskdb, section-1, lastSectionHead) } @@ -404,7 +404,7 @@ func (b *BloomTrieIndexerBackend) fetchMissingNodes(ctx context.Context, section // Reset implements core.ChainIndexerBackend func (b *BloomTrieIndexerBackend) Reset(ctx context.Context, section uint64, lastSectionHead common.Hash) error { - var root common.Hash + root := types.EmptyRootHash if section > 0 { root = GetBloomTrieRoot(b.diskdb, section-1, lastSectionHead) } diff --git a/miner/miner_test.go b/miner/miner_test.go index 6bf3edae5d..5ea6e18301 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -264,7 +264,7 @@ func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { if err != nil { t.Fatalf("can't create new chain %v", err) } - statedb, _ := state.New(common.Hash{}, state.NewDatabase(chainDB), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(chainDB), nil) blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)} pool := txpool.NewTxPool(testTxPoolConfig, chainConfig, blockchain) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 14b6fe5341..d9b646918d 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -286,7 +286,7 @@ func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter bool) (*snapshot.Tree, *state.StateDB) { sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) - statedb, _ := state.New(common.Hash{}, sdb, nil) + statedb, _ := state.New(types.EmptyRootHash, sdb, nil) for addr, a := range accounts { statedb.SetCode(addr, a.Code) statedb.SetNonce(addr, a.Nonce) diff --git a/trie/iterator_test.go b/trie/iterator_test.go index fca8c823b9..8003858e5b 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -584,7 +584,7 @@ func makeLargeTestTrie() (*Database, *StateTrie, *loggingDb) { // Create an empty trie logDb := &loggingDb{0, memorydb.New()} triedb := NewDatabase(rawdb.NewDatabase(logDb)) - trie, _ := NewStateTrie(TrieID(common.Hash{}), triedb) + trie, _ := NewStateTrie(TrieID(types.EmptyRootHash), triedb) // Fill it with some arbitrary data for i := 0; i < 10000; i++ { diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index 2da7e6ccb2..e4f6bca97d 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -31,7 +31,7 @@ import ( ) func newEmptySecure() *StateTrie { - trie, _ := NewStateTrie(TrieID(common.Hash{}), NewDatabase(rawdb.NewMemoryDatabase())) + trie, _ := NewStateTrie(TrieID(types.EmptyRootHash), NewDatabase(rawdb.NewMemoryDatabase())) return trie } @@ -39,7 +39,7 @@ func newEmptySecure() *StateTrie { func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) { // Create an empty trie triedb := NewDatabase(rawdb.NewMemoryDatabase()) - trie, _ := NewStateTrie(TrieID(common.Hash{}), triedb) + trie, _ := NewStateTrie(TrieID(types.EmptyRootHash), triedb) // Fill it with some arbitrary data content := make(map[string][]byte) diff --git a/trie/sync_test.go b/trie/sync_test.go index 9114501ca2..7cd4058176 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -35,7 +35,7 @@ func makeTestTrie(scheme string) (ethdb.Database, *Database, *StateTrie, map[str // Create an empty trie db := rawdb.NewMemoryDatabase() triedb := newTestDatabase(db, scheme) - trie, _ := NewStateTrie(TrieID(common.Hash{}), triedb) + trie, _ := NewStateTrie(TrieID(types.EmptyRootHash), triedb) // Fill it with some arbitrary data content := make(map[string][]byte) From a340721aa909ea4b541ffd1ea5e9c7bd441ff769 Mon Sep 17 00:00:00 2001 From: Exca-DK <85954505+Exca-DK@users.noreply.github.com> Date: Thu, 11 May 2023 11:39:13 +0200 Subject: [PATCH 110/988] metrics: use sync.map in registry (#27159) --- metrics/registry.go | 99 ++++++++++++++++++---------------------- metrics/registry_test.go | 25 ++++++++++ 2 files changed, 69 insertions(+), 55 deletions(-) diff --git a/metrics/registry.go b/metrics/registry.go index 4c62248351..ec6e37c54f 100644 --- a/metrics/registry.go +++ b/metrics/registry.go @@ -45,21 +45,17 @@ type Registry interface { // Unregister the metric with the given name. Unregister(string) - - // Unregister all metrics. (Mostly for testing.) - UnregisterAll() } -// The standard implementation of a Registry is a mutex-protected map +// The standard implementation of a Registry uses sync.map // of names to metrics. type StandardRegistry struct { - metrics map[string]interface{} - mutex sync.Mutex + metrics sync.Map } // Create a new registry. func NewRegistry() Registry { - return &StandardRegistry{metrics: make(map[string]interface{})} + return &StandardRegistry{} } // Call the given function for each registered metric. @@ -71,9 +67,8 @@ func (r *StandardRegistry) Each(f func(string, interface{})) { // Get the metric by the given name or nil if none is registered. func (r *StandardRegistry) Get(name string) interface{} { - r.mutex.Lock() - defer r.mutex.Unlock() - return r.metrics[name] + item, _ := r.metrics.Load(name) + return item } // Gets an existing metric or creates and registers a new one. Threadsafe @@ -81,35 +76,48 @@ func (r *StandardRegistry) Get(name string) interface{} { // The interface can be the metric to register if not found in registry, // or a function returning the metric for lazy instantiation. func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} { - r.mutex.Lock() - defer r.mutex.Unlock() - if metric, ok := r.metrics[name]; ok { - return metric + // fast path + cached, ok := r.metrics.Load(name) + if ok { + return cached } if v := reflect.ValueOf(i); v.Kind() == reflect.Func { i = v.Call(nil)[0].Interface() } - r.register(name, i) - return i + item, _, ok := r.loadOrRegister(name, i) + if !ok { + return i + } + return item } // Register the given metric under the given name. Returns a DuplicateMetric // if a metric by the given name is already registered. func (r *StandardRegistry) Register(name string, i interface{}) error { - r.mutex.Lock() - defer r.mutex.Unlock() - return r.register(name, i) + // fast path + _, ok := r.metrics.Load(name) + if ok { + return DuplicateMetric(name) + } + + if v := reflect.ValueOf(i); v.Kind() == reflect.Func { + i = v.Call(nil)[0].Interface() + } + _, loaded, _ := r.loadOrRegister(name, i) + if loaded { + return DuplicateMetric(name) + } + return nil } // Run all registered healthchecks. func (r *StandardRegistry) RunHealthchecks() { - r.mutex.Lock() - defer r.mutex.Unlock() - for _, i := range r.metrics { - if h, ok := i.(Healthcheck); ok { + r.metrics.Range(func(key, value any) bool { + if h, ok := value.(Healthcheck); ok { h.Check() } - } + return true + }) } // GetAll metrics in the Registry @@ -177,45 +185,31 @@ func (r *StandardRegistry) GetAll() map[string]map[string]interface{} { // Unregister the metric with the given name. func (r *StandardRegistry) Unregister(name string) { - r.mutex.Lock() - defer r.mutex.Unlock() r.stop(name) - delete(r.metrics, name) -} - -// Unregister all metrics. (Mostly for testing.) -func (r *StandardRegistry) UnregisterAll() { - r.mutex.Lock() - defer r.mutex.Unlock() - for name := range r.metrics { - r.stop(name) - delete(r.metrics, name) - } + r.metrics.LoadAndDelete(name) } -func (r *StandardRegistry) register(name string, i interface{}) error { - if _, ok := r.metrics[name]; ok { - return DuplicateMetric(name) - } +func (r *StandardRegistry) loadOrRegister(name string, i interface{}) (interface{}, bool, bool) { switch i.(type) { case Counter, CounterFloat64, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer: - r.metrics[name] = i + default: + return nil, false, false } - return nil + item, loaded := r.metrics.LoadOrStore(name, i) + return item, loaded, true } func (r *StandardRegistry) registered() map[string]interface{} { - r.mutex.Lock() - defer r.mutex.Unlock() - metrics := make(map[string]interface{}, len(r.metrics)) - for name, i := range r.metrics { - metrics[name] = i - } + metrics := make(map[string]interface{}) + r.metrics.Range(func(key, value any) bool { + metrics[key.(string)] = value + return true + }) return metrics } func (r *StandardRegistry) stop(name string) { - if i, ok := r.metrics[name]; ok { + if i, ok := r.metrics.Load(name); ok { if s, ok := i.(Stoppable); ok { s.Stop() } @@ -308,11 +302,6 @@ func (r *PrefixedRegistry) Unregister(name string) { r.underlying.Unregister(realName) } -// Unregister all metrics. (Mostly for testing.) -func (r *PrefixedRegistry) UnregisterAll() { - r.underlying.UnregisterAll() -} - var ( DefaultRegistry = NewRegistry() EphemeralRegistry = NewRegistry() diff --git a/metrics/registry_test.go b/metrics/registry_test.go index d277ae5c3e..7cc5cf14fe 100644 --- a/metrics/registry_test.go +++ b/metrics/registry_test.go @@ -1,6 +1,7 @@ package metrics import ( + "sync" "testing" ) @@ -13,6 +14,30 @@ func BenchmarkRegistry(b *testing.B) { } } +func BenchmarkRegistryGetOrRegisterParallel_8(b *testing.B) { + benchmarkRegistryGetOrRegisterParallel(b, 8) +} + +func BenchmarkRegistryGetOrRegisterParallel_32(b *testing.B) { + benchmarkRegistryGetOrRegisterParallel(b, 32) +} + +func benchmarkRegistryGetOrRegisterParallel(b *testing.B, amount int) { + r := NewRegistry() + b.ResetTimer() + var wg sync.WaitGroup + for i := 0; i < amount; i++ { + wg.Add(1) + go func() { + for i := 0; i < b.N; i++ { + r.GetOrRegister("foo", NewMeter) + } + wg.Done() + }() + } + wg.Wait() +} + func TestRegistry(t *testing.T) { r := NewRegistry() r.Register("foo", NewCounter()) From 0b66d47449f61e9ebaf9e1db3ed290b59844d4c1 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Thu, 11 May 2023 20:23:05 +0800 Subject: [PATCH 111/988] internal/ethapi: make EstimateGas use `latest` block by default (#24363) * EstimateGas should use LatestBlockNumber by default * graphql: default to use latest for gas estimation --------- Co-authored-by: Martin Holst Swende --- graphql/graphql.go | 4 ++-- internal/ethapi/api.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index ac80304f87..1ac439753d 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -1150,8 +1150,8 @@ func (p *Pending) Call(ctx context.Context, args struct { func (p *Pending) EstimateGas(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (hexutil.Uint64, error) { - pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) - return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, pendingBlockNr, p.r.backend.RPCGasCap()) + latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) + return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, p.r.backend.RPCGasCap()) } // Resolver is the top-level object in the GraphQL hierarchy. diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 9a0aed7b18..589a0eed33 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1217,7 +1217,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr // EstimateGas returns an estimate of the amount of gas needed to execute the // given transaction against the current pending block. func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) { - bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) + bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash } From dffd804ca20ccbfa557bc9d71183d41c97a5fff3 Mon Sep 17 00:00:00 2001 From: makcandrov Date: Thu, 11 May 2023 04:23:47 -0800 Subject: [PATCH 112/988] internal/ethapi: remove unused err-return (#27240) --- eth/api_backend.go | 4 ++-- internal/ethapi/api.go | 11 +++-------- internal/ethapi/api_test.go | 4 ++-- internal/ethapi/backend.go | 2 +- internal/ethapi/transaction_args_test.go | 4 ++-- les/api_backend.go | 4 ++-- 6 files changed, 12 insertions(+), 17 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index 9ea288a949..1789f106e9 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -246,7 +246,7 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) { +func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error) { if vmConfig == nil { vmConfig = b.eth.blockchain.GetVMConfig() } @@ -257,7 +257,7 @@ func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *st } else { context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) } - return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), state.Error, nil + return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), state.Error } func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 589a0eed33..1f9f6cc80d 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1018,10 +1018,8 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash if blockOverrides != nil { blockOverrides.Apply(&blockCtx) } - evm, vmError, err := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, &blockCtx) - if err != nil { - return nil, err - } + evm, vmError := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, &blockCtx) + // Wait for the context to be done and cancel the evm. Even if the // EVM has finished, cancelling may be done (repeatedly) go func() { @@ -1514,10 +1512,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) config := vm.Config{Tracer: tracer, NoBaseFee: true} - vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config, nil) - if err != nil { - return nil, 0, nil, err - } + vmenv, _ := b.GetEVM(ctx, msg, statedb, header, &config, nil) res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) if err != nil { return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err) diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 39f912a349..93993d20ca 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -283,7 +283,7 @@ func (b testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.R panic("implement me") } func (b testBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { panic("implement me") } -func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) (*vm.EVM, func() error, error) { +func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) (*vm.EVM, func() error) { vmError := func() error { return nil } if vmConfig == nil { vmConfig = b.chain.GetVMConfig() @@ -293,7 +293,7 @@ func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state if blockContext != nil { context = *blockContext } - return vm.NewEVM(context, txContext, state, b.chain.Config(), *vmConfig), vmError, nil + return vm.NewEVM(context, txContext, state, b.chain.Config(), *vmConfig), vmError } func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { panic("implement me") diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 3e4ee505f3..918b3b6309 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -68,7 +68,7 @@ type Backend interface { PendingBlockAndReceipts() (*types.Block, types.Receipts) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) GetTd(ctx context.Context, hash common.Hash) *big.Int - GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) + GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 124f2164cf..4da98718b5 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -305,8 +305,8 @@ func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number return nil, nil } func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) { - return nil, nil, nil +func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error) { + return nil, nil } func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil } func (b *backendMock) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { diff --git a/les/api_backend.go b/les/api_backend.go index 86da26da65..97665757b1 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -184,7 +184,7 @@ func (b *LesApiBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) { +func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error) { if vmConfig == nil { vmConfig = new(vm.Config) } @@ -193,7 +193,7 @@ func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state *st if blockCtx != nil { context = *blockCtx } - return vm.NewEVM(context, txContext, state, b.eth.chainConfig, *vmConfig), state.Error, nil + return vm.NewEVM(context, txContext, state, b.eth.chainConfig, *vmConfig), state.Error } func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { From 1982437259a2353fa22050c55abeb40eca7300c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 12 May 2023 20:14:29 +0300 Subject: [PATCH 113/988] core/types: un-ssz blob txs, add json marshalling and tweaks (#27256) --- core/types/gen_access_tuple.go | 8 +- core/types/transaction.go | 8 +- core/types/transaction_marshalling.go | 178 +++++++++++++++++++------- core/types/tx_access_list.go | 4 +- core/types/tx_blob.go | 2 +- 5 files changed, 138 insertions(+), 62 deletions(-) diff --git a/core/types/gen_access_tuple.go b/core/types/gen_access_tuple.go index fc48a84cc0..d740b70981 100644 --- a/core/types/gen_access_tuple.go +++ b/core/types/gen_access_tuple.go @@ -12,8 +12,8 @@ import ( // MarshalJSON marshals as JSON. func (a AccessTuple) MarshalJSON() ([]byte, error) { type AccessTuple struct { - Address common.Address `json:"address" gencodec:"required"` - StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"` + Address common.Address `json:"address" gencodec:"required"` + StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"` } var enc AccessTuple enc.Address = a.Address @@ -24,8 +24,8 @@ func (a AccessTuple) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (a *AccessTuple) UnmarshalJSON(input []byte) error { type AccessTuple struct { - Address *common.Address `json:"address" gencodec:"required"` - StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"` + Address *common.Address `json:"address" gencodec:"required"` + StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"` } var dec AccessTuple if err := json.Unmarshal(input, &dec); err != nil { diff --git a/core/types/transaction.go b/core/types/transaction.go index f0b674f344..b7cb36b602 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -198,7 +198,7 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { return &inner, err case BlobTxType: var inner BlobTx - err := rlp.DecodeBytes(b[1:], &inner) // TODO(karalabe): This needs to be ssz + err := rlp.DecodeBytes(b[1:], &inner) return &inner, err default: return nil, ErrTxTypeNotSupported @@ -417,11 +417,7 @@ func (tx *Transaction) Size() uint64 { return size.(uint64) } c := writeCounter(0) - if tx.Type() == BlobTxType { - rlp.Encode(&c, &tx.inner) // TODO(karalabe): Replace with SSZ encoding - } else { - rlp.Encode(&c, &tx.inner) - } + rlp.Encode(&c, &tx.inner) size := uint64(c) if tx.Type() != LegacyTxType { diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 2566d0b8d6..6c6c50d498 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -23,28 +23,28 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/holiman/uint256" ) // txJSON is the JSON representation of transactions. type txJSON struct { Type hexutil.Uint64 `json:"type"` - // Common transaction fields: + ChainID *hexutil.Big `json:"chainId,omitempty"` Nonce *hexutil.Uint64 `json:"nonce"` + To *common.Address `json:"to"` + Gas *hexutil.Uint64 `json:"gas"` GasPrice *hexutil.Big `json:"gasPrice"` MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` - Gas *hexutil.Uint64 `json:"gas"` + MaxFeePerDataGas *hexutil.Big `json:"maxFeePerDataGas,omitempty"` Value *hexutil.Big `json:"value"` - Data *hexutil.Bytes `json:"input"` + Input *hexutil.Bytes `json:"input"` + AccessList *AccessList `json:"accessList,omitempty"` + BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` V *hexutil.Big `json:"v"` R *hexutil.Big `json:"r"` S *hexutil.Big `json:"s"` - To *common.Address `json:"to"` - - // Access list transaction fields: - ChainID *hexutil.Big `json:"chainId,omitempty"` - AccessList *AccessList `json:"accessList,omitempty"` // Only used for encoding: Hash common.Hash `json:"hash"` @@ -61,39 +61,57 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { switch itx := tx.inner.(type) { case *LegacyTx: enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) + enc.To = tx.To() enc.Gas = (*hexutil.Uint64)(&itx.Gas) enc.GasPrice = (*hexutil.Big)(itx.GasPrice) enc.Value = (*hexutil.Big)(itx.Value) - enc.Data = (*hexutil.Bytes)(&itx.Data) - enc.To = tx.To() + enc.Input = (*hexutil.Bytes)(&itx.Data) enc.V = (*hexutil.Big)(itx.V) enc.R = (*hexutil.Big)(itx.R) enc.S = (*hexutil.Big)(itx.S) + case *AccessListTx: enc.ChainID = (*hexutil.Big)(itx.ChainID) - enc.AccessList = &itx.AccessList enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) + enc.To = tx.To() enc.Gas = (*hexutil.Uint64)(&itx.Gas) enc.GasPrice = (*hexutil.Big)(itx.GasPrice) enc.Value = (*hexutil.Big)(itx.Value) - enc.Data = (*hexutil.Bytes)(&itx.Data) - enc.To = tx.To() + enc.Input = (*hexutil.Bytes)(&itx.Data) + enc.AccessList = &itx.AccessList enc.V = (*hexutil.Big)(itx.V) enc.R = (*hexutil.Big)(itx.R) enc.S = (*hexutil.Big)(itx.S) + case *DynamicFeeTx: enc.ChainID = (*hexutil.Big)(itx.ChainID) - enc.AccessList = &itx.AccessList enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) + enc.To = tx.To() enc.Gas = (*hexutil.Uint64)(&itx.Gas) enc.MaxFeePerGas = (*hexutil.Big)(itx.GasFeeCap) enc.MaxPriorityFeePerGas = (*hexutil.Big)(itx.GasTipCap) enc.Value = (*hexutil.Big)(itx.Value) - enc.Data = (*hexutil.Bytes)(&itx.Data) - enc.To = tx.To() + enc.Input = (*hexutil.Bytes)(&itx.Data) + enc.AccessList = &itx.AccessList enc.V = (*hexutil.Big)(itx.V) enc.R = (*hexutil.Big)(itx.R) enc.S = (*hexutil.Big)(itx.S) + + case *BlobTx: + enc.ChainID = (*hexutil.Big)(itx.ChainID.ToBig()) + enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) + enc.Gas = (*hexutil.Uint64)(&itx.Gas) + enc.MaxFeePerGas = (*hexutil.Big)(itx.GasFeeCap.ToBig()) + enc.MaxPriorityFeePerGas = (*hexutil.Big)(itx.GasTipCap.ToBig()) + enc.MaxFeePerDataGas = (*hexutil.Big)(itx.BlobFeeCap.ToBig()) + enc.Value = (*hexutil.Big)(itx.Value.ToBig()) + enc.Input = (*hexutil.Bytes)(&itx.Data) + enc.AccessList = &itx.AccessList + enc.BlobVersionedHashes = itx.BlobHashes + enc.To = tx.To() + enc.V = (*hexutil.Big)(itx.V.ToBig()) + enc.R = (*hexutil.Big)(itx.R.ToBig()) + enc.S = (*hexutil.Big)(itx.S.ToBig()) } return json.Marshal(&enc) } @@ -111,29 +129,29 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { case LegacyTxType: var itx LegacyTx inner = &itx - if dec.To != nil { - itx.To = dec.To - } if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } itx.Nonce = uint64(*dec.Nonce) - if dec.GasPrice == nil { - return errors.New("missing required field 'gasPrice' in transaction") + if dec.To != nil { + itx.To = dec.To } - itx.GasPrice = (*big.Int)(dec.GasPrice) if dec.Gas == nil { return errors.New("missing required field 'gas' in transaction") } itx.Gas = uint64(*dec.Gas) + if dec.GasPrice == nil { + return errors.New("missing required field 'gasPrice' in transaction") + } + itx.GasPrice = (*big.Int)(dec.GasPrice) if dec.Value == nil { return errors.New("missing required field 'value' in transaction") } itx.Value = (*big.Int)(dec.Value) - if dec.Data == nil { + if dec.Input == nil { return errors.New("missing required field 'input' in transaction") } - itx.Data = *dec.Data + itx.Data = *dec.Input if dec.V == nil { return errors.New("missing required field 'v' in transaction") } @@ -156,40 +174,39 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { case AccessListTxType: var itx AccessListTx inner = &itx - // Access list is optional for now. - if dec.AccessList != nil { - itx.AccessList = *dec.AccessList - } if dec.ChainID == nil { return errors.New("missing required field 'chainId' in transaction") } itx.ChainID = (*big.Int)(dec.ChainID) - if dec.To != nil { - itx.To = dec.To - } if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } itx.Nonce = uint64(*dec.Nonce) - if dec.GasPrice == nil { - return errors.New("missing required field 'gasPrice' in transaction") + if dec.To != nil { + itx.To = dec.To } - itx.GasPrice = (*big.Int)(dec.GasPrice) if dec.Gas == nil { return errors.New("missing required field 'gas' in transaction") } itx.Gas = uint64(*dec.Gas) + if dec.GasPrice == nil { + return errors.New("missing required field 'gasPrice' in transaction") + } + itx.GasPrice = (*big.Int)(dec.GasPrice) if dec.Value == nil { return errors.New("missing required field 'value' in transaction") } itx.Value = (*big.Int)(dec.Value) - if dec.Data == nil { + if dec.Input == nil { return errors.New("missing required field 'input' in transaction") } - itx.Data = *dec.Data + itx.Data = *dec.Input if dec.V == nil { return errors.New("missing required field 'v' in transaction") } + if dec.AccessList != nil { + itx.AccessList = *dec.AccessList + } itx.V = (*big.Int)(dec.V) if dec.R == nil { return errors.New("missing required field 'r' in transaction") @@ -209,21 +226,21 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { case DynamicFeeTxType: var itx DynamicFeeTx inner = &itx - // Access list is optional for now. - if dec.AccessList != nil { - itx.AccessList = *dec.AccessList - } if dec.ChainID == nil { return errors.New("missing required field 'chainId' in transaction") } itx.ChainID = (*big.Int)(dec.ChainID) - if dec.To != nil { - itx.To = dec.To - } if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } itx.Nonce = uint64(*dec.Nonce) + if dec.To != nil { + itx.To = dec.To + } + if dec.Gas == nil { + return errors.New("missing required field 'gas' for txdata") + } + itx.Gas = uint64(*dec.Gas) if dec.MaxPriorityFeePerGas == nil { return errors.New("missing required field 'maxPriorityFeePerGas' for txdata") } @@ -232,21 +249,20 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'maxFeePerGas' for txdata") } itx.GasFeeCap = (*big.Int)(dec.MaxFeePerGas) - if dec.Gas == nil { - return errors.New("missing required field 'gas' for txdata") - } - itx.Gas = uint64(*dec.Gas) if dec.Value == nil { return errors.New("missing required field 'value' in transaction") } itx.Value = (*big.Int)(dec.Value) - if dec.Data == nil { + if dec.Input == nil { return errors.New("missing required field 'input' in transaction") } - itx.Data = *dec.Data + itx.Data = *dec.Input if dec.V == nil { return errors.New("missing required field 'v' in transaction") } + if dec.AccessList != nil { + itx.AccessList = *dec.AccessList + } itx.V = (*big.Int)(dec.V) if dec.R == nil { return errors.New("missing required field 'r' in transaction") @@ -263,6 +279,70 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { } } + case BlobTxType: + var itx BlobTx + inner = &itx + if dec.ChainID == nil { + return errors.New("missing required field 'chainId' in transaction") + } + itx.ChainID = uint256.MustFromBig((*big.Int)(dec.ChainID)) + if dec.Nonce == nil { + return errors.New("missing required field 'nonce' in transaction") + } + itx.Nonce = uint64(*dec.Nonce) + if dec.To != nil { + itx.To = dec.To + } + if dec.Gas == nil { + return errors.New("missing required field 'gas' for txdata") + } + itx.Gas = uint64(*dec.Gas) + if dec.MaxPriorityFeePerGas == nil { + return errors.New("missing required field 'maxPriorityFeePerGas' for txdata") + } + itx.GasTipCap = uint256.MustFromBig((*big.Int)(dec.MaxPriorityFeePerGas)) + if dec.MaxFeePerGas == nil { + return errors.New("missing required field 'maxFeePerGas' for txdata") + } + itx.GasFeeCap = uint256.MustFromBig((*big.Int)(dec.MaxFeePerGas)) + if dec.MaxFeePerDataGas == nil { + return errors.New("missing required field 'maxFeePerDataGas' for txdata") + } + itx.BlobFeeCap = uint256.MustFromBig((*big.Int)(dec.MaxFeePerDataGas)) + if dec.Value == nil { + return errors.New("missing required field 'value' in transaction") + } + itx.Value = uint256.MustFromBig((*big.Int)(dec.Value)) + if dec.Input == nil { + return errors.New("missing required field 'input' in transaction") + } + itx.Data = *dec.Input + if dec.V == nil { + return errors.New("missing required field 'v' in transaction") + } + if dec.AccessList != nil { + itx.AccessList = *dec.AccessList + } + if dec.BlobVersionedHashes == nil { + return errors.New("missing required field 'blobVersionedHashes' in transaction") + } + itx.BlobHashes = dec.BlobVersionedHashes + itx.V = uint256.MustFromBig((*big.Int)(dec.V)) + if dec.R == nil { + return errors.New("missing required field 'r' in transaction") + } + itx.R = uint256.MustFromBig((*big.Int)(dec.R)) + if dec.S == nil { + return errors.New("missing required field 's' in transaction") + } + itx.S = uint256.MustFromBig((*big.Int)(dec.S)) + withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 + if withSignature { + if err := sanityCheckSignature(itx.V.ToBig(), itx.R.ToBig(), itx.S.ToBig(), false); err != nil { + return err + } + } + default: return ErrTxTypeNotSupported } diff --git a/core/types/tx_access_list.go b/core/types/tx_access_list.go index 825942a41d..7ce9da73ec 100644 --- a/core/types/tx_access_list.go +++ b/core/types/tx_access_list.go @@ -29,8 +29,8 @@ type AccessList []AccessTuple // AccessTuple is the element type of an access list. type AccessTuple struct { - Address common.Address `json:"address" gencodec:"required"` - StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"` + Address common.Address `json:"address" gencodec:"required"` + StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"` } // StorageKeys returns the total number of storage keys in the access list. diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go index 1f64a9871b..58065d0017 100644 --- a/core/types/tx_blob.go +++ b/core/types/tx_blob.go @@ -31,7 +31,7 @@ type BlobTx struct { GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas GasFeeCap *uint256.Int // a.k.a. maxFeePerGas Gas uint64 - To *common.Address // `rlp:"nil"` // nil means contract creation + To *common.Address `rlp:"nil"` // nil means contract creation Value *uint256.Int Data []byte AccessList AccessList From 9ca84e6b0b8302a0834534f262d4d2dd232640c5 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Fri, 12 May 2023 12:16:14 -0500 Subject: [PATCH 114/988] crypto/kzg4844: upgrade c-kzg-4844 to v0.2.0 (#27257) Upgrade c-kzg-4844 to v0.2.0 --- crypto/kzg4844/kzg4844.go | 2 +- crypto/kzg4844/kzg4844_ckzg_cgo.go | 4 ++-- go.mod | 2 +- go.sum | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/crypto/kzg4844/kzg4844.go b/crypto/kzg4844/kzg4844.go index d54376965f..3bd814159d 100644 --- a/crypto/kzg4844/kzg4844.go +++ b/crypto/kzg4844/kzg4844.go @@ -55,7 +55,7 @@ func UseCKZG(use bool) error { // Initializing the library can take 2-4 seconds - and can potentially crash // on CKZG and non-ADX CPUs - so might as well so it now and don't wait until - // a crpyto operation is actually needed live. + // a crypto operation is actually needed live. if use { ckzgIniter.Do(ckzgInit) } else { diff --git a/crypto/kzg4844/kzg4844_ckzg_cgo.go b/crypto/kzg4844/kzg4844_ckzg_cgo.go index 76ff0a45cc..d62ca3fad6 100644 --- a/crypto/kzg4844/kzg4844_ckzg_cgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_cgo.go @@ -47,8 +47,8 @@ func ckzgInit() { if err = gokzg4844.CheckTrustedSetupIsWellFormed(params); err != nil { panic(err) } - g1s := make([]byte, len(params.SetupG1)*(len(params.SetupG1[0])-2)/2) - for i, g1 := range params.SetupG1 { + g1s := make([]byte, len(params.SetupG1Lagrange)*(len(params.SetupG1Lagrange[0])-2)/2) + for i, g1 := range params.SetupG1Lagrange { copy(g1s[i*(len(g1)-2)/2:], hexutil.MustDecode(g1)) } g2s := make([]byte, len(params.SetupG2)*(len(params.SetupG2[0])-2)/2) diff --git a/go.mod b/go.mod index 68929fb8af..7061e69466 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/docker/docker v1.6.2 github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 github.com/edsrzf/mmap-go v1.0.0 - github.com/ethereum/c-kzg-4844 v0.1.0 + github.com/ethereum/c-kzg-4844 v0.2.0 github.com/fatih/color v1.7.0 github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 diff --git a/go.sum b/go.sum index 7f463184be..6a31436ec9 100644 --- a/go.sum +++ b/go.sum @@ -130,6 +130,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/c-kzg-4844 v0.1.0 h1:BR9kUo6zAaFphuoNj39NquE3Sl0sD/oT0+idKZ4mkiI= github.com/ethereum/c-kzg-4844 v0.1.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8= +github.com/ethereum/c-kzg-4844 v0.2.0 h1:+cUvymlnoDDQgMInp25Bo3OmLajmmY8mLJ/tLjqd77Q= +github.com/ethereum/c-kzg-4844 v0.2.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= From 73697529994e14996b7740730481e926d5ec3e40 Mon Sep 17 00:00:00 2001 From: oseau Date: Mon, 15 May 2023 13:48:06 +0800 Subject: [PATCH 115/988] rpc: websocket should respect the "HTTP_PROXY" by default (#27264) rpc: the default dialer for websocket should respect the proxy environment variables like "HTTP_PROXY" --- rpc/websocket.go | 1 + 1 file changed, 1 insertion(+) diff --git a/rpc/websocket.go b/rpc/websocket.go index a6b95dd2ac..889562d1ab 100644 --- a/rpc/websocket.go +++ b/rpc/websocket.go @@ -224,6 +224,7 @@ func newClientTransportWS(endpoint string, cfg *clientConfig) (reconnectFunc, er ReadBufferSize: wsReadBuffer, WriteBufferSize: wsWriteBuffer, WriteBufferPool: wsBufferPool, + Proxy: http.ProxyFromEnvironment, } } From c2148c644da6c804f9070d32e311d5c479da3436 Mon Sep 17 00:00:00 2001 From: joohhnnn <68833933+joohhnnn@users.noreply.github.com> Date: Tue, 16 May 2023 16:14:04 +0800 Subject: [PATCH 116/988] core/asm: remove unused return value (#27272) --- core/asm/compiler.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/asm/compiler.go b/core/asm/compiler.go index ce2d23abd0..4b1d379206 100644 --- a/core/asm/compiler.go +++ b/core/asm/compiler.go @@ -157,13 +157,12 @@ func (c *Compiler) compileLine() error { } // compileNumber compiles the number to bytes -func (c *Compiler) compileNumber(element token) (int, error) { +func (c *Compiler) compileNumber(element token) { num := math.MustParseBig256(element.text).Bytes() if len(num) == 0 { num = []byte{0} } c.pushBin(num) - return len(num), nil } // compileElement compiles the element (push & label or both) From 6e3aa86a2b53e98e0946752f40408846662f2b0c Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 16 May 2023 16:40:47 +0800 Subject: [PATCH 117/988] internal/ethapi: minor refactor in block serialization (#27268) --- internal/ethapi/api.go | 23 ++------ internal/ethapi/api_test.go | 103 +++++++++++++++++++++++++++++++++++- 2 files changed, 107 insertions(+), 19 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1f9f6cc80d..5ebb6924ef 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1263,21 +1263,18 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param fields["size"] = hexutil.Uint64(block.Size()) if inclTx { - formatTx := func(tx *types.Transaction) (interface{}, error) { - return tx.Hash(), nil + formatTx := func(idx int, tx *types.Transaction) interface{} { + return tx.Hash() } if fullTx { - formatTx = func(tx *types.Transaction) (interface{}, error) { - return newRPCTransactionFromBlockHash(block, tx.Hash(), config), nil + formatTx = func(idx int, tx *types.Transaction) interface{} { + return newRPCTransactionFromBlockIndex(block, uint64(idx), config) } } txs := block.Transactions() transactions := make([]interface{}, len(txs)) - var err error for i, tx := range txs { - if transactions[i], err = formatTx(tx); err != nil { - return nil, err - } + transactions[i] = formatTx(i, tx) } fields["transactions"] = transactions } @@ -1424,16 +1421,6 @@ func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.By return blob } -// newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. -func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash, config *params.ChainConfig) *RPCTransaction { - for idx, tx := range b.Transactions() { - if tx.Hash() == hash { - return newRPCTransactionFromBlockIndex(b, uint64(idx), config) - } - } - return nil -} - // accessListResult returns an optional accesslist // It's the result of the `debug_createAccessList` RPC call. // It contains an error if the transaction itself failed. diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 93993d20ca..61024900b2 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -22,6 +22,7 @@ import ( "crypto/ecdsa" "encoding/json" "errors" + "hash" "math/big" "reflect" "sort" @@ -45,6 +46,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" + "golang.org/x/crypto/sha3" ) func TestTransaction_RoundTripRpcJSON(t *testing.T) { @@ -549,7 +551,7 @@ func TestCall(t *testing.T) { overrides: StateOverride{ randomAccounts[2].addr: OverrideAccount{ Code: hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"), - StateDiff: &map[common.Hash]common.Hash{common.Hash{}: common.BigToHash(big.NewInt(123))}, + StateDiff: &map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))}, }, }, want: "0x000000000000000000000000000000000000000000000000000000000000007b", @@ -624,3 +626,102 @@ func hex2Bytes(str string) *hexutil.Bytes { rpcBytes := hexutil.Bytes(common.Hex2Bytes(str)) return &rpcBytes } + +// testHasher is the helper tool for transaction/receipt list hashing. +// The original hasher is trie, in order to get rid of import cycle, +// use the testing hasher instead. +type testHasher struct { + hasher hash.Hash +} + +func newHasher() *testHasher { + return &testHasher{hasher: sha3.NewLegacyKeccak256()} +} + +func (h *testHasher) Reset() { + h.hasher.Reset() +} + +func (h *testHasher) Update(key, val []byte) error { + h.hasher.Write(key) + h.hasher.Write(val) + return nil +} + +func (h *testHasher) Hash() common.Hash { + return common.BytesToHash(h.hasher.Sum(nil)) +} + +func TestRPCMarshalBlock(t *testing.T) { + var ( + txs []*types.Transaction + to = common.BytesToAddress([]byte{0x11}) + ) + for i := uint64(1); i <= 4; i++ { + var tx *types.Transaction + if i%2 == 0 { + tx = types.NewTx(&types.LegacyTx{ + Nonce: i, + GasPrice: big.NewInt(11111), + Gas: 1111, + To: &to, + Value: big.NewInt(111), + Data: []byte{0x11, 0x11, 0x11}, + }) + } else { + tx = types.NewTx(&types.AccessListTx{ + ChainID: big.NewInt(1337), + Nonce: i, + GasPrice: big.NewInt(11111), + Gas: 1111, + To: &to, + Value: big.NewInt(111), + Data: []byte{0x11, 0x11, 0x11}, + }) + } + txs = append(txs, tx) + } + block := types.NewBlock(&types.Header{Number: big.NewInt(100)}, txs, nil, nil, newHasher()) + + var testSuite = []struct { + inclTx bool + fullTx bool + want string + }{ + // without txs + { + inclTx: false, + fullTx: false, + want: `{"difficulty":"0x0","extraData":"0x","gasLimit":"0x0","gasUsed":"0x0","hash":"0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","number":"0x64","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x296","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","transactionsRoot":"0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e","uncles":[]}`, + }, + // only tx hashes + { + inclTx: true, + fullTx: false, + want: `{"difficulty":"0x0","extraData":"0x","gasLimit":"0x0","gasUsed":"0x0","hash":"0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","number":"0x64","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x296","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","transactions":["0x7d39df979e34172322c64983a9ad48302c2b889e55bda35324afecf043a77605","0x9bba4c34e57c875ff57ac8d172805a26ae912006985395dc1bdf8f44140a7bf4","0x98909ea1ff040da6be56bc4231d484de1414b3c1dac372d69293a4beb9032cb5","0x12e1f81207b40c3bdcc13c0ee18f5f86af6d31754d57a0ea1b0d4cfef21abef1"],"transactionsRoot":"0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e","uncles":[]}`, + }, + + // full tx details + { + inclTx: true, + fullTx: true, + want: `{"difficulty":"0x0","extraData":"0x","gasLimit":"0x0","gasUsed":"0x0","hash":"0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","number":"0x64","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x296","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","transactions":[{"blockHash":"0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee","blockNumber":"0x64","from":"0x0000000000000000000000000000000000000000","gas":"0x457","gasPrice":"0x2b67","hash":"0x7d39df979e34172322c64983a9ad48302c2b889e55bda35324afecf043a77605","input":"0x111111","nonce":"0x1","to":"0x0000000000000000000000000000000000000011","transactionIndex":"0x0","value":"0x6f","type":"0x1","accessList":[],"chainId":"0x539","v":"0x0","r":"0x0","s":"0x0"},{"blockHash":"0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee","blockNumber":"0x64","from":"0x0000000000000000000000000000000000000000","gas":"0x457","gasPrice":"0x2b67","hash":"0x9bba4c34e57c875ff57ac8d172805a26ae912006985395dc1bdf8f44140a7bf4","input":"0x111111","nonce":"0x2","to":"0x0000000000000000000000000000000000000011","transactionIndex":"0x1","value":"0x6f","type":"0x0","chainId":"0x7fffffffffffffee","v":"0x0","r":"0x0","s":"0x0"},{"blockHash":"0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee","blockNumber":"0x64","from":"0x0000000000000000000000000000000000000000","gas":"0x457","gasPrice":"0x2b67","hash":"0x98909ea1ff040da6be56bc4231d484de1414b3c1dac372d69293a4beb9032cb5","input":"0x111111","nonce":"0x3","to":"0x0000000000000000000000000000000000000011","transactionIndex":"0x2","value":"0x6f","type":"0x1","accessList":[],"chainId":"0x539","v":"0x0","r":"0x0","s":"0x0"},{"blockHash":"0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee","blockNumber":"0x64","from":"0x0000000000000000000000000000000000000000","gas":"0x457","gasPrice":"0x2b67","hash":"0x12e1f81207b40c3bdcc13c0ee18f5f86af6d31754d57a0ea1b0d4cfef21abef1","input":"0x111111","nonce":"0x4","to":"0x0000000000000000000000000000000000000011","transactionIndex":"0x3","value":"0x6f","type":"0x0","chainId":"0x7fffffffffffffee","v":"0x0","r":"0x0","s":"0x0"}],"transactionsRoot":"0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e","uncles":[]}`, + }, + } + + for i, tc := range testSuite { + resp, err := RPCMarshalBlock(block, tc.inclTx, tc.fullTx, params.MainnetChainConfig) + if err != nil { + t.Errorf("test %d: got error %v", i, err) + continue + } + out, err := json.Marshal(resp) + if err != nil { + t.Errorf("test %d: json marshal error: %v", i, err) + continue + } + if have := string(out); have != tc.want { + t.Errorf("test %d: want: %s have: %s", i, tc.want, have) + } + } +} From d46f69dc7a71e0f203a197064ed556a6f283d9e4 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 16 May 2023 13:27:54 +0200 Subject: [PATCH 118/988] tests/fuzzers/bn256: add PairingCheck fuzzer (#27252) * tests/fuzzers/bn256: scale gnark result by constant * tests/fuzzers/bn256: scale gnark result by constant --- tests/fuzzers/bn256/bn256_fuzz.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/fuzzers/bn256/bn256_fuzz.go b/tests/fuzzers/bn256/bn256_fuzz.go index 1ce20571fc..abf1b88615 100644 --- a/tests/fuzzers/bn256/bn256_fuzz.go +++ b/tests/fuzzers/bn256/bn256_fuzz.go @@ -156,12 +156,29 @@ func FuzzPair(data []byte) int { if !bytes.Equal(clPair, gPair) { panic("pairing mismatch: cloudflare/google") } - cPair, err := bn254.Pair([]bn254.G1Affine{*ps}, []bn254.G2Affine{*ts}) if err != nil { panic(fmt.Sprintf("gnark/bn254 encountered error: %v", err)) } - if !bytes.Equal(clPair, cPair.Marshal()) { + + // gnark uses a different pairing algorithm which might produce + // different but also correct outputs, we need to scale the output by s + + u, _ := new(big.Int).SetString("0x44e992b44a6909f1", 0) + u_exp2 := new(big.Int).Exp(u, big.NewInt(2), nil) // u^2 + u_6_exp2 := new(big.Int).Mul(big.NewInt(6), u_exp2) // 6*u^2 + u_3 := new(big.Int).Mul(big.NewInt(3), u) // 3*u + inner := u_6_exp2.Add(u_6_exp2, u_3) // 6*u^2 + 3*u + inner.Add(inner, big.NewInt(1)) // 6*u^2 + 3*u + 1 + u_2 := new(big.Int).Mul(big.NewInt(2), u) // 2*u + s := u_2.Mul(u_2, inner) // 2*u(6*u^2 + 3*u + 1) + + gRes := new(bn254.GT) + if err := gRes.SetBytes(clPair); err != nil { + panic(err) + } + gRes = gRes.Exp(*gRes, s) + if !bytes.Equal(cPair.Marshal(), gRes.Marshal()) { panic("pairing mismatch: cloudflare/gnark") } From eb83e7c54021573eaceb14236af3a7a8c64f6027 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 16 May 2023 09:18:39 -0400 Subject: [PATCH 119/988] core/state/snapshot: check difflayer staleness early (#27255) This PR adds a staleness-check to AccountRLP, before checking the bloom-filter and potentially going directly into the disklayer. --------- Co-authored-by: rjl493456442 --- core/state/snapshot/difflayer.go | 12 +++++++++++- core/state/snapshot/snapshot_test.go | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index 4701acccd3..203d66f93d 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -292,9 +292,14 @@ func (dl *diffLayer) Account(hash common.Hash) (*Account, error) { // // Note the returned account is not a copy, please don't modify it. func (dl *diffLayer) AccountRLP(hash common.Hash) ([]byte, error) { + dl.lock.RLock() + // Check staleness before reaching further. + if dl.Stale() { + dl.lock.RUnlock() + return nil, ErrSnapshotStale + } // Check the bloom filter first whether there's even a point in reaching into // all the maps in all the layers below - dl.lock.RLock() hit := dl.diffed.Contains(accountBloomHasher(hash)) if !hit { hit = dl.diffed.Contains(destructBloomHasher(hash)) @@ -361,6 +366,11 @@ func (dl *diffLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro // Check the bloom filter first whether there's even a point in reaching into // all the maps in all the layers below dl.lock.RLock() + // Check staleness before reaching further. + if dl.Stale() { + dl.lock.RUnlock() + return nil, ErrSnapshotStale + } hit := dl.diffed.Contains(storageBloomHasher{accountHash, storageHash}) if !hit { hit = dl.diffed.Contains(destructBloomHasher(accountHash)) diff --git a/core/state/snapshot/snapshot_test.go b/core/state/snapshot/snapshot_test.go index 249da10aa6..038bd6df62 100644 --- a/core/state/snapshot/snapshot_test.go +++ b/core/state/snapshot/snapshot_test.go @@ -185,6 +185,10 @@ func TestDiskLayerExternalInvalidationPartialFlatten(t *testing.T) { // be returned with junk data. This version of the test retains the bottom diff // layer to check the usual mode of operation where the accumulator is retained. func TestDiffLayerExternalInvalidationPartialFlatten(t *testing.T) { + // Un-commenting this triggers the bloom set to be deterministic. The values below + // were used to trigger the flaw described in https://github.com/ethereum/go-ethereum/issues/27254. + // bloomDestructHasherOffset, bloomAccountHasherOffset, bloomStorageHasherOffset = 14, 24, 5 + // Create an empty base layer and a snapshot tree out of it base := &diskLayer{ diskdb: rawdb.NewMemoryDatabase(), From 2f2959d00399c80ef3771729a0c37897451166da Mon Sep 17 00:00:00 2001 From: John Chase <68833933+joohhnnn@users.noreply.github.com> Date: Wed, 17 May 2023 16:23:06 +0800 Subject: [PATCH 120/988] core/state/pruner: remove unused error-return (#27273) --- core/state/pruner/bloom.go | 4 ++-- core/state/pruner/pruner.go | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/core/state/pruner/bloom.go b/core/state/pruner/bloom.go index 72315db720..9f068eaf2d 100644 --- a/core/state/pruner/bloom.go +++ b/core/state/pruner/bloom.go @@ -127,6 +127,6 @@ func (bloom *stateBloom) Delete(key []byte) error { panic("not supported") } // reports whether the key is contained. // - If it says yes, the key may be contained // - If it says no, the key is definitely not contained. -func (bloom *stateBloom) Contain(key []byte) (bool, error) { - return bloom.bloom.Contains(stateBloomHasher(key)), nil +func (bloom *stateBloom) Contain(key []byte) bool { + return bloom.bloom.Contains(stateBloomHasher(key)) } diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 2bd5658e0a..a8142c51f0 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -146,9 +146,7 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta if _, exist := middleStateRoots[common.BytesToHash(checkKey)]; exist { log.Debug("Forcibly delete the middle state roots", "hash", common.BytesToHash(checkKey)) } else { - if ok, err := stateBloom.Contain(checkKey); err != nil { - return err - } else if ok { + if stateBloom.Contain(checkKey) { continue } } From ae1d90e7102ba0404668e08d773126aa079b71ad Mon Sep 17 00:00:00 2001 From: Alex Mylonas Date: Wed, 17 May 2023 11:29:56 +0300 Subject: [PATCH 121/988] internal/ethapi: make NewAccount return EIP-55 format (#26973) This change implements returning the address as EIP-55 encoded when creating a new account. --- common/types.go | 13 +++++++++++++ common/types_test.go | 24 ++++++++++++++++++++++++ internal/ethapi/api.go | 11 ++++++----- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/common/types.go b/common/types.go index 0b68a19dd3..3712df2fee 100644 --- a/common/types.go +++ b/common/types.go @@ -429,3 +429,16 @@ func (ma *MixedcaseAddress) ValidChecksum() bool { func (ma *MixedcaseAddress) Original() string { return ma.original } + +// AddressEIP55 is an alias of Address with a customized json marshaller +type AddressEIP55 Address + +// String returns the hex representation of the address in the manner of EIP55. +func (addr AddressEIP55) String() string { + return Address(addr).Hex() +} + +// MarshalJSON marshals the address in the manner of EIP55. +func (addr AddressEIP55) MarshalJSON() ([]byte, error) { + return json.Marshal(addr.String()) +} diff --git a/common/types_test.go b/common/types_test.go index 88c642522d..ad892671b5 100644 --- a/common/types_test.go +++ b/common/types_test.go @@ -559,3 +559,27 @@ func TestHash_Format(t *testing.T) { }) } } + +func TestAddressEIP55(t *testing.T) { + addr := HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed") + addrEIP55 := AddressEIP55(addr) + + if addr.Hex() != addrEIP55.String() { + t.Fatal("AddressEIP55 should match original address hex") + } + + blob, err := addrEIP55.MarshalJSON() + if err != nil { + t.Fatal("Failed to marshal AddressEIP55", err) + } + if strings.Trim(string(blob), "\"") != addr.Hex() { + t.Fatal("Address with checksum is expected") + } + var dec Address + if err := json.Unmarshal(blob, &dec); err != nil { + t.Fatal("Failed to unmarshal AddressEIP55", err) + } + if addr != dec { + t.Fatal("Unexpected address after unmarshal") + } +} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 5ebb6924ef..9a821be0c1 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -354,19 +354,20 @@ func (s *PersonalAccountAPI) DeriveAccount(url string, path string, pin *bool) ( } // NewAccount will create a new account and returns the address for the new account. -func (s *PersonalAccountAPI) NewAccount(password string) (common.Address, error) { +func (s *PersonalAccountAPI) NewAccount(password string) (common.AddressEIP55, error) { ks, err := fetchKeystore(s.am) if err != nil { - return common.Address{}, err + return common.AddressEIP55{}, err } acc, err := ks.NewAccount(password) if err == nil { - log.Info("Your new key was generated", "address", acc.Address) + addrEIP55 := common.AddressEIP55(acc.Address) + log.Info("Your new key was generated", "address", addrEIP55.String()) log.Warn("Please backup your key file!", "path", acc.URL.Path) log.Warn("Please remember your password!") - return acc.Address, nil + return addrEIP55, nil } - return common.Address{}, err + return common.AddressEIP55{}, err } // fetchKeystore retrieves the encrypted keystore from the account manager. From 84c3799e21d61d677965715fe09f8209660b4009 Mon Sep 17 00:00:00 2001 From: Stephen Guo Date: Wed, 17 May 2023 18:27:51 +0800 Subject: [PATCH 122/988] rpc: more accurate checking of handler method signatures (#27287) This changes the RPC server to ignore methods using *context.Context as parameter and *error as return value type. Methods with such types would crash the server when called. --- rpc/service.go | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/rpc/service.go b/rpc/service.go index cfdfba023a..8485cab3aa 100644 --- a/rpc/service.go +++ b/rpc/service.go @@ -214,19 +214,8 @@ func (c *callback) call(ctx context.Context, method string, args []reflect.Value return results[0].Interface(), nil } -// Is t context.Context or *context.Context? -func isContextType(t reflect.Type) bool { - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - return t == contextType -} - // Does t satisfy the error interface? func isErrorType(t reflect.Type) bool { - for t.Kind() == reflect.Ptr { - t = t.Elem() - } return t.Implements(errorType) } @@ -245,7 +234,7 @@ func isPubSub(methodType reflect.Type) bool { if methodType.NumIn() < 2 || methodType.NumOut() != 2 { return false } - return isContextType(methodType.In(1)) && + return methodType.In(1) == contextType && isSubscriptionType(methodType.Out(0)) && isErrorType(methodType.Out(1)) } From 41fafa47b652797fecebd7c9f07af0841dde1793 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 17 May 2023 14:03:38 +0200 Subject: [PATCH 123/988] go.mod: upgrade gencodec (#27288) --- go.mod | 3 +-- go.sum | 14 ++------------ 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index 7061e69466..a32d65a0ce 100644 --- a/go.mod +++ b/go.mod @@ -19,10 +19,9 @@ require ( github.com/deckarep/golang-set/v2 v2.1.0 github.com/docker/docker v1.6.2 github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 - github.com/edsrzf/mmap-go v1.0.0 github.com/ethereum/c-kzg-4844 v0.2.0 github.com/fatih/color v1.7.0 - github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c + github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/fsnotify/fsnotify v1.6.0 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff diff --git a/go.sum b/go.sum index 6a31436ec9..2d02b123f4 100644 --- a/go.sum +++ b/go.sum @@ -43,8 +43,6 @@ github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8= -github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= @@ -85,8 +83,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 h1:6IrxszG5G+O7zhtkWxq6+unVvnrm1fqV2Pe+T95DUzw= github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= -github.com/crate-crypto/go-kzg-4844 v0.1.0 h1:2PXr2wKBNTmSsoYLCmaNg5Z6uQUf7LiUAsnDbTfq+0M= -github.com/crate-crypto/go-kzg-4844 v0.1.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= github.com/crate-crypto/go-kzg-4844 v0.2.0 h1:UVuHOE+5tIWrim4zf/Xaa43+MIsDCPyW76QhUpiMGj4= github.com/crate-crypto/go-kzg-4844 v0.2.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -120,24 +116,20 @@ github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7/go.mod h1:yRkwfj0CBpOG github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/ethereum/c-kzg-4844 v0.1.0 h1:BR9kUo6zAaFphuoNj39NquE3Sl0sD/oT0+idKZ4mkiI= -github.com/ethereum/c-kzg-4844 v0.1.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8= github.com/ethereum/c-kzg-4844 v0.2.0 h1:+cUvymlnoDDQgMInp25Bo3OmLajmmY8mLJ/tLjqd77Q= github.com/ethereum/c-kzg-4844 v0.2.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq6Q+cGWcGHz0FjGR3QqcInWcW0= -github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= +github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY= +github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -556,8 +548,6 @@ golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= From c08dc59aad35fe3fb0f6644c2816ce95e3c736ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Wed, 17 May 2023 16:39:33 +0200 Subject: [PATCH 124/988] beacon/types: add beacon chain data types (#27292) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * beacon/types: add beacon chain data types * beacon/merkle: added comments * go.mod: cleanups --------- Co-authored-by: Péter Szilágyi --- beacon/merkle/merkle.go | 67 ++++++++++ beacon/params/params.go | 44 +++++++ beacon/types/committee.go | 214 ++++++++++++++++++++++++++++++++ beacon/types/config.go | 176 ++++++++++++++++++++++++++ beacon/types/gen_header_json.go | 66 ++++++++++ beacon/types/header.go | 121 ++++++++++++++++++ beacon/types/update.go | 118 ++++++++++++++++++ common/types.go | 20 +++ go.mod | 3 + go.sum | 7 ++ 10 files changed, 836 insertions(+) create mode 100644 beacon/merkle/merkle.go create mode 100644 beacon/params/params.go create mode 100644 beacon/types/committee.go create mode 100644 beacon/types/config.go create mode 100644 beacon/types/gen_header_json.go create mode 100644 beacon/types/header.go create mode 100644 beacon/types/update.go diff --git a/beacon/merkle/merkle.go b/beacon/merkle/merkle.go new file mode 100644 index 0000000000..30896f9b01 --- /dev/null +++ b/beacon/merkle/merkle.go @@ -0,0 +1,67 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package merkle implements proof verifications in binary merkle trees. +package merkle + +import ( + "crypto/sha256" + "errors" + "reflect" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +// Value represents either a 32 byte leaf value or hash node in a binary merkle tree/partial proof. +type Value [32]byte + +// Values represent a series of merkle tree leaves/nodes. +type Values []Value + +var valueT = reflect.TypeOf(Value{}) + +// UnmarshalJSON parses a merkle value in hex syntax. +func (m *Value) UnmarshalJSON(input []byte) error { + return hexutil.UnmarshalFixedJSON(valueT, input, m[:]) +} + +// VerifyProof verifies a Merkle proof branch for a single value in a +// binary Merkle tree (index is a generalized tree index). +func VerifyProof(root common.Hash, index uint64, branch Values, value Value) error { + hasher := sha256.New() + for _, sibling := range branch { + hasher.Reset() + if index&1 == 0 { + hasher.Write(value[:]) + hasher.Write(sibling[:]) + } else { + hasher.Write(sibling[:]) + hasher.Write(value[:]) + } + hasher.Sum(value[:0]) + if index >>= 1; index == 0 { + return errors.New("branch has extra items") + } + } + if index != 1 { + return errors.New("branch is missing items") + } + if common.Hash(value) != root { + return errors.New("root mismatch") + } + return nil +} diff --git a/beacon/params/params.go b/beacon/params/params.go new file mode 100644 index 0000000000..ee9feb1acb --- /dev/null +++ b/beacon/params/params.go @@ -0,0 +1,44 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package params + +const ( + EpochLength = 32 + SyncPeriodLength = 8192 + + BLSSignatureSize = 96 + BLSPubkeySize = 48 + + SyncCommitteeSize = 512 + SyncCommitteeBitmaskSize = SyncCommitteeSize / 8 + SyncCommitteeSupermajority = (SyncCommitteeSize*2 + 2) / 3 +) + +const ( + StateIndexGenesisTime = 32 + StateIndexGenesisValidators = 33 + StateIndexForkVersion = 141 + StateIndexLatestHeader = 36 + StateIndexBlockRoots = 37 + StateIndexStateRoots = 38 + StateIndexHistoricRoots = 39 + StateIndexFinalBlock = 105 + StateIndexSyncCommittee = 54 + StateIndexNextSyncCommittee = 55 + StateIndexExecPayload = 56 + StateIndexExecHead = 908 +) diff --git a/beacon/types/committee.go b/beacon/types/committee.go new file mode 100644 index 0000000000..9d3b9ff9e9 --- /dev/null +++ b/beacon/types/committee.go @@ -0,0 +1,214 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package types + +import ( + "crypto/sha256" + "encoding/json" + "fmt" + "math/bits" + + "github.com/ethereum/go-ethereum/beacon/params" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + bls "github.com/protolambda/bls12-381-util" +) + +// SerializedSyncCommitteeSize is the size of the sync committee plus the +// aggregate public key. +const SerializedSyncCommitteeSize = (params.SyncCommitteeSize + 1) * params.BLSPubkeySize + +// SerializedSyncCommittee is the serialized version of a sync committee +// plus the aggregate public key. +type SerializedSyncCommittee [SerializedSyncCommitteeSize]byte + +// jsonSyncCommittee is the JSON representation of a sync committee. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate +type jsonSyncCommittee struct { + Pubkeys []hexutil.Bytes `json:"pubkeys"` + Aggregate hexutil.Bytes `json:"aggregate_pubkey"` +} + +// MarshalJSON implements json.Marshaler. +func (s *SerializedSyncCommittee) MarshalJSON() ([]byte, error) { + sc := jsonSyncCommittee{Pubkeys: make([]hexutil.Bytes, params.SyncCommitteeSize)} + for i := range sc.Pubkeys { + sc.Pubkeys[i] = make(hexutil.Bytes, params.BLSPubkeySize) + copy(sc.Pubkeys[i][:], s[i*params.BLSPubkeySize:(i+1)*params.BLSPubkeySize]) + } + sc.Aggregate = make(hexutil.Bytes, params.BLSPubkeySize) + copy(sc.Aggregate[:], s[params.SyncCommitteeSize*params.BLSPubkeySize:]) + return json.Marshal(&sc) +} + +// UnmarshalJSON implements json.Marshaler. +func (s *SerializedSyncCommittee) UnmarshalJSON(input []byte) error { + var sc jsonSyncCommittee + if err := json.Unmarshal(input, &sc); err != nil { + return err + } + if len(sc.Pubkeys) != params.SyncCommitteeSize { + return fmt.Errorf("invalid number of pubkeys %d", len(sc.Pubkeys)) + } + for i, key := range sc.Pubkeys { + if len(key) != params.BLSPubkeySize { + return fmt.Errorf("pubkey %d has invalid size %d", i, len(key)) + } + copy(s[i*params.BLSPubkeySize:], key[:]) + } + if len(sc.Aggregate) != params.BLSPubkeySize { + return fmt.Errorf("invalid aggregate pubkey size %d", len(sc.Aggregate)) + } + copy(s[params.SyncCommitteeSize*params.BLSPubkeySize:], sc.Aggregate[:]) + return nil +} + +// Root calculates the root hash of the binary tree representation of a sync +// committee provided in serialized format. +// +// TODO(zsfelfoldi): Get rid of this when SSZ encoding lands. +func (s *SerializedSyncCommittee) Root() common.Hash { + var ( + hasher = sha256.New() + padding [64 - params.BLSPubkeySize]byte + data [params.SyncCommitteeSize]common.Hash + l = params.SyncCommitteeSize + ) + for i := range data { + hasher.Reset() + hasher.Write(s[i*params.BLSPubkeySize : (i+1)*params.BLSPubkeySize]) + hasher.Write(padding[:]) + hasher.Sum(data[i][:0]) + } + for l > 1 { + for i := 0; i < l/2; i++ { + hasher.Reset() + hasher.Write(data[i*2][:]) + hasher.Write(data[i*2+1][:]) + hasher.Sum(data[i][:0]) + } + l /= 2 + } + hasher.Reset() + hasher.Write(s[SerializedSyncCommitteeSize-params.BLSPubkeySize : SerializedSyncCommitteeSize]) + hasher.Write(padding[:]) + hasher.Sum(data[1][:0]) + hasher.Reset() + hasher.Write(data[0][:]) + hasher.Write(data[1][:]) + hasher.Sum(data[0][:0]) + return data[0] +} + +// Deserialize splits open the pubkeys into proper BLS key types. +func (s *SerializedSyncCommittee) Deserialize() (*SyncCommittee, error) { + sc := new(SyncCommittee) + for i := 0; i <= params.SyncCommitteeSize; i++ { + key := new(bls.Pubkey) + + var bytes [params.BLSPubkeySize]byte + copy(bytes[:], s[i*params.BLSPubkeySize:(i+1)*params.BLSPubkeySize]) + + if err := key.Deserialize(&bytes); err != nil { + return nil, err + } + if i < params.SyncCommitteeSize { + sc.keys[i] = key + } else { + sc.aggregate = key + } + } + return sc, nil +} + +// SyncCommittee is a set of sync committee signer pubkeys and the aggregate key. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate +type SyncCommittee struct { + keys [params.SyncCommitteeSize]*bls.Pubkey + aggregate *bls.Pubkey +} + +// VerifySignature returns true if the given sync aggregate is a valid signature +// or the given hash. +func (sc *SyncCommittee) VerifySignature(signingRoot common.Hash, signature *SyncAggregate) bool { + var ( + sig bls.Signature + keys = make([]*bls.Pubkey, 0, params.SyncCommitteeSize) + ) + if err := sig.Deserialize(&signature.Signature); err != nil { + return false + } + for i, key := range sc.keys { + if signature.Signers[i/8]&(byte(1)<<(i%8)) != 0 { + keys = append(keys, key) + } + } + return bls.FastAggregateVerify(keys, signingRoot[:], &sig) +} + +// SyncAggregate represents an aggregated BLS signature with Signers referring +// to a subset of the corresponding sync committee. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate +type SyncAggregate struct { + Signers [params.SyncCommitteeBitmaskSize]byte + Signature [params.BLSSignatureSize]byte +} + +type jsonSyncAggregate struct { + Signers hexutil.Bytes `json:"sync_committee_bits"` + Signature hexutil.Bytes `json:"sync_committee_signature"` +} + +// MarshalJSON implements json.Marshaler. +func (s *SyncAggregate) MarshalJSON() ([]byte, error) { + return json.Marshal(&jsonSyncAggregate{ + Signers: s.Signers[:], + Signature: s.Signature[:], + }) +} + +// UnmarshalJSON implements json.Marshaler. +func (s *SyncAggregate) UnmarshalJSON(input []byte) error { + var sc jsonSyncAggregate + if err := json.Unmarshal(input, &sc); err != nil { + return err + } + if len(sc.Signers) != params.SyncCommitteeBitmaskSize { + return fmt.Errorf("invalid signature bitmask size %d", len(sc.Signers)) + } + if len(sc.Signature) != params.BLSSignatureSize { + return fmt.Errorf("invalid signature size %d", len(sc.Signature)) + } + copy(s.Signers[:], sc.Signers) + copy(s.Signature[:], sc.Signature) + return nil +} + +// SignerCount returns the number of signers in the aggregate signature. +func (s *SyncAggregate) SignerCount() int { + var count int + for _, v := range s.Signers { + count += bits.OnesCount8(v) + } + return count +} diff --git a/beacon/types/config.go b/beacon/types/config.go new file mode 100644 index 0000000000..3e5f7a6fba --- /dev/null +++ b/beacon/types/config.go @@ -0,0 +1,176 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package types + +import ( + "crypto/sha256" + "fmt" + "os" + "sort" + "strconv" + "strings" + + "github.com/ethereum/go-ethereum/beacon/merkle" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/go-yaml/yaml" +) + +// syncCommitteeDomain specifies the signatures specific use to avoid clashes +// across signing different data structures. +const syncCommitteeDomain = 7 + +// Fork describes a single beacon chain fork and also stores the calculated +// signature domain used after this fork. +type Fork struct { + // Name of the fork in the chain config (config.yaml) file{ + Name string + + // Epoch when given fork version is activated + Epoch uint64 + + // Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types + Version []byte + + // calculated by computeDomain, based on fork version and genesis validators root + domain merkle.Value +} + +// computeDomain returns the signature domain based on the given fork version +// and genesis validator set root. +func (f *Fork) computeDomain(genesisValidatorsRoot common.Hash) { + var ( + hasher = sha256.New() + forkVersion32 merkle.Value + forkDataRoot merkle.Value + ) + copy(forkVersion32[:], f.Version) + hasher.Write(forkVersion32[:]) + hasher.Write(genesisValidatorsRoot[:]) + hasher.Sum(forkDataRoot[:0]) + + f.domain[0] = syncCommitteeDomain + copy(f.domain[4:], forkDataRoot[:28]) +} + +// Forks is the list of all beacon chain forks in the chain configuration. +type Forks []*Fork + +// domain returns the signature domain for the given epoch (assumes that domains +// have already been calculated). +func (f Forks) domain(epoch uint64) (merkle.Value, error) { + for i := len(f) - 1; i >= 0; i-- { + if epoch >= f[i].Epoch { + return f[i].domain, nil + } + } + return merkle.Value{}, fmt.Errorf("unknown fork for epoch %d", epoch) +} + +// SigningRoot calculates the signing root of the given header. +func (f Forks) SigningRoot(header Header) (common.Hash, error) { + domain, err := f.domain(header.Epoch()) + if err != nil { + return common.Hash{}, err + } + var ( + signingRoot common.Hash + headerHash = header.Hash() + hasher = sha256.New() + ) + hasher.Write(headerHash[:]) + hasher.Write(domain[:]) + hasher.Sum(signingRoot[:0]) + + return signingRoot, nil +} + +func (f Forks) Len() int { return len(f) } +func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] } +func (f Forks) Less(i, j int) bool { return f[i].Epoch < f[j].Epoch } + +// ChainConfig contains the beacon chain configuration. +type ChainConfig struct { + GenesisTime uint64 // Unix timestamp of slot 0 + GenesisValidatorsRoot common.Hash // Root hash of the genesis validator set, used for signature domain calculation + Forks Forks +} + +// AddFork adds a new item to the list of forks. +func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig { + fork := &Fork{ + Name: name, + Epoch: epoch, + Version: version, + } + fork.computeDomain(c.GenesisValidatorsRoot) + + c.Forks = append(c.Forks, fork) + sort.Sort(c.Forks) + + return c +} + +// LoadForks parses the beacon chain configuration file (config.yaml) and extracts +// the list of forks. +func (c *ChainConfig) LoadForks(path string) error { + file, err := os.ReadFile(path) + if err != nil { + return fmt.Errorf("failed to read beacon chain config file: %v", err) + } + config := make(map[string]string) + if err := yaml.Unmarshal(file, &config); err != nil { + return fmt.Errorf("failed to parse beacon chain config file: %v", err) + } + var ( + versions = make(map[string][]byte) + epochs = make(map[string]uint64) + ) + epochs["GENESIS"] = 0 + + for key, value := range config { + if strings.HasSuffix(key, "_FORK_VERSION") { + name := key[:len(key)-len("_FORK_VERSION")] + if v, err := hexutil.Decode(value); err == nil { + versions[name] = v + } else { + return fmt.Errorf("failed to decode hex fork id %q in beacon chain config file: %v", value, err) + } + } + if strings.HasSuffix(key, "_FORK_EPOCH") { + name := key[:len(key)-len("_FORK_EPOCH")] + if v, err := strconv.ParseUint(value, 10, 64); err == nil { + epochs[name] = v + } else { + return fmt.Errorf("failed to parse epoch number %q in beacon chain config file: %v", value, err) + } + } + } + for name, epoch := range epochs { + if version, ok := versions[name]; ok { + delete(versions, name) + c.AddFork(name, epoch, version) + } else { + return fmt.Errorf("fork id missing for %q in beacon chain config file", name) + } + } + for name := range versions { + return fmt.Errorf("epoch number missing for fork %q in beacon chain config file", name) + } + sort.Sort(c.Forks) + return nil +} diff --git a/beacon/types/gen_header_json.go b/beacon/types/gen_header_json.go new file mode 100644 index 0000000000..9b3ffea06f --- /dev/null +++ b/beacon/types/gen_header_json.go @@ -0,0 +1,66 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package types + +import ( + "encoding/json" + "errors" + + "github.com/ethereum/go-ethereum/common" +) + +var _ = (*headerMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (h Header) MarshalJSON() ([]byte, error) { + type Header struct { + Slot common.Decimal `gencodec:"required" json:"slot"` + ProposerIndex common.Decimal `gencodec:"required" json:"proposer_index"` + ParentRoot common.Hash `gencodec:"required" json:"parent_root"` + StateRoot common.Hash `gencodec:"required" json:"state_root"` + BodyRoot common.Hash `gencodec:"required" json:"body_root"` + } + var enc Header + enc.Slot = common.Decimal(h.Slot) + enc.ProposerIndex = common.Decimal(h.ProposerIndex) + enc.ParentRoot = h.ParentRoot + enc.StateRoot = h.StateRoot + enc.BodyRoot = h.BodyRoot + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (h *Header) UnmarshalJSON(input []byte) error { + type Header struct { + Slot *common.Decimal `gencodec:"required" json:"slot"` + ProposerIndex *common.Decimal `gencodec:"required" json:"proposer_index"` + ParentRoot *common.Hash `gencodec:"required" json:"parent_root"` + StateRoot *common.Hash `gencodec:"required" json:"state_root"` + BodyRoot *common.Hash `gencodec:"required" json:"body_root"` + } + var dec Header + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Slot == nil { + return errors.New("missing required field 'slot' for Header") + } + h.Slot = uint64(*dec.Slot) + if dec.ProposerIndex == nil { + return errors.New("missing required field 'proposer_index' for Header") + } + h.ProposerIndex = uint64(*dec.ProposerIndex) + if dec.ParentRoot == nil { + return errors.New("missing required field 'parent_root' for Header") + } + h.ParentRoot = *dec.ParentRoot + if dec.StateRoot == nil { + return errors.New("missing required field 'state_root' for Header") + } + h.StateRoot = *dec.StateRoot + if dec.BodyRoot == nil { + return errors.New("missing required field 'body_root' for Header") + } + h.BodyRoot = *dec.BodyRoot + return nil +} diff --git a/beacon/types/header.go b/beacon/types/header.go new file mode 100644 index 0000000000..2ddc4575f1 --- /dev/null +++ b/beacon/types/header.go @@ -0,0 +1,121 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package types implements a few types of the beacon chain for light client usage. +package types + +import ( + "crypto/sha256" + "encoding/binary" + + "github.com/ethereum/go-ethereum/beacon/merkle" + "github.com/ethereum/go-ethereum/beacon/params" + "github.com/ethereum/go-ethereum/common" +) + +//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go + +const ( + headerIndexSlot = 8 + headerIndexProposerIndex = 9 + headerIndexParentRoot = 10 + headerIndexStateRoot = 11 + headerIndexBodyRoot = 12 +) + +// Header defines a beacon header. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader +type Header struct { + // Monotonically increasing slot number for the beacon block (may be gapped) + Slot uint64 `gencodec:"required" json:"slot"` + + // Index into the validator table who created the beacon block + ProposerIndex uint64 `gencodec:"required" json:"proposer_index"` + + // SSZ hash of the parent beacon header + ParentRoot common.Hash `gencodec:"required" json:"parent_root"` + + // SSZ hash of the beacon state (https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#beacon-state) + StateRoot common.Hash `gencodec:"required" json:"state_root"` + + // SSZ hash of the beacon block body (https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#beaconblockbody) + BodyRoot common.Hash `gencodec:"required" json:"body_root"` +} + +// headerMarshaling is a field type overrides for gencodec. +type headerMarshaling struct { + Slot common.Decimal + ProposerIndex common.Decimal +} + +// Hash calculates the block root of the header. +// +// TODO(zsfelfoldi): Remove this when an SSZ encoder lands. +func (h *Header) Hash() common.Hash { + var values [16]merkle.Value // values corresponding to indices 8 to 15 of the beacon header tree + binary.LittleEndian.PutUint64(values[headerIndexSlot][:8], h.Slot) + binary.LittleEndian.PutUint64(values[headerIndexProposerIndex][:8], h.ProposerIndex) + values[headerIndexParentRoot] = merkle.Value(h.ParentRoot) + values[headerIndexStateRoot] = merkle.Value(h.StateRoot) + values[headerIndexBodyRoot] = merkle.Value(h.BodyRoot) + hasher := sha256.New() + for i := 7; i > 0; i-- { + hasher.Reset() + hasher.Write(values[i*2][:]) + hasher.Write(values[i*2+1][:]) + hasher.Sum(values[i][:0]) + } + return common.Hash(values[1]) +} + +// Epoch returns the epoch the header belongs to. +func (h *Header) Epoch() uint64 { + return h.Slot / params.EpochLength +} + +// SyncPeriod returns the sync period the header belongs to. +func (h *Header) SyncPeriod() uint64 { + return SyncPeriod(h.Slot) +} + +// SyncPeriodStart returns the first slot of the given period. +func SyncPeriodStart(period uint64) uint64 { + return period * params.SyncPeriodLength +} + +// SyncPeriod returns the sync period that the given slot belongs to. +func SyncPeriod(slot uint64) uint64 { + return slot / params.SyncPeriodLength +} + +// SignedHeader represents a beacon header signed by a sync committee. +// +// This structure is created from either an optimistic update or an instant update: +// - https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate +// - https://github.com/zsfelfoldi/beacon-APIs/blob/instant_update/apis/beacon/light_client/instant_update.yaml +type SignedHeader struct { + // Beacon header being signed + Header Header + + // Sync committee BLS signature aggregate + Signature SyncAggregate + + // Slot in which the signature has been created (newer than Header.Slot, + // determines the signing sync committee) + SignatureSlot uint64 +} diff --git a/beacon/types/update.go b/beacon/types/update.go new file mode 100644 index 0000000000..06c1b61792 --- /dev/null +++ b/beacon/types/update.go @@ -0,0 +1,118 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package types + +import ( + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/beacon/merkle" + "github.com/ethereum/go-ethereum/beacon/params" + "github.com/ethereum/go-ethereum/common" +) + +// LightClientUpdate is a proof of the next sync committee root based on a header +// signed by the sync committee of the given period. Optionally, the update can +// prove quasi-finality by the signed header referring to a previous, finalized +// header from the same period, and the finalized header referring to the next +// sync committee root. +// +// See data structure definition here: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate +type LightClientUpdate struct { + AttestedHeader SignedHeader // Arbitrary header out of the period signed by the sync committee + NextSyncCommitteeRoot common.Hash // Sync committee of the next period advertised in the current one + NextSyncCommitteeBranch merkle.Values // Proof for the next period's sync committee + + FinalizedHeader *Header `rlp:"nil"` // Optional header to announce a point of finality + FinalityBranch merkle.Values // Proof for the announced finality + + score *UpdateScore // Weight of the update to compare between competing ones +} + +// Validate verifies the validity of the update. +func (update *LightClientUpdate) Validate() error { + period := update.AttestedHeader.Header.SyncPeriod() + if SyncPeriod(update.AttestedHeader.SignatureSlot) != period { + return errors.New("signature slot and signed header are from different periods") + } + if update.FinalizedHeader != nil { + if update.FinalizedHeader.SyncPeriod() != period { + return errors.New("finalized header is from different period") + } + if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexFinalBlock, update.FinalityBranch, merkle.Value(update.FinalizedHeader.Hash())); err != nil { + return fmt.Errorf("invalid finalized header proof: %w", err) + } + } + if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexNextSyncCommittee, update.NextSyncCommitteeBranch, merkle.Value(update.NextSyncCommitteeRoot)); err != nil { + return fmt.Errorf("invalid next sync committee proof: %w", err) + } + return nil +} + +// Score returns the UpdateScore describing the proof strength of the update +// Note: thread safety can be ensured by always calling Score on a newly received +// or decoded update before making it potentially available for other threads +func (update *LightClientUpdate) Score() UpdateScore { + if update.score == nil { + update.score = &UpdateScore{ + SignerCount: uint32(update.AttestedHeader.Signature.SignerCount()), + SubPeriodIndex: uint32(update.AttestedHeader.Header.Slot & 0x1fff), + FinalizedHeader: update.FinalizedHeader != nil, + } + } + return *update.score +} + +// UpdateScore allows the comparison between updates at the same period in order +// to find the best update chain that provides the strongest proof of being canonical. +// +// UpdateScores have a tightly packed binary encoding format for efficient p2p +// protocol transmission. Each UpdateScore is encoded in 3 bytes. +// When interpreted as a 24 bit little indian unsigned integer: +// - the lowest 10 bits contain the number of signers in the header signature aggregate +// - the next 13 bits contain the "sub-period index" which is he signed header's +// slot modulo params.SyncPeriodLength (which is correlated with the risk of the chain being +// re-orged before the previous period boundary in case of non-finalized updates) +// - the highest bit is set when the update is finalized (meaning that the finality +// header referenced by the signed header is in the same period as the signed +// header, making reorgs before the period boundary impossible +type UpdateScore struct { + SignerCount uint32 // number of signers in the header signature aggregate + SubPeriodIndex uint32 // signed header's slot modulo params.SyncPeriodLength + FinalizedHeader bool // update is considered finalized if has finalized header from the same period and 2/3 signatures +} + +// finalized returns true if the update has a header signed by at least 2/3 of +// the committee, referring to a finalized header that refers to the next sync +// committee. This condition is a close approximation of the actual finality +// condition that can only be verified by full beacon nodes. +func (u *UpdateScore) finalized() bool { + return u.FinalizedHeader && u.SignerCount >= params.SyncCommitteeSupermajority +} + +// BetterThan returns true if update u is considered better than w. +func (u UpdateScore) BetterThan(w UpdateScore) bool { + var ( + uFinalized = u.finalized() + wFinalized = w.finalized() + ) + if uFinalized != wFinalized { + return uFinalized + } + return u.SignerCount > w.SignerCount +} diff --git a/common/types.go b/common/types.go index 3712df2fee..bdfd964237 100644 --- a/common/types.go +++ b/common/types.go @@ -26,6 +26,7 @@ import ( "math/big" "math/rand" "reflect" + "strconv" "strings" "github.com/ethereum/go-ethereum/common/hexutil" @@ -442,3 +443,22 @@ func (addr AddressEIP55) String() string { func (addr AddressEIP55) MarshalJSON() ([]byte, error) { return json.Marshal(addr.String()) } + +type Decimal uint64 + +func isString(input []byte) bool { + return len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' +} + +// UnmarshalJSON parses a hash in hex syntax. +func (d *Decimal) UnmarshalJSON(input []byte) error { + if !isString(input) { + return &json.UnmarshalTypeError{Value: "non-string", Type: reflect.TypeOf(uint64(0))} + } + if i, err := strconv.ParseInt(string(input[1:len(input)-1]), 10, 64); err == nil { + *d = Decimal(i) + return nil + } else { + return err + } +} diff --git a/go.mod b/go.mod index a32d65a0ce..aec45bc1ef 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 github.com/go-stack/stack v1.8.1 + github.com/go-yaml/yaml v2.1.0+incompatible github.com/gofrs/flock v0.8.1 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/golang/protobuf v1.5.2 @@ -51,6 +52,7 @@ require ( github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 + github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.2.0 @@ -98,6 +100,7 @@ require ( github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect + github.com/kilic/bls12-381 v0.1.0 // indirect github.com/klauspost/compress v1.15.15 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect diff --git a/go.sum b/go.sum index 2d02b123f4..3c35d378bc 100644 --- a/go.sum +++ b/go.sum @@ -164,6 +164,8 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyL github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= @@ -270,6 +272,8 @@ github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYb github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= +github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= +github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -375,6 +379,8 @@ github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8u github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 h1:cZC+usqsYgHtlBaGulVnZ1hfKAi8iWtujBnRLQE698c= +github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7/go.mod h1:IToEjHuttnUzwZI5KBSM/LOOW3qLbbrHOEfp3SbECGY= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= @@ -532,6 +538,7 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From 6a6318b1d23ec20d1a8735cf1852c11726a4ac9a Mon Sep 17 00:00:00 2001 From: Shude Li Date: Thu, 18 May 2023 05:35:30 +0800 Subject: [PATCH 125/988] go.mod: use`gopkg.in/yaml.v3` instead of `github.com/go-yaml/yaml` (#27295) --- beacon/types/config.go | 4 ++-- go.mod | 3 +-- go.sum | 2 -- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/beacon/types/config.go b/beacon/types/config.go index 3e5f7a6fba..8cb8808b6f 100644 --- a/beacon/types/config.go +++ b/beacon/types/config.go @@ -27,7 +27,7 @@ import ( "github.com/ethereum/go-ethereum/beacon/merkle" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/go-yaml/yaml" + "gopkg.in/yaml.v3" ) // syncCommitteeDomain specifies the signatures specific use to avoid clashes @@ -121,7 +121,7 @@ func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainC c.Forks = append(c.Forks, fork) sort.Sort(c.Forks) - + return c } diff --git a/go.mod b/go.mod index aec45bc1ef..ef4ea6ee74 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,6 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 github.com/go-stack/stack v1.8.1 - github.com/go-yaml/yaml v2.1.0+incompatible github.com/gofrs/flock v0.8.1 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/golang/protobuf v1.5.2 @@ -70,6 +69,7 @@ require ( golang.org/x/tools v0.7.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce + gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -127,6 +127,5 @@ require ( golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index 3c35d378bc..e021530963 100644 --- a/go.sum +++ b/go.sum @@ -164,8 +164,6 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyL github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= -github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o= -github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= From 85a4b82b3373fc5f3fa8b7c68061c55b0db0e9b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 19 May 2023 11:27:19 +0300 Subject: [PATCH 126/988] all: tie timestamp based forks to the passage of London (#27279) --- cmd/evm/internal/t8ntool/transaction.go | 4 ++-- cmd/evm/internal/t8ntool/transition.go | 2 +- consensus/beacon/consensus.go | 6 +++--- consensus/clique/clique.go | 4 ++-- consensus/ethash/consensus.go | 4 ++-- core/genesis.go | 2 +- core/state_processor.go | 2 +- core/state_processor_test.go | 4 ++-- core/txpool/txpool.go | 2 +- core/types/transaction_signing.go | 2 +- eth/catalyst/api.go | 7 ++++--- light/txpool.go | 2 +- params/config.go | 18 +++++++++--------- params/config_test.go | 1 + 14 files changed, 31 insertions(+), 29 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index b1f65815b7..03a2e2eb99 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -140,7 +140,7 @@ func Transaction(ctx *cli.Context) error { } // Check intrinsic gas if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, - chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(0)); err != nil { + chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int), 0)); err != nil { r.Error = err results = append(results, r) continue @@ -172,7 +172,7 @@ func Transaction(ctx *cli.Context) error { r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits") } // Check whether the init code size has been exceeded. - if chainConfig.IsShanghai(0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { + if chainConfig.IsShanghai(new(big.Int), 0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { r.Error = errors.New("max initcode size exceeded") } results = append(results, r) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index a5d061292f..ce7197d103 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -261,7 +261,7 @@ func Transition(ctx *cli.Context) error { return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) } } - if chainConfig.IsShanghai(prestate.Env.Number) && prestate.Env.Withdrawals == nil { + if chainConfig.IsShanghai(big.NewInt(int64(prestate.Env.Number)), prestate.Env.Timestamp) && prestate.Env.Withdrawals == nil { return NewError(ErrorConfig, errors.New("Shanghai config but missing 'withdrawals' in env section")) } isMerged := chainConfig.TerminalTotalDifficulty != nil && chainConfig.TerminalTotalDifficulty.BitLen() == 0 diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 284477b277..75f1b65efa 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -261,7 +261,7 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa return err } // Verify existence / non-existence of withdrawalsHash. - shanghai := chain.Config().IsShanghai(header.Time) + shanghai := chain.Config().IsShanghai(header.Number, header.Time) if shanghai && header.WithdrawalsHash == nil { return errors.New("missing withdrawalsHash") } @@ -269,7 +269,7 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash) } // Verify the existence / non-existence of excessDataGas - cancun := chain.Config().IsCancun(header.Time) + cancun := chain.Config().IsCancun(header.Number, header.Time) if cancun && header.ExcessDataGas == nil { return errors.New("missing excessDataGas") } @@ -356,7 +356,7 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea if !beacon.IsPoSHeader(header) { return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts, nil) } - shanghai := chain.Config().IsShanghai(header.Time) + shanghai := chain.Config().IsShanghai(header.Number, header.Time) if shanghai { // All blocks after Shanghai must include a withdrawals root. if withdrawals == nil { diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 535cbeb262..01d27482da 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -298,10 +298,10 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H if header.GasLimit > params.MaxGasLimit { return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit) } - if chain.Config().IsShanghai(header.Time) { + if chain.Config().IsShanghai(header.Number, header.Time) { return fmt.Errorf("clique does not support shanghai fork") } - if chain.Config().IsCancun(header.Time) { + if chain.Config().IsCancun(header.Number, header.Time) { return fmt.Errorf("clique does not support cancun fork") } // All basic checks passed, verify cascading fields diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index b912fb513a..b36637c5b9 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -262,10 +262,10 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { return consensus.ErrInvalidNumber } - if chain.Config().IsShanghai(header.Time) { + if chain.Config().IsShanghai(header.Number, header.Time) { return fmt.Errorf("ethash does not support shanghai fork") } - if chain.Config().IsCancun(header.Time) { + if chain.Config().IsCancun(header.Number, header.Time) { return fmt.Errorf("ethash does not support cancun fork") } // Add some fake checks for tests diff --git a/core/genesis.go b/core/genesis.go index 26f31c0863..68eeec2161 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -463,7 +463,7 @@ func (g *Genesis) ToBlock() *types.Block { } } var withdrawals []*types.Withdrawal - if g.Config != nil && g.Config.IsShanghai(g.Timestamp) { + if g.Config != nil && g.Config.IsShanghai(big.NewInt(int64(g.Number)), g.Timestamp) { head.WithdrawalsHash = &types.EmptyWithdrawalsHash withdrawals = make([]*types.Withdrawal, 0) } diff --git a/core/state_processor.go b/core/state_processor.go index 25266f13b4..03de673e19 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -91,7 +91,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } // Fail if Shanghai not enabled and len(withdrawals) is non-zero. withdrawals := block.Withdrawals() - if len(withdrawals) > 0 && !p.config.IsShanghai(block.Time()) { + if len(withdrawals) > 0 && !p.config.IsShanghai(block.Number(), block.Time()) { return nil, nil, 0, fmt.Errorf("withdrawals before shanghai") } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 59391fa861..5dbeed97a0 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -403,7 +403,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr if config.IsLondon(header.Number) { header.BaseFee = misc.CalcBaseFee(config, parent.Header()) } - if config.IsShanghai(header.Time) { + if config.IsShanghai(header.Number, header.Time) { header.WithdrawalsHash = &types.EmptyWithdrawalsHash } var receipts []*types.Receipt @@ -423,7 +423,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr } header.Root = common.BytesToHash(hasher.Sum(nil)) // Assemble and return the final block for sealing - if config.IsShanghai(header.Time) { + if config.IsShanghai(header.Number, header.Time) { return types.NewBlockWithWithdrawals(header, txs, nil, receipts, []*types.Withdrawal{}, trie.NewStackTrie(nil)) } return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 056b1ebe87..cbb8cc287a 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -1397,7 +1397,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { pool.istanbul.Store(pool.chainconfig.IsIstanbul(next)) pool.eip2718.Store(pool.chainconfig.IsBerlin(next)) pool.eip1559.Store(pool.chainconfig.IsLondon(next)) - pool.shanghai.Store(pool.chainconfig.IsShanghai(uint64(time.Now().Unix()))) + pool.shanghai.Store(pool.chainconfig.IsShanghai(next, uint64(time.Now().Unix()))) } // promoteExecutables moves transactions that have become processable from the diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index d7c162898c..59dd2e76eb 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -40,7 +40,7 @@ type sigCache struct { func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) Signer { var signer Signer switch { - case config.IsCancun(blockTime): + case config.IsCancun(blockNumber, blockTime): signer = NewCancunSigner(config.ChainID) case config.IsLondon(blockNumber): signer = NewLondonSigner(config.ChainID) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 1fe9842472..58681df2ea 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -20,6 +20,7 @@ package catalyst import ( "errors" "fmt" + "math/big" "sync" "time" @@ -167,7 +168,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, pa if payloadAttributes.Withdrawals != nil { return engine.STATUS_INVALID, engine.InvalidParams.With(fmt.Errorf("withdrawals not supported in V1")) } - if api.eth.BlockChain().Config().IsShanghai(payloadAttributes.Timestamp) { + if api.eth.BlockChain().Config().IsShanghai(api.eth.BlockChain().Config().LondonBlock, payloadAttributes.Timestamp) { return engine.STATUS_INVALID, engine.InvalidParams.With(fmt.Errorf("forkChoiceUpdateV1 called post-shanghai")) } } @@ -185,7 +186,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, pa } func (api *ConsensusAPI) verifyPayloadAttributes(attr *engine.PayloadAttributes) error { - if !api.eth.BlockChain().Config().IsShanghai(attr.Timestamp) { + if !api.eth.BlockChain().Config().IsShanghai(api.eth.BlockChain().Config().LondonBlock, attr.Timestamp) { // Reject payload attributes with withdrawals before shanghai if attr.Withdrawals != nil { return errors.New("withdrawals before shanghai") @@ -423,7 +424,7 @@ func (api *ConsensusAPI) NewPayloadV1(params engine.ExecutableData) (engine.Payl // NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.PayloadStatusV1, error) { - if api.eth.BlockChain().Config().IsShanghai(params.Timestamp) { + if api.eth.BlockChain().Config().IsShanghai(new(big.Int).SetUint64(params.Number), params.Timestamp) { if params.Withdrawals == nil { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(fmt.Errorf("nil withdrawals post-shanghai")) } diff --git a/light/txpool.go b/light/txpool.go index e59dc3e774..8d2a189c01 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -318,7 +318,7 @@ func (pool *TxPool) setNewHead(head *types.Header) { next := new(big.Int).Add(head.Number, big.NewInt(1)) pool.istanbul = pool.config.IsIstanbul(next) pool.eip2718 = pool.config.IsBerlin(next) - pool.shanghai = pool.config.IsShanghai(uint64(time.Now().Unix())) + pool.shanghai = pool.config.IsShanghai(next, uint64(time.Now().Unix())) } // Stop stops the light transaction pool diff --git a/params/config.go b/params/config.go index c1614bdbad..08e5ea0be0 100644 --- a/params/config.go +++ b/params/config.go @@ -492,18 +492,18 @@ func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *bi } // IsShanghai returns whether time is either equal to the Shanghai fork time or greater. -func (c *ChainConfig) IsShanghai(time uint64) bool { - return isTimestampForked(c.ShanghaiTime, time) +func (c *ChainConfig) IsShanghai(num *big.Int, time uint64) bool { + return c.IsLondon(num) && isTimestampForked(c.ShanghaiTime, time) } // IsCancun returns whether num is either equal to the Cancun fork time or greater. -func (c *ChainConfig) IsCancun(time uint64) bool { - return isTimestampForked(c.CancunTime, time) +func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool { + return c.IsLondon(num) && isTimestampForked(c.CancunTime, time) } // IsPrague returns whether num is either equal to the Prague fork time or greater. -func (c *ChainConfig) IsPrague(time uint64) bool { - return isTimestampForked(c.PragueTime, time) +func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool { + return c.IsLondon(num) && isTimestampForked(c.PragueTime, time) } // CheckCompatible checks whether scheduled fork transitions have been imported @@ -829,8 +829,8 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules IsBerlin: c.IsBerlin(num), IsLondon: c.IsLondon(num), IsMerge: isMerge, - IsShanghai: c.IsShanghai(timestamp), - IsCancun: c.IsCancun(timestamp), - IsPrague: c.IsPrague(timestamp), + IsShanghai: c.IsShanghai(num, timestamp), + IsCancun: c.IsCancun(num, timestamp), + IsPrague: c.IsPrague(num, timestamp), } } diff --git a/params/config_test.go b/params/config_test.go index 5634569e29..bf8ce2fc5e 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -121,6 +121,7 @@ func TestCheckCompatible(t *testing.T) { func TestConfigRules(t *testing.T) { c := &ChainConfig{ + LondonBlock: new(big.Int), ShanghaiTime: newUint64(500), } var stamp uint64 From 99394adcb8e5d2708e773b838dc92b4a0896ed2d Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 19 May 2023 08:36:21 -0400 Subject: [PATCH 127/988] ethdb/pebble: prevent shutdown-panic (#27238) One difference between pebble and leveldb is that the latter returns error when performing Get on a closed database, the former does a panic. This may be triggered during shutdown (see #27237) This PR changes the pebble driver so we check that the db is not closed already, for several operations. It also adds tests to the db test-suite, so the previously implicit assumption of "not panic:ing at ops on closed database" is covered by tests. --- ethdb/dbtest/testsuite.go | 26 ++++++++++++++++++++ ethdb/memorydb/memorydb.go | 3 +++ ethdb/pebble/pebble.go | 49 ++++++++++++++++++++++++++++++-------- 3 files changed, 68 insertions(+), 10 deletions(-) diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index e455215cb0..d82dbd6992 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -376,6 +376,32 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { } } }) + + t.Run("OperatonsAfterClose", func(t *testing.T) { + db := New() + db.Put([]byte("key"), []byte("value")) + db.Close() + if _, err := db.Get([]byte("key")); err == nil { + t.Fatalf("expected error on Get after Close") + } + if _, err := db.Has([]byte("key")); err == nil { + t.Fatalf("expected error on Get after Close") + } + if err := db.Put([]byte("key2"), []byte("value2")); err == nil { + t.Fatalf("expected error on Put after Close") + } + if err := db.Delete([]byte("key")); err == nil { + t.Fatalf("expected error on Delete after Close") + } + + b := db.NewBatch() + if err := b.Put([]byte("batchkey"), []byte("batchval")); err != nil { + t.Fatalf("expected no error on batch.Put after Close, got %v", err) + } + if err := b.Write(); err == nil { + t.Fatalf("expected error on batch.Write after Close") + } + }) } // BenchDatabaseSuite runs a suite of benchmarks against a KeyValueStore database diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index 6ca7ce7d91..f9f74322b5 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -244,6 +244,9 @@ func (b *batch) Write() error { b.db.lock.Lock() defer b.db.lock.Unlock() + if b.db.db == nil { + return errMemorydbClosed + } for _, keyvalue := range b.writes { if keyvalue.delete { delete(b.db.db, string(keyvalue.key)) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 5be4c1af73..e538084777 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -70,8 +70,9 @@ type Database struct { seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt manualMemAllocGauge metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated - quitLock sync.Mutex // Mutex protecting the quit channel access + quitLock sync.RWMutex // Mutex protecting the quit channel and the closed flag quitChan chan chan error // Quit channel to stop the metrics collection before closing the database + closed bool // keep track of whether we're Closed log log.Logger // Contextual logger tracking the database path @@ -221,23 +222,29 @@ func New(file string, cache int, handles int, namespace string, readonly bool) ( func (d *Database) Close() error { d.quitLock.Lock() defer d.quitLock.Unlock() - // Allow double closing, simplifies things - if d.quitChan == nil { + if d.closed { return nil } - errc := make(chan error) - d.quitChan <- errc - if err := <-errc; err != nil { - d.log.Error("Metrics collection failed", "err", err) + d.closed = true + if d.quitChan != nil { + errc := make(chan error) + d.quitChan <- errc + if err := <-errc; err != nil { + d.log.Error("Metrics collection failed", "err", err) + } + d.quitChan = nil } - d.quitChan = nil - return d.db.Close() } // Has retrieves if a key is present in the key-value store. func (d *Database) Has(key []byte) (bool, error) { + d.quitLock.RLock() + defer d.quitLock.RUnlock() + if d.closed { + return false, pebble.ErrClosed + } _, closer, err := d.db.Get(key) if err == pebble.ErrNotFound { return false, nil @@ -250,6 +257,11 @@ func (d *Database) Has(key []byte) (bool, error) { // Get retrieves the given key if it's present in the key-value store. func (d *Database) Get(key []byte) ([]byte, error) { + d.quitLock.RLock() + defer d.quitLock.RUnlock() + if d.closed { + return nil, pebble.ErrClosed + } dat, closer, err := d.db.Get(key) if err != nil { return nil, err @@ -262,11 +274,21 @@ func (d *Database) Get(key []byte) ([]byte, error) { // Put inserts the given value into the key-value store. func (d *Database) Put(key []byte, value []byte) error { + d.quitLock.RLock() + defer d.quitLock.RUnlock() + if d.closed { + return pebble.ErrClosed + } return d.db.Set(key, value, pebble.NoSync) } // Delete removes the key from the key-value store. func (d *Database) Delete(key []byte) error { + d.quitLock.RLock() + defer d.quitLock.RUnlock() + if d.closed { + return pebble.ErrClosed + } return d.db.Delete(key, nil) } @@ -274,7 +296,8 @@ func (d *Database) Delete(key []byte) error { // database until a final write is called. func (d *Database) NewBatch() ethdb.Batch { return &batch{ - b: d.db.NewBatch(), + b: d.db.NewBatch(), + db: d, } } @@ -481,6 +504,7 @@ func (d *Database) meter(refresh time.Duration) { // when Write is called. A batch cannot be used concurrently. type batch struct { b *pebble.Batch + db *Database size int } @@ -505,6 +529,11 @@ func (b *batch) ValueSize() int { // Write flushes any accumulated data to disk. func (b *batch) Write() error { + b.db.quitLock.RLock() + defer b.db.quitLock.RUnlock() + if b.db.closed { + return pebble.ErrClosed + } return b.b.Commit(pebble.NoSync) } From 3223950a5d5329f8c5b60de2b4408f29a6f06704 Mon Sep 17 00:00:00 2001 From: Shude Li Date: Fri, 19 May 2023 20:38:21 +0800 Subject: [PATCH 128/988] cmd/utils: do not check free disk space in dev mode (#27281) --- cmd/utils/cmd.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index c9e02eb68c..b91c36d67d 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -118,6 +118,9 @@ func StartNode(ctx *cli.Context, stack *node.Node, isConsole bool) { } func monitorFreeDiskSpace(sigc chan os.Signal, path string, freeDiskSpaceCritical uint64) { + if path == "" { + return + } for { freeSpace, err := getFreeDiskSpace(path) if err != nil { From 944e1a0f906e021f9e513730af87144d61b1fcce Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 19 May 2023 16:05:50 +0200 Subject: [PATCH 129/988] beacon/types: auto-generate SyncCommittee marshaling methods (#27296) --- beacon/types/committee.go | 37 ++++--------------- beacon/types/gen_syncaggregate_json.go | 51 ++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 30 deletions(-) create mode 100644 beacon/types/gen_syncaggregate_json.go diff --git a/beacon/types/committee.go b/beacon/types/committee.go index 9d3b9ff9e9..5f89c27554 100644 --- a/beacon/types/committee.go +++ b/beacon/types/committee.go @@ -164,44 +164,21 @@ func (sc *SyncCommittee) VerifySignature(signingRoot common.Hash, signature *Syn return bls.FastAggregateVerify(keys, signingRoot[:], &sig) } +//go:generate go run github.com/fjl/gencodec -type SyncAggregate -field-override syncAggregateMarshaling -out gen_syncaggregate_json.go + // SyncAggregate represents an aggregated BLS signature with Signers referring // to a subset of the corresponding sync committee. // // See data structure definition here: // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate type SyncAggregate struct { - Signers [params.SyncCommitteeBitmaskSize]byte - Signature [params.BLSSignatureSize]byte -} - -type jsonSyncAggregate struct { - Signers hexutil.Bytes `json:"sync_committee_bits"` - Signature hexutil.Bytes `json:"sync_committee_signature"` + Signers [params.SyncCommitteeBitmaskSize]byte `gencodec:"required" json:"sync_committee_bits"` + Signature [params.BLSSignatureSize]byte `gencodec:"required" json:"sync_committee_signature"` } -// MarshalJSON implements json.Marshaler. -func (s *SyncAggregate) MarshalJSON() ([]byte, error) { - return json.Marshal(&jsonSyncAggregate{ - Signers: s.Signers[:], - Signature: s.Signature[:], - }) -} - -// UnmarshalJSON implements json.Marshaler. -func (s *SyncAggregate) UnmarshalJSON(input []byte) error { - var sc jsonSyncAggregate - if err := json.Unmarshal(input, &sc); err != nil { - return err - } - if len(sc.Signers) != params.SyncCommitteeBitmaskSize { - return fmt.Errorf("invalid signature bitmask size %d", len(sc.Signers)) - } - if len(sc.Signature) != params.BLSSignatureSize { - return fmt.Errorf("invalid signature size %d", len(sc.Signature)) - } - copy(s.Signers[:], sc.Signers) - copy(s.Signature[:], sc.Signature) - return nil +type syncAggregateMarshaling struct { + Signers hexutil.Bytes + Signature hexutil.Bytes } // SignerCount returns the number of signers in the aggregate signature. diff --git a/beacon/types/gen_syncaggregate_json.go b/beacon/types/gen_syncaggregate_json.go new file mode 100644 index 0000000000..1547ec5f01 --- /dev/null +++ b/beacon/types/gen_syncaggregate_json.go @@ -0,0 +1,51 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package types + +import ( + "encoding/json" + "errors" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var _ = (*syncAggregateMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (s SyncAggregate) MarshalJSON() ([]byte, error) { + type SyncAggregate struct { + Signers hexutil.Bytes `gencodec:"required" json:"sync_committee_bits"` + Signature hexutil.Bytes `gencodec:"required" json:"sync_committee_signature"` + } + var enc SyncAggregate + enc.Signers = s.Signers[:] + enc.Signature = s.Signature[:] + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (s *SyncAggregate) UnmarshalJSON(input []byte) error { + type SyncAggregate struct { + Signers *hexutil.Bytes `gencodec:"required" json:"sync_committee_bits"` + Signature *hexutil.Bytes `gencodec:"required" json:"sync_committee_signature"` + } + var dec SyncAggregate + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Signers == nil { + return errors.New("missing required field 'sync_committee_bits' for SyncAggregate") + } + if len(*dec.Signers) != len(s.Signers) { + return errors.New("field 'sync_committee_bits' has wrong length, need 64 items") + } + copy(s.Signers[:], *dec.Signers) + if dec.Signature == nil { + return errors.New("missing required field 'sync_committee_signature' for SyncAggregate") + } + if len(*dec.Signature) != len(s.Signature) { + return errors.New("field 'sync_committee_signature' has wrong length, need 96 items") + } + copy(s.Signature[:], *dec.Signature) + return nil +} From 6fe0252571537227001a4f861f31cf5163a68b4f Mon Sep 17 00:00:00 2001 From: Delweng Date: Mon, 22 May 2023 20:13:03 +0800 Subject: [PATCH 130/988] rpc, internal/cmdtest: increase timeout in tests (#27083) This change gives the cmd-tests have a bit more time to finish before getting forcibly torn down. --- cmd/geth/consolecmd_test.go | 2 +- internal/cmdtest/test_cmd.go | 2 +- rpc/client.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index 46bdf3c90d..5046906c0a 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -116,7 +116,7 @@ func TestAttachWelcome(t *testing.T) { waitForEndpoint(t, endpoint, 3*time.Second) testAttachWelcome(t, geth, endpoint, httpAPIs) }) - geth.ExpectExit() + geth.Kill() } func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) { diff --git a/internal/cmdtest/test_cmd.go b/internal/cmdtest/test_cmd.go index fd7a4a8b7f..df5107952e 100644 --- a/internal/cmdtest/test_cmd.go +++ b/internal/cmdtest/test_cmd.go @@ -237,7 +237,7 @@ func (tt *TestCmd) Kill() { } func (tt *TestCmd) withKillTimeout(fn func()) { - timeout := time.AfterFunc(5*time.Second, func() { + timeout := time.AfterFunc(30*time.Second, func() { tt.Log("killing the child process (timeout)") tt.Kill() }) diff --git a/rpc/client.go b/rpc/client.go index fbeb5a1814..fae8536b26 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -43,7 +43,7 @@ var ( const ( // Timeouts defaultDialTimeout = 10 * time.Second // used if context has no deadline - subscribeTimeout = 5 * time.Second // overall timeout eth_subscribe, rpc_modules calls + subscribeTimeout = 10 * time.Second // overall timeout eth_subscribe, rpc_modules calls ) const ( From b46d37ea521ebca31e795b274461490c549b7309 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Mon, 22 May 2023 14:15:05 +0200 Subject: [PATCH 131/988] graphql: upgrade UI to v2 (#27294) Upgrades graphiql to v2.4.4. The interface has become much nicer, and there are extra features like tabs, history, dark mode etc. This change also now uses golang embed to bundle the resources. --------- Co-authored-by: Martin Holst Swende --- graphql/graphiql.go | 120 +++---- graphql/internal/graphiql/build.go | 8 + graphql/internal/graphiql/graphiql.min.css | 337 ++++++++++++++++++ graphql/internal/graphiql/graphiql.min.js | 3 + graphql/internal/graphiql/index.html | 46 +++ .../graphiql/react-dom.production.min.js | 245 +++++++++++++ .../internal/graphiql/react.production.min.js | 31 ++ graphql/service.go | 1 + 8 files changed, 715 insertions(+), 76 deletions(-) create mode 100644 graphql/internal/graphiql/build.go create mode 100644 graphql/internal/graphiql/graphiql.min.css create mode 100644 graphql/internal/graphiql/graphiql.min.js create mode 100644 graphql/internal/graphiql/index.html create mode 100644 graphql/internal/graphiql/react-dom.production.min.js create mode 100644 graphql/internal/graphiql/react.production.min.js diff --git a/graphql/graphiql.go b/graphql/graphiql.go index 576a0cbe95..823df0c641 100644 --- a/graphql/graphiql.go +++ b/graphql/graphiql.go @@ -23,9 +23,12 @@ package graphql import ( - "bytes" - "fmt" + "encoding/json" "net/http" + "path/filepath" + + "github.com/ethereum/go-ethereum/graphql/internal/graphiql" + "github.com/ethereum/go-ethereum/log" ) // GraphiQL is an in-browser IDE for exploring GraphiQL APIs. @@ -34,87 +37,52 @@ import ( // For more information, see https://github.com/graphql/graphiql. type GraphiQL struct{} -func respond(w http.ResponseWriter, body []byte, code int) { - w.Header().Set("Content-Type", "application/json; charset=utf-8") +func respOk(w http.ResponseWriter, body []byte, ctype string) { + w.Header().Set("Content-Type", ctype) w.Header().Set("X-Content-Type-Options", "nosniff") - w.WriteHeader(code) - _, _ = w.Write(body) + w.Write(body) } -func errorJSON(msg string) []byte { - buf := bytes.Buffer{} - fmt.Fprintf(&buf, `{"error": "%s"}`, msg) - return buf.Bytes() +func respErr(w http.ResponseWriter, msg string, code int) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + errMsg, _ := json.Marshal(struct { + Error string + }{Error: msg}) + w.Write(errMsg) } func (h GraphiQL) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { - respond(w, errorJSON("only GET requests are supported"), http.StatusMethodNotAllowed) + respErr(w, "only GET allowed", http.StatusMethodNotAllowed) return } - w.Header().Set("Content-Type", "text/html") - w.Write(graphiql) + switch r.URL.Path { + case "/graphql/ui/graphiql.min.css": + data, err := graphiql.Assets.ReadFile(filepath.Base(r.URL.Path)) + if err != nil { + log.Warn("Error loading graphiql asset", "err", err) + respErr(w, "internal error", http.StatusInternalServerError) + return + } + respOk(w, data, "text/css") + case "/graphql/ui/graphiql.min.js", + "/graphql/ui/react.production.min.js", + "/graphql/ui/react-dom.production.min.js": + data, err := graphiql.Assets.ReadFile(filepath.Base(r.URL.Path)) + if err != nil { + log.Warn("Error loading graphiql asset", "err", err) + respErr(w, "internal error", http.StatusInternalServerError) + return + } + respOk(w, data, "application/javascript; charset=utf-8") + default: + data, err := graphiql.Assets.ReadFile("index.html") + if err != nil { + log.Warn("Error loading graphiql asset", "err", err) + respErr(w, "internal error", http.StatusInternalServerError) + return + } + respOk(w, data, "text/html") + } } - -var graphiql = []byte(` - - - - - - - - - - - -
Loading...
- - - -`) diff --git a/graphql/internal/graphiql/build.go b/graphql/internal/graphiql/build.go new file mode 100644 index 0000000000..0065c1112f --- /dev/null +++ b/graphql/internal/graphiql/build.go @@ -0,0 +1,8 @@ +package graphiql + +import ( + "embed" +) + +//go:embed *.js *.css *.html +var Assets embed.FS diff --git a/graphql/internal/graphiql/graphiql.min.css b/graphql/internal/graphiql/graphiql.min.css new file mode 100644 index 0000000000..521452299c --- /dev/null +++ b/graphql/internal/graphiql/graphiql.min.css @@ -0,0 +1,337 @@ +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, + U+FE2E-FE2F; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,d09GMgABAAAAAAMwAA4AAAAABZgAAALdAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANBEMCoI4ghsLEAABNgIkAxwEIAWDCgcgG3YEyI7DdHsjE9IUV+CFDh74vPL9/MmgO0un0soqjWt7En2kQoCMtXsRxyxkMqP9iO6NfSiUaLJuoRIKnhI0+ImbcWOB5XOAFVmCgxZQQmuBJRhZtsUCXm/492Dyuk2YZJdkdApZeOzyEQgKOwDgRjASBEEBVmAlgACtOHEhpjLyyrACMAB0vaLa6cAw5bc5bvhA2uwO7zXAyKPmkYNnAJgBxLEMDxFLqVBPI6EQ/daTr/QOAgfCngRoZc4UZiL623qCkf/oHVsfRCOuAIbJyF4ajQQKQLmQhNBAA4aygH9b19Xw4iAC8DkKM6WrYw/ABMAOWEAamA7sgBWACgAUSlc3SCmlc95o45idYD92Qt/+5gF19v3FALtB9+7dq/h6/Ljyu/zzYfnngwdlHxO+k39nOcO/e7nPf2vCoo3HVlmNTdnWwW3JZffuVU6cQX14kb3qUGOOJ+mjP9iMeb1Nivq5gXpJUWm+cmVK56e6PjI2uce23hHlG48vyDvym5/5q+wbkjq90rN+z53D6zXqmVUPVshZoVtrZgc4vleS1NNrni6VR8I/vTrpzpPwu1+1Pel4xBIzK16W3KcLNnVGl2RGZHbPXBAvhw4M02Ci/t0BBfw/p79XS9V7CKAMF0++DK9rtI/7MXvGATjz0TEA4K4oef476t9dS555BAoLBYCA6ei/FSzVgvg/cIR45gpTaLWeLiB+oa4xJuTks7r7/xwCmCzlpoJKALCDQmkyEsCsN0mELUADghGsGgAF6c9IXkabDYyqg6WMkZd9z7BT5gaphhhqnOH66aOvkTQhggQLpsk0xBB9DNSLJttgPQTQJBtoIE0JEY2wb+1lhF6GG62XngKUGKLFECMNkW2kZgP10+M31GZUwfojwkU0uAcQkISKFNtqGMlau3vIjjRUjMANjYkDNKeouYh7CRBmuD4CHQgHG6GXET8oT7ZU6QqUStddiABBJPSv6P315AAA) + format('woff2'); + unicode-range: U+1F00-1FFF; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0370-03FF; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, + U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, + U+FE2E-FE2F; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,d09GMgABAAAAAANUAA4AAAAABbwAAAMBAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANBEMCoI0ghgLEAABNgIkAxwEIAWDMgcgG5sECK4GbGM62A+KOMNGmZWUwcdhKI9l4Sh/WwYP/3af9w0W4ERa2bOg405uoSptTooGKkF8HniO5b+Iojvye4dReBbNtVHwcLQTG2gBzQfYOqjJ/XYU/jItwgxa4I3czM4Fj9LAAnlHz+dzgSO71Jqn2QML8H66dROj0qAFLYnRhtm0b89/erW/v8l/LA6we9gCizDBtQzSf4EtkcwDT6RtmgYEQXnDKGQslZyX/CkQSFgBAE4ERggEAgmwACwQgADMsONAJKVkFWEBgAJgwMz1NlLWec3G+jtZu+rXO1i7rx/sZi0AEwB5WVY28FUE1CORQAjvtSPftAwCQQjGAbTUfm4qwrvbNmDEf5pjR4JoxElAiYiMWjQyIAEy4EBGAA4UNKCgIMC7a5Cej2sCAA+SMEEyYA2AMQBWgCmQAObACrAAQAUAJCSDMEDmo7CztfXoRGu7SUeVdbvosOq6N6PHnZ2yf9l3eXPj/q2qXdkjBL+qrix1cYsqzItOvXfRPaMXkUvPeFWoxr7tZB8gfxIhMauBapmSUhO8d3O8wUt0MoI7UAxLzt0/zhCwJnVHrsPYXenm8suPeLYORWqn/3wwK6Qp+frDiYGvxHSXFzoXfpihfmlODl9oFbOqKa8nXbZgd6axNivh4JS8xEZKChij/nuDBPx/MrxQA/WBACCtK44947xa66g/k0YcALjxaesDuBuQP/7x/3bTwmQACVMkAAQYd/7HYBqK1H97hriqWIzlN7cD8Qu1mY6Ql7eR9v8qAcCY/apKqAgArEBCCmOEAExoJiOUENTgBAI3NSBhwSjIbLboV0Blo3PIiN06hxVFfmrr0WtMvzYtWg3SBPDjz58mVY8eLTrpNOm6NfKhidepk6ZAbgbym+oG6PoN0zXxUaBHgx6Demiy6Zq0GdIl3aB6ndo04r7WvSV0/Qa0Nd2+yKcNFCrSvh/6dNKO3xV33aBeEXxNZKTyQUaverfOR49+LZno1XUboBt4oSzpEiXLUSjZDgF8+JHBMIY0KQAA) + format('woff2'); + unicode-range: U+1F00-1FFF; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0370-03FF; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, + U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: Roboto; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, + U+FE2E-FE2F; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,d09GMgABAAAAAALsAA4AAAAABWAAAAKbAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANBEMCoIYgXsLEAABNgIkAxwEIAWCdAcgG0AEAB6HcYyyEjO2Dy0eKLv4XvfsrGs+wIhEBOHOERRRTI2158fc/aln0WYmSJq8uTRSIgUyIVMqpfa/7uYHCqzWDuHREj0f5UuuL+ZAokTaYgiIs5sF5aUutjO7QhBlgMaYvCAIIqqoCggoq0+HjRlX70MGclDLyR3Z8fb0q/ectzCv30obmLesvO5hBhRhcp7kToaLpaRXpL0htKmb5C3rIgzUIwA1fnqrhHSbqXhA3v+sK1wRtcWuhdyg9E5tGXERkaAhroCGeNqCnJxAm6m1Sb58SICvFhXFWnVAAWQoYRjYADJUQQqIYm0uSZKkfpYv1sv21dm9b7kWbV6i3BQ2Z/sOf/hl+ezXH88LRz75pnLuq4/MO/Zx+eyHc3x9VDn3yfx9n1ILyusq3ps75y90fVZ657PJ2iXgF+odHbvzv7Lrm+uTsPR0WJqYcelN7180rHDDnbeWbrx0QHht49uXjCzffOsd5RsvGvHe4yF5o+Ej97/ZMP62+Z+3Wz/08CtZ/FezhpdvG/nb6PMhC9vNvHFx3Du9X47etewROuONg4L0v2eI+L9X7dt0evq+gNihfvWttiuWK4f8VmxWBM/+WK8b8F6Y9evfLf57r9SjuA2URBAobPm/Smni3y3+n1TqgQEACsl5awAI/5AetjNp65A+/38vDAUXaayPL4CMKHYkEFC0DlfIlbAMegyqlmGU2eSTO58TTHX2xLyWvlczc/wY7eDo5WxlYenKyMvNg9Go5MAatqis2Jty2oytLaPupFxOlsgFObsjM05dBxMHVwcMbeFma4xFh8jZxUr2e62Th09I7Bd96I2RI3gzYzqKcsHjqZzGjsamlojTwdmCy9bKFNm7IBcudRU5BU09BQ5eTm5coMaMAw==) + format('woff2'); + unicode-range: U+1F00-1FFF; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0370-03FF; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, + U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, + U+FE2E-FE2F; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,d09GMgABAAAAAAMAAA4AAAAABWwAAAKuAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANBEMCoIYgXkLEAABNgIkAxwEIAWDAAcgG0oEAB6D426JQgSiDJGrY+EepR5ejwf4/fWd+/C1EBKYZDS7sRFxHTf9uCJn/m9Of4qsOwRQBbqEex0QSbKziM9Pj42dA85/tYTLU84Cj+f+PIAlq3AtV5GCrQWUqr11TNFedSEUjKs7rSju46fX7RWCSHFAeYQcQRBEKIqiAgIKlGZBdO5a3w4akEBWj6orkgSzThrq5iF0WjfiKGe7e/0dAHkwOR8nW+GblHR72hyEGmzEl02NcDPu9oBKt35NVVBcoyEuIJNhau72SE3EHkhapkdqCiZGhBhliQWUJVETSCQCNfr8o/boWoBjI3miLHqQC4ojH22AaUBxFAUpIBJlJeIVGIvLFI6PlFi4hGYVs0brZ4ZZlT0rbz1SLT+50xlW3X269vh2x+CpO/n7bw02ebvIys0wMkpteMHUIq4PGfxCRBdKjxXGaDRIc42rK+a/qgeebsfBvjGMiQ14cnJjW8fSe6fHlr2NIrgbeH2jS+k9X+md9WJP/5IvZ8LRg1cQ3gz+dJMePnr2/6ZSiy3c9rHc87Zj4tqOx0WLe1U0VR2OOEt9kq4gV/r/NBEyVbPvpL70poCoTunu3LVVZ4nW3xWV8gAKP5VqBMD10Pruq+7/52x5c4B8EQjkzs5oyJ/1JzxT0mgEACA3XjUZACFDut7UuAEqPZepikCuTcprJBVAcSJREzIBeaYSC4kSGAs2BJU5IFLcQjt+sxNAqr55kwOx947iBrvVCRYwpBuDQusVLFWyFCmCVcEwCg8JVsPPK1GwEjxesNZJv6dyHtID6dYP8UnUCvPAemHBGiA+jD6CVgilD8+tWyfSPRiYXwVJDNNkydPUzvrRmeBZvFdArqSTDSCJ3ALcvDp0JBHWjTK8pb0Qvx7N35CkXo0yFRq1qZAgVaJkYiA7H3AA) + format('woff2'); + unicode-range: U+1F00-1FFF; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0370-03FF; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, + U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: Roboto; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(data:font/woff2;base64,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) + format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} + +@font-face { + font-family: Fira Code; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff;base64,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) + format('woff'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, + U+FE2E-FE2F; +} +@font-face { + font-family: Fira Code; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff;base64,d09GRgABAAAAAB4cAA8AAAAAKSgAAQABAAAAAAAAAAAAAAAAAAAAAAAAAABHREVGAAABWAAAADYAAABAAdsBp0dQT1MAAAGQAAAAIAAAACBEdkx1R1NVQgAAAbAAAABAAAAAQodMa01PUy8yAAAB8AAAAFYAAABgc4zF9lNUQVQAAAJIAAAAKgAAAC55kWzdY21hcAAAAnQAAAC/AAABEGjeCRlnYXNwAAADNAAAAAgAAAAIAAAAEGdseWYAAAM8AAAXagAAINJZlxASaGVhZAAAGqgAAAA2AAAANhL1JvtoaGVhAAAa4AAAAB8AAAAkAzn9jmhtdHgAABsAAAAAxwAAARIsXijQbG9jYQAAG8gAAAESAAABElQQS61tYXhwAAAc3AAAABwAAAAgAPYCg25hbWUAABz4AAABCwAAAkgzWFNlcG9zdAAAHgQAAAAWAAAAIP+fADN42mNgZGBi4GOAAAMgm5VBisEGKGrH4AYkPRh8gaQ/Qx6QLGCoBZJA9UCVPCAMZDMAAGrQA4MAAAABAAAACgAcAB4AAURGTFQACAAEAAAAAP//AAAAAAAAeNpjYGRgYOBisGNwYGBzcfMJYVBLrizKYTBIL0rNZjDISSzJYzCoyszLAJKVlZUMBgwsDEDw/z8DHAAAwqUNgnjaY2Bh2ck4gYGVgYHlC8skBgaGSRCaaTWDEVMFkObm4GQFUgwsIAIIOBigwDnExYnhAAuDohj7nr81QIkS5hcJDAzz718HmiXLmghUosDACgDVgg+uAAB42mNgBEIOIGZgEAGTMgxM5ekZJSAmAxMDM4hkZGKcAKT2MDAAADlQA1MAAHjaHchDQgVQFAbgr7rzbBvTbL1su0bZ9h5qDWFcK2ohuc75jWjEIOlXo/49+ECCuN8lOmSEwtAQOsNKuA+v+Snf3wQhMxSFxhAJd+Hlf/MR98sC4G1DlAREsOfRMyhQqF+ODu0iunRr1aZHhTJVGmXIlCVbnnxFipUoVa5ajTq16jVo1qJJp159Bg0ZNmLchGkzZs1ZsG7Dlk3bduw7sOfUlWuTptwYdeLYmXMXDh25tGjeml25xgy4/QFZryhCAAABAAH//wAPeNp9WQdck0naf+ctiRUMVURwYwQsSAshqHQp0jtSBI2KDRCRjiAi0rFgd7HRsWH5LHv23ns/D/vd7a6eu+7ZhQzf805CxGs/JclM3uf/1HnmPxOKpUK61rNTuPMUQwmp4ZQ9RYWLRWIzkViE9ASSoeYymYODzN5cMlQgJEN7BwepnYGBvp5AyNjzH/XJYyHsgI63TGPnZdT6g47ukGQ/a/8h1oO0+xoMco6yiFJYxCTmDDc1Hc7/cee/3J7FJXytp1mDQYMMWgVeweOC+/YVGOsaSwa4z3aanaGNP/KPDhk1iqKpERTFlnEKsK4PRbmLGQmSIgkSM8w05dO5O9DJJ+jkQeVmdOEFmozrOMXXLeh3+hl4cwrk5CDXl9LjMdztzc0lEpHUzoVm7FWfHHT1tGgJeGtnSoMXAqEpzSwKLQ15/VI6J04urym49iSv+LeYNYcm42UoPG5XVYRvpkdgTQIqnpVmiYV69pPpC5nTsEcK5uatj7XgFOLg0sSYBX7a/byqKApRhV2/sqlcNmUC2u0MDIXmfBQF+noGBqBbbiiAuA2jZfY6w+irZQfDFO41wWknM1OPZ2askce6Xl7Vgv/YXIf6c9meHmly66RPd659nus9er5zTCNy/vkX5FTP6+gAL415L0GHSKwvVv0J0TaEMU3P73zGaOmxd7DNcmxYxSmWgUQLSPRWSSggyxAIkRj+mEnKz7t20b120UuV6ZxCeZj2/rqF13CdopgXag0qfBm8ypgX+Dqy6/wHssPXOUVVx4GqKta/Cp6v6fqVeQ7P6/IWQYChOCzkxGUZL/Z8dNLB8sQzYYGxq51X1OJZnKJzVtSOqgg353RHi5/qGIq30RlsBCMoA8DQlTBWtL2MkTCmNNScRFeqq8uaBbWMYgT0L21fEI0Yxqwh6J9P7/HJp2/4rq1MNu2UMVdM0patcVNag4JQZjcFlRQP+QiHfGhTxoCrR/N1y8efr2Id4QCwlBYN0JHa6bDhaS9aW16mpb1saX2RdnBdW9u6jdva1tG7b+ITB/Yil3u3kMehffjkfaSLhuFH+A38e47EvI6fwfJYsLwPZdCj5hwc5FBf8FECxcYyWyNWJlw4qVgddbji7cY9bWjKR2TC/JRUIFfulxVn152OxohT3IA4TASLbcHi0YAFAJpQkiVpbmFFk+X4fW0ZmtKsbdazunUfJs6ccLggYmWs/ZKs8gsp8y8VL78TNcNve7R/gb/b+uKkQ/NQQdahmZMiMsYHy9Mmjk/wlQxPXJ0yc2tcaECax7jRMV7jonwshsSTKggBvyaTVQhZBS9kYiG9YxcOY7V12Ksd9uzVNWvgKRd4ar6qVsKlCMF/Cf9/2gVkhayP4lx08ALehpuOoD1QYb/TImWp0oieq1xJP+FjVwHeilgpNYQaSVGJesQrC4G660il6i5kQTzWR7CERDAGl5kjIy1HeM4wHLN95uaD+G1tSZZ9dZilYnvguXM4MGiZ1fq25Yl/dx2rldXby9vXf9+qhrbo+ZONTAqHmR7apKwM9kbaOYlTE3kvD4EFvcGCwaC/e4mam38XZBJjuim4YmyY1+n4TY8zMh9vTtzrFza+zLt8T+jSPPvhc8d5ln1o2tyxwtl5nrX11VvVe8N57zYBtj5gD6LEEENTWqpR8F1TReCi2NwcBXIRlaGhxV7BfsembXiYNv96dcnJmTSNYzM39aXNmGXoTl6tr4116liPyk8NWz8vK/h5q7G1Drrf3LZtB2izgFX7K3eP4kAfv27FMqlcpIocpI9EUiCET/QZ3IYP1re6HIj/cVlrdIJTctTgVs62tLRR+VN4eONKJUN/mTzRIWSkEnFnAPcPyLBQ0IfqTekDrqYboO59AFyhn6ARna+QFz6H4h3Hj3eUeXqyJp2zSkoY3RL0xtNW6uUltfWkkAqLNQGsHkjfpDVCfPRO4GgmD/T2p4xIXxGwQgsXWvYvqpm8zfjuvcEb35ZhP3TK0dPT0cHDA3Cq97xZMWzxoFkHltJfe9pAU6sgKyasVN0TVDnQ5MSQZBsSBaVHx665lDjr0urVl2fOurK6vKqivLyinJWWfWyp+7y0/FNTw+eqikt3b16+fPv2JcC9hKMJroga0hPXQiQUSQ0JslBkoIY2p7dWt/jF7K/YNbt1udbYOvnEklEjCvyLl9jPYaUAveXLsjzcR587tyo0umy2m/Kjs8/FO5WH4viKBfuZ16BnFKnY/9gV1E1B/1sDoa1zl0qS56XUxSTuzy485uHntGJG/ixpXtLMDVGLrqQtv+Q5xaUuIy7AxttxsLHP/LiYIq/xtvNHyAKdrZxtTYwD8qfOq3INH5cqdQULUiGL7qwJ2U9gtUN3Vi1765OoBO+48P7TSbwTLbmOn9GW6A+cg8qxgfIaOguSC3AMKwNJbYgQ0qL5hMr53R2xMrzMLO1A1aCUhb6DHfGK/dA+RrImHe1J+zK1SnX8MkIhp9OYTV1d3exAIAA8io87jJ05BdTJQEAViqH5ssRz4DOkE5MYMVdEymOwdwyp+GMjrkcZ589PWR0VuZpTrMA5px9tOhoB7SlBed0qP2NGrgy0EC5BtNCgBaEBvM+ghVPpkIhYdx3lsl2cYn0HTzm6ulRPCPUE5vzuTwmoJTPBOtWsoIRiVDUvFOmqpbdv5+UFJbhdDznidhUMS1H4ETub7Ca6UPdDiIwYwqQj1+XEsP8JoFcAACORi6WG8MYyXp1vokZKzS1M7WkarzUdaDZirBUdhQwqTUb164w/39/SpJJTdNjU1IxI3ofE7ah6Fe64iX85kDYS+yLzmhr8CKzvZhXgL0tpxkJj8EZMvCkepZkV3IdZlswuhiJEfNzZ9ZyC9AcwSZeR6kqBX8ArowtjkYTum3+j9cPDlgN5P+Ydanr4Yee1vB950kH/mS7naQf5y1Fa8HOA5w0rdAzsgdbf1pGwRzVrFpFEIu9Or3qboG1X3U0PKgqKWpdQ+Lpx5ZfYpNCjqXV7I2smvde7HVgeGVwamb4zcOqMv3HZsfVzIhf49hWG1iQtOJs2I2GKd8C6ovh0h1XW04P9ptr4uMyKjOzBnSCP6eATbwqS8v1UR45adgq0eqP3T3fq9sVaUD8T8vavCWQvAiX502bUK6FjPESMyAtZiJg5iVgZRWlmjTWzxYiP4zGYXQO6+vFxJDRNSjZUus+WtrZ61HwU26CPt+kqZSYoO0p78iHj0YgcqbwRqsqz5NFMu14Ry3XU+zcUD1lxjFyX7b0LL7UZaOPoGekQMNTJ0WFQEM+k2Kt41gncsS3F36xosGfR2wt0AqATZkYqo9c328mYI2M1x4IxVHiPiAm72aZYxTSZqezlDgdeDy9FWBNB6UNQ1MwZxgwZq9kHjPsRVBl8X87ngXQOpkfnKMdxw8LnbUwZNGtxlIUXHrsfVaIZQAGFUcXx47SqtB1nT2T+3lnJZAEqQRF8gEhJSaRKIDgMNajrPLuWq4XObUR2an0DHdEAWqgvkZnz9FAuM9Si9YGc6IpUxUbv+vIWv97+D+XbL3RSteea5ubmNZ7VXG2GDr6IH+Ib+EK/3NzeaCyYNxw56mR8YKY92K98rcX83Gmk9Vq5/8E03kPCnIiH/UkfS1THTaTaZ8kuJAfNZGsigUS6S4ty6uz1PXMKQ3MPTGcaof0oOyqLwx0rHDx/SDy4gNb7ugUQaKoFusgSkgPATlfzfTlpGy0841/ANwfoCtbsra9bakgfgBjHgwXhat5PJFR/bHhnnwbUZyPqwyeP7yXsTf6P59eg5wbpiiLYjQi+bk/JG5Umlv39usVVitib34GorCWeM7zmRCkjQWoEmtpjsATX8BaH4zJk3m0xRZOaDya28qz7P/d8NOfGF2RS8bYWL0arf/77pFVRkTWcAtOXnm49Ew2hy1Hut12cm7RQDngI8Ko0u0gPPImsJ2L93c/IpPyPWpz/T7rm7btJKyIiVmog2UvrldnKgzaAWSCnGA037kPp8FaGi8jZmdUYKRuAIKu/Lez4iPFrOFu516xaug5d2wOA1KOrz/4CJuYr2yqa0DB6CUks2MnAqoYHKENSqSIekJwyGC1Gtba/WUuf//Chq/3wUSttMzsPy1hDC/Hgfk70kCGmMQXuS3mjr7b/do29raw99LzQb+h8I/fUw6vo35ULlHvsFuduLea1AY0l2nSowbw2BxWnkWgOkbrwZqBSdu7T+4y7Ncfwy+3bkcmVH36IzvcAJcpH6NTtjUfC6MNKb35EmyujlTeRZX52bTasAXLaIau+L1nl6TCeDp3/h+/Oz0Jgiqb0v56gT5UcDonxXhsya392f3qKcmOv9J/S0tfbTXK9tnonfr+hnj9He7klSW3ib+6tOfhitt/otLHxmoM0oiJAl6z7rE6J9Ogeu4suMFNas6kM+oKGln/ZXv4saLZP7ZQDp/sp6+kEreONGbWuU4Luc9m4FTe+xYcbFcHT3cZ/Rr1XIu5hiHSmZyJ4qD5Lg4cCiuoekx1UoNpBET9LTtDkKSEfh65PEPcUkmXCNr5n8UJyGmPG6uAT8qUJB3a3Tc+Nz7Zow8d5MjNO5nHjAtZFz5cX+AxTLmRvreg+B5eCr3rUMBJZHX3+7GtOW6i3GR0dQ/VZUsOXeq9o9tl7dXmTD1Pa2lreb+dZv9jhI2L8vGMsR8Vy2XX47Gs419W0oFEXlAshs3vQCOS8bM6Xe/e+JsHr/S9JvN7x6p7Wn6xS3m4kQTzTHgbkRUW1pfxmdA23n0aeObmoT9ex21tql5V9Iif7EcoHdKj8zMJTDyoXV1eXksjgP0hkCDNSxwVqkhwNeoZHLEQ/y2tiD+wOq02xjI6XdMeIGa/D3sLjbL0hSrer9qaYVUtCMmPRUE24SLyswe4i0te0us9ShgCL+BMusxd34eCzb/Zg4LspKG0/XVBaOkf5hhYxIcogeh/ks/tcC/nUInW9DsaGXDtlC2jQ0oWwWA3BeXWwSY1baA6EmksKuQvNKPwksZlBbtN8R/cRLsv1zfYtSPRckiKhLU+Vp++cMv/KksLLWe6tGwJTJ3Htxfq29iaGTlO35vV+ffyaa9OGkxudK9J35demP1i37XVeAepzqx1Zn5YZW9qCj0/BxxGsFNa2hYZnCdUGiEXqA0s304IAkE+0V/HJ2bF55UvyLuXi+eH/N9UpwuZFaWlInhvu/DIrfyErdcuNCcsc0r8wZ26FG6utrV8qEHT+HBEbGGi8xCs+ypvn0k6g2Yg14fmDAnIlFKO/ttKP9ZRPWZOlED3V94KxsEaCyRopCoWcqGY5i24mLRUhIsuk7FReUYsL0Q/4Y8dLHoal7GFXsSJnTR3o6aYaJs0TaT4BYhWBRmTXYp5HKf3jbFxH9h+IlLi2X2/jEa5W9KhO/ErgY1LNfK0y9ebgBJJcUTEy78lxFFFxouZcUfjQCvwI7cahyLwC7O4+70PWB1CascAM/AgnfizS18xyP8PsADJbqA8x4XPAVoC1MFCI/hOJpvvPu9n8/tn2n+atnXes6dn7HTeS0RusS8vQLzgC7SR/A5VX+DkeLxm09FGdEt1J6qDKehTZfyTUEgkqPD4nb3FO8K4JISHtczOPzcudNCE/oOBBZe1f/EL89mfX1JQvuUsnRXtHhNhYJY7zdC2cEpNqLHSaFZC6LmCiU7LMdU7MxAjQz5/KmJ/VJz2+cTnIEd9pQDFifm7t1we7XW3t1xsdgTPeS/Rm5okJnU2sCdabccGFmchHicgLekGUokmUSvG3WTPN7CKyuu7w+yzoAqaYriHNoO5O6x1kcwxvRhuu4MabAB+FtpMYvcYkE0SO1Fmcqs6GU2RfeMV0AppI3bE0OyvT2YqzBva3cJns7WM21lrST8wbz9TgV3sel0daJBuOST69BW3nMSIBOQ4w9FS3mebmcgkD/ww0t5naAXUjBBzd61brL71YljPd4vf4xS0ejmYi989RjqPPRZ2LVH5lTZS29I2e8fzXO1xXbNfaiq63ont4FHjogY53vOR9I7ccpBb1qZ7yPVg5kWVMmVWdKbxmEl8crZYyIBVMbsfIWJugFINfYwiK+hQslrFj9HBZKy5kTao7U5maapBSn/JByoigkDHJpVF3LmEVjwFd2dwj4DFW1Di+L4q+64D8vcm/XMZ1383IRebm4p7XKXS/9ZbTZLMzbT2K4q0nDV8/XGEVX+gmy5ttP2nUGp8JE3ws3UYMd0GbbL2HD3Oz9A1y4x7pY1YuLf/Y1PypUj4G6+nTaIy88lNz08dya7npiWfPTtnb0flWNjY2ylJb2emnz06AH+Teg/g1kEQDUs3chmjoqiqFWCuDpKiNZG63Ou2ctmFja0xCQJMNKfTjDu4Nq9BWnDE7zs0RPeR5LHSpAhLR/oCiJs6cqidJWztfQG6RX5WJD8fLsyYQYlW7QZSCZ8Ag+a9sPbhTZzPquxH11UjU8H+gSwG6noDEf2PrT3g9cd3iFUQRs/o7EHLP9YivpB5sXQ1A2DoaoTIa+Do3XiUKMp1g6yiyQsnZhqS5J12HHKLGG42nwjN+momno4yrz+eUp0I574+pS15YFwCfbPBYxeK0+YDlAVjjAUsLsvA9Vk+qjv6Wv+ZBVsGfq3F7By1dsTxkkd8agDngs3FRRZ0XU7sY2+IxZtMnL5jO12I+YNqTWOpTRmpUNdXV/QbJM4DBPrd+T71U9svvwYEROW5FtFs9oG5vOLSIWDkajxmROCknEd3hXeejJQS+vhU+DqTEBPe/EHZSxfeNr/z1l3Mn7vYXmrlPcXcZLLMU9zKkHYYNz1yYBeA7mg4c3s+sw693Pq2Ks0gb6DT3RC1qxlbYUVGRMwN0QXrYZtJ1TNW6/hNfVx8O2o1LTs1OOlF4Gnc2NyP2rMTMf65TDqjJcF+WnVfjRusrX/MjVK38iOcZRUVnRqj7CvOadARDquf9uWkPxk4IO1mbPa+76Zbp+wJCvIv983bro+fYpN//FQUVewX5norc8jQz4wkrdXRKth7Z0lJyZNto62QXF9WN+r/rMPh+35ID1/t2/2NZf2dW6sOtU0/6hrlXBpa29sNa6K325iL/Ze4hE06z0tJ3TU0d1W7OqTY2246U7GgYbTd3nDP41X3LDX7pUJox2aV1Vbs0w8+SO2nylB55Sn3nDmMROcOngqXzwFIDatj3d8vdRNuFNhzak2czqKAhOLB+Uc6PQYLS5uZSYdiP6ckBpiF+AeGm4ay0+OOOxs+VRU+qsSXkYvyK22mVl28X/jRt2p8W3bwM+maD/isk4wMJb1B1SIi+BYm5VAyE25BhJE/ScpNzEYObE1OTn55CizthiTf9k1k7cWpiXInRyA1Jm7dCd/qLBQ4gXATH8V5RZjz3BTANz9aie/BsQrQlMqkMpaEw3Oa6H35OsAhKD3T1jrWcOJn8qlBfz91rLMW/BvA/K8jnrpvpPzTvhwmFGfSZqbHkBwZ2R+lKPm7psBc4gx8s3wUT9YFu6qrINhIx+bdxxR2csg/JkbQNp6woK1NeRJeYzs5GZlInCxaDlCO8LOfySBzIL9rufHczZfgzEzAoe/4GBekD6v+67o9/9KgXEvYSFLY/6NW3L92ADd4r0m3t5isUGXbSjClOo0Y5OY+0JBdlG3pPqqwPVfrChYSib+WDAvpgx6jqava3uefLFl+cl3KhdPHFtPSmhqYG+N9E0ciYEzGruJ+pvuRER364UHUCcY/PqMLGxcVmtKsrSrVycbGydnXlRE5W1s7O1lZO3e8UQmlsO+MkMKMYQDKTcwyHk2P5ycPL/wHfZnMUEygYS7415CzoriCcYC8Yu2J7LM+sBwkoZqXgPiukCqF6f4fnU7mfGRehMXmeE5qhayhNiqcLjR/FNsK3SfDteKGeBu1TAI4cLdRbsSmW5/HW3BumWPCB0iY+aRYkHHDoqICisF4Z+hN9vBP0M3pFFnNvnJImGI3z8xtnNCHJicj2B9le/13WIEotu5jrbz/dz8hdLnc38ptuD15YCnozi4QseFHahanO/wexyY1KAAAAAQAAAAUAg4V762hfDzz1AAMH0AAAAADbCS13AAAAAN1Vrr7yK/wYCVAJYAAAAAYAAgAAAAAAAHjaY2BkYGDf87eGgYEz4ZP2tw2cAUARVMAIAJK+BcUAeNpi2QAoeQ4gGgqjKAB/vxBAgCwCmBGDomhDEYDRMjCEkOLJEBZDYIDnITAAjwDggckADwYBIMAABMKi7sznHFwXjp6WhYm10lKuY2hloKdrqjLT9B0+FOpIZqyltkh7G1gL9l0pBfNwqKM0jKxM9JyEhq47cQ3xJenacW1gpG8Z8r8fQ5fRbVNvvtL5hmMzQdOjWvAZ+m7UCnWovBqHM5l3c7eh9uvCi125QhW2O5oy99Ejp+kgPaXn1EhZekjtcPQPfPVGPwAAAABQAGwArQDfAPgBEAEoAUoBdQGnAc4CEwImAkUChgK0AusDFwM9A1MDfwOrA98EIAQ9BF8EZwSSBJoEqwS2BM4FCgUSBR0FKAVQBZYFtgXBBcwF6AXzBhcGHwYnBi8GQgZKBlIGWgZ9BogGwwbLBvEHDAclB0gHYgeKB7QH3ggVCEUITQiDCLYIvgjJCNEI+Qk1CV4JkQmxCbkKAwpAClAKWwpzCqwKtAq/CsoK8gsyC1ILXQtoC4QLjwuxC9oL8gv6DA0MFQwdDDAMOAxDDJwMpAzGDOMM/A0fDTkNXw2JDbYN7A4eDiYOWA6KDpIOnQ6lDq0O5Q8QD0kPaQ+5D98P7g/9EAYQFRAkEEIQYBBpAAB42mNgZGBg6GBiY0hgqGDgAvMQgJmBBQAitQF8eNqUkMVZhDEQQB/uXHHIDXd354Lrdd3ldxwKoJatgQKogG6QfIPrRl8yPkAl1xRRUFwB5EC4gFZywoXUcidcxAL3wsX0FdQLl9BYsCZcSleBX7iWkYIbNBdAdcGtsPbJMgYmZ9gkiBHHRTHEAIOM0MsT6a04IE4ExRoJbAIobRnWfzvYGCSfOKTtF/FwiWNg46Do0H5dTBym6KefGAmt4RGkjxAGGfpxMcjikOKMfiTSa5zOb2NvvOa9R+SJPNIEsBmljwGd/TTLHLDC0hN99vlm3fvJ/vdY6pP2ERFsHBK6AvUWPY+I0iPpkEMImwQmLg592neaPgxsYvSzzRobPC6cIRVmHgCRt1ftAHjaY2BmAIP/cxiMgBQjAxoAACqUAdIAAA==) + format('woff'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +@font-face { + font-family: Fira Code; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff;base64,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) + format('woff'); + unicode-range: U+1F00-1FFF; +} +@font-face { + font-family: Fira Code; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff;base64,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) + format('woff'); + unicode-range: U+0370-03FF; +} +@font-face { + font-family: Fira Code; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff;base64,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) + format('woff'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: Fira Code; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(data:font/woff;base64,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) + format('woff'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} + +.graphiql-container *{box-sizing:border-box}.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal{--color-primary: 320, 95%, 43%;--color-secondary: 242, 51%, 61%;--color-tertiary: 188, 100%, 36%;--color-info: 208, 100%, 46%;--color-success: 158, 60%, 42%;--color-warning: 36, 100%, 41%;--color-error: 13, 93%, 58%;--color-neutral: 219, 28%, 32%;--color-base: 219, 28%, 100%;--alpha-secondary: .76;--alpha-tertiary: .5;--alpha-background-heavy: .15;--alpha-background-medium: .1;--alpha-background-light: .07;--font-family: "Roboto", sans-serif;--font-family-mono: "Fira Code", monospace;--font-size-hint:.75rem;--font-size-inline-code:.8125rem;--font-size-body:.9375rem;--font-size-h4:1.125rem;--font-size-h3:1.375rem;--font-size-h2:1.8125rem;--font-weight-regular: 400;--font-weight-medium: 500;--line-height: 1.5;--px-2: 2px;--px-4: 4px;--px-6: 6px;--px-8: 8px;--px-10: 10px;--px-12: 12px;--px-16: 16px;--px-20: 20px;--px-24: 24px;--border-radius-2: 2px;--border-radius-4: 4px;--border-radius-8: 8px;--border-radius-12: 12px;--popover-box-shadow: 0px 6px 20px rgba(59, 76, 106, .13), 0px 1.34018px 4.46726px rgba(59, 76, 106, .0774939), 0px .399006px 1.33002px rgba(59, 76, 106, .0525061);--popover-border: none;--sidebar-width: 60px;--toolbar-width: 40px;--session-header-height: 51px}@media (prefers-color-scheme: dark){body:not(.graphiql-light) .graphiql-container,body:not(.graphiql-light) .CodeMirror-info,body:not(.graphiql-light) .CodeMirror-lint-tooltip,body:not(.graphiql-light) reach-portal{--color-primary: 338, 100%, 67%;--color-secondary: 243, 100%, 77%;--color-tertiary: 188, 100%, 44%;--color-info: 208, 100%, 72%;--color-success: 158, 100%, 42%;--color-warning: 30, 100%, 80%;--color-error: 13, 100%, 58%;--color-neutral: 219, 29%, 78%;--color-base: 219, 29%, 18%;--popover-box-shadow: none;--popover-border: 1px solid hsl(var(--color-neutral))}}body.graphiql-dark .graphiql-container,body.graphiql-dark .CodeMirror-info,body.graphiql-dark .CodeMirror-lint-tooltip,body.graphiql-dark reach-portal{--color-primary: 338, 100%, 67%;--color-secondary: 243, 100%, 77%;--color-tertiary: 188, 100%, 44%;--color-info: 208, 100%, 72%;--color-success: 158, 100%, 42%;--color-warning: 30, 100%, 80%;--color-error: 13, 100%, 58%;--color-neutral: 219, 29%, 78%;--color-base: 219, 29%, 18%;--popover-box-shadow: none;--popover-border: 1px solid hsl(var(--color-neutral))}:is(.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal),:is(.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal):is(button){color:hsla(var(--color-neutral),1);font-family:var(--font-family);font-size:var(--font-size-body);font-weight:var(----font-weight-regular);line-height:var(--line-height)}:is(.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal) input{color:hsla(var(--color-neutral),1);font-family:var(--font-family);font-size:var(--font-size-caption)}:is(.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal) input::placeholder{color:hsla(var(--color-neutral),var(--alpha-secondary))}:is(.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal) a{color:hsl(var(--color-primary))}:is(.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal) a:focus{outline:hsl(var(--color-primary)) auto 1px}.graphiql-un-styled,button.graphiql-un-styled{all:unset;border-radius:var(--border-radius-4);cursor:pointer}:is(.graphiql-un-styled,button.graphiql-un-styled):hover{background-color:hsla(var(--color-neutral),var(--alpha-background-light))}:is(.graphiql-un-styled,button.graphiql-un-styled):active{background-color:hsla(var(--color-neutral),var(--alpha-background-medium))}:is(.graphiql-un-styled,button.graphiql-un-styled):focus{outline:hsla(var(--color-neutral),var(--alpha-background-heavy)) auto 1px}.graphiql-button,button.graphiql-button{background-color:hsla(var(--color-neutral),var(--alpha-background-light));border:none;border-radius:var(--border-radius-4);color:hsla(var(--color-neutral),1);cursor:pointer;font-size:var(--font-size-body);padding:var(--px-8) var(--px-12)}:is(.graphiql-button,button.graphiql-button):hover,:is(.graphiql-button,button.graphiql-button):active{background-color:hsla(var(--color-neutral),var(--alpha-background-medium))}:is(.graphiql-button,button.graphiql-button):focus{outline:hsla(var(--color-neutral),var(--alpha-background-heavy)) auto 1px}.graphiql-button-success:is(.graphiql-button,button.graphiql-button){background-color:hsla(var(--color-success),var(--alpha-background-heavy))}.graphiql-button-error:is(.graphiql-button,button.graphiql-button){background-color:hsla(var(--color-error),var(--alpha-background-heavy))}.graphiql-button-group{background-color:hsla(var(--color-neutral),var(--alpha-background-light));border-radius:calc(var(--border-radius-4) + var(--px-4));display:flex;padding:var(--px-4)}.graphiql-button-group>button.graphiql-button{background-color:transparent}.graphiql-button-group>button.graphiql-button:hover{background-color:hsla(var(--color-neutral),var(--alpha-background-light))}.graphiql-button-group>button.graphiql-button.active{background-color:hsl(var(--color-base));cursor:default}.graphiql-button-group>*+*{margin-left:var(--px-8)}:root{--reach-dialog: 1}[data-reach-dialog-overlay]{background:hsla(0,0%,0%,.33);position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto}[data-reach-dialog-content]{width:50vw;margin:10vh auto;background:white;padding:2rem;outline:none}[data-reach-dialog-overlay]{align-items:center;background-color:hsla(var(--color-neutral),var(--alpha-background-heavy));display:flex;justify-content:center;z-index:10}[data-reach-dialog-content]{background-color:hsl(var(--color-base));border:var(--popover-border);border-radius:var(--border-radius-12);box-shadow:var(--popover-box-shadow);margin:0;max-height:80vh;max-width:80vw;overflow:auto;padding:0;width:unset}.graphiql-dialog-close>svg{color:hsla(var(--color-neutral),var(--alpha-secondary));display:block;height:var(--px-12);padding:var(--px-12);width:var(--px-12)}:root{--reach-listbox: 1}[data-reach-listbox-popover]{display:block;position:absolute;min-width:-moz-fit-content;min-width:-webkit-min-content;min-width:min-content;padding:.25rem 0;background:hsl(0,0%,100%);outline:none;border:solid 1px hsla(0,0%,0%,.25)}[data-reach-listbox-popover]:focus-within{box-shadow:0 0 4px Highlight;outline:-webkit-focus-ring-color auto 4px}[data-reach-listbox-popover][hidden]{display:none}[data-reach-listbox-list]{margin:0;padding:0;list-style:none}[data-reach-listbox-list]:focus{box-shadow:none;outline:none}[data-reach-listbox-option]{display:block;margin:0;padding:.25rem .5rem;white-space:nowrap;user-select:none}[data-reach-listbox-option][data-current-nav]{background:hsl(211,81%,46%);color:#fff}[data-reach-listbox-option][data-current-selected]{font-weight:bolder}[data-reach-listbox-option][data-current-selected][data-confirming]{animation:flash .1s;animation-iteration-count:1}[data-reach-listbox-option][aria-disabled=true]{opacity:.5}[data-reach-listbox-button]{display:inline-flex;align-items:center;justify-content:space-between;padding:1px 10px 2px;border:1px solid;border-color:rgb(216,216,216) rgb(209,209,209) rgb(186,186,186);cursor:default;user-select:none}[data-reach-listbox-button][aria-disabled=true]{opacity:.5}[data-reach-listbox-arrow]{margin-left:.5rem;display:block;font-size:.5em}[data-reach-listbox-group-label]{display:block;margin:0;padding:.25rem .5rem;white-space:nowrap;user-select:none;font-weight:bolder}@keyframes flash{0%{background:hsla(211,81%,36%,1);color:#fff;opacity:1}50%{opacity:.5;background:inherit;color:inherit}to{background:hsla(211,81%,36%,1);color:#fff;opacity:1}}:root{--reach-menu-button: 1}[data-reach-menu]{position:relative}[data-reach-menu-popover]{display:block;position:absolute}[data-reach-menu-popover][hidden]{display:none}[data-reach-menu-list],[data-reach-menu-items]{display:block;white-space:nowrap;border:solid 1px hsla(0,0%,0%,.25);background:hsla(0,100%,100%,.99);outline:none;padding:1rem 0;font-size:85%}[data-reach-menu-item]{display:block;user-select:none}[data-reach-menu-item]{cursor:pointer;display:block;color:inherit;font:inherit;text-decoration:initial;padding:5px 20px}[data-reach-menu-item][data-selected]{background:hsl(211,81%,36%);color:#fff;outline:none}[data-reach-menu-item][aria-disabled]{opacity:.5;cursor:not-allowed}[data-reach-listbox-popover],[data-reach-menu-list]{background-color:hsl(var(--color-base));border:var(--popover-border);border-radius:var(--border-radius-8);box-shadow:var(--popover-box-shadow);font-size:inherit;max-width:250px;padding:var(--px-4)}[data-reach-listbox-option],[data-reach-menu-item]{border-radius:var(--border-radius-4);font-size:inherit;margin:var(--px-4);overflow:hidden;padding:var(--px-6) var(--px-8);text-overflow:ellipsis;white-space:nowrap}[data-reach-listbox-option][data-selected],[data-reach-menu-item][data-selected],[data-reach-listbox-option][data-current-nav],[data-reach-menu-item][data-current-nav],[data-reach-listbox-option]:hover,[data-reach-menu-item]:hover{background-color:hsla(var(--color-neutral),var(--alpha-background-light));color:inherit}[data-reach-listbox-option]:not(:first-child),[data-reach-menu-item]:not(:first-child){margin-top:0}[data-reach-listbox-button]{border:none;cursor:pointer;padding:0}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) blockquote{margin-left:0;margin-right:0;padding-left:var(--px-8)}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) code,:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) pre{border-radius:var(--border-radius-4);font-family:var(--font-family-mono);font-size:var(--font-size-inline-code)}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) code{padding:var(--px-2)}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) pre{overflow:auto;padding:var(--px-6) var(--px-8)}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) pre code{background-color:initial;border-radius:0;padding:0}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) ol,:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) ul{padding-left:var(--px-16)}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) ol{list-style-type:decimal}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) ul{list-style-type:disc}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation) img{border-radius:var(--border-radius-4);max-height:120px;max-width:100%}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation)>:first-child{margin-top:0}:is(.graphiql-markdown-description,.graphiql-markdown-deprecation,.CodeMirror-hint-information-description,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-description,.CodeMirror-info .info-deprecation)>:last-child{margin-bottom:0}:is(.graphiql-markdown-description,.CodeMirror-hint-information-description,.CodeMirror-info .info-description) a{color:hsl(var(--color-primary));text-decoration:none}:is(.graphiql-markdown-description,.CodeMirror-hint-information-description,.CodeMirror-info .info-description) a:hover{text-decoration:underline}:is(.graphiql-markdown-description,.CodeMirror-hint-information-description,.CodeMirror-info .info-description) blockquote{border-left:1.5px solid hsla(var(--color-neutral),var(--alpha-tertiary))}:is(.graphiql-markdown-description,.CodeMirror-hint-information-description,.CodeMirror-info .info-description) code,:is(.graphiql-markdown-description,.CodeMirror-hint-information-description,.CodeMirror-info .info-description) pre{background-color:hsla(var(--color-neutral),var(--alpha-background-light));color:hsla(var(--color-neutral),1)}:is(.graphiql-markdown-description,.CodeMirror-hint-information-description,.CodeMirror-info .info-description)>*{margin:var(--px-12) 0}:is(.graphiql-markdown-deprecation,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-deprecation) a{color:hsl(var(--color-warning));text-decoration:underline}:is(.graphiql-markdown-deprecation,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-deprecation) blockquote{border-left:1.5px solid hsl(var(--color-warning))}:is(.graphiql-markdown-deprecation,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-deprecation) code,:is(.graphiql-markdown-deprecation,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-deprecation) pre{background-color:hsla(var(--color-warning),var(--alpha-background-heavy))}:is(.graphiql-markdown-deprecation,.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-deprecation)>*{margin:var(--px-8) 0}.graphiql-markdown-preview>:not(:first-child){display:none}.CodeMirror-hint-information-deprecation,.CodeMirror-info .info-deprecation{background-color:hsla(var(--color-warning),var(--alpha-background-light));border:1px solid hsl(var(--color-warning));border-radius:var(--border-radius-4);color:hsl(var(--color-warning));margin-top:var(--px-12);padding:var(--px-6) var(--px-8)}.CodeMirror-hint-information-deprecation-label,.CodeMirror-info .info-deprecation-label{font-size:var(--font-size-hint);font-weight:var(--font-weight-medium)}.CodeMirror-hint-information-deprecation-reason,.CodeMirror-info .info-deprecation-reason{margin-top:var(--px-6)}.graphiql-spinner{height:56px;margin:auto;margin-top:var(--px-16);width:56px}.graphiql-spinner:after{animation:rotation .8s linear 0s infinite;border:4px solid transparent;border-radius:100%;border-top:4px solid hsla(var(--color-neutral),var(--alpha-tertiary));content:"";display:inline-block;height:46px;vertical-align:middle;width:46px}@keyframes rotation{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:root{--reach-tooltip: 1}[data-reach-tooltip]{z-index:1;pointer-events:none;position:absolute;padding:.25em .5em;box-shadow:2px 2px 10px #0000001a;white-space:nowrap;font-size:85%;background:#f0f0f0;color:#444;border:solid 1px #ccc}[data-reach-tooltip]{background:hsl(var(--color-base));border:var(--popover-border);border-radius:var(--border-radius-4);box-shadow:var(--popover-box-shadow);color:hsl(var(--color-neutral));font-size:inherit;padding:var(--px-4) var(--px-6)}.graphiql-tabs{display:flex;overflow-x:auto;padding:var(--px-12)}.graphiql-tabs>:not(:first-child){margin-left:var(--px-12)}.graphiql-tab{align-items:stretch;border-radius:var(--border-radius-8);color:hsla(var(--color-neutral),var(--alpha-secondary));display:flex}.graphiql-tab>button.graphiql-tab-close{visibility:hidden}.graphiql-tab.graphiql-tab-active>button.graphiql-tab-close,.graphiql-tab:hover>button.graphiql-tab-close,.graphiql-tab:focus-within>button.graphiql-tab-close{visibility:unset}.graphiql-tab.graphiql-tab-active{background-color:hsla(var(--color-neutral),var(--alpha-background-heavy));color:hsla(var(--color-neutral),1)}button.graphiql-tab-button{padding:var(--px-4) 0 var(--px-4) var(--px-8)}button.graphiql-tab-close{align-items:center;display:flex;padding:var(--px-4) var(--px-8)}button.graphiql-tab-close>svg{height:var(--px-8);width:var(--px-8)}.graphiql-history-header{font-size:var(--font-size-h2);font-weight:var(--font-weight-medium)}.graphiql-history-items{margin:var(--px-16) 0 0;list-style:none;padding:0}.graphiql-history-item{border-radius:var(--border-radius-4);color:hsla(var(--color-neutral),var(--alpha-secondary));display:flex;font-size:var(--font-size-inline-code);font-family:var(--font-family-mono);height:34px}.graphiql-history-item:hover{color:hsla(var(--color-neutral),1);background-color:hsla(var(--color-neutral),var(--alpha-background-light))}.graphiql-history-item:not(:first-child){margin-top:var(--px-4)}.graphiql-history-item.editable{background-color:hsla(var(--color-primary),var(--alpha-background-medium))}.graphiql-history-item.editable>input{background:transparent;border:none;flex:1;margin:0;outline:none;padding:0 var(--px-10);width:100%}.graphiql-history-item.editable>input::placeholder{color:hsla(var(--color-neutral),var(--alpha-secondary))}.graphiql-history-item.editable>button{color:hsl(var(--color-primary));padding:0 var(--px-10)}.graphiql-history-item.editable>button:active{background-color:hsla(var(--color-primary),var(--alpha-background-heavy))}.graphiql-history-item.editable>button:focus{outline:hsl(var(--color-primary)) auto 1px}.graphiql-history-item.editable>button>svg{display:block}button.graphiql-history-item-label{flex:1;padding:var(--px-8) var(--px-10);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}button.graphiql-history-item-action{align-items:center;color:hsla(var(--color-neutral),var(--alpha-secondary));display:flex;padding:var(--px-8) var(--px-6)}button.graphiql-history-item-action:hover{color:hsla(var(--color-neutral),1)}button.graphiql-history-item-action>svg{height:14px;width:14px}.graphiql-history-item-spacer{height:var(--px-16)}.graphiql-doc-explorer-default-value{color:hsl(var(--color-success))}a.graphiql-doc-explorer-type-name{color:hsl(var(--color-warning));text-decoration:none}a.graphiql-doc-explorer-type-name:hover{text-decoration:underline}a.graphiql-doc-explorer-type-name:focus{outline:hsl(var(--color-warning)) auto 1px}.graphiql-doc-explorer-argument>*+*{margin-top:var(--px-12)}.graphiql-doc-explorer-argument-name{color:hsl(var(--color-secondary))}.graphiql-doc-explorer-argument-deprecation{background-color:hsla(var(--color-warning),var(--alpha-background-light));border:1px solid hsl(var(--color-warning));border-radius:var(--border-radius-4);color:hsl(var(--color-warning));padding:var(--px-8)}.graphiql-doc-explorer-argument-deprecation-label{font-size:var(--font-size-hint);font-weight:var(--font-weight-medium)}.graphiql-doc-explorer-deprecation{background-color:hsla(var(--color-warning),var(--alpha-background-light));border:1px solid hsl(var(--color-warning));border-radius:var(--px-4);color:hsl(var(--color-warning));padding:var(--px-8)}.graphiql-doc-explorer-deprecation-label{font-size:var(--font-size-hint);font-weight:var(--font-weight-medium)}.graphiql-doc-explorer-directive{color:hsl(var(--color-secondary))}.graphiql-doc-explorer-section-title{align-items:center;display:flex;font-size:var(--font-size-hint);font-weight:var(--font-weight-medium);line-height:1}.graphiql-doc-explorer-section-title>svg{height:var(--px-16);margin-right:var(--px-8);width:var(--px-16)}.graphiql-doc-explorer-section-content{margin-left:var(--px-8);margin-top:var(--px-16)}.graphiql-doc-explorer-section-content>*+*{margin-top:var(--px-16)}.graphiql-doc-explorer-root-type{color:hsl(var(--color-info))}:root{--reach-combobox: 1}[data-reach-combobox-popover]{border:solid 1px hsla(0,0%,0%,.25);background:hsla(0,100%,100%,.99);font-size:85%}[data-reach-combobox-list]{list-style:none;margin:0;padding:0;user-select:none}[data-reach-combobox-option]{cursor:pointer;margin:0;padding:.25rem .5rem}[data-reach-combobox-option][aria-selected=true]{background:hsl(211,10%,95%)}[data-reach-combobox-option]:hover{background:hsl(211,10%,92%)}[data-reach-combobox-option][aria-selected=true]:hover{background:hsl(211,10%,90%)}[data-suggested-value]{font-weight:700}[data-reach-combobox]{color:hsla(var(--color-neutral),var(--alpha-secondary))}[data-reach-combobox]:not([data-state="idle"]){border:var(--popover-border);border-radius:var(--border-radius-4);box-shadow:var(--popover-box-shadow);color:hsla(var(--color-neutral),1)}[data-reach-combobox]:not([data-state="idle"]) .graphiql-doc-explorer-search-input{background:hsl(var(--color-base));border-bottom-left-radius:0;border-bottom-right-radius:0}.graphiql-doc-explorer-search-input{align-items:center;background-color:hsla(var(--color-neutral),var(--alpha-background-light));border-radius:var(--border-radius-4);display:flex;padding:var(--px-8) var(--px-12)}[data-reach-combobox-input]{border:none;background-color:transparent;margin-left:var(--px-4);width:100%}[data-reach-combobox-input]:focus{outline:none}[data-reach-combobox-popover]{background-color:hsl(var(--color-base));border:none;border-bottom-left-radius:var(--border-radius-4);border-bottom-right-radius:var(--border-radius-4);border-top:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));max-height:400px;overflow-y:auto;position:relative}[data-reach-combobox-list]{font-size:var(--font-size-body);padding:var(--px-4)}[data-reach-combobox-option]{border-radius:var(--border-radius-4);color:hsla(var(--color-neutral),var(--alpha-secondary));overflow-x:hidden;padding:var(--px-8) var(--px-12);text-overflow:ellipsis;white-space:nowrap}[data-reach-combobox-option][data-highlighted]{background-color:hsla(var(--color-neutral),var(--alpha-background-light))}[data-reach-combobox-option]:hover{background-color:hsla(var(--color-neutral),var(--alpha-background-medium))}[data-reach-combobox-option][data-highlighted]:hover{background-color:hsla(var(--color-neutral),var(--alpha-background-heavy))}[data-reach-combobox-option]+[data-reach-combobox-option]{margin-top:var(--px-4)}.graphiql-doc-explorer-search-type{color:hsl(var(--color-info))}.graphiql-doc-explorer-search-field{color:hsl(var(--color-warning))}.graphiql-doc-explorer-search-argument{color:hsl(var(--color-secondary))}.graphiql-doc-explorer-search-divider{color:hsla(var(--color-neutral),var(--alpha-secondary));font-size:var(--font-size-hint);font-weight:var(--font-weight-medium);margin-top:var(--px-8);padding:var(--px-8) var(--px-12)}.graphiql-doc-explorer-search-empty{color:hsla(var(--color-neutral),var(--alpha-secondary));padding:var(--px-8) var(--px-12)}a.graphiql-doc-explorer-field-name{color:hsl(var(--color-info));text-decoration:none}a.graphiql-doc-explorer-field-name:hover{text-decoration:underline}a.graphiql-doc-explorer-field-name:focus{outline:hsl(var(--color-info)) auto 1px}.graphiql-doc-explorer-item>:not(:first-child){margin-top:var(--px-12)}.graphiql-doc-explorer-argument-multiple{margin-left:var(--px-8)}.graphiql-doc-explorer-enum-value{color:hsl(var(--color-info))}.graphiql-doc-explorer-header{display:flex;justify-content:space-between;position:relative}.graphiql-doc-explorer-header:focus-within .graphiql-doc-explorer-title{visibility:hidden}.graphiql-doc-explorer-header:focus-within .graphiql-doc-explorer-back:not(:focus){color:transparent}.graphiql-doc-explorer-header-content{display:flex;flex-direction:column;min-width:0}.graphiql-doc-explorer-search{height:100%;position:absolute;right:0;top:0}.graphiql-doc-explorer-search:focus-within{left:0}.graphiql-doc-explorer-search [data-reach-combobox-input]{height:24px;width:4ch}.graphiql-doc-explorer-search [data-reach-combobox-input]:focus{width:100%}a.graphiql-doc-explorer-back{align-items:center;color:hsla(var(--color-neutral),var(--alpha-secondary));display:flex;text-decoration:none}a.graphiql-doc-explorer-back:hover{text-decoration:underline}a.graphiql-doc-explorer-back:focus{outline:hsla(var(--color-neutral),var(--alpha-secondary)) auto 1px}a.graphiql-doc-explorer-back:focus+.graphiql-doc-explorer-title{visibility:unset}a.graphiql-doc-explorer-back>svg{height:var(--px-8);margin-right:var(--px-8);width:var(--px-8)}.graphiql-doc-explorer-title{font-weight:var(--font-weight-medium);font-size:var(--font-size-h2);overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}.graphiql-doc-explorer-title:not(:first-child){font-size:var(--font-size-h3);margin-top:var(--px-8)}.graphiql-doc-explorer-content>*{color:hsla(var(--color-neutral),var(--alpha-secondary));margin-top:var(--px-20)}.graphiql-doc-explorer-error{background-color:hsla(var(--color-error),var(--alpha-background-heavy));border:1px solid hsl(var(--color-error));border-radius:var(--border-radius-8);color:hsl(var(--color-error));padding:var(--px-8) var(--px-12)}.CodeMirror{font-family:monospace;height:300px;color:#000;direction:ltr}.CodeMirror-lines{padding:4px 0}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{padding:0 4px}.CodeMirror-scrollbar-filler,.CodeMirror-gutter-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid black;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor .CodeMirror-line::selection,.cm-fat-cursor .CodeMirror-line>span::selection,.cm-fat-cursor .CodeMirror-line>span>span::selection{background:transparent}.cm-fat-cursor .CodeMirror-line::-moz-selection,.cm-fat-cursor .CodeMirror-line>span::-moz-selection,.cm-fat-cursor .CodeMirror-line>span>span::-moz-selection{background:transparent}.cm-fat-cursor{caret-color:transparent}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:0;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3,.cm-s-default .cm-type{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error,.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:white}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-50px;margin-right:-50px;padding-bottom:50px;height:100%;outline:none;position:relative;z-index:0}.CodeMirror-sizer{position:relative;border-right:50px solid transparent}.CodeMirror-vscrollbar,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-gutter-filler{position:absolute;z-index:6;display:none;outline:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-50px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:none!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:transparent;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}.CodeMirror-wrap pre.CodeMirror-line,.CodeMirror-wrap pre.CodeMirror-line-like{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;padding:.1px}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:none}.CodeMirror-scroll,.CodeMirror-sizer,.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute;pointer-events:none}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}div.CodeMirror-dragcursors,.CodeMirror-focused div.CodeMirror-cursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background-color:#ffa;background-color:#ff06}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:""}span.CodeMirror-selectedtext{background:none}.CodeMirror{height:100%;position:absolute;width:100%}.CodeMirror{font-family:var(--font-family-mono)}.CodeMirror,.CodeMirror-gutters{background:none;background-color:var(--editor-background, hsl(var(--color-base)))}.CodeMirror-linenumber{padding:0}.CodeMirror-gutters{border:none}.cm-s-graphiql{color:hsla(var(--color-neutral),var(--alpha-tertiary))}.cm-s-graphiql .cm-keyword{color:hsl(var(--color-primary))}.cm-s-graphiql .cm-def{color:hsl(var(--color-tertiary))}.cm-s-graphiql .cm-punctuation{color:hsla(var(--color-neutral),var(--alpha-tertiary))}.cm-s-graphiql .cm-variable{color:hsl(var(--color-secondary))}.cm-s-graphiql .cm-atom{color:hsl(var(--color-tertiary))}.cm-s-graphiql .cm-number{color:hsl(var(--color-success))}.cm-s-graphiql .cm-string{color:hsl(var(--color-warning))}.cm-s-graphiql .cm-builtin{color:hsl(var(--color-success))}.cm-s-graphiql .cm-string-2{color:hsl(var(--color-secondary))}.cm-s-graphiql .cm-attribute,.cm-s-graphiql .cm-meta{color:hsl(var(--color-tertiary))}.cm-s-graphiql .cm-property{color:hsl(var(--color-info))}.cm-s-graphiql .cm-qualifier{color:hsl(var(--color-secondary))}.cm-s-graphiql .cm-comment{color:hsla(var(--color-neutral),var(--alpha-secondary))}.cm-s-graphiql .cm-ws{color:hsla(var(--color-neutral),var(--alpha-tertiary))}.cm-s-graphiql .cm-invalidchar{color:hsl(var(--color-error))}.cm-s-graphiql .CodeMirror-cursor{border-left:2px solid hsla(var(--color-neutral),var(--alpha-secondary))}.cm-s-graphiql .CodeMirror-linenumber{color:hsla(var(--color-neutral),var(--alpha-tertiary))}div.CodeMirror span.CodeMirror-matchingbracket,div.CodeMirror span.CodeMirror-nonmatchingbracket{color:hsl(var(--color-warning))}.CodeMirror-selected,.CodeMirror-focused .CodeMirror-selected{background:hsla(var(--color-neutral),var(--alpha-background-heavy))}.CodeMirror-dialog{background:inherit;color:inherit;left:0;right:0;overflow:hidden;padding:var(--px-2) var(--px-6);position:absolute;z-index:6}.CodeMirror-dialog-top{border-bottom:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));padding-bottom:var(--px-12);top:0}.CodeMirror-dialog-bottom{border-top:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));bottom:0;padding-top:var(--px-12)}.CodeMirror-search-hint{display:none}.CodeMirror-dialog input{border:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));border-radius:var(--border-radius-4);padding:var(--px-4)}.CodeMirror-dialog input:focus{outline:hsl(var(--color-primary)) solid 2px}.cm-searching{background-color:hsla(var(--color-warning),var(--alpha-background-light));padding-bottom:1.5px;padding-top:.5px}.CodeMirror-foldmarker{color:#00f;text-shadow:#b9f 1px 1px 2px,#b9f -1px -1px 2px,#b9f 1px -1px 2px,#b9f -1px 1px 2px;font-family:arial;line-height:.3;cursor:pointer}.CodeMirror-foldgutter{width:.7em}.CodeMirror-foldgutter-open,.CodeMirror-foldgutter-folded{cursor:pointer}.CodeMirror-foldgutter-open:after{content:"\25be"}.CodeMirror-foldgutter-folded:after{content:"\25b8"}.CodeMirror-foldgutter{width:var(--px-12)}.CodeMirror-foldmarker{background-color:hsl(var(--color-info));border-radius:var(--border-radius-4);color:hsl(var(--color-base));font-family:inherit;margin:0 var(--px-4);padding:0 var(--px-8);text-shadow:none}.CodeMirror-foldgutter-open,.CodeMirror-foldgutter-folded{color:hsla(var(--color-neutral),var(--alpha-tertiary))}.CodeMirror-foldgutter-open:after,.CodeMirror-foldgutter-folded:after{margin:0 var(--px-2)}.graphiql-editor{height:100%;position:relative;width:100%}.graphiql-editor.hidden{left:-9999px;position:absolute;top:-9999px;visibility:hidden}.CodeMirror-lint-markers{width:16px}.CodeMirror-lint-tooltip{background-color:#ffd;border:1px solid black;border-radius:4px;color:#000;font-family:monospace;font-size:10pt;overflow:hidden;padding:2px 5px;position:fixed;white-space:pre;white-space:pre-wrap;z-index:100;max-width:600px;opacity:0;transition:opacity .4s;-moz-transition:opacity .4s;-webkit-transition:opacity .4s;-o-transition:opacity .4s;-ms-transition:opacity .4s}.CodeMirror-lint-mark{background-position:left bottom;background-repeat:repeat-x}.CodeMirror-lint-mark-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=)}.CodeMirror-lint-mark-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==)}.CodeMirror-lint-marker{background-position:center center;background-repeat:no-repeat;cursor:pointer;display:inline-block;height:16px;width:16px;vertical-align:middle;position:relative}.CodeMirror-lint-message{padding-left:18px;background-position:top left;background-repeat:no-repeat}.CodeMirror-lint-marker-warning,.CodeMirror-lint-message-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=)}.CodeMirror-lint-marker-error,.CodeMirror-lint-message-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=)}.CodeMirror-lint-marker-multiple{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-position:right bottom;width:100%;height:100%}.CodeMirror-lint-line-error{background-color:#b74c5114}.CodeMirror-lint-line-warning{background-color:#ffd3001a}.CodeMirror-lint-mark-error,.CodeMirror-lint-mark-warning{background-repeat:repeat-x;background-size:10px 3px;background-position:0 95%}.cm-s-graphiql .CodeMirror-lint-mark-error{color:hsl(var(--color-error))}.CodeMirror-lint-mark-error{background-image:linear-gradient(45deg,transparent 65%,hsl(var(--color-error)) 80%,transparent 90%),linear-gradient(135deg,transparent 5%,hsl(var(--color-error)) 15%,transparent 25%),linear-gradient(135deg,transparent 45%,hsl(var(--color-error)) 55%,transparent 65%),linear-gradient(45deg,transparent 25%,hsl(var(--color-error)) 35%,transparent 50%)}.cm-s-graphiql .CodeMirror-lint-mark-warning{color:hsl(var(--color-warning))}.CodeMirror-lint-mark-warning{background-image:linear-gradient(45deg,transparent 65%,hsl(var(--color-warning)) 80%,transparent 90%),linear-gradient(135deg,transparent 5%,hsl(var(--color-warning)) 15%,transparent 25%),linear-gradient(135deg,transparent 45%,hsl(var(--color-warning)) 55%,transparent 65%),linear-gradient(45deg,transparent 25%,hsl(var(--color-warning)) 35%,transparent 50%)}.CodeMirror-lint-tooltip{background-color:hsl(var(--color-base));border:var(--popover-border);border-radius:var(--border-radius-8);box-shadow:var(--popover-box-shadow);font-size:var(--font-size-body);font-family:var(--font-family);max-width:600px;overflow:hidden;padding:var(--px-12)}.CodeMirror-lint-message-error,.CodeMirror-lint-message-warning{background-image:none;padding:0}.CodeMirror-lint-message-error{color:hsl(var(--color-error))}.CodeMirror-lint-message-warning{color:hsl(var(--color-warning))}.CodeMirror-hints{position:absolute;z-index:10;overflow:hidden;list-style:none;margin:0;padding:2px;-webkit-box-shadow:2px 3px 5px rgba(0,0,0,.2);-moz-box-shadow:2px 3px 5px rgba(0,0,0,.2);box-shadow:2px 3px 5px #0003;border-radius:3px;border:1px solid silver;background:white;font-size:90%;font-family:monospace;max-height:20em;overflow-y:auto}.CodeMirror-hint{margin:0;padding:0 4px;border-radius:2px;white-space:pre;color:#000;cursor:pointer}li.CodeMirror-hint-active{background:#08f;color:#fff}.CodeMirror-hints{background:hsl(var(--color-base));border:var(--popover-border);border-radius:var(--border-radius-8);box-shadow:var(--popover-box-shadow);display:grid;font-family:var(--font-family);font-size:var(--font-size-body);grid-template-columns:auto fit-content(300px);max-height:264px;padding:0}.CodeMirror-hint{border-radius:var(--border-radius-4);color:hsla(var(--color-neutral),var(--alpha-secondary));grid-column:1 / 2;margin:var(--px-4);padding:var(--px-6) var(--px-8)!important}.CodeMirror-hint:not(:first-child){margin-top:0}li.CodeMirror-hint-active{background:hsla(var(--color-primary),var(--alpha-background-medium));color:hsl(var(--color-primary))}.CodeMirror-hint-information{border-left:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));grid-column:2 / 3;grid-row:1 / 99999;max-height:264px;overflow:auto;padding:var(--px-12)}.CodeMirror-hint-information-header{display:flex;align-items:baseline}.CodeMirror-hint-information-field-name{font-size:var(--font-size-h4);font-weight:var(--font-weight-medium)}.CodeMirror-hint-information-type-name-pill{border:1px solid hsla(var(--color-neutral),var(--alpha-tertiary));border-radius:var(--border-radius-4);color:hsla(var(--color-neutral),var(--alpha-secondary));margin-left:var(--px-6);padding:var(--px-4)}.CodeMirror-hint-information-type-name{color:inherit;text-decoration:none}.CodeMirror-hint-information-type-name:hover{text-decoration:underline dotted}.CodeMirror-hint-information-description{color:hsla(var(--color-neutral),var(--alpha-secondary));margin-top:var(--px-12)}.CodeMirror-info{background-color:hsl(var(--color-base));border:var(--popover-border);border-radius:var(--border-radius-8);box-shadow:var(--popover-box-shadow);color:hsla(var(--color-neutral),1);max-height:300px;max-width:400px;opacity:0;overflow:auto;padding:var(--px-12);position:fixed;transition:opacity .15s;z-index:10}.CodeMirror-info a{color:inherit;text-decoration:none}.CodeMirror-info a:hover{text-decoration:underline dotted}.CodeMirror-info .CodeMirror-info-header{display:flex;align-items:baseline}.CodeMirror-info .CodeMirror-info-header>.type-name,.CodeMirror-info .CodeMirror-info-header>.field-name,.CodeMirror-info .CodeMirror-info-header>.arg-name,.CodeMirror-info .CodeMirror-info-header>.directive-name,.CodeMirror-info .CodeMirror-info-header>.enum-value{font-size:var(--font-size-h4);font-weight:var(--font-weight-medium)}.CodeMirror-info .type-name-pill{border:1px solid hsla(var(--color-neutral),var(--alpha-tertiary));border-radius:var(--border-radius-4);color:hsla(var(--color-neutral),var(--alpha-secondary));margin-left:var(--px-6);padding:var(--px-4)}.CodeMirror-info .info-description{color:hsla(var(--color-neutral),var(--alpha-secondary));margin-top:var(--px-12);overflow:hidden}.CodeMirror-jump-token{text-decoration:underline dotted;cursor:pointer}.auto-inserted-leaf.cm-property{animation-duration:6s;animation-name:insertionFade;border-radius:var(--border-radius-4);padding:var(--px-2)}@keyframes insertionFade{0%,to{background-color:none}15%,85%{background-color:hsla(var(--color-warning),var(--alpha-background-light))}}button.graphiql-toolbar-button{display:flex;align-items:center;justify-content:center;height:var(--toolbar-width);width:var(--toolbar-width)}button.graphiql-toolbar-button.error{background:hsla(var(--color-error),var(--alpha-background-heavy))}.graphiql-execute-button-wrapper{position:relative}button.graphiql-execute-button{background-color:hsl(var(--color-primary));border:none;border-radius:var(--border-radius-8);cursor:pointer;height:var(--toolbar-width);padding:0;width:var(--toolbar-width)}button.graphiql-execute-button:hover{background-color:hsla(var(--color-primary),.9)}button.graphiql-execute-button:active{background-color:hsla(var(--color-primary),.8)}button.graphiql-execute-button:focus{outline:hsla(var(--color-primary),.8) auto 1px}button.graphiql-execute-button>svg{color:#fff;display:block;height:var(--px-16);margin:auto;width:var(--px-16)}.graphiql-toolbar-listbox,button.graphiql-toolbar-menu{display:block;height:var(--toolbar-width);width:var(--toolbar-width)} + +.graphiql-container{background-color:hsl(var(--color-base));display:flex;height:100%;margin:0;overflow:hidden;width:100%}.graphiql-container .graphiql-sidebar{display:flex;flex-direction:column;justify-content:space-between;padding:var(--px-8);width:var(--sidebar-width)}.graphiql-container .graphiql-sidebar .graphiql-sidebar-section{display:flex;flex-direction:column;gap:var(--px-8)}.graphiql-container .graphiql-sidebar button{align-items:center;color:hsla(var(--color-neutral),var(--alpha-secondary));display:flex;height:calc(var(--sidebar-width) - var(--px-8)*2);justify-content:center;width:calc(var(--sidebar-width) - var(--px-8)*2)}.graphiql-container .graphiql-sidebar button.active{color:hsla(var(--color-neutral),1)}.graphiql-container .graphiql-sidebar button:not(:first-child){margin-top:var(--px-4)}.graphiql-container .graphiql-sidebar button>svg{height:var(--px-20);width:var(--px-20)}.graphiql-container .graphiql-main{display:flex;flex:1;min-width:0}.graphiql-container .graphiql-sessions{background-color:hsla(var(--color-neutral),var(--alpha-background-light));border-radius:calc(var(--border-radius-12) + var(--px-8));display:flex;flex:1;flex-direction:column;margin:var(--px-16);margin-left:0;max-height:100%;min-width:0}.graphiql-container .graphiql-session-header{align-items:center;display:flex;height:var(--session-header-height);justify-content:space-between}button.graphiql-tab-add{height:100%;padding:0 var(--px-4)}button.graphiql-tab-add>svg{color:hsla(var(--color-neutral),var(--alpha-secondary));display:block;height:var(--px-16);width:var(--px-16)}.graphiql-add-tab-wrapper{padding:var(--px-12) 0}.graphiql-container .graphiql-session-header-right{align-items:stretch;display:flex}.graphiql-container .graphiql-logo{color:hsla(var(--color-neutral),var(--alpha-secondary));font-size:var(--font-size-h4);font-weight:var(--font-weight-medium);padding:var(--px-12) var(--px-16)}.graphiql-container .graphiql-logo .graphiql-logo-link{color:hsla(var(--color-neutral),var(--alpha-secondary));text-decoration:none}.graphiql-container .graphiql-session{display:flex;flex:1;padding:0 var(--px-8) var(--px-8)}.graphiql-container .graphiql-editors{background-color:hsl(var(--color-base));border-radius:calc(var(--border-radius-12));box-shadow:var(--popover-box-shadow);display:flex;flex:1;flex-direction:column}.graphiql-container .graphiql-editors.full-height{margin-top:calc(var(--px-8) - var(--session-header-height))}.graphiql-container .graphiql-query-editor{border-bottom:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));display:flex;flex:1;padding:var(--px-16)}.graphiql-container .graphiql-query-editor-wrapper{display:flex;flex:1}.graphiql-container .graphiql-toolbar{margin-left:var(--px-16);width:var(--toolbar-width)}.graphiql-container .graphiql-toolbar>*+*{margin-top:var(--px-8)}.graphiql-toolbar-icon{color:hsla(var(--color-neutral),var(--alpha-tertiary));display:block;height:calc(var(--toolbar-width) - var(--px-8)*2);width:calc(var(--toolbar-width) - var(--px-8)*2)}.graphiql-container .graphiql-editor-tools{align-items:center;cursor:row-resize;display:flex;justify-content:space-between;padding:var(--px-8)}.graphiql-container .graphiql-editor-tools button{color:hsla(var(--color-neutral),var(--alpha-secondary))}.graphiql-container .graphiql-editor-tools button.active{color:hsla(var(--color-neutral),1)}.graphiql-container .graphiql-editor-tools-tabs{cursor:auto;display:flex}.graphiql-container .graphiql-editor-tools-tabs>button{padding:var(--px-8) var(--px-12)}.graphiql-container .graphiql-editor-tools-tabs>button+button{margin-left:var(--px-8)}.graphiql-container .graphiql-editor-tool{flex:1;padding:var(--px-16)}.graphiql-container .graphiql-editor-tool,.graphiql-container .graphiql-editor-tools,.graphiql-container .graphiql-toolbar{position:relative}.graphiql-container .graphiql-response{--editor-background:transparent;display:flex;flex:1;flex-direction:column;position:relative}.graphiql-container .graphiql-response .result-window{flex:1;position:relative}.graphiql-container .graphiql-footer{border-top:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy))}.graphiql-container .graphiql-plugin{border-left:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));flex:1;overflow-y:auto;padding:var(--px-16)}.graphiql-container .graphiql-horizontal-drag-bar{cursor:col-resize;width:var(--px-12)}.graphiql-container .graphiql-horizontal-drag-bar:hover:after{border:var(--px-2) solid hsla(var(--color-neutral),var(--alpha-background-heavy));border-radius:var(--border-radius-2);content:"";display:block;height:25%;margin:0 auto;position:relative;top:37.5%;width:0}.graphiql-container .graphiql-chevron-icon{color:hsla(var(--color-neutral),var(--alpha-tertiary));display:block;height:var(--px-12);margin:var(--px-12);width:var(--px-12)}.graphiql-spin{animation:spin .8s linear 0s infinite}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}reach-portal .graphiql-dialog-header{align-items:center;display:flex;justify-content:space-between;padding:var(--px-24)}reach-portal .graphiql-dialog-title{font-size:var(--font-size-h3);font-weight:var(--font-weight-medium)}reach-portal .graphiql-dialog-section{align-items:center;border-top:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));display:flex;justify-content:space-between;padding:var(--px-24)}reach-portal .graphiql-dialog-section>:not(:first-child){margin-left:var(--px-24)}reach-portal .graphiql-dialog-section-title{font-size:var(--font-size-h4);font-weight:var(--font-weight-medium)}reach-portal .graphiql-dialog-section-caption{color:hsla(var(--color-neutral),var(--alpha-secondary))}reach-portal .graphiql-warning-text{color:hsl(var(--color-warning));font-weight:var(--font-weight-medium)}reach-portal .graphiql-table{border-collapse:collapse;width:100%}reach-portal .graphiql-table :is(th,td){border:1px solid hsla(var(--color-neutral),var(--alpha-background-heavy));padding:var(--px-8) var(--px-12)}reach-portal .graphiql-key{background-color:hsla(var(--color-neutral),var(--alpha-background-medium));border-radius:var(--border-radius-4);padding:var(--px-4)}.graphiql-container svg{pointer-events:none} + +/*# sourceMappingURL=graphiql.min.css.map*/ \ No newline at end of file diff --git a/graphql/internal/graphiql/graphiql.min.js b/graphql/internal/graphiql/graphiql.min.js new file mode 100644 index 0000000000..73c32f32a4 --- /dev/null +++ b/graphql/internal/graphiql/graphiql.min.js @@ -0,0 +1,3 @@ +/*! For license information please see graphiql.min.js.LICENSE.txt */ +!function(){var e,t,n={8042:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,n=function(){"use strict";function e(){const e={};return e.promise=new Promise(((t,n)=>{e.resolve=t,e.reject=n})),e}Object.defineProperty(t,"__esModule",{value:!0});const n=Symbol(),r=Symbol();function i(){let t=!0;const i=[];let o=e();const a=e(),s=async function*(){for(;;)if(i.length>0)yield i.shift();else{const e=await Promise.race([o.promise,a.promise]);if(e===n)break;if(e!==r)throw e}}();const l=s.return.bind(s);s.return=function(){return t=!1,a.resolve(n),l(...arguments)};const u=s.throw.bind(s);return s.throw=e=>(t=!1,a.resolve(e),u(e)),{pushValue:function(n){!1!==t&&(i.push(n),o.resolve(r),o=e())},asyncIterableIterator:s}}t.applyAsyncIterableIteratorToSink=function(e,t){return(async()=>{try{for await(const n of e)t.next(n);t.complete()}catch(e){t.error(e)}})(),()=>{var t;null===(t=e.return)||void 0===t||t.call(e)}},t.isAsyncIterable=function(e){return"object"==typeof e&&null!==e&&("AsyncGenerator"===e[Symbol.toStringTag]||Symbol.asyncIterator&&Symbol.asyncIterator in e)},t.makeAsyncIterableIteratorFromSink=e=>{const{pushValue:t,asyncIterableIterator:n}=i(),r=e({next:e=>{t(e)},complete:()=>{n.return()},error:e=>{n.throw(e)}}),o=n.return;let a;return n.return=()=>(void 0===a&&(r(),a=o()),a),n},t.makePushPullAsyncIterableIterator=i},void 0===(r=n.apply(t,[]))||(e.exports=r)},7674:function(e,t,n){var r,i;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(i="function"==typeof(r=function(){"use strict";var e=Object.create?function(e,t,n,r){void 0===r&&(r=n),Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]},r=function(t,n){for(var r in t)"default"===r||Object.prototype.hasOwnProperty.call(n,r)||e(n,t,r)};Object.defineProperty(t,"__esModule",{value:!0}),r(n(5313),t),r(n(6718),t),r(n(863),t)})?r.apply(t,[]):r)||(e.exports=i)},5609:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(r="function"==typeof(n=function(e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.R=e.P=void 0;var t=Object.defineProperty,n=(e,n)=>t(e,"name",{value:n,configurable:!0});class r{constructor(e,t){this.containsPosition=e=>this.start.line===e.line?this.start.character<=e.character:this.end.line===e.line?this.end.character>=e.character:this.start.line<=e.line&&this.end.line>=e.line,this.start=e,this.end=t}setStart(e,t){this.start=new i(e,t)}setEnd(e,t){this.end=new i(e,t)}}e.R=r,n(r,"Range");class i{constructor(e,t){this.lessThanOrEqualTo=e=>this.linei(e,"name",{value:t,configurable:!0});function a(e,n){const i={schema:e,type:null,parentType:null,inputType:null,directiveDef:null,fieldDef:null,argDef:null,argDefs:null,objectFieldDefs:null};return(0,r.f)(n,(n=>{var r,o;switch(n.kind){case"Query":case"ShortQuery":i.type=e.getQueryType();break;case"Mutation":i.type=e.getMutationType();break;case"Subscription":i.type=e.getSubscriptionType();break;case"InlineFragment":case"FragmentDefinition":n.type&&(i.type=e.getType(n.type));break;case"Field":case"AliasedField":i.fieldDef=i.type&&n.name?s(e,i.parentType,n.name):null,i.type=null===(r=i.fieldDef)||void 0===r?void 0:r.type;break;case"SelectionSet":i.parentType=i.type?(0,t.getNamedType)(i.type):null;break;case"Directive":i.directiveDef=n.name?e.getDirective(n.name):null;break;case"Arguments":const a=n.prevState?"Field"===n.prevState.kind?i.fieldDef:"Directive"===n.prevState.kind?i.directiveDef:"AliasedField"===n.prevState.kind?n.prevState.name&&s(e,i.parentType,n.prevState.name):null:null;i.argDefs=a?a.args:null;break;case"Argument":if(i.argDef=null,i.argDefs)for(let e=0;ee.value===n.name)):null;break;case"ListValue":const c=i.inputType?(0,t.getNullableType)(i.inputType):null;i.inputType=c instanceof t.GraphQLList?c.ofType:null;break;case"ObjectValue":const d=i.inputType?(0,t.getNamedType)(i.inputType):null;i.objectFieldDefs=d instanceof t.GraphQLInputObjectType?d.getFields():null;break;case"ObjectField":const f=n.name&&i.objectFieldDefs?i.objectFieldDefs[n.name]:null;i.inputType=null==f?void 0:f.type;break;case"NamedType":i.type=n.name?e.getType(n.name):null}})),i}function s(e,r,i){return i===n.S.name&&e.getQueryType()===r?n.S:i===n.T.name&&e.getQueryType()===r?n.T:i===n.a.name&&(0,t.isCompositeType)(r)?n.a:r&&r.getFields?r.getFields()[i]:void 0}function l(e,t){for(let n=0;nn(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};!function(e){function t(t){return function(n,i){var o=i.line,a=n.getLine(o);function s(t){for(var r,s=i.ch,l=0;;){var u=s<=0?-1:a.lastIndexOf(t[0],s-1);if(-1!=u){if(1==l&&ut.lastLine())return null;var r=t.getTokenAt(e.Pos(n,1));if(/\S/.test(r.string)||(r=t.getTokenAt(e.Pos(n,r.end+1))),"keyword"!=r.type||"import"!=r.string)return null;for(var i=n,o=Math.min(t.lastLine(),n+10);i<=o;++i){var a=t.getLine(i).indexOf(";");if(-1!=a)return{startCh:r.end,end:e.Pos(i,a)}}}r(i,"hasImport");var o,a=n.line,s=i(a);if(!s||i(a-1)||(o=i(a-2))&&o.end.line==a-1)return null;for(var l=s.end;;){var u=i(l.line+1);if(null==u)break;l=u.end}return{from:t.clipPos(e.Pos(a,s.startCh+1)),to:l}})),e.registerHelper("fold","include",(function(t,n){function i(n){if(nt.lastLine())return null;var r=t.getTokenAt(e.Pos(n,1));return/\S/.test(r.string)||(r=t.getTokenAt(e.Pos(n,r.end+1))),"meta"==r.type&&"#include"==r.string.slice(0,8)?r.start+8:void 0}r(i,"hasInclude");var o=n.line,a=i(o);if(null==a||null!=i(o-1))return null;for(var s=o;null!=i(s+1);)++s;return{from:e.Pos(o,a+1),to:t.clipPos(e.Pos(s))}}))}(t.a.exports);var a=i({__proto__:null,default:o.exports},[o.exports]);e.b=a})?r.apply(t,i):r)||(e.exports=o)},5728:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535)],void 0===(o="function"==typeof(r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.c=void 0;var n=Object.defineProperty,r=(e,t)=>n(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};!function(e){var t={pairs:"()[]{}''\"\"",closeBefore:")]}'\":;>",triples:"",explode:"[]{}"},n=e.Pos;function i(e,n){return"pairs"==n&&"string"==typeof e?e:"object"==typeof e&&null!=e[n]?e[n]:t[n]}e.defineOption("autoCloseBrackets",!1,(function(t,n,r){r&&r!=e.Init&&(t.removeKeyMap(o),t.state.closeBrackets=null),n&&(a(i(n,"pairs")),t.state.closeBrackets=n,t.addKeyMap(o))})),r(i,"getOption");var o={Backspace:u,Enter:c};function a(e){for(var t=0;t=0;s--){var c=a[s].head;t.replaceRange("",n(c.line,c.ch-1),n(c.line,c.ch+1),"+delete")}}function c(t){var n=l(t),r=n&&i(n,"explode");if(!r||t.getOption("disableInput"))return e.Pass;for(var o=t.listSelections(),a=0;a0?{line:a.head.line,ch:a.head.ch+t}:{line:a.head.line-1};n.push({anchor:s,head:s})}e.setSelections(n,i)}function f(t){var r=e.cmpPos(t.anchor,t.head)>0;return{anchor:new n(t.anchor.line,t.anchor.ch+(r?-1:1)),head:new n(t.head.line,t.head.ch+(r?1:-1))}}function p(t,r){var o=l(t);if(!o||t.getOption("disableInput"))return e.Pass;var a=i(o,"pairs"),s=a.indexOf(r);if(-1==s)return e.Pass;for(var u,c=i(o,"closeBefore"),p=i(o,"triples"),h=a.charAt(s+1)==r,g=t.listSelections(),v=s%2==0,y=0;y1&&p.indexOf(r)>=0&&t.getRange(n(T.line,T.ch-2),T)==r+r){if(T.ch>2&&/\bstring/.test(t.getTokenTypeAt(n(T.line,T.ch-2))))return e.Pass;b="addFour"}else if(h){var C=0==T.ch?" ":t.getRange(n(T.line,T.ch-1),T);if(e.isWordChar(w)||C==r||e.isWordChar(C))return e.Pass;b="both"}else{if(!v||!(0===w.length||/\s/.test(w)||c.indexOf(w)>-1))return e.Pass;b="both"}else b=h&&m(t,T)?"both":p.indexOf(r)>=0&&t.getRange(T,n(T.line,T.ch+3))==r+r+r?"skipThree":"skip";if(u){if(u!=b)return e.Pass}else u=b}var S=s%2?a.charAt(s-1):r,x=s%2?r:a.charAt(s+1);t.operation((function(){if("skip"==u)d(t,1);else if("skipThree"==u)d(t,3);else if("surround"==u){for(var e=t.getSelections(),n=0;nn(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};e.a=o,function(e,n){t.c,e.exports=function(){var e=navigator.userAgent,t=navigator.platform,n=/gecko\/\d/i.test(e),i=/MSIE \d/.test(e),o=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(e),a=/Edge\/(\d+)/.exec(e),s=i||o||a,l=s&&(i?document.documentMode||6:+(a||o)[1]),u=!a&&/WebKit\//.test(e),c=u&&/Qt\/\d+\.\d+/.test(e),d=!a&&/Chrome\//.test(e),f=/Opera\//.test(e),p=/Apple Computer/.test(navigator.vendor),h=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(e),m=/PhantomJS/.test(e),g=p&&(/Mobile\/\w+/.test(e)||navigator.maxTouchPoints>2),v=/Android/.test(e),y=g||v||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(e),b=g||/Mac/.test(t),E=/\bCrOS\b/.test(e),T=/win/i.test(t),w=f&&e.match(/Version\/(\d*\.\d*)/);w&&(w=Number(w[1])),w&&w>=15&&(f=!1,u=!0);var C=b&&(c||f&&(null==w||w<12.11)),S=n||s&&l>=9;function x(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}r(x,"classTest");var k,N=r((function(e,t){var n=e.className,r=x(t).exec(n);if(r){var i=n.slice(r.index+r[0].length);e.className=n.slice(0,r.index)+(i?r[1]+i:"")}}),"rmClass");function _(e){for(var t=e.childNodes.length;t>0;--t)e.removeChild(e.firstChild);return e}function O(e,t){return _(e).appendChild(t)}function I(e,t,n,r){var i=document.createElement(e);if(n&&(i.className=n),r&&(i.style.cssText=r),"string"==typeof t)i.appendChild(document.createTextNode(t));else if(t)for(var o=0;o=t)return a+(t-o);a+=s-o,a+=n-a%n,o=s+1}}g?F=r((function(e){e.selectionStart=0,e.selectionEnd=e.value.length}),"selectInput"):s&&(F=r((function(e){try{e.select()}catch(e){}}),"selectInput")),r(P,"bind"),r(j,"copyObj"),r(V,"countColumn");var U=r((function(){this.id=null,this.f=null,this.time=0,this.handler=P(this.onTimeout,this)}),"Delayed");function B(e,t){for(var n=0;n=t)return r+Math.min(a,t-i);if(i+=o-r,r=o+1,(i+=n-i%n)>=t)return r}}r(W,"findColumn");var K=[""];function Q(e){for(;K.length<=e;)K.push(X(K)+" ");return K[e]}function X(e){return e[e.length-1]}function Y(e,t){for(var n=[],r=0;r"€"&&(e.toUpperCase()!=e.toLowerCase()||te.test(e))}function re(e,t){return t?!!(t.source.indexOf("\\w")>-1&&ne(e))||t.test(e):ne(e)}function ie(e){for(var t in e)if(e.hasOwnProperty(t)&&e[t])return!1;return!0}r(ne,"isWordCharBasic"),r(re,"isWordChar"),r(ie,"isEmpty");var oe=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;function ae(e){return e.charCodeAt(0)>=768&&oe.test(e)}function se(e,t,n){for(;(n<0?t>0:tn?-1:1;;){if(t==n)return t;var i=(t+n)/2,o=r<0?Math.ceil(i):Math.floor(i);if(o==t)return e(o)?t:n;e(o)?n=o:t=o+r}}function ue(e,t,n,r){if(!e)return r(t,n,"ltr",0);for(var i=!1,o=0;ot||t==n&&a.to==t)&&(r(Math.max(a.from,t),Math.min(a.to,n),1==a.level?"rtl":"ltr",o),i=!0)}i||r(t,n,"ltr")}r(ae,"isExtendingChar"),r(se,"skipExtendingChars"),r(le,"findFirst"),r(ue,"iterateBidiSections");var ce=null;function de(e,t,n){var r;ce=null;for(var i=0;it)return i;o.to==t&&(o.from!=o.to&&"before"==n?r=i:ce=i),o.from==t&&(o.from!=o.to&&"before"!=n?r=i:ce=i)}return null!=r?r:ce}r(de,"getBidiPartAt");var fe=function(){var e="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",t="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";function n(n){return n<=247?e.charAt(n):1424<=n&&n<=1524?"R":1536<=n&&n<=1785?t.charAt(n-1536):1774<=n&&n<=2220?"r":8192<=n&&n<=8203?"w":8204==n?"b":"L"}r(n,"charType");var i=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,o=/[stwN]/,a=/[LRr]/,s=/[Lb1n]/,l=/[1n]/;function u(e,t,n){this.level=e,this.from=t,this.to=n}return r(u,"BidiSpan"),function(e,t){var r="ltr"==t?"L":"R";if(0==e.length||"ltr"==t&&!i.test(e))return!1;for(var c=e.length,d=[],f=0;f-1&&(r[t]=i.slice(0,o).concat(i.slice(o+1)))}}}function ye(e,t){var n=ge(e,t);if(n.length)for(var r=Array.prototype.slice.call(arguments,2),i=0;i0}function we(e){e.prototype.on=function(e,t){me(this,e,t)},e.prototype.off=function(e,t){ve(this,e,t)}}function Ce(e){e.preventDefault?e.preventDefault():e.returnValue=!1}function Se(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}function xe(e){return null!=e.defaultPrevented?e.defaultPrevented:0==e.returnValue}function ke(e){Ce(e),Se(e)}function Ne(e){return e.target||e.srcElement}function _e(e){var t=e.which;return null==t&&(1&e.button?t=1:2&e.button?t=3:4&e.button&&(t=2)),b&&e.ctrlKey&&1==t&&(t=3),t}r(ge,"getHandlers"),r(ve,"off"),r(ye,"signal"),r(be,"signalDOMEvent"),r(Ee,"signalCursorActivity"),r(Te,"hasHandler"),r(we,"eventMixin"),r(Ce,"e_preventDefault"),r(Se,"e_stopPropagation"),r(xe,"e_defaultPrevented"),r(ke,"e_stop"),r(Ne,"e_target"),r(_e,"e_button");var Oe,Ie,De=function(){if(s&&l<9)return!1;var e=I("div");return"draggable"in e||"dragDrop"in e}();function Le(e){if(null==Oe){var t=I("span","​");O(e,I("span",[t,document.createTextNode("x")])),0!=e.firstChild.offsetHeight&&(Oe=t.offsetWidth<=1&&t.offsetHeight>2&&!(s&&l<8))}var n=Oe?I("span","​"):I("span"," ",null,"display: inline-block; width: 1px; margin-right: -1px");return n.setAttribute("cm-text",""),n}function Ae(e){if(null!=Ie)return Ie;var t=O(e,document.createTextNode("AØ®A")),n=k(t,0,1).getBoundingClientRect(),r=k(t,1,2).getBoundingClientRect();return _(e),!(!n||n.left==n.right)&&(Ie=r.right-n.right<3)}r(Le,"zeroWidthElement"),r(Ae,"hasBadBidiRects");var Me,Re=3!="\n\nb".split(/\n/).length?function(e){for(var t=0,n=[],r=e.length;t<=r;){var i=e.indexOf("\n",t);-1==i&&(i=e.length);var o=e.slice(t,"\r"==e.charAt(i-1)?i-1:i),a=o.indexOf("\r");-1!=a?(n.push(o.slice(0,a)),t+=a+1):(n.push(o),t=i+1)}return n}:function(e){return e.split(/\r\n?|\n/)},Fe=window.getSelection?function(e){try{return e.selectionStart!=e.selectionEnd}catch(e){return!1}}:function(e){var t;try{t=e.ownerDocument.selection.createRange()}catch(e){}return!(!t||t.parentElement()!=e)&&0!=t.compareEndPoints("StartToEnd",t)},Pe="oncopy"in(Me=I("div"))||(Me.setAttribute("oncopy","return;"),"function"==typeof Me.oncopy),je=null;function Ve(e){if(null!=je)return je;var t=O(e,I("span","x")),n=t.getBoundingClientRect(),r=k(t,0,1).getBoundingClientRect();return je=Math.abs(n.left-r.left)>1}r(Ve,"hasBadZoomedRects");var Ue={},Be={};function $e(e,t){arguments.length>2&&(t.dependencies=Array.prototype.slice.call(arguments,2)),Ue[e]=t}function qe(e,t){Be[e]=t}function He(e){if("string"==typeof e&&Be.hasOwnProperty(e))e=Be[e];else if(e&&"string"==typeof e.name&&Be.hasOwnProperty(e.name)){var t=Be[e.name];"string"==typeof t&&(t={name:t}),(e=ee(t,e)).name=t.name}else{if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+xml$/.test(e))return He("application/xml");if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+json$/.test(e))return He("application/json")}return"string"==typeof e?{name:e}:e||{name:"null"}}function Ge(e,t){t=He(t);var n=Ue[t.name];if(!n)return Ge(e,"text/plain");var r=n(e,t);if(ze.hasOwnProperty(t.name)){var i=ze[t.name];for(var o in i)i.hasOwnProperty(o)&&(r.hasOwnProperty(o)&&(r["_"+o]=r[o]),r[o]=i[o])}if(r.name=t.name,t.helperType&&(r.helperType=t.helperType),t.modeProps)for(var a in t.modeProps)r[a]=t.modeProps[a];return r}r($e,"defineMode"),r(qe,"defineMIME"),r(He,"resolveMode"),r(Ge,"getMode");var ze={};function We(e,t){j(t,ze.hasOwnProperty(e)?ze[e]:ze[e]={})}function Ke(e,t){if(!0===t)return t;if(e.copyState)return e.copyState(t);var n={};for(var r in t){var i=t[r];i instanceof Array&&(i=i.concat([])),n[r]=i}return n}function Qe(e,t){for(var n;e.innerMode&&(n=e.innerMode(t))&&n.mode!=e;)t=n.state,e=n.mode;return n||{mode:e,state:t}}function Xe(e,t,n){return!e.startState||e.startState(t,n)}r(We,"extendMode"),r(Ke,"copyState"),r(Qe,"innerMode"),r(Xe,"startState");var Ye=r((function(e,t,n){this.pos=this.start=0,this.string=e,this.tabSize=t||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0,this.lineOracle=n}),"StringStream");function Je(e,t){if((t-=e.first)<0||t>=e.size)throw new Error("There is no line "+(t+e.first)+" in the document.");for(var n=e;!n.lines;)for(var r=0;;++r){var i=n.children[r],o=i.chunkSize();if(t=e.first&&tn?at(n,Je(e,n).text.length):ht(t,Je(e,t.line).text.length)}function ht(e,t){var n=e.ch;return null==n||n>t?at(e.line,t):n<0?at(e.line,0):e}function mt(e,t){for(var n=[],r=0;r=this.string.length},Ye.prototype.sol=function(){return this.pos==this.lineStart},Ye.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},Ye.prototype.next=function(){if(this.post},Ye.prototype.eatSpace=function(){for(var e=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>e},Ye.prototype.skipToEnd=function(){this.pos=this.string.length},Ye.prototype.skipTo=function(e){var t=this.string.indexOf(e,this.pos);if(t>-1)return this.pos=t,!0},Ye.prototype.backUp=function(e){this.pos-=e},Ye.prototype.column=function(){return this.lastColumnPos0?null:(i&&!1!==t&&(this.pos+=i[0].length),i)}var o=r((function(e){return n?e.toLowerCase():e}),"cased");if(o(this.string.substr(this.pos,e.length))==o(e))return!1!==t&&(this.pos+=e.length),!0},Ye.prototype.current=function(){return this.string.slice(this.start,this.pos)},Ye.prototype.hideFirstChars=function(e,t){this.lineStart+=e;try{return t()}finally{this.lineStart-=e}},Ye.prototype.lookAhead=function(e){var t=this.lineOracle;return t&&t.lookAhead(e)},Ye.prototype.baseToken=function(){var e=this.lineOracle;return e&&e.baseToken(this.pos)},r(Je,"getLine"),r(Ze,"getBetween"),r(et,"getLines"),r(tt,"updateLineHeight"),r(nt,"lineNo"),r(rt,"lineAtHeight"),r(it,"isLine"),r(ot,"lineNumberFor"),r(at,"Pos"),r(st,"cmp"),r(lt,"equalCursorPos"),r(ut,"copyPos"),r(ct,"maxPos"),r(dt,"minPos"),r(ft,"clipLine"),r(pt,"clipPos"),r(ht,"clipToLen"),r(mt,"clipPosArray");var gt=r((function(e,t){this.state=e,this.lookAhead=t}),"SavedContext"),vt=r((function(e,t,n,r){this.state=t,this.doc=e,this.line=n,this.maxLookAhead=r||0,this.baseTokens=null,this.baseTokenPos=1}),"Context");function yt(e,t,n,i){var o=[e.state.modeGen],a={};Nt(e,t.text,e.doc.mode,n,(function(e,t){return o.push(e,t)}),a,i);for(var s=n.state,l=r((function(r){n.baseTokens=o;var i=e.state.overlays[r],l=1,u=0;n.state=!0,Nt(e,t.text,i.mode,n,(function(e,t){for(var n=l;ue&&o.splice(l,1,e,o[l+1],r),l+=2,u=Math.min(e,r)}if(t)if(i.opaque)o.splice(n,l-n,e,"overlay "+t),l=n+2;else for(;ne.options.maxHighlightLength&&Ke(e.doc.mode,r.state),o=yt(e,t,r);i&&(r.state=i),t.stateAfter=r.save(!i),t.styles=o.styles,o.classes?t.styleClasses=o.classes:t.styleClasses&&(t.styleClasses=null),n===e.doc.highlightFrontier&&(e.doc.modeFrontier=Math.max(e.doc.modeFrontier,++e.doc.highlightFrontier))}return t.styles}function Et(e,t,n){var r=e.doc,i=e.display;if(!r.mode.startState)return new vt(r,!0,t);var o=_t(e,t,n),a=o>r.first&&Je(r,o-1).stateAfter,s=a?vt.fromSaved(r,a,o):new vt(r,Xe(r.mode),o);return r.iter(o,t,(function(n){Tt(e,n.text,s);var r=s.line;n.stateAfter=r==t-1||r%5==0||r>=i.viewFrom&&rt.start)return o}throw new Error("Mode "+e.name+" failed to advance stream.")}vt.prototype.lookAhead=function(e){var t=this.doc.getLine(this.line+e);return null!=t&&e>this.maxLookAhead&&(this.maxLookAhead=e),t},vt.prototype.baseToken=function(e){if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=e;)this.baseTokenPos+=2;var t=this.baseTokens[this.baseTokenPos+1];return{type:t&&t.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-e}},vt.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},vt.fromSaved=function(e,t,n){return t instanceof gt?new vt(e,Ke(e.mode,t.state),n,t.lookAhead):new vt(e,Ke(e.mode,t),n)},vt.prototype.save=function(e){var t=!1!==e?Ke(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new gt(t,this.maxLookAhead):t},r(yt,"highlightLine"),r(bt,"getLineStyles"),r(Et,"getContextBefore"),r(Tt,"processLine"),r(wt,"callBlankLine"),r(Ct,"readToken");var St=r((function(e,t,n){this.start=e.start,this.end=e.pos,this.string=e.current(),this.type=t||null,this.state=n}),"Token");function xt(e,t,n,r){var i,o,a=e.doc,s=a.mode,l=Je(a,(t=pt(a,t)).line),u=Et(e,t.line,n),c=new Ye(l.text,e.options.tabSize,u);for(r&&(o=[]);(r||c.pose.options.maxHighlightLength?(s=!1,a&&Tt(e,t,r,d.pos),d.pos=t.length,l=null):l=kt(Ct(n,d,r.state,f),o),f){var p=f[0].name;p&&(l="m-"+(l?p+" "+l:p))}if(!s||c!=l){for(;ua;--s){if(s<=o.first)return o.first;var l=Je(o,s-1),u=l.stateAfter;if(u&&(!n||s+(u instanceof gt?u.lookAhead:0)<=o.modeFrontier))return s;var c=V(l.text,null,e.options.tabSize);(null==i||r>c)&&(i=s-1,r=c)}return i}function Ot(e,t){if(e.modeFrontier=Math.min(e.modeFrontier,t),!(e.highlightFrontiern;r--){var i=Je(e,r).stateAfter;if(i&&(!(i instanceof gt)||r+i.lookAhead=t:o.to>t);(r||(r=[])).push(new Mt(a,o.from,s?null:o.to))}}return r}function Vt(e,t,n){var r;if(e)for(var i=0;i=t:o.to>t)||o.from==t&&"bookmark"==a.type&&(!n||o.marker.insertLeft)){var s=null==o.from||(a.inclusiveLeft?o.from<=t:o.from0&&s)for(var b=0;b0)){var c=[l,1],d=st(u.from,s.from),f=st(u.to,s.to);(d<0||!a.inclusiveLeft&&!d)&&c.push({from:u.from,to:s.from}),(f>0||!a.inclusiveRight&&!f)&&c.push({from:s.to,to:u.to}),i.splice.apply(i,c),l+=c.length-3}}return i}function qt(e){var t=e.markedSpans;if(t){for(var n=0;nt)&&(!n||Wt(n,o.marker)<0)&&(n=o.marker)}return n}function Jt(e,t,n,r,i){var o=Je(e,t),a=Dt&&o.markedSpans;if(a)for(var s=0;s=0&&d<=0||c<=0&&d>=0)&&(c<=0&&(l.marker.inclusiveRight&&i.inclusiveLeft?st(u.to,n)>=0:st(u.to,n)>0)||c>=0&&(l.marker.inclusiveRight&&i.inclusiveLeft?st(u.from,r)<=0:st(u.from,r)<0)))return!0}}}function Zt(e){for(var t;t=Qt(e);)e=t.find(-1,!0).line;return e}function en(e){for(var t;t=Xt(e);)e=t.find(1,!0).line;return e}function tn(e){for(var t,n;t=Xt(e);)e=t.find(1,!0).line,(n||(n=[])).push(e);return n}function nn(e,t){var n=Je(e,t),r=Zt(n);return n==r?t:nt(r)}function rn(e,t){if(t>e.lastLine())return t;var n,r=Je(e,t);if(!on(e,r))return t;for(;n=Xt(r);)r=n.find(1,!0).line;return nt(r)+1}function on(e,t){var n=Dt&&t.markedSpans;if(n)for(var r=void 0,i=0;it.maxLineLength&&(t.maxLineLength=n,t.maxLine=e)}))}r(Lt,"seeReadOnlySpans"),r(At,"seeCollapsedSpans"),r(Mt,"MarkedSpan"),r(Rt,"getMarkedSpanFor"),r(Ft,"removeMarkedSpan"),r(Pt,"addMarkedSpan"),r(jt,"markedSpansBefore"),r(Vt,"markedSpansAfter"),r(Ut,"stretchSpansOverChange"),r(Bt,"clearEmptySpans"),r($t,"removeReadOnlyRanges"),r(qt,"detachMarkedSpans"),r(Ht,"attachMarkedSpans"),r(Gt,"extraLeft"),r(zt,"extraRight"),r(Wt,"compareCollapsedMarkers"),r(Kt,"collapsedSpanAtSide"),r(Qt,"collapsedSpanAtStart"),r(Xt,"collapsedSpanAtEnd"),r(Yt,"collapsedSpanAround"),r(Jt,"conflictingCollapsedRange"),r(Zt,"visualLine"),r(en,"visualLineEnd"),r(tn,"visualLineContinued"),r(nn,"visualLineNo"),r(rn,"visualLineEndNo"),r(on,"lineIsHidden"),r(an,"lineIsHiddenInner"),r(sn,"heightAtLine"),r(ln,"lineLength"),r(un,"findMaxLine");var cn=r((function(e,t,n){this.text=e,Ht(this,t),this.height=n?n(this):1}),"Line");function dn(e,t,n,r){e.text=t,e.stateAfter&&(e.stateAfter=null),e.styles&&(e.styles=null),null!=e.order&&(e.order=null),qt(e),Ht(e,n);var i=r?r(e):1;i!=e.height&&tt(e,i)}function fn(e){e.parent=null,qt(e)}cn.prototype.lineNo=function(){return nt(this)},we(cn),r(dn,"updateLine"),r(fn,"cleanUpLine");var pn={},hn={};function mn(e,t){if(!e||/^\s*$/.test(e))return null;var n=t.addModeClass?hn:pn;return n[e]||(n[e]=e.replace(/\S+/g,"cm-$&"))}function gn(e,t){var n=D("span",null,null,u?"padding-right: .1px":null),r={pre:D("pre",[n],"CodeMirror-line"),content:n,col:0,pos:0,cm:e,trailingSpace:!1,splitSpaces:e.getOption("lineWrapping")};t.measure={};for(var i=0;i<=(t.rest?t.rest.length:0);i++){var o=i?t.rest[i-1]:t.line,a=void 0;r.pos=0,r.addToken=yn,Ae(e.display.measure)&&(a=pe(o,e.doc.direction))&&(r.addToken=En(r.addToken,a)),r.map=[],wn(o,r,bt(e,o,t!=e.display.externalMeasured&&nt(o))),o.styleClasses&&(o.styleClasses.bgClass&&(r.bgClass=R(o.styleClasses.bgClass,r.bgClass||"")),o.styleClasses.textClass&&(r.textClass=R(o.styleClasses.textClass,r.textClass||""))),0==r.map.length&&r.map.push(0,0,r.content.appendChild(Le(e.display.measure))),0==i?(t.measure.map=r.map,t.measure.cache={}):((t.measure.maps||(t.measure.maps=[])).push(r.map),(t.measure.caches||(t.measure.caches=[])).push({}))}if(u){var s=r.content.lastChild;(/\bcm-tab\b/.test(s.className)||s.querySelector&&s.querySelector(".cm-tab"))&&(r.content.className="cm-tab-wrap-hack")}return ye(e,"renderLine",e,t.line,r.pre),r.pre.className&&(r.textClass=R(r.pre.className,r.textClass||"")),r}function vn(e){var t=I("span","•","cm-invalidchar");return t.title="\\u"+e.charCodeAt(0).toString(16),t.setAttribute("aria-label",t.title),t}function yn(e,t,n,r,i,o,a){if(t){var u,c=e.splitSpaces?bn(t,e.trailingSpace):t,d=e.cm.state.specialChars,f=!1;if(d.test(t)){u=document.createDocumentFragment();for(var p=0;;){d.lastIndex=p;var h=d.exec(t),m=h?h.index-p:t.length-p;if(m){var g=document.createTextNode(c.slice(p,p+m));s&&l<9?u.appendChild(I("span",[g])):u.appendChild(g),e.map.push(e.pos,e.pos+m,g),e.col+=m,e.pos+=m}if(!h)break;p+=m+1;var v=void 0;if("\t"==h[0]){var y=e.cm.options.tabSize,b=y-e.col%y;(v=u.appendChild(I("span",Q(b),"cm-tab"))).setAttribute("role","presentation"),v.setAttribute("cm-text","\t"),e.col+=b}else"\r"==h[0]||"\n"==h[0]?((v=u.appendChild(I("span","\r"==h[0]?"â":"â¤","cm-invalidchar"))).setAttribute("cm-text",h[0]),e.col+=1):((v=e.cm.options.specialCharPlaceholder(h[0])).setAttribute("cm-text",h[0]),s&&l<9?u.appendChild(I("span",[v])):u.appendChild(v),e.col+=1);e.map.push(e.pos,e.pos+1,v),e.pos++}}else e.col+=t.length,u=document.createTextNode(c),e.map.push(e.pos,e.pos+t.length,u),s&&l<9&&(f=!0),e.pos+=t.length;if(e.trailingSpace=32==c.charCodeAt(t.length-1),n||r||i||f||o||a){var E=n||"";r&&(E+=r),i&&(E+=i);var T=I("span",[u],E,o);if(a)for(var w in a)a.hasOwnProperty(w)&&"style"!=w&&"class"!=w&&T.setAttribute(w,a[w]);return e.content.appendChild(T)}e.content.appendChild(u)}}function bn(e,t){if(e.length>1&&!/ /.test(e))return e;for(var n=t,r="",i=0;iu&&d.from<=u);f++);if(d.to>=c)return e(n,r,i,o,a,s,l);e(n,r.slice(0,d.to-u),i,o,null,s,l),o=null,r=r.slice(d.to-u),u=d.to}}}function Tn(e,t,n,r){var i=!r&&n.widgetNode;i&&e.map.push(e.pos,e.pos+t,i),!r&&e.cm.display.input.needsContentAttribute&&(i||(i=e.content.appendChild(document.createElement("span"))),i.setAttribute("cm-marker",n.id)),i&&(e.cm.display.input.setUneditable(i),e.content.appendChild(i)),e.pos+=t,e.trailingSpace=!1}function wn(e,t,n){var r=e.markedSpans,i=e.text,o=0;if(r)for(var a,s,l,u,c,d,f,p=i.length,h=0,m=1,g="",v=0;;){if(v==h){l=u=c=s="",f=null,d=null,v=1/0;for(var y=[],b=void 0,E=0;Eh||w.collapsed&&T.to==h&&T.from==h)){if(null!=T.to&&T.to!=h&&v>T.to&&(v=T.to,u=""),w.className&&(l+=" "+w.className),w.css&&(s=(s?s+";":"")+w.css),w.startStyle&&T.from==h&&(c+=" "+w.startStyle),w.endStyle&&T.to==v&&(b||(b=[])).push(w.endStyle,T.to),w.title&&((f||(f={})).title=w.title),w.attributes)for(var C in w.attributes)(f||(f={}))[C]=w.attributes[C];w.collapsed&&(!d||Wt(d.marker,w)<0)&&(d=T)}else T.from>h&&v>T.from&&(v=T.from)}if(b)for(var S=0;S=p)break;for(var k=Math.min(p,v);;){if(g){var N=h+g.length;if(!d){var _=N>k?g.slice(0,k-h):g;t.addToken(t,_,a?a+l:l,c,h+_.length==v?u:"",s,f)}if(N>=k){g=g.slice(k-h),h=k;break}h=N,c=""}g=i.slice(o,o=n[m++]),a=mn(n[m++],t.cm.options)}}else for(var O=1;O2&&o.push((l.bottom+u.top)/2-n.top)}}o.push(n.bottom-n.top)}}function Zn(e,t,n){if(e.line==t)return{map:e.measure.map,cache:e.measure.cache};if(e.rest){for(var r=0;rn)return{map:e.measure.maps[i],cache:e.measure.caches[i],before:!0}}}function er(e,t){var n=nt(t=Zt(t)),r=e.display.externalMeasured=new Cn(e.doc,t,n);r.lineN=n;var i=r.built=gn(e,r);return r.text=i.pre,O(e.display.lineMeasure,i.pre),r}function tr(e,t,n,r){return ir(e,rr(e,t),n,r)}function nr(e,t){if(t>=e.display.viewFrom&&t=n.lineN&&tt)&&(i=(o=l-s)-1,t>=l&&(a="right")),null!=i){if(r=e[u+2],s==l&&n==(r.insertLeft?"left":"right")&&(a=n),"left"==n&&0==i)for(;u&&e[u-2]==e[u-3]&&e[u-1].insertLeft;)r=e[2+(u-=3)],a="left";if("right"==n&&i==l-s)for(;u=0&&(n=e[i]).left==n.right;i--);return n}function ur(e,t,n,r){var i,o=sr(t.map,n,r),a=o.node,u=o.start,c=o.end,d=o.collapse;if(3==a.nodeType){for(var f=0;f<4;f++){for(;u&&ae(t.line.text.charAt(o.coverStart+u));)--u;for(;o.coverStart+c0&&(d=r="right"),i=e.options.lineWrapping&&(p=a.getClientRects()).length>1?p["right"==r?p.length-1:0]:a.getBoundingClientRect()}if(s&&l<9&&!u&&(!i||!i.left&&!i.right)){var h=a.parentNode.getClientRects()[0];i=h?{left:h.left,right:h.left+Dr(e.display),top:h.top,bottom:h.bottom}:ar}for(var m=i.top-t.rect.top,g=i.bottom-t.rect.top,v=(m+g)/2,y=t.view.measure.heights,b=0;b=i.text.length?(u=i.text.length,c="before"):u<=0&&(u=0,c="after"),!l)return s("before"==c?u-1:u,"before"==c);function d(e,t,n){return s(n?e-1:e,1==l[t].level!=n)}r(d,"getBidi");var f=de(l,u,c),p=ce,h=d(u,f,"before"==c);return null!=p&&(h.other=d(u,p,"before"!=c)),h}function Tr(e,t){var n=0;t=pt(e.doc,t),e.options.lineWrapping||(n=Dr(e.display)*t.ch);var r=Je(e.doc,t.line),i=sn(r)+zn(e.display);return{left:n,right:n,top:i,bottom:i+r.height}}function wr(e,t,n,r,i){var o=at(e,t,n);return o.xRel=i,r&&(o.outside=r),o}function Cr(e,t,n){var r=e.doc;if((n+=e.display.viewOffset)<0)return wr(r.first,0,null,-1,-1);var i=rt(r,n),o=r.first+r.size-1;if(i>o)return wr(r.first+r.size-1,Je(r,o).text.length,null,1,1);t<0&&(t=0);for(var a=Je(r,i);;){var s=Nr(e,a,i,t,n),l=Yt(a,s.ch+(s.xRel>0||s.outside>0?1:0));if(!l)return s;var u=l.find(1);if(u.line==i)return u;a=Je(r,i=u.line)}}function Sr(e,t,n,r){r-=gr(t);var i=t.text.length,o=le((function(t){return ir(e,n,t-1).bottom<=r}),i,0);return{begin:o,end:i=le((function(t){return ir(e,n,t).top>r}),o,i)}}function xr(e,t,n,r){return n||(n=rr(e,t)),Sr(e,t,n,vr(e,t,ir(e,n,r),"line").top)}function kr(e,t,n,r){return!(e.bottom<=n)&&(e.top>n||(r?e.left:e.right)>t)}function Nr(e,t,n,r,i){i-=sn(t);var o=rr(e,t),a=gr(t),s=0,l=t.text.length,u=!0,c=pe(t,e.doc.direction);if(c){var d=(e.options.lineWrapping?Or:_r)(e,t,n,o,c,r,i);s=(u=1!=d.level)?d.from:d.to-1,l=u?d.to:d.from-1}var f,p,h=null,m=null,g=le((function(t){var n=ir(e,o,t);return n.top+=a,n.bottom+=a,!!kr(n,r,i,!1)&&(n.top<=i&&n.left<=r&&(h=t,m=n),!0)}),s,l),v=!1;if(m){var y=r-m.left=E.bottom?1:0}return wr(n,g=se(t.text,g,1),p,v,r-f)}function _r(e,t,n,r,i,o,a){var s=le((function(s){var l=i[s],u=1!=l.level;return kr(Er(e,at(n,u?l.to:l.from,u?"before":"after"),"line",t,r),o,a,!0)}),0,i.length-1),l=i[s];if(s>0){var u=1!=l.level,c=Er(e,at(n,u?l.from:l.to,u?"after":"before"),"line",t,r);kr(c,o,a,!0)&&c.top>a&&(l=i[s-1])}return l}function Or(e,t,n,r,i,o,a){var s=Sr(e,t,r,a),l=s.begin,u=s.end;/\s/.test(t.text.charAt(u-1))&&u--;for(var c=null,d=null,f=0;f=u||p.to<=l)){var h=ir(e,r,1!=p.level?Math.min(u,p.to)-1:Math.max(l,p.from)).right,m=hm)&&(c=p,d=m)}}return c||(c=i[i.length-1]),c.fromu&&(c={from:c.from,to:u,level:c.level}),c}function Ir(e){if(null!=e.cachedTextHeight)return e.cachedTextHeight;if(null==or){or=I("pre",null,"CodeMirror-line-like");for(var t=0;t<49;++t)or.appendChild(document.createTextNode("x")),or.appendChild(I("br"));or.appendChild(document.createTextNode("x"))}O(e.measure,or);var n=or.offsetHeight/50;return n>3&&(e.cachedTextHeight=n),_(e.measure),n||1}function Dr(e){if(null!=e.cachedCharWidth)return e.cachedCharWidth;var t=I("span","xxxxxxxxxx"),n=I("pre",[t],"CodeMirror-line-like");O(e.measure,n);var r=t.getBoundingClientRect(),i=(r.right-r.left)/10;return i>2&&(e.cachedCharWidth=i),i||10}function Lr(e){for(var t=e.display,n={},r={},i=t.gutters.clientLeft,o=t.gutters.firstChild,a=0;o;o=o.nextSibling,++a){var s=e.display.gutterSpecs[a].className;n[s]=o.offsetLeft+o.clientLeft+i,r[s]=o.clientWidth}return{fixedPos:Ar(t),gutterTotalWidth:t.gutters.offsetWidth,gutterLeft:n,gutterWidth:r,wrapperWidth:t.wrapper.clientWidth}}function Ar(e){return e.scroller.getBoundingClientRect().left-e.sizer.getBoundingClientRect().left}function Mr(e){var t=Ir(e.display),n=e.options.lineWrapping,r=n&&Math.max(5,e.display.scroller.clientWidth/Dr(e.display)-3);return function(i){if(on(e.doc,i))return 0;var o=0;if(i.widgets)for(var a=0;a0&&(l=Je(e.doc,u.line).text).length==u.ch){var c=V(l,l.length,e.options.tabSize)-l.length;u=at(u.line,Math.max(0,Math.round((o-Kn(e.display).left)/Dr(e.display))-c))}return u}function Pr(e,t){if(t>=e.display.viewTo)return null;if((t-=e.display.viewFrom)<0)return null;for(var n=e.display.view,r=0;rt)&&(i.updateLineNumbers=t),e.curOp.viewChanged=!0,t>=i.viewTo)Dt&&nn(e.doc,t)i.viewFrom?Ur(e):(i.viewFrom+=r,i.viewTo+=r);else if(t<=i.viewFrom&&n>=i.viewTo)Ur(e);else if(t<=i.viewFrom){var o=Br(e,n,n+r,1);o?(i.view=i.view.slice(o.index),i.viewFrom=o.lineN,i.viewTo+=r):Ur(e)}else if(n>=i.viewTo){var a=Br(e,t,t,-1);a?(i.view=i.view.slice(0,a.index),i.viewTo=a.lineN):Ur(e)}else{var s=Br(e,t,t,-1),l=Br(e,n,n+r,1);s&&l?(i.view=i.view.slice(0,s.index).concat(Sn(e,s.lineN,l.lineN)).concat(i.view.slice(l.index)),i.viewTo+=r):Ur(e)}var u=i.externalMeasured;u&&(n=i.lineN&&t=r.viewTo)){var o=r.view[Pr(e,t)];if(null!=o.node){var a=o.changes||(o.changes=[]);-1==B(a,n)&&a.push(n)}}}function Ur(e){e.display.viewFrom=e.display.viewTo=e.doc.first,e.display.view=[],e.display.viewOffset=0}function Br(e,t,n,r){var i,o=Pr(e,t),a=e.display.view;if(!Dt||n==e.doc.first+e.doc.size)return{index:o,lineN:n};for(var s=e.display.viewFrom,l=0;l0){if(o==a.length-1)return null;i=s+a[o].size-t,o++}else i=s-t;t+=i,n+=i}for(;nn(e.doc,n)!=n;){if(o==(r<0?0:a.length-1))return null;n+=r*a[o-(r<0?1:0)].size,o+=r}return{index:o,lineN:n}}function $r(e,t,n){var r=e.display;0==r.view.length||t>=r.viewTo||n<=r.viewFrom?(r.view=Sn(e,t,n),r.viewFrom=t):(r.viewFrom>t?r.view=Sn(e,t,r.viewFrom).concat(r.view):r.viewFromn&&(r.view=r.view.slice(0,Pr(e,n)))),r.viewTo=n}function qr(e){for(var t=e.display.view,n=0,r=0;r=e.display.viewTo||l.to().line0?a:e.defaultCharWidth())+"px"}if(r.other){var s=n.appendChild(I("div"," ","CodeMirror-cursor CodeMirror-secondarycursor"));s.style.display="",s.style.left=r.other.left+"px",s.style.top=r.other.top+"px",s.style.height=.85*(r.other.bottom-r.other.top)+"px"}}function Wr(e,t){return e.top-t.top||e.left-t.left}function Kr(e,t,n){var i=e.display,o=e.doc,a=document.createDocumentFragment(),s=Kn(e.display),l=s.left,u=Math.max(i.sizerWidth,Xn(e)-i.sizer.offsetLeft)-s.right,c="ltr"==o.direction;function d(e,t,n,r){t<0&&(t=0),t=Math.round(t),r=Math.round(r),a.appendChild(I("div",null,"CodeMirror-selected","position: absolute; left: "+e+"px;\n top: "+t+"px; width: "+(null==n?u-e:n)+"px;\n height: "+(r-t)+"px"))}function f(t,n,i){var a,s,f=Je(o,t),p=f.text.length;function h(n,r){return br(e,at(t,n),"div",f,r)}function m(t,n,r){var i=xr(e,f,null,t),o="ltr"==n==("after"==r)?"left":"right";return h("after"==r?i.begin:i.end-(/\s/.test(f.text.charAt(i.end-1))?2:1),o)[o]}r(h,"coords"),r(m,"wrapX");var g=pe(f,o.direction);return ue(g,n||0,null==i?p:i,(function(e,t,r,o){var f="ltr"==r,v=h(e,f?"left":"right"),y=h(t-1,f?"right":"left"),b=null==n&&0==e,E=null==i&&t==p,T=0==o,w=!g||o==g.length-1;if(y.top-v.top<=3){var C=(c?E:b)&&w,S=(c?b:E)&&T?l:(f?v:y).left,x=C?u:(f?y:v).right;d(S,v.top,x-S,v.bottom)}else{var k,N,_,O;f?(k=c&&b&&T?l:v.left,N=c?u:m(e,r,"before"),_=c?l:m(t,r,"after"),O=c&&E&&w?u:y.right):(k=c?m(e,r,"before"):l,N=!c&&b&&T?u:v.right,_=!c&&E&&w?l:y.left,O=c?m(t,r,"after"):u),d(k,v.top,N-k,v.bottom),v.bottom0?t.blinker=setInterval((function(){e.hasFocus()||Zr(e),t.cursorDiv.style.visibility=(n=!n)?"":"hidden"}),e.options.cursorBlinkRate):e.options.cursorBlinkRate<0&&(t.cursorDiv.style.visibility="hidden")}}function Xr(e){e.hasFocus()||(e.display.input.focus(),e.state.focused||Jr(e))}function Yr(e){e.state.delayingBlurEvent=!0,setTimeout((function(){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1,e.state.focused&&Zr(e))}),100)}function Jr(e,t){e.state.delayingBlurEvent&&!e.state.draggingText&&(e.state.delayingBlurEvent=!1),"nocursor"!=e.options.readOnly&&(e.state.focused||(ye(e,"focus",e,t),e.state.focused=!0,M(e.display.wrapper,"CodeMirror-focused"),e.curOp||e.display.selForContextMenu==e.doc.sel||(e.display.input.reset(),u&&setTimeout((function(){return e.display.input.reset(!0)}),20)),e.display.input.receivedFocus()),Qr(e))}function Zr(e,t){e.state.delayingBlurEvent||(e.state.focused&&(ye(e,"blur",e,t),e.state.focused=!1,N(e.display.wrapper,"CodeMirror-focused")),clearInterval(e.display.blinker),setTimeout((function(){e.state.focused||(e.display.shift=!1)}),150))}function ei(e){for(var t=e.display,n=t.lineDiv.offsetTop,r=Math.max(0,t.scroller.getBoundingClientRect().top),i=t.lineDiv.getBoundingClientRect().top,o=0,a=0;a.005||m<-.005)&&(ie.display.sizerWidth){var v=Math.ceil(f/Dr(e.display));v>e.display.maxLineLength&&(e.display.maxLineLength=v,e.display.maxLine=u.line,e.display.maxLineChanged=!0)}}}Math.abs(o)>2&&(t.scroller.scrollTop+=o)}function ti(e){if(e.widgets)for(var t=0;t=a&&(o=rt(t,sn(Je(t,l))-e.wrapper.clientHeight),a=l)}return{from:o,to:Math.max(a,o+1)}}function ri(e,t){if(!be(e,"scrollCursorIntoView")){var n=e.display,r=n.sizer.getBoundingClientRect(),i=null;if(t.top+r.top<0?i=!0:t.bottom+r.top>(window.innerHeight||document.documentElement.clientHeight)&&(i=!1),null!=i&&!m){var o=I("div","​",null,"position: absolute;\n top: "+(t.top-n.viewOffset-zn(e.display))+"px;\n height: "+(t.bottom-t.top+Qn(e)+n.barHeight)+"px;\n left: "+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;");e.display.lineSpace.appendChild(o),o.scrollIntoView(i),e.display.lineSpace.removeChild(o)}}}function ii(e,t,n,r){var i;null==r&&(r=0),e.options.lineWrapping||t!=n||(n="before"==t.sticky?at(t.line,t.ch+1,"before"):t,t=t.ch?at(t.line,"before"==t.sticky?t.ch-1:t.ch,"after"):t);for(var o=0;o<5;o++){var a=!1,s=Er(e,t),l=n&&n!=t?Er(e,n):s,u=ai(e,i={left:Math.min(s.left,l.left),top:Math.min(s.top,l.top)-r,right:Math.max(s.left,l.left),bottom:Math.max(s.bottom,l.bottom)+r}),c=e.doc.scrollTop,d=e.doc.scrollLeft;if(null!=u.scrollTop&&(pi(e,u.scrollTop),Math.abs(e.doc.scrollTop-c)>1&&(a=!0)),null!=u.scrollLeft&&(mi(e,u.scrollLeft),Math.abs(e.doc.scrollLeft-d)>1&&(a=!0)),!a)break}return i}function oi(e,t){var n=ai(e,t);null!=n.scrollTop&&pi(e,n.scrollTop),null!=n.scrollLeft&&mi(e,n.scrollLeft)}function ai(e,t){var n=e.display,r=Ir(e.display);t.top<0&&(t.top=0);var i=e.curOp&&null!=e.curOp.scrollTop?e.curOp.scrollTop:n.scroller.scrollTop,o=Yn(e),a={};t.bottom-t.top>o&&(t.bottom=t.top+o);var s=e.doc.height+Wn(n),l=t.tops-r;if(t.topi+o){var c=Math.min(t.top,(u?s:t.bottom)-o);c!=i&&(a.scrollTop=c)}var d=e.options.fixedGutter?0:n.gutters.offsetWidth,f=e.curOp&&null!=e.curOp.scrollLeft?e.curOp.scrollLeft:n.scroller.scrollLeft-d,p=Xn(e)-n.gutters.offsetWidth,h=t.right-t.left>p;return h&&(t.right=t.left+p),t.left<10?a.scrollLeft=0:t.leftp+f-3&&(a.scrollLeft=t.right+(h?0:10)-p),a}function si(e,t){null!=t&&(di(e),e.curOp.scrollTop=(null==e.curOp.scrollTop?e.doc.scrollTop:e.curOp.scrollTop)+t)}function li(e){di(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function ui(e,t,n){null==t&&null==n||di(e),null!=t&&(e.curOp.scrollLeft=t),null!=n&&(e.curOp.scrollTop=n)}function ci(e,t){di(e),e.curOp.scrollToPos=t}function di(e){var t=e.curOp.scrollToPos;t&&(e.curOp.scrollToPos=null,fi(e,Tr(e,t.from),Tr(e,t.to),t.margin))}function fi(e,t,n,r){var i=ai(e,{left:Math.min(t.left,n.left),top:Math.min(t.top,n.top)-r,right:Math.max(t.right,n.right),bottom:Math.max(t.bottom,n.bottom)+r});ui(e,i.scrollLeft,i.scrollTop)}function pi(e,t){Math.abs(e.doc.scrollTop-t)<2||(n||Hi(e,{top:t}),hi(e,t,!0),n&&Hi(e),Fi(e,100))}function hi(e,t,n){t=Math.max(0,Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t)),(e.display.scroller.scrollTop!=t||n)&&(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function mi(e,t,n,r){t=Math.max(0,Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth)),(n?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!r||(e.doc.scrollLeft=t,Ki(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function gi(e){var t=e.display,n=t.gutters.offsetWidth,r=Math.round(e.doc.height+Wn(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?n:0,docHeight:r,scrollHeight:r+Qn(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:n}}r(sr,"nodeAndOffsetInLineMap"),r(lr,"getUsefulRect"),r(ur,"measureCharInner"),r(cr,"maybeUpdateRectForZooming"),r(dr,"clearLineMeasurementCacheFor"),r(fr,"clearLineMeasurementCache"),r(pr,"clearCaches"),r(hr,"pageScrollX"),r(mr,"pageScrollY"),r(gr,"widgetTopHeight"),r(vr,"intoCoordSystem"),r(yr,"fromCoordSystem"),r(br,"charCoords"),r(Er,"cursorCoords"),r(Tr,"estimateCoords"),r(wr,"PosWithInfo"),r(Cr,"coordsChar"),r(Sr,"wrappedLineExtent"),r(xr,"wrappedLineExtentChar"),r(kr,"boxIsAfter"),r(Nr,"coordsCharInner"),r(_r,"coordsBidiPart"),r(Or,"coordsBidiPartWrapped"),r(Ir,"textHeight"),r(Dr,"charWidth"),r(Lr,"getDimensions"),r(Ar,"compensateForHScroll"),r(Mr,"estimateHeight"),r(Rr,"estimateLineHeights"),r(Fr,"posFromMouse"),r(Pr,"findViewIndex"),r(jr,"regChange"),r(Vr,"regLineChange"),r(Ur,"resetView"),r(Br,"viewCuttingPoint"),r($r,"adjustView"),r(qr,"countDirtyView"),r(Hr,"updateSelection"),r(Gr,"prepareSelection"),r(zr,"drawSelectionCursor"),r(Wr,"cmpCoords"),r(Kr,"drawSelectionRange"),r(Qr,"restartBlink"),r(Xr,"ensureFocus"),r(Yr,"delayBlurEvent"),r(Jr,"onFocus"),r(Zr,"onBlur"),r(ei,"updateHeightsInViewport"),r(ti,"updateWidgetHeight"),r(ni,"visibleLines"),r(ri,"maybeScrollWindow"),r(ii,"scrollPosIntoView"),r(oi,"scrollIntoView"),r(ai,"calculateScrollPos"),r(si,"addToScrollTop"),r(li,"ensureCursorVisible"),r(ui,"scrollToCoords"),r(ci,"scrollToRange"),r(di,"resolveScrollToPos"),r(fi,"scrollToCoordsRange"),r(pi,"updateScrollTop"),r(hi,"setScrollTop"),r(mi,"setScrollLeft"),r(gi,"measureForScrollbars");var vi=r((function(e,t,n){this.cm=n;var r=this.vert=I("div",[I("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),i=this.horiz=I("div",[I("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");r.tabIndex=i.tabIndex=-1,e(r),e(i),me(r,"scroll",(function(){r.clientHeight&&t(r.scrollTop,"vertical")})),me(i,"scroll",(function(){i.clientWidth&&t(i.scrollLeft,"horizontal")})),this.checkedZeroWidth=!1,s&&l<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")}),"NativeScrollbars");vi.prototype.update=function(e){var t=e.scrollWidth>e.clientWidth+1,n=e.scrollHeight>e.clientHeight+1,r=e.nativeBarWidth;if(n){this.vert.style.display="block",this.vert.style.bottom=t?r+"px":"0";var i=e.viewHeight-(t?r:0);this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+i)+"px"}else this.vert.scrollTop=0,this.vert.style.display="",this.vert.firstChild.style.height="0";if(t){this.horiz.style.display="block",this.horiz.style.right=n?r+"px":"0",this.horiz.style.left=e.barLeft+"px";var o=e.viewWidth-e.barLeft-(n?r:0);this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+o)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&e.clientHeight>0&&(0==r&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:n?r:0,bottom:t?r:0}},vi.prototype.setScrollLeft=function(e){this.horiz.scrollLeft!=e&&(this.horiz.scrollLeft=e),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},vi.prototype.setScrollTop=function(e){this.vert.scrollTop!=e&&(this.vert.scrollTop=e),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},vi.prototype.zeroWidthHack=function(){var e=b&&!h?"12px":"18px";this.horiz.style.height=this.vert.style.width=e,this.horiz.style.pointerEvents=this.vert.style.pointerEvents="none",this.disableHoriz=new U,this.disableVert=new U},vi.prototype.enableZeroWidthBar=function(e,t,n){function i(){var r=e.getBoundingClientRect();("vert"==n?document.elementFromPoint(r.right-1,(r.top+r.bottom)/2):document.elementFromPoint((r.right+r.left)/2,r.bottom-1))!=e?e.style.pointerEvents="none":t.set(1e3,i)}e.style.pointerEvents="auto",r(i,"maybeDisable"),t.set(1e3,i)},vi.prototype.clear=function(){var e=this.horiz.parentNode;e.removeChild(this.horiz),e.removeChild(this.vert)};var yi=r((function(){}),"NullScrollbars");function bi(e,t){t||(t=gi(e));var n=e.display.barWidth,r=e.display.barHeight;Ei(e,t);for(var i=0;i<4&&n!=e.display.barWidth||r!=e.display.barHeight;i++)n!=e.display.barWidth&&e.options.lineWrapping&&ei(e),Ei(e,gi(e)),n=e.display.barWidth,r=e.display.barHeight}function Ei(e,t){var n=e.display,r=n.scrollbars.update(t);n.sizer.style.paddingRight=(n.barWidth=r.right)+"px",n.sizer.style.paddingBottom=(n.barHeight=r.bottom)+"px",n.heightForcer.style.borderBottom=r.bottom+"px solid transparent",r.right&&r.bottom?(n.scrollbarFiller.style.display="block",n.scrollbarFiller.style.height=r.bottom+"px",n.scrollbarFiller.style.width=r.right+"px"):n.scrollbarFiller.style.display="",r.bottom&&e.options.coverGutterNextToScrollbar&&e.options.fixedGutter?(n.gutterFiller.style.display="block",n.gutterFiller.style.height=r.bottom+"px",n.gutterFiller.style.width=t.gutterWidth+"px"):n.gutterFiller.style.display=""}yi.prototype.update=function(){return{bottom:0,right:0}},yi.prototype.setScrollLeft=function(){},yi.prototype.setScrollTop=function(){},yi.prototype.clear=function(){},r(bi,"updateScrollbars"),r(Ei,"updateScrollbarsInner");var Ti={native:vi,null:yi};function wi(e){e.display.scrollbars&&(e.display.scrollbars.clear(),e.display.scrollbars.addClass&&N(e.display.wrapper,e.display.scrollbars.addClass)),e.display.scrollbars=new Ti[e.options.scrollbarStyle]((function(t){e.display.wrapper.insertBefore(t,e.display.scrollbarFiller),me(t,"mousedown",(function(){e.state.focused&&setTimeout((function(){return e.display.input.focus()}),0)})),t.setAttribute("cm-not-content","true")}),(function(t,n){"horizontal"==n?mi(e,t):pi(e,t)}),e),e.display.scrollbars.addClass&&M(e.display.wrapper,e.display.scrollbars.addClass)}r(wi,"initScrollbars");var Ci=0;function Si(e){e.curOp={cm:e,viewChanged:!1,startHeight:e.doc.height,forceUpdate:!1,updateInput:0,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++Ci,markArrays:null},kn(e.curOp)}function xi(e){var t=e.curOp;t&&_n(t,(function(e){for(var t=0;t=n.viewTo)||n.maxLineChanged&&t.options.lineWrapping,e.update=e.mustUpdate&&new ji(t,e.mustUpdate&&{top:e.scrollTop,ensure:e.scrollToPos},e.forceUpdate)}function _i(e){e.updatedDisplay=e.mustUpdate&&$i(e.cm,e.update)}function Oi(e){var t=e.cm,n=t.display;e.updatedDisplay&&ei(t),e.barMeasure=gi(t),n.maxLineChanged&&!t.options.lineWrapping&&(e.adjustWidthTo=tr(t,n.maxLine,n.maxLine.text.length).left+3,t.display.sizerWidth=e.adjustWidthTo,e.barMeasure.scrollWidth=Math.max(n.scroller.clientWidth,n.sizer.offsetLeft+e.adjustWidthTo+Qn(t)+t.display.barWidth),e.maxScrollLeft=Math.max(0,n.sizer.offsetLeft+e.adjustWidthTo-Xn(t))),(e.updatedDisplay||e.selectionChanged)&&(e.preparedSelection=n.input.prepareSelection())}function Ii(e){var t=e.cm;null!=e.adjustWidthTo&&(t.display.sizer.style.minWidth=e.adjustWidthTo+"px",e.maxScrollLeft=e.display.viewTo)){var n=+new Date+e.options.workTime,r=Et(e,t.highlightFrontier),i=[];t.iter(r.line,Math.min(t.first+t.size,e.display.viewTo+500),(function(o){if(r.line>=e.display.viewFrom){var a=o.styles,s=o.text.length>e.options.maxHighlightLength?Ke(t.mode,r.state):null,l=yt(e,o,r,!0);s&&(r.state=s),o.styles=l.styles;var u=o.styleClasses,c=l.classes;c?o.styleClasses=c:u&&(o.styleClasses=null);for(var d=!a||a.length!=o.styles.length||u!=c&&(!u||!c||u.bgClass!=c.bgClass||u.textClass!=c.textClass),f=0;!d&&fn)return Fi(e,e.options.workDelay),!0})),t.highlightFrontier=r.line,t.modeFrontier=Math.max(t.modeFrontier,r.line),i.length&&Li(e,(function(){for(var t=0;t=n.viewFrom&&t.visible.to<=n.viewTo&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo)&&n.renderedView==n.view&&0==qr(e))return!1;Qi(e)&&(Ur(e),t.dims=Lr(e));var i=r.first+r.size,o=Math.max(t.visible.from-e.options.viewportMargin,r.first),a=Math.min(i,t.visible.to+e.options.viewportMargin);n.viewFroma&&n.viewTo-a<20&&(a=Math.min(i,n.viewTo)),Dt&&(o=nn(e.doc,o),a=rn(e.doc,a));var s=o!=n.viewFrom||a!=n.viewTo||n.lastWrapHeight!=t.wrapperHeight||n.lastWrapWidth!=t.wrapperWidth;$r(e,o,a),n.viewOffset=sn(Je(e.doc,n.viewFrom)),e.display.mover.style.top=n.viewOffset+"px";var l=qr(e);if(!s&&0==l&&!t.force&&n.renderedView==n.view&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo))return!1;var u=Ui(e);return l>4&&(n.lineDiv.style.display="none"),Gi(e,n.updateLineNumbers,t.dims),l>4&&(n.lineDiv.style.display=""),n.renderedView=n.view,Bi(u),_(n.cursorDiv),_(n.selectionDiv),n.gutters.style.height=n.sizer.style.minHeight=0,s&&(n.lastWrapHeight=t.wrapperHeight,n.lastWrapWidth=t.wrapperWidth,Fi(e,400)),n.updateLineNumbers=null,!0}function qi(e,t){for(var n=t.viewport,r=!0;;r=!1){if(r&&e.options.lineWrapping&&t.oldDisplayWidth!=Xn(e))r&&(t.visible=ni(e.display,e.doc,n));else if(n&&null!=n.top&&(n={top:Math.min(e.doc.height+Wn(e.display)-Yn(e),n.top)}),t.visible=ni(e.display,e.doc,n),t.visible.from>=e.display.viewFrom&&t.visible.to<=e.display.viewTo)break;if(!$i(e,t))break;ei(e);var i=gi(e);Hr(e),bi(e,i),Wi(e,i),t.force=!1}t.signal(e,"update",e),e.display.viewFrom==e.display.reportedViewFrom&&e.display.viewTo==e.display.reportedViewTo||(t.signal(e,"viewportChange",e,e.display.viewFrom,e.display.viewTo),e.display.reportedViewFrom=e.display.viewFrom,e.display.reportedViewTo=e.display.viewTo)}function Hi(e,t){var n=new ji(e,t);if($i(e,n)){ei(e),qi(e,n);var r=gi(e);Hr(e),bi(e,r),Wi(e,r),n.finish()}}function Gi(e,t,n){var i=e.display,o=e.options.lineNumbers,a=i.lineDiv,s=a.firstChild;function l(t){var n=t.nextSibling;return u&&b&&e.display.currentWheelTarget==t?t.style.display="none":t.parentNode.removeChild(t),n}r(l,"rm");for(var c=i.view,d=i.viewFrom,f=0;f-1&&(h=!1),Ln(e,p,d,n)),h&&(_(p.lineNumber),p.lineNumber.appendChild(document.createTextNode(ot(e.options,d)))),s=p.node.nextSibling}else{var m=Un(e,p,d,n);a.insertBefore(m,s)}d+=p.size}for(;s;)s=l(s)}function zi(e){var t=e.gutters.offsetWidth;e.sizer.style.marginLeft=t+"px",In(e,"gutterChanged",e)}function Wi(e,t){e.display.sizer.style.minHeight=t.docHeight+"px",e.display.heightForcer.style.top=t.docHeight+"px",e.display.gutters.style.height=t.docHeight+e.display.barHeight+Qn(e)+"px"}function Ki(e){var t=e.display,n=t.view;if(t.alignWidgets||t.gutters.firstChild&&e.options.fixedGutter){for(var r=Ar(t)-t.scroller.scrollLeft+e.doc.scrollLeft,i=t.gutters.offsetWidth,o=r+"px",a=0;al.clientWidth,d=l.scrollHeight>l.clientHeight;if(i&&c||o&&d){if(o&&b&&u)e:for(var p=t.target,h=s.view;p!=l;p=p.parentNode)for(var m=0;m=0&&st(e,r.to())<=0)return n}return-1};var ao=r((function(e,t){this.anchor=e,this.head=t}),"Range");function so(e,t,n){var r=e&&e.options.selectionsMayTouch,i=t[n];t.sort((function(e,t){return st(e.from(),t.from())})),n=B(t,i);for(var o=1;o0:l>=0){var u=dt(s.from(),a.from()),c=ct(s.to(),a.to()),d=s.empty()?a.from()==a.head:s.from()==s.head;o<=n&&--n,t.splice(--o,2,new ao(d?c:u,d?u:c))}}return new oo(t,n)}function lo(e,t){return new oo([new ao(e,t||e)],0)}function uo(e){return e.text?at(e.from.line+e.text.length-1,X(e.text).length+(1==e.text.length?e.from.ch:0)):e.to}function co(e,t){if(st(e,t.from)<0)return e;if(st(e,t.to)<=0)return uo(t);var n=e.line+t.text.length-(t.to.line-t.from.line)-1,r=e.ch;return e.line==t.to.line&&(r+=uo(t).ch-t.to.ch),at(n,r)}function fo(e,t){for(var n=[],r=0;r1&&e.remove(l.line+1,m-1),e.insert(l.line+1,y)}In(e,"change",e,t)}function bo(e,t,n){function i(e,r,o){if(e.linked)for(var a=0;a1&&!e.done[e.done.length-2].ranges?(e.done.pop(),X(e.done)):void 0}function No(e,t,n,r){var i=e.history;i.undone.length=0;var o,a,s=+new Date;if((i.lastOp==r||i.lastOrigin==t.origin&&t.origin&&("+"==t.origin.charAt(0)&&i.lastModTime>s-(e.cm?e.cm.options.historyEventDelay:500)||"*"==t.origin.charAt(0)))&&(o=ko(i,i.lastOp==r)))a=X(o.changes),0==st(t.from,t.to)&&0==st(t.from,a.to)?a.to=uo(t):o.changes.push(So(e,t));else{var l=X(i.done);for(l&&l.ranges||Io(e.sel,i.done),o={changes:[So(e,t)],generation:i.generation},i.done.push(o);i.done.length>i.undoDepth;)i.done.shift(),i.done[0].ranges||i.done.shift()}i.done.push(n),i.generation=++i.maxGeneration,i.lastModTime=i.lastSelTime=s,i.lastOp=i.lastSelOp=r,i.lastOrigin=i.lastSelOrigin=t.origin,a||ye(e,"historyAdded")}function _o(e,t,n,r){var i=t.charAt(0);return"*"==i||"+"==i&&n.ranges.length==r.ranges.length&&n.somethingSelected()==r.somethingSelected()&&new Date-e.history.lastSelTime<=(e.cm?e.cm.options.historyEventDelay:500)}function Oo(e,t,n,r){var i=e.history,o=r&&r.origin;n==i.lastSelOp||o&&i.lastSelOrigin==o&&(i.lastModTime==i.lastSelTime&&i.lastOrigin==o||_o(e,o,X(i.done),t))?i.done[i.done.length-1]=t:Io(t,i.done),i.lastSelTime=+new Date,i.lastSelOrigin=o,i.lastSelOp=n,r&&!1!==r.clearRedo&&xo(i.undone)}function Io(e,t){var n=X(t);n&&n.ranges&&n.equals(e)||t.push(e)}function Do(e,t,n,r){var i=t["spans_"+e.id],o=0;e.iter(Math.max(e.first,n),Math.min(e.first+e.size,r),(function(n){n.markedSpans&&((i||(i=t["spans_"+e.id]={}))[o]=n.markedSpans),++o}))}function Lo(e){if(!e)return null;for(var t,n=0;n-1&&(X(s)[d]=u[d],delete u[d])}}}return r}function Fo(e,t,n,r){if(r){var i=e.anchor;if(n){var o=st(t,i)<0;o!=st(n,i)<0?(i=t,t=n):o!=st(t,n)<0&&(t=n)}return new ao(i,t)}return new ao(n||t,t)}function Po(e,t,n,r,i){null==i&&(i=e.cm&&(e.cm.display.shift||e.extend)),qo(e,new oo([Fo(e.sel.primary(),t,n,i)],0),r)}function jo(e,t,n){for(var r=[],i=e.cm&&(e.cm.display.shift||e.extend),o=0;o=t.ch:s.to>t.ch))){if(i&&(ye(l,"beforeCursorEnter"),l.explicitlyCleared)){if(o.markedSpans){--a;continue}break}if(!l.atomic)continue;if(n){var d=l.find(r<0?1:-1),f=void 0;if((r<0?c:u)&&(d=Xo(e,d,-r,d&&d.line==t.line?o:null)),d&&d.line==t.line&&(f=st(d,n))&&(r<0?f<0:f>0))return Ko(e,d,t,r,i)}var p=l.find(r<0?-1:1);return(r<0?u:c)&&(p=Xo(e,p,r,p.line==t.line?o:null)),p?Ko(e,p,t,r,i):null}}return t}function Qo(e,t,n,r,i){var o=r||1;return Ko(e,t,n,o,i)||!i&&Ko(e,t,n,o,!0)||Ko(e,t,n,-o,i)||!i&&Ko(e,t,n,-o,!0)||(e.cantEdit=!0,at(e.first,0))}function Xo(e,t,n,r){return n<0&&0==t.ch?t.line>e.first?pt(e,at(t.line-1)):null:n>0&&t.ch==(r||Je(e,t.line)).text.length?t.line=0;--i)ea(e,{from:r[i].from,to:r[i].to,text:i?[""]:t.text,origin:t.origin});else ea(e,t)}}function ea(e,t){if(1!=t.text.length||""!=t.text[0]||0!=st(t.from,t.to)){var n=fo(e,t);No(e,t,n,e.cm?e.cm.curOp.id:NaN),ra(e,t,n,Ut(e,t));var r=[];bo(e,(function(e,n){n||-1!=B(r,e.history)||(la(e.history,t),r.push(e.history)),ra(e,t,null,Ut(e,t))}))}}function ta(e,t,n){var i=e.cm&&e.cm.state.suppressEdits;if(!i||n){for(var o,a=e.history,s=e.sel,l="undo"==t?a.done:a.undone,u="undo"==t?a.undone:a.done,c=0;c=0;--h){var m=p(h);if(m)return m.v}}}}function na(e,t){if(0!=t&&(e.first+=t,e.sel=new oo(Y(e.sel.ranges,(function(e){return new ao(at(e.anchor.line+t,e.anchor.ch),at(e.head.line+t,e.head.ch))})),e.sel.primIndex),e.cm)){jr(e.cm,e.first,e.first-t,t);for(var n=e.cm.display,r=n.viewFrom;re.lastLine())){if(t.from.lineo&&(t={from:t.from,to:at(o,Je(e,o).text.length),text:[t.text[0]],origin:t.origin}),t.removed=Ze(e,t.from,t.to),n||(n=fo(e,t)),e.cm?ia(e.cm,t,r):yo(e,t,r),Ho(e,n,H),e.cantEdit&&Qo(e,at(e.firstLine(),0))&&(e.cantEdit=!1)}}function ia(e,t,n){var r=e.doc,i=e.display,o=t.from,a=t.to,s=!1,l=o.line;e.options.lineWrapping||(l=nt(Zt(Je(r,o.line))),r.iter(l,a.line+1,(function(e){if(e==i.maxLine)return s=!0,!0}))),r.sel.contains(t.from,t.to)>-1&&Ee(e),yo(r,t,n,Mr(e)),e.options.lineWrapping||(r.iter(l,o.line+t.text.length,(function(e){var t=ln(e);t>i.maxLineLength&&(i.maxLine=e,i.maxLineLength=t,i.maxLineChanged=!0,s=!1)})),s&&(e.curOp.updateMaxLine=!0)),Ot(r,o.line),Fi(e,400);var u=t.text.length-(a.line-o.line)-1;t.full?jr(e):o.line!=a.line||1!=t.text.length||vo(e.doc,t)?jr(e,o.line,a.line+1,u):Vr(e,o.line,"text");var c=Te(e,"changes"),d=Te(e,"change");if(d||c){var f={from:o,to:a,text:t.text,removed:t.removed,origin:t.origin};d&&In(e,"change",e,f),c&&(e.curOp.changeObjs||(e.curOp.changeObjs=[])).push(f)}e.display.selForContextMenu=null}function oa(e,t,n,r,i){var o;r||(r=n),st(r,n)<0&&(n=(o=[r,n])[0],r=o[1]),"string"==typeof t&&(t=e.splitLines(t)),Zo(e,{from:n,to:r,text:t,origin:i})}function aa(e,t,n,r){n1||!(this.children[0]instanceof ca))){var s=[];this.collapse(s),this.children=[new ca(s)],this.children[0].parent=this}},collapse:function(e){for(var t=0;t50){for(var a=i.lines.length%25+25,s=a;s10);e.parent.maybeSpill()}},iterN:function(e,t,n){for(var r=0;r0||0==a&&!1!==o.clearWhenEmpty)return o;if(o.replacedWith&&(o.collapsed=!0,o.widgetNode=D("span",[o.replacedWith],"CodeMirror-widget"),r.handleMouseEvents||o.widgetNode.setAttribute("cm-ignore-events","true"),r.insertLeft&&(o.widgetNode.insertLeft=!0)),o.collapsed){if(Jt(e,t.line,t,n,o)||t.line!=n.line&&Jt(e,n.line,t,n,o))throw new Error("Inserting collapsed marker partially overlapping an existing one");At()}o.addToHistory&&No(e,{from:t,to:n,origin:"markText"},e.sel,NaN);var s,l=t.line,u=e.cm;if(e.iter(l,n.line+1,(function(r){u&&o.collapsed&&!u.options.lineWrapping&&Zt(r)==u.display.maxLine&&(s=!0),o.collapsed&&l!=t.line&&tt(r,0),Pt(r,new Mt(o,l==t.line?t.ch:null,l==n.line?n.ch:null),e.cm&&e.cm.curOp),++l})),o.collapsed&&e.iter(t.line,n.line+1,(function(t){on(e,t)&&tt(t,0)})),o.clearOnEnter&&me(o,"beforeCursorEnter",(function(){return o.clear()})),o.readOnly&&(Lt(),(e.history.done.length||e.history.undone.length)&&e.clearHistory()),o.collapsed&&(o.id=++ma,o.atomic=!0),u){if(s&&(u.curOp.updateMaxLine=!0),o.collapsed)jr(u,t.line,n.line+1);else if(o.className||o.startStyle||o.endStyle||o.css||o.attributes||o.title)for(var c=t.line;c<=n.line;c++)Vr(u,c,"text");o.atomic&&zo(u.doc),In(u,"markerAdded",u,o)}return o}ga.prototype.clear=function(){if(!this.explicitlyCleared){var e=this.doc.cm,t=e&&!e.curOp;if(t&&Si(e),Te(this,"clear")){var n=this.find();n&&In(this,"clear",n.from,n.to)}for(var r=null,i=null,o=0;oe.display.maxLineLength&&(e.display.maxLine=u,e.display.maxLineLength=c,e.display.maxLineChanged=!0)}null!=r&&e&&this.collapsed&&jr(e,r,i+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,e&&zo(e.doc)),e&&In(e,"markerCleared",e,this,r,i),t&&xi(e),this.parent&&this.parent.clear()}},ga.prototype.find=function(e,t){var n,r;null==e&&"bookmark"==this.type&&(e=1);for(var i=0;i=0;l--)Zo(this,r[l]);s?$o(this,s):this.cm&&li(this.cm)})),undo:Ri((function(){ta(this,"undo")})),redo:Ri((function(){ta(this,"redo")})),undoSelection:Ri((function(){ta(this,"undo",!0)})),redoSelection:Ri((function(){ta(this,"redo",!0)})),setExtending:function(e){this.extend=e},getExtending:function(){return this.extend},historySize:function(){for(var e=this.history,t=0,n=0,r=0;r=e.ch)&&t.push(i.marker.parent||i.marker)}return t},findMarks:function(e,t,n){e=pt(this,e),t=pt(this,t);var r=[],i=e.line;return this.iter(e.line,t.line+1,(function(o){var a=o.markedSpans;if(a)for(var s=0;s=l.to||null==l.from&&i!=e.line||null!=l.from&&i==t.line&&l.from>=t.ch||n&&!n(l.marker)||r.push(l.marker.parent||l.marker)}++i})),r},getAllMarks:function(){var e=[];return this.iter((function(t){var n=t.markedSpans;if(n)for(var r=0;re)return t=e,!0;e-=o,++n})),pt(this,at(n,t))},indexFromPos:function(e){var t=(e=pt(this,e)).ch;if(e.linet&&(t=e.from),null!=e.to&&e.to-1)return t.state.draggingText(e),void setTimeout((function(){return t.display.input.focus()}),20);try{var f=e.dataTransfer.getData("Text");if(f){var p;if(t.state.draggingText&&!t.state.draggingText.copy&&(p=t.listSelections()),Ho(t.doc,lo(n,n)),p)for(var h=0;h=0;t--)oa(e.doc,"",r[t].from,r[t].to,"+delete");li(e)}))}function Ka(e,t,n){var r=se(e.text,t+n,n);return r<0||r>e.text.length?null:r}function Qa(e,t,n){var r=Ka(e,t.ch,n);return null==r?null:new at(t.line,r,n<0?"after":"before")}function Xa(e,t,n,r,i){if(e){"rtl"==t.doc.direction&&(i=-i);var o=pe(n,t.doc.direction);if(o){var a,s=i<0?X(o):o[0],l=i<0==(1==s.level)?"after":"before";if(s.level>0||"rtl"==t.doc.direction){var u=rr(t,n);a=i<0?n.text.length-1:0;var c=ir(t,u,a).top;a=le((function(e){return ir(t,u,e).top==c}),i<0==(1==s.level)?s.from:s.to-1,a),"before"==l&&(a=Ka(n,a,1))}else a=i<0?s.to:s.from;return new at(r,a,l)}}return new at(r,i<0?n.text.length:0,i<0?"before":"after")}function Ya(e,t,n,i){var o=pe(t,e.doc.direction);if(!o)return Qa(t,n,i);n.ch>=t.text.length?(n.ch=t.text.length,n.sticky="before"):n.ch<=0&&(n.ch=0,n.sticky="after");var a=de(o,n.ch,n.sticky),s=o[a];if("ltr"==e.doc.direction&&s.level%2==0&&(i>0?s.to>n.ch:s.from=s.from&&p>=d.begin)){var h=f?"before":"after";return new at(n.line,p,h)}}var m=r((function(e,t,i){for(var a=r((function(e,t){return t?new at(n.line,u(e,1),"before"):new at(n.line,e,"after")}),"getRes");e>=0&&e0==(1!=s.level),c=l?i.begin:u(i.end,-1);if(s.from<=c&&c0?d.end:u(d.begin,-1);return null==v||i>0&&v==t.text.length||!(g=m(i>0?0:o.length-1,i,c(v)))?null:g}Va.basic={Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite",Esc:"singleSelection"},Va.pcDefault={"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart","Ctrl-End":"goDocEnd","Ctrl-Up":"goLineUp","Ctrl-Down":"goLineDown","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore","Ctrl-U":"undoSelection","Shift-Ctrl-U":"redoSelection","Alt-U":"redoSelection",fallthrough:"basic"},Va.emacsy={"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars","Ctrl-O":"openLine"},Va.macDefault={"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo","Cmd-Home":"goDocStart","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineLeft","Cmd-Right":"goLineRight","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delWrappedLineLeft","Cmd-Delete":"delWrappedLineRight","Cmd-U":"undoSelection","Shift-Cmd-U":"redoSelection","Ctrl-Up":"goDocStart","Ctrl-Down":"goDocEnd",fallthrough:["basic","emacsy"]},Va.default=b?Va.macDefault:Va.pcDefault,r(Ua,"normalizeKeyName"),r(Ba,"normalizeKeyMap"),r($a,"lookupKey"),r(qa,"isModifierKey"),r(Ha,"addModifierNames"),r(Ga,"keyName"),r(za,"getKeyMap"),r(Wa,"deleteNearSelection"),r(Ka,"moveCharLogically"),r(Qa,"moveLogically"),r(Xa,"endOfLine"),r(Ya,"moveVisually");var Ja={selectAll:Yo,singleSelection:function(e){return e.setSelection(e.getCursor("anchor"),e.getCursor("head"),H)},killLine:function(e){return Wa(e,(function(t){if(t.empty()){var n=Je(e.doc,t.head.line).text.length;return t.head.ch==n&&t.head.line0)i=new at(i.line,i.ch+1),e.replaceRange(o.charAt(i.ch-1)+o.charAt(i.ch-2),at(i.line,i.ch-2),i,"+transpose");else if(i.line>e.doc.first){var a=Je(e.doc,i.line-1).text;a&&(i=new at(i.line,1),e.replaceRange(o.charAt(0)+e.doc.lineSeparator()+a.charAt(a.length-1),at(i.line-1,a.length-1),i,"+transpose"))}n.push(new ao(i,i))}e.setSelections(n)}))},newlineAndIndent:function(e){return Li(e,(function(){for(var t=e.listSelections(),n=t.length-1;n>=0;n--)e.replaceRange(e.doc.lineSeparator(),t[n].anchor,t[n].head,"+input");t=e.listSelections();for(var r=0;r-1&&(st((i=a.ranges[i]).from(),t)<0||t.xRel>0)&&(st(i.to(),t)>0||t.xRel<0)?Cs(e,r,t,o):xs(e,r,t,o)}function Cs(e,t,n,i){var o=e.display,a=!1,c=Ai(e,(function(t){u&&(o.scroller.draggable=!1),e.state.draggingText=!1,e.state.delayingBlurEvent&&(e.hasFocus()?e.state.delayingBlurEvent=!1:Yr(e)),ve(o.wrapper.ownerDocument,"mouseup",c),ve(o.wrapper.ownerDocument,"mousemove",d),ve(o.scroller,"dragstart",f),ve(o.scroller,"drop",c),a||(Ce(t),i.addNew||Po(e.doc,n,null,null,i.extend),u&&!p||s&&9==l?setTimeout((function(){o.wrapper.ownerDocument.body.focus({preventScroll:!0}),o.input.focus()}),20):o.input.focus())})),d=r((function(e){a=a||Math.abs(t.clientX-e.clientX)+Math.abs(t.clientY-e.clientY)>=10}),"mouseMove"),f=r((function(){return a=!0}),"dragStart");u&&(o.scroller.draggable=!0),e.state.draggingText=c,c.copy=!i.moveOnDrag,me(o.wrapper.ownerDocument,"mouseup",c),me(o.wrapper.ownerDocument,"mousemove",d),me(o.scroller,"dragstart",f),me(o.scroller,"drop",c),e.state.delayingBlurEvent=!0,setTimeout((function(){return o.input.focus()}),20),o.scroller.dragDrop&&o.scroller.dragDrop()}function Ss(e,t,n){if("char"==n)return new ao(t,t);if("word"==n)return e.findWordAt(t);if("line"==n)return new ao(at(t.line,0),pt(e.doc,at(t.line+1,0)));var r=n(e,t);return new ao(r.from,r.to)}function xs(e,t,n,i){s&&Yr(e);var o=e.display,a=e.doc;Ce(t);var l,u,c=a.sel,d=c.ranges;if(i.addNew&&!i.extend?(u=a.sel.contains(n),l=u>-1?d[u]:new ao(n,n)):(l=a.sel.primary(),u=a.sel.primIndex),"rectangle"==i.unit)i.addNew||(l=new ao(n,n)),n=Fr(e,t,!0,!0),u=-1;else{var f=Ss(e,n,i.unit);l=i.extend?Fo(l,f.anchor,f.head,i.extend):f}i.addNew?-1==u?(u=d.length,qo(a,so(e,d.concat([l]),u),{scroll:!1,origin:"*mouse"})):d.length>1&&d[u].empty()&&"char"==i.unit&&!i.extend?(qo(a,so(e,d.slice(0,u).concat(d.slice(u+1)),0),{scroll:!1,origin:"*mouse"}),c=a.sel):Vo(a,u,l,G):(u=0,qo(a,new oo([l],0),G),c=a.sel);var p=n;function h(t){if(0!=st(p,t))if(p=t,"rectangle"==i.unit){for(var r=[],o=e.options.tabSize,s=V(Je(a,n.line).text,n.ch,o),d=V(Je(a,t.line).text,t.ch,o),f=Math.min(s,d),h=Math.max(s,d),m=Math.min(n.line,t.line),g=Math.min(e.lastLine(),Math.max(n.line,t.line));m<=g;m++){var v=Je(a,m).text,y=W(v,f,o);f==h?r.push(new ao(at(m,y),at(m,y))):v.length>y&&r.push(new ao(at(m,y),at(m,W(v,h,o))))}r.length||r.push(new ao(n,n)),qo(a,so(e,c.ranges.slice(0,u).concat(r),u),{origin:"*mouse",scroll:!1}),e.scrollIntoView(t)}else{var b,E=l,T=Ss(e,t,i.unit),w=E.anchor;st(T.anchor,w)>0?(b=T.head,w=dt(E.from(),T.anchor)):(b=T.anchor,w=ct(E.to(),T.head));var C=c.ranges.slice(0);C[u]=ks(e,new ao(pt(a,w),b)),qo(a,so(e,C,u),G)}}r(h,"extendTo");var m=o.wrapper.getBoundingClientRect(),g=0;function v(t){var n=++g,r=Fr(e,t,!0,"rectangle"==i.unit);if(r)if(0!=st(r,p)){e.curOp.focus=A(),h(r);var s=ni(o,a);(r.line>=s.to||r.linem.bottom?20:0;l&&setTimeout(Ai(e,(function(){g==n&&(o.scroller.scrollTop+=l,v(t))})),50)}}function y(t){e.state.selectingText=!1,g=1/0,t&&(Ce(t),o.input.focus()),ve(o.wrapper.ownerDocument,"mousemove",b),ve(o.wrapper.ownerDocument,"mouseup",E),a.history.lastSelOrigin=null}r(v,"extend"),r(y,"done");var b=Ai(e,(function(e){0!==e.buttons&&_e(e)?v(e):y(e)})),E=Ai(e,y);e.state.selectingText=E,me(o.wrapper.ownerDocument,"mousemove",b),me(o.wrapper.ownerDocument,"mouseup",E)}function ks(e,t){var n=t.anchor,r=t.head,i=Je(e.doc,n.line);if(0==st(n,r)&&n.sticky==r.sticky)return t;var o=pe(i);if(!o)return t;var a=de(o,n.ch,n.sticky),s=o[a];if(s.from!=n.ch&&s.to!=n.ch)return t;var l,u=a+(s.from==n.ch==(1!=s.level)?0:1);if(0==u||u==o.length)return t;if(r.line!=n.line)l=(r.line-n.line)*("ltr"==e.doc.direction?1:-1)>0;else{var c=de(o,r.ch,r.sticky),d=c-a||(r.ch-n.ch)*(1==s.level?-1:1);l=c==u-1||c==u?d<0:d>0}var f=o[u+(l?-1:0)],p=l==(1==f.level),h=p?f.from:f.to,m=p?"after":"before";return n.ch==h&&n.sticky==m?t:new ao(new at(n.line,h,m),r)}function Ns(e,t,n,r){var i,o;if(t.touches)i=t.touches[0].clientX,o=t.touches[0].clientY;else try{i=t.clientX,o=t.clientY}catch(e){return!1}if(i>=Math.floor(e.display.gutters.getBoundingClientRect().right))return!1;r&&Ce(t);var a=e.display,s=a.lineDiv.getBoundingClientRect();if(o>s.bottom||!Te(e,n))return xe(t);o-=s.top-a.viewOffset;for(var l=0;l=i)return ye(e,n,e,rt(e.doc,o),e.display.gutterSpecs[l].className,t),xe(t)}}function _s(e,t){return Ns(e,t,"gutterClick",!0)}function Os(e,t){Gn(e.display,t)||Is(e,t)||be(e,t,"contextmenu")||S||e.display.input.onContextMenu(t)}function Is(e,t){return!!Te(e,"gutterContextMenu")&&Ns(e,t,"gutterContextMenu",!1)}function Ds(e){e.display.wrapper.className=e.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+e.options.theme.replace(/(^|\s)\s*/g," cm-s-"),pr(e)}vs.prototype.compare=function(e,t,n){return this.time+gs>e&&0==st(t,this.pos)&&n==this.button},r(ys,"clickRepeat"),r(bs,"onMouseDown"),r(Es,"handleMappedButton"),r(Ts,"configureMouse"),r(ws,"leftButtonDown"),r(Cs,"leftButtonStartDrag"),r(Ss,"rangeForUnit"),r(xs,"leftButtonSelect"),r(ks,"bidiSimplify"),r(Ns,"gutterEvent"),r(_s,"clickInGutter"),r(Os,"onContextMenu"),r(Is,"contextMenuInGutter"),r(Ds,"themeChanged");var Ls={toString:function(){return"CodeMirror.Init"}},As={},Ms={};function Rs(e){var t=e.optionHandlers;function n(n,r,i,o){e.defaults[n]=r,i&&(t[n]=o?function(e,t,n){n!=Ls&&i(e,t,n)}:i)}r(n,"option"),e.defineOption=n,e.Init=Ls,n("value","",(function(e,t){return e.setValue(t)}),!0),n("mode",null,(function(e,t){e.doc.modeOption=t,mo(e)}),!0),n("indentUnit",2,mo,!0),n("indentWithTabs",!1),n("smartIndent",!0),n("tabSize",4,(function(e){go(e),pr(e),jr(e)}),!0),n("lineSeparator",null,(function(e,t){if(e.doc.lineSep=t,t){var n=[],r=e.doc.first;e.doc.iter((function(e){for(var i=0;;){var o=e.text.indexOf(t,i);if(-1==o)break;i=o+t.length,n.push(at(r,o))}r++}));for(var i=n.length-1;i>=0;i--)oa(e.doc,t,n[i],at(n[i].line,n[i].ch+t.length))}})),n("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g,(function(e,t,n){e.state.specialChars=new RegExp(t.source+(t.test("\t")?"":"|\t"),"g"),n!=Ls&&e.refresh()})),n("specialCharPlaceholder",vn,(function(e){return e.refresh()}),!0),n("electricChars",!0),n("inputStyle",y?"contenteditable":"textarea",(function(){throw new Error("inputStyle can not (yet) be changed in a running editor")}),!0),n("spellcheck",!1,(function(e,t){return e.getInputField().spellcheck=t}),!0),n("autocorrect",!1,(function(e,t){return e.getInputField().autocorrect=t}),!0),n("autocapitalize",!1,(function(e,t){return e.getInputField().autocapitalize=t}),!0),n("rtlMoveVisually",!T),n("wholeLineUpdateBefore",!0),n("theme","default",(function(e){Ds(e),Ji(e)}),!0),n("keyMap","default",(function(e,t,n){var r=za(t),i=n!=Ls&&za(n);i&&i.detach&&i.detach(e,r),r.attach&&r.attach(e,i||null)})),n("extraKeys",null),n("configureMouse",null),n("lineWrapping",!1,Ps,!0),n("gutters",[],(function(e,t){e.display.gutterSpecs=Xi(t,e.options.lineNumbers),Ji(e)}),!0),n("fixedGutter",!0,(function(e,t){e.display.gutters.style.left=t?Ar(e.display)+"px":"0",e.refresh()}),!0),n("coverGutterNextToScrollbar",!1,(function(e){return bi(e)}),!0),n("scrollbarStyle","native",(function(e){wi(e),bi(e),e.display.scrollbars.setScrollTop(e.doc.scrollTop),e.display.scrollbars.setScrollLeft(e.doc.scrollLeft)}),!0),n("lineNumbers",!1,(function(e,t){e.display.gutterSpecs=Xi(e.options.gutters,t),Ji(e)}),!0),n("firstLineNumber",1,Ji,!0),n("lineNumberFormatter",(function(e){return e}),Ji,!0),n("showCursorWhenSelecting",!1,Hr,!0),n("resetSelectionOnContextMenu",!0),n("lineWiseCopyCut",!0),n("pasteLinesPerSelection",!0),n("selectionsMayTouch",!1),n("readOnly",!1,(function(e,t){"nocursor"==t&&(Zr(e),e.display.input.blur()),e.display.input.readOnlyChanged(t)})),n("screenReaderLabel",null,(function(e,t){t=""===t?null:t,e.display.input.screenReaderLabelChanged(t)})),n("disableInput",!1,(function(e,t){t||e.display.input.reset()}),!0),n("dragDrop",!0,Fs),n("allowDropFileTypes",null),n("cursorBlinkRate",530),n("cursorScrollMargin",0),n("cursorHeight",1,Hr,!0),n("singleCursorHeightPerLine",!0,Hr,!0),n("workTime",100),n("workDelay",100),n("flattenSpans",!0,go,!0),n("addModeClass",!1,go,!0),n("pollInterval",100),n("undoDepth",200,(function(e,t){return e.doc.history.undoDepth=t})),n("historyEventDelay",1250),n("viewportMargin",10,(function(e){return e.refresh()}),!0),n("maxHighlightLength",1e4,go,!0),n("moveInputWithCursor",!0,(function(e,t){t||e.display.input.resetPosition()})),n("tabindex",null,(function(e,t){return e.display.input.getField().tabIndex=t||""})),n("autofocus",null),n("direction","ltr",(function(e,t){return e.doc.setDirection(t)}),!0),n("phrases",null)}function Fs(e,t,n){if(!t!=!(n&&n!=Ls)){var r=e.display.dragFunctions,i=t?me:ve;i(e.display.scroller,"dragstart",r.start),i(e.display.scroller,"dragenter",r.enter),i(e.display.scroller,"dragover",r.over),i(e.display.scroller,"dragleave",r.leave),i(e.display.scroller,"drop",r.drop)}}function Ps(e){e.options.lineWrapping?(M(e.display.wrapper,"CodeMirror-wrap"),e.display.sizer.style.minWidth="",e.display.sizerWidth=null):(N(e.display.wrapper,"CodeMirror-wrap"),un(e)),Rr(e),jr(e),pr(e),setTimeout((function(){return bi(e)}),100)}function js(e,t){var n=this;if(!(this instanceof js))return new js(e,t);this.options=t=t?j(t):{},j(As,t,!1);var r=t.value;"string"==typeof r?r=new Sa(r,t.mode,null,t.lineSeparator,t.direction):t.mode&&(r.modeOption=t.mode),this.doc=r;var i=new js.inputStyles[t.inputStyle](this),o=this.display=new Zi(e,r,i,t);for(var a in o.wrapper.CodeMirror=this,Ds(this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),wi(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:-1,cutIncoming:-1,selectingText:!1,draggingText:!1,highlight:new U,keySeq:null,specialChars:null},t.autofocus&&!y&&o.input.focus(),s&&l<11&&setTimeout((function(){return n.display.input.reset(!0)}),20),Vs(this),La(),Si(this),this.curOp.forceUpdate=!0,Eo(this,r),t.autofocus&&!y||this.hasFocus()?setTimeout((function(){n.hasFocus()&&!n.state.focused&&Jr(n)}),20):Zr(this),Ms)Ms.hasOwnProperty(a)&&Ms[a](this,t[a],Ls);Qi(this),t.finishInit&&t.finishInit(this);for(var c=0;c400}r(o,"finishTouch"),r(a,"isMouseLikeTouchEvent"),r(u,"farAway"),me(t.scroller,"touchstart",(function(r){if(!be(e,r)&&!a(r)&&!_s(e,r)){t.input.ensurePolled(),clearTimeout(n);var o=+new Date;t.activeTouch={start:o,moved:!1,prev:o-i.end<=300?i:null},1==r.touches.length&&(t.activeTouch.left=r.touches[0].pageX,t.activeTouch.top=r.touches[0].pageY)}})),me(t.scroller,"touchmove",(function(){t.activeTouch&&(t.activeTouch.moved=!0)})),me(t.scroller,"touchend",(function(n){var r=t.activeTouch;if(r&&!Gn(t,n)&&null!=r.left&&!r.moved&&new Date-r.start<300){var i,a=e.coordsChar(t.activeTouch,"page");i=!r.prev||u(r,r.prev)?new ao(a,a):!r.prev.prev||u(r,r.prev.prev)?e.findWordAt(a):new ao(at(a.line,0),pt(e.doc,at(a.line+1,0))),e.setSelection(i.anchor,i.head),e.focus(),Ce(n)}o()})),me(t.scroller,"touchcancel",o),me(t.scroller,"scroll",(function(){t.scroller.clientHeight&&(pi(e,t.scroller.scrollTop),mi(e,t.scroller.scrollLeft,!0),ye(e,"scroll",e))})),me(t.scroller,"mousewheel",(function(t){return io(e,t)})),me(t.scroller,"DOMMouseScroll",(function(t){return io(e,t)})),me(t.wrapper,"scroll",(function(){return t.wrapper.scrollTop=t.wrapper.scrollLeft=0})),t.dragFunctions={enter:function(t){be(e,t)||ke(t)},over:function(t){be(e,t)||(_a(e,t),ke(t))},start:function(t){return Na(e,t)},drop:Ai(e,ka),leave:function(t){be(e,t)||Oa(e)}};var c=t.input.getField();me(c,"keyup",(function(t){return fs.call(e,t)})),me(c,"keydown",Ai(e,cs)),me(c,"keypress",Ai(e,ps)),me(c,"focus",(function(t){return Jr(e,t)})),me(c,"blur",(function(t){return Zr(e,t)}))}r(Rs,"defineOptions"),r(Fs,"dragDropChanged"),r(Ps,"wrappingChanged"),r(js,"CodeMirror"),js.defaults=As,js.optionHandlers=Ms,r(Vs,"registerEventHandlers");var Us=[];function Bs(e,t,n,r){var i,o=e.doc;null==n&&(n="add"),"smart"==n&&(o.mode.indent?i=Et(e,t).state:n="prev");var a=e.options.tabSize,s=Je(o,t),l=V(s.text,null,a);s.stateAfter&&(s.stateAfter=null);var u,c=s.text.match(/^\s*/)[0];if(r||/\S/.test(s.text)){if("smart"==n&&((u=o.mode.indent(i,s.text.slice(c.length),s.text))==q||u>150)){if(!r)return;n="prev"}}else u=0,n="not";"prev"==n?u=t>o.first?V(Je(o,t-1).text,null,a):0:"add"==n?u=l+e.options.indentUnit:"subtract"==n?u=l-e.options.indentUnit:"number"==typeof n&&(u=l+n),u=Math.max(0,u);var d="",f=0;if(e.options.indentWithTabs)for(var p=Math.floor(u/a);p;--p)f+=a,d+="\t";if(fa,l=Re(t),u=null;if(s&&r.ranges.length>1)if($s&&$s.text.join("\n")==t){if(r.ranges.length%$s.text.length==0){u=[];for(var c=0;c<$s.text.length;c++)u.push(o.splitLines($s.text[c]))}}else l.length==r.ranges.length&&e.options.pasteLinesPerSelection&&(u=Y(l,(function(e){return[e]})));for(var d=e.curOp.updateInput,f=r.ranges.length-1;f>=0;f--){var p=r.ranges[f],h=p.from(),m=p.to();p.empty()&&(n&&n>0?h=at(h.line,h.ch-n):e.state.overwrite&&!s?m=at(m.line,Math.min(Je(o,m.line).text.length,m.ch+X(l).length)):s&&$s&&$s.lineWise&&$s.text.join("\n")==l.join("\n")&&(h=m=at(h.line,0)));var g={from:h,to:m,text:u?u[f%u.length]:l,origin:i||(s?"paste":e.state.cutIncoming>a?"cut":"+input")};Zo(e.doc,g),In(e,"inputRead",e,g)}t&&!s&&zs(e,t),li(e),e.curOp.updateInput<2&&(e.curOp.updateInput=d),e.curOp.typing=!0,e.state.pasteIncoming=e.state.cutIncoming=-1}function Gs(e,t){var n=e.clipboardData&&e.clipboardData.getData("Text");if(n)return e.preventDefault(),t.isReadOnly()||t.options.disableInput||Li(t,(function(){return Hs(t,n,0,null,"paste")})),!0}function zs(e,t){if(e.options.electricChars&&e.options.smartIndent)for(var n=e.doc.sel,r=n.ranges.length-1;r>=0;r--){var i=n.ranges[r];if(!(i.head.ch>100||r&&n.ranges[r-1].head.line==i.head.line)){var o=e.getModeAt(i.head),a=!1;if(o.electricChars){for(var s=0;s-1){a=Bs(e,i.head.line,"smart");break}}else o.electricInput&&o.electricInput.test(Je(e.doc,i.head.line).text.slice(0,i.head.ch))&&(a=Bs(e,i.head.line,"smart"));a&&In(e,"electricInput",e,i.head.line)}}}function Ws(e){for(var t=[],n=[],r=0;rn&&(Bs(this,i.head.line,e,!0),n=i.head.line,r==this.doc.sel.primIndex&&li(this));else{var o=i.from(),a=i.to(),s=Math.max(n,o.line);n=Math.min(this.lastLine(),a.line-(a.ch?0:1))+1;for(var l=s;l0&&Vo(this.doc,r,new ao(o,u[r].to()),H)}}})),getTokenAt:function(e,t){return xt(this,e,t)},getLineTokens:function(e,t){return xt(this,at(e),t,!0)},getTokenTypeAt:function(e){e=pt(this.doc,e);var t,n=bt(this,Je(this.doc,e.line)),r=0,i=(n.length-1)/2,o=e.ch;if(0==o)t=n[2];else for(;;){var a=r+i>>1;if((a?n[2*a-1]:0)>=o)i=a;else{if(!(n[2*a+1]o&&(e=o,i=!0),r=Je(this.doc,e)}else r=e;return vr(this,r,{top:0,left:0},t||"page",n||i).top+(i?this.doc.height-sn(r):0)},defaultTextHeight:function(){return Ir(this.display)},defaultCharWidth:function(){return Dr(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(e,t,n,r,i){var o=this.display,a=(e=Er(this,pt(this.doc,e))).bottom,s=e.left;if(t.style.position="absolute",t.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(t),o.sizer.appendChild(t),"over"==r)a=e.top;else if("above"==r||"near"==r){var l=Math.max(o.wrapper.clientHeight,this.doc.height),u=Math.max(o.sizer.clientWidth,o.lineSpace.clientWidth);("above"==r||e.bottom+t.offsetHeight>l)&&e.top>t.offsetHeight?a=e.top-t.offsetHeight:e.bottom+t.offsetHeight<=l&&(a=e.bottom),s+t.offsetWidth>u&&(s=u-t.offsetWidth)}t.style.top=a+"px",t.style.left=t.style.right="","right"==i?(s=o.sizer.clientWidth-t.offsetWidth,t.style.right="0px"):("left"==i?s=0:"middle"==i&&(s=(o.sizer.clientWidth-t.offsetWidth)/2),t.style.left=s+"px"),n&&oi(this,{left:s,top:a,right:s+t.offsetWidth,bottom:a+t.offsetHeight})},triggerOnKeyDown:Mi(cs),triggerOnKeyPress:Mi(ps),triggerOnKeyUp:fs,triggerOnMouseDown:Mi(bs),execCommand:function(e){if(Ja.hasOwnProperty(e))return Ja[e].call(null,this)},triggerElectric:Mi((function(e){zs(this,e)})),findPosH:function(e,t,n,r){var i=1;t<0&&(i=-1,t=-t);for(var o=pt(this.doc,e),a=0;a0&&a(t.charAt(n-1));)--n;for(;r.5||this.options.lineWrapping)&&Rr(this),ye(this,"refresh",this)})),swapDoc:Mi((function(e){var t=this.doc;return t.cm=null,this.state.selectingText&&this.state.selectingText(),Eo(this,e),pr(this),this.display.input.reset(),ui(this,e.scrollLeft,e.scrollTop),this.curOp.forceScroll=!0,In(this,"swapDoc",this,t),t})),phrase:function(e){var t=this.options.phrases;return t&&Object.prototype.hasOwnProperty.call(t,e)?t[e]:e},getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},we(e),e.registerHelper=function(t,r,i){n.hasOwnProperty(t)||(n[t]=e[t]={_global:[]}),n[t][r]=i},e.registerGlobalHelper=function(t,r,i,o){e.registerHelper(t,r,o),n[t]._global.push({pred:i,val:o})}}function Ys(e,t,n,i,o){var a=t,s=n,l=Je(e,t.line),u=o&&"rtl"==e.direction?-n:n;function c(){var n=t.line+u;return!(n=e.first+e.size)&&(t=new at(n,t.ch,t.sticky),l=Je(e,n))}function d(r){var a;if("codepoint"==i){var s=l.text.charCodeAt(t.ch+(n>0?0:-1));if(isNaN(s))a=null;else{var d=n>0?s>=55296&&s<56320:s>=56320&&s<57343;a=new at(t.line,Math.max(0,Math.min(l.text.length,t.ch+n*(d?2:1))),-n)}}else a=o?Ya(e.cm,l,t,n):Qa(l,t,n);if(null==a){if(r||!c())return!1;t=Xa(o,e.cm,l,t.line,u)}else t=a;return!0}if(r(c,"findNextLine"),r(d,"moveOnce"),"char"==i||"codepoint"==i)d();else if("column"==i)d(!0);else if("word"==i||"group"==i)for(var f=null,p="group"==i,h=e.cm&&e.cm.getHelper(t,"wordChars"),m=!0;!(n<0)||d(!m);m=!1){var g=l.text.charAt(t.ch)||"\n",v=re(g,h)?"w":p&&"\n"==g?"n":!p||/\s/.test(g)?null:"p";if(!p||m||v||(v="s"),f&&f!=v){n<0&&(n=1,d(),t.sticky="after");break}if(v&&(f=v),n>0&&!d(!m))break}var y=Qo(e,t,a,s,!0);return lt(a,y)&&(y.hitSide=!0),y}function Js(e,t,n,r){var i,o,a=e.doc,s=t.left;if("page"==r){var l=Math.min(e.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight),u=Math.max(l-.5*Ir(e.display),3);i=(n>0?t.bottom:t.top)+n*u}else"line"==r&&(i=n>0?t.bottom+3:t.top-3);for(;(o=Cr(e,s,i)).outside;){if(n<0?i<=0:i>=a.height){o.hitSide=!0;break}i+=5*n}return o}r(qs,"setLastCopied"),r(Hs,"applyTextInput"),r(Gs,"handlePaste"),r(zs,"triggerElectric"),r(Ws,"copyableRanges"),r(Ks,"disableBrowserMagic"),r(Qs,"hiddenTextarea"),r(Xs,"addEditorMethods"),r(Ys,"findPosH"),r(Js,"findPosV");var Zs=r((function(e){this.cm=e,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new U,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null}),"ContentEditableInput");function el(e,t){var n=nr(e,t.line);if(!n||n.hidden)return null;var r=Je(e.doc,t.line),i=Zn(n,r,t.line),o=pe(r,e.doc.direction),a="left";o&&(a=de(o,t.ch)%2?"right":"left");var s=sr(i.map,t.ch,a);return s.offset="right"==s.collapse?s.end:s.start,s}function tl(e){for(var t=e;t;t=t.parentNode)if(/CodeMirror-gutter-wrapper/.test(t.className))return!0;return!1}function nl(e,t){return t&&(e.bad=!0),e}function rl(e,t,n,i,o){var a="",s=!1,l=e.doc.lineSeparator(),u=!1;function c(e){return function(t){return t.id==e}}function d(){s&&(a+=l,u&&(a+=l),s=u=!1)}function f(e){e&&(d(),a+=e)}function p(t){if(1==t.nodeType){var n=t.getAttribute("cm-text");if(n)return void f(n);var r,a=t.getAttribute("cm-marker");if(a){var h=e.findMarks(at(i,0),at(o+1,0),c(+a));return void(h.length&&(r=h[0].find(0))&&f(Ze(e.doc,r.from,r.to).join(l)))}if("false"==t.getAttribute("contenteditable"))return;var m=/^(pre|div|p|li|table|br)$/i.test(t.nodeName);if(!/^br$/i.test(t.nodeName)&&0==t.textContent.length)return;m&&d();for(var g=0;g=t.display.viewTo||o.line=t.display.viewFrom&&el(t,i)||{node:l[0].measure.map[2],offset:0},c=o.liner.firstLine()&&(a=at(a.line-1,Je(r.doc,a.line-1).length)),s.ch==Je(r.doc,s.line).text.length&&s.linei.viewTo-1)return!1;a.line==i.viewFrom||0==(e=Pr(r,a.line))?(t=nt(i.view[0].line),n=i.view[0].node):(t=nt(i.view[e].line),n=i.view[e-1].node.nextSibling);var l,u,c=Pr(r,s.line);if(c==i.view.length-1?(l=i.viewTo-1,u=i.lineDiv.lastChild):(l=nt(i.view[c+1].line)-1,u=i.view[c+1].node.previousSibling),!n)return!1;for(var d=r.doc.splitLines(rl(r,n,u,t,l)),f=Ze(r.doc,at(t,0),at(l,Je(r.doc,l).text.length));d.length>1&&f.length>1;)if(X(d)==X(f))d.pop(),f.pop(),l--;else{if(d[0]!=f[0])break;d.shift(),f.shift(),t++}for(var p=0,h=0,m=d[0],g=f[0],v=Math.min(m.length,g.length);pa.ch&&y.charCodeAt(y.length-h-1)==b.charCodeAt(b.length-h-1);)p--,h++;d[d.length-1]=y.slice(0,y.length-h).replace(/^\u200b+/,""),d[0]=d[0].slice(p).replace(/\u200b+$/,"");var T=at(t,p),w=at(l,f.length?X(f).length-h:0);return d.length>1||d[0]||st(T,w)?(oa(r.doc,d,T,w,"+input"),!0):void 0},Zs.prototype.ensurePolled=function(){this.forceCompositionEnd()},Zs.prototype.reset=function(){this.forceCompositionEnd()},Zs.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},Zs.prototype.readFromDOMSoon=function(){var e=this;null==this.readDOMTimeout&&(this.readDOMTimeout=setTimeout((function(){if(e.readDOMTimeout=null,e.composing){if(!e.composing.done)return;e.composing=null}e.updateFromDOM()}),80))},Zs.prototype.updateFromDOM=function(){var e=this;!this.cm.isReadOnly()&&this.pollContent()||Li(this.cm,(function(){return jr(e.cm)}))},Zs.prototype.setUneditable=function(e){e.contentEditable="false"},Zs.prototype.onKeyPress=function(e){0==e.charCode||this.composing||(e.preventDefault(),this.cm.isReadOnly()||Ai(this.cm,Hs)(this.cm,String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),0))},Zs.prototype.readOnlyChanged=function(e){this.div.contentEditable=String("nocursor"!=e)},Zs.prototype.onContextMenu=function(){},Zs.prototype.resetPosition=function(){},Zs.prototype.needsContentAttribute=!0,r(el,"posToDOM"),r(tl,"isInGutter"),r(nl,"badPos"),r(rl,"domTextBetween"),r(il,"domToPos"),r(ol,"locateNodeInLineView");var al=r((function(e){this.cm=e,this.prevInput="",this.pollingFast=!1,this.polling=new U,this.hasSelection=!1,this.composing=null}),"TextareaInput");function sl(e,t){if((t=t?j(t):{}).value=e.value,!t.tabindex&&e.tabIndex&&(t.tabindex=e.tabIndex),!t.placeholder&&e.placeholder&&(t.placeholder=e.placeholder),null==t.autofocus){var n=A();t.autofocus=n==e||null!=e.getAttribute("autofocus")&&n==document.body}function i(){e.value=l.getValue()}var o;if(r(i,"save"),e.form&&(me(e.form,"submit",i),!t.leaveSubmitMethodAlone)){var a=e.form;o=a.submit;try{var s=a.submit=function(){i(),a.submit=o,a.submit(),a.submit=s}}catch(e){}}t.finishInit=function(n){n.save=i,n.getTextArea=function(){return e},n.toTextArea=function(){n.toTextArea=isNaN,i(),e.parentNode.removeChild(n.getWrapperElement()),e.style.display="",e.form&&(ve(e.form,"submit",i),t.leaveSubmitMethodAlone||"function"!=typeof e.form.submit||(e.form.submit=o))}},e.style.display="none";var l=js((function(t){return e.parentNode.insertBefore(t,e.nextSibling)}),t);return l}function ll(e){e.off=ve,e.on=me,e.wheelEventPixels=ro,e.Doc=Sa,e.splitLines=Re,e.countColumn=V,e.findColumn=W,e.isWordChar=ne,e.Pass=q,e.signal=ye,e.Line=cn,e.changeEnd=uo,e.scrollbarModel=Ti,e.Pos=at,e.cmpPos=st,e.modes=Ue,e.mimeModes=Be,e.resolveMode=He,e.getMode=Ge,e.modeExtensions=ze,e.extendMode=We,e.copyState=Ke,e.startState=Xe,e.innerMode=Qe,e.commands=Ja,e.keyMap=Va,e.keyName=Ga,e.isModifierKey=qa,e.lookupKey=$a,e.normalizeKeyMap=Ba,e.StringStream=Ye,e.SharedTextMarker=ya,e.TextMarker=ga,e.LineWidget=fa,e.e_preventDefault=Ce,e.e_stopPropagation=Se,e.e_stop=ke,e.addClass=M,e.contains=L,e.rmClass=N,e.keyNames=Ra}al.prototype.init=function(e){var t=this,n=this,i=this.cm;this.createField(e);var o=this.textarea;function a(e){if(!be(i,e)){if(i.somethingSelected())qs({lineWise:!1,text:i.getSelections()});else{if(!i.options.lineWiseCopyCut)return;var t=Ws(i);qs({lineWise:!0,text:t.text}),"cut"==e.type?i.setSelections(t.ranges,null,H):(n.prevInput="",o.value=t.text.join("\n"),F(o))}"cut"==e.type&&(i.state.cutIncoming=+new Date)}}e.wrapper.insertBefore(this.wrapper,e.wrapper.firstChild),g&&(o.style.width="0px"),me(o,"input",(function(){s&&l>=9&&t.hasSelection&&(t.hasSelection=null),n.poll()})),me(o,"paste",(function(e){be(i,e)||Gs(e,i)||(i.state.pasteIncoming=+new Date,n.fastPoll())})),r(a,"prepareCopyCut"),me(o,"cut",a),me(o,"copy",a),me(e.scroller,"paste",(function(t){if(!Gn(e,t)&&!be(i,t)){if(!o.dispatchEvent)return i.state.pasteIncoming=+new Date,void n.focus();var r=new Event("paste");r.clipboardData=t.clipboardData,o.dispatchEvent(r)}})),me(e.lineSpace,"selectstart",(function(t){Gn(e,t)||Ce(t)})),me(o,"compositionstart",(function(){var e=i.getCursor("from");n.composing&&n.composing.range.clear(),n.composing={start:e,range:i.markText(e,i.getCursor("to"),{className:"CodeMirror-composing"})}})),me(o,"compositionend",(function(){n.composing&&(n.poll(),n.composing.range.clear(),n.composing=null)}))},al.prototype.createField=function(e){this.wrapper=Qs(),this.textarea=this.wrapper.firstChild},al.prototype.screenReaderLabelChanged=function(e){e?this.textarea.setAttribute("aria-label",e):this.textarea.removeAttribute("aria-label")},al.prototype.prepareSelection=function(){var e=this.cm,t=e.display,n=e.doc,r=Gr(e);if(e.options.moveInputWithCursor){var i=Er(e,n.sel.primary().head,"div"),o=t.wrapper.getBoundingClientRect(),a=t.lineDiv.getBoundingClientRect();r.teTop=Math.max(0,Math.min(t.wrapper.clientHeight-10,i.top+a.top-o.top)),r.teLeft=Math.max(0,Math.min(t.wrapper.clientWidth-10,i.left+a.left-o.left))}return r},al.prototype.showSelection=function(e){var t=this.cm.display;O(t.cursorDiv,e.cursors),O(t.selectionDiv,e.selection),null!=e.teTop&&(this.wrapper.style.top=e.teTop+"px",this.wrapper.style.left=e.teLeft+"px")},al.prototype.reset=function(e){if(!this.contextMenuPending&&!this.composing){var t=this.cm;if(t.somethingSelected()){this.prevInput="";var n=t.getSelection();this.textarea.value=n,t.state.focused&&F(this.textarea),s&&l>=9&&(this.hasSelection=n)}else e||(this.prevInput=this.textarea.value="",s&&l>=9&&(this.hasSelection=null))}},al.prototype.getField=function(){return this.textarea},al.prototype.supportsTouch=function(){return!1},al.prototype.focus=function(){if("nocursor"!=this.cm.options.readOnly&&(!y||A()!=this.textarea))try{this.textarea.focus()}catch(e){}},al.prototype.blur=function(){this.textarea.blur()},al.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},al.prototype.receivedFocus=function(){this.slowPoll()},al.prototype.slowPoll=function(){var e=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,(function(){e.poll(),e.cm.state.focused&&e.slowPoll()}))},al.prototype.fastPoll=function(){var e=!1,t=this;function n(){t.poll()||e?(t.pollingFast=!1,t.slowPoll()):(e=!0,t.polling.set(60,n))}t.pollingFast=!0,r(n,"p"),t.polling.set(20,n)},al.prototype.poll=function(){var e=this,t=this.cm,n=this.textarea,r=this.prevInput;if(this.contextMenuPending||!t.state.focused||Fe(n)&&!r&&!this.composing||t.isReadOnly()||t.options.disableInput||t.state.keySeq)return!1;var i=n.value;if(i==r&&!t.somethingSelected())return!1;if(s&&l>=9&&this.hasSelection===i||b&&/[\uf700-\uf7ff]/.test(i))return t.display.input.reset(),!1;if(t.doc.sel==t.display.selForContextMenu){var o=i.charCodeAt(0);if(8203!=o||r||(r="​"),8666==o)return this.reset(),this.cm.execCommand("undo")}for(var a=0,u=Math.min(r.length,i.length);a1e3||i.indexOf("\n")>-1?n.value=e.prevInput="":e.prevInput=i,e.composing&&(e.composing.range.clear(),e.composing.range=t.markText(e.composing.start,t.getCursor("to"),{className:"CodeMirror-composing"}))})),!0},al.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},al.prototype.onKeyPress=function(){s&&l>=9&&(this.hasSelection=null),this.fastPoll()},al.prototype.onContextMenu=function(e){var t=this,n=t.cm,i=n.display,o=t.textarea;t.contextMenuPending&&t.contextMenuPending();var a=Fr(n,e),c=i.scroller.scrollTop;if(a&&!f){n.options.resetSelectionOnContextMenu&&-1==n.doc.sel.contains(a)&&Ai(n,qo)(n.doc,lo(a),H);var d,p=o.style.cssText,h=t.wrapper.style.cssText,m=t.wrapper.offsetParent.getBoundingClientRect();if(t.wrapper.style.cssText="position: static",o.style.cssText="position: absolute; width: 30px; height: 30px;\n top: "+(e.clientY-m.top-5)+"px; left: "+(e.clientX-m.left-5)+"px;\n z-index: 1000; background: "+(s?"rgba(255, 255, 255, .05)":"transparent")+";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);",u&&(d=window.scrollY),i.input.focus(),u&&window.scrollTo(null,d),i.input.reset(),n.somethingSelected()||(o.value=t.prevInput=" "),t.contextMenuPending=y,i.selForContextMenu=n.doc.sel,clearTimeout(i.detectingSelectAll),r(v,"prepareSelectAllHack"),r(y,"rehide"),s&&l>=9&&v(),S){ke(e);var g=r((function(){ve(window,"mouseup",g),setTimeout(y,20)}),"mouseup");me(window,"mouseup",g)}else setTimeout(y,50)}function v(){if(null!=o.selectionStart){var e=n.somethingSelected(),r="​"+(e?o.value:"");o.value="⇚",o.value=r,t.prevInput=e?"":"​",o.selectionStart=1,o.selectionEnd=r.length,i.selForContextMenu=n.doc.sel}}function y(){if(t.contextMenuPending==y&&(t.contextMenuPending=!1,t.wrapper.style.cssText=h,o.style.cssText=p,s&&l<9&&i.scrollbars.setScrollTop(i.scroller.scrollTop=c),null!=o.selectionStart)){(!s||s&&l<9)&&v();var e=0,a=r((function(){i.selForContextMenu==n.doc.sel&&0==o.selectionStart&&o.selectionEnd>0&&"​"==t.prevInput?Ai(n,Yo)(n):e++<10?i.detectingSelectAll=setTimeout(a,500):(i.selForContextMenu=null,i.input.reset())}),"poll");i.detectingSelectAll=setTimeout(a,200)}}},al.prototype.readOnlyChanged=function(e){e||this.reset(),this.textarea.disabled="nocursor"==e,this.textarea.readOnly=!!e},al.prototype.setUneditable=function(){},al.prototype.needsContentAttribute=!1,r(sl,"fromTextArea"),r(ll,"addLegacyProps"),Rs(js),Xs(js);var ul="iter insert remove copy getEditor constructor".split(" ");for(var cl in Sa.prototype)Sa.prototype.hasOwnProperty(cl)&&B(ul,cl)<0&&(js.prototype[cl]=function(e){return function(){return e.apply(this.doc,arguments)}}(Sa.prototype[cl]));return we(Sa),js.inputStyles={textarea:al,contenteditable:Zs},js.defineMode=function(e){js.defaults.mode||"null"==e||(js.defaults.mode=e),$e.apply(this,arguments)},js.defineMIME=qe,js.defineMode("null",(function(){return{token:function(e){return e.skipToEnd()}}})),js.defineMIME("text/plain","null"),js.defineExtension=function(e,t){js.prototype[e]=t},js.defineDocExtension=function(e,t){Sa.prototype[e]=t},js.fromTextArea=sl,ll(js),js.version="5.65.3",js}()}(o);var a=o.exports;e.C=a;var s=i({__proto__:null,default:a},[o.exports]);e.c=s},void 0===(o=r.apply(t,i))||(e.exports=o)},6754:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535)],void 0===(o="function"==typeof(r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.c=void 0;var n=Object.defineProperty,r=(e,t)=>n(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};!function(e){var t={},n=/[^\s\u00a0]/,i=e.Pos,o=e.cmpPos;function a(e){var t=e.search(n);return-1==t?0:t}function s(e,t,n){return/\bstring\b/.test(e.getTokenTypeAt(i(t.line,0)))&&!/^[\'\"\`]/.test(n)}function l(e,t){var n=e.getMode();return!1!==n.useInnerComments&&n.innerMode?e.getModeAt(t):n}r(a,"firstNonWS"),e.commands.toggleComment=function(e){e.toggleComment()},e.defineExtension("toggleComment",(function(e){e||(e=t);for(var n=this,r=1/0,o=this.listSelections(),a=null,s=o.length-1;s>=0;s--){var l=o[s].from(),u=o[s].to();l.line>=r||(u.line>=r&&(u=i(r,0)),r=l.line,null==a?n.uncomment(l,u,e)?a="un":(n.lineComment(l,u,e),a="line"):"un"==a?n.uncomment(l,u,e):n.lineComment(l,u,e))}})),r(s,"probablyInsideString"),r(l,"getMode"),e.defineExtension("lineComment",(function(e,r,o){o||(o=t);var u=this,c=l(u,e),d=u.getLine(e.line);if(null!=d&&!s(u,e,d)){var f=o.lineComment||c.lineComment;if(f){var p=Math.min(0!=r.ch||r.line==e.line?r.line+1:r.line,u.lastLine()+1),h=null==o.padding?" ":o.padding,m=o.commentBlankLines||e.line==r.line;u.operation((function(){if(o.indent){for(var t=null,r=e.line;rs.length)&&(t=s)}for(r=e.line;rf||s.operation((function(){if(0!=a.fullLines){var t=n.test(s.getLine(f));s.replaceRange(p+d,i(f)),s.replaceRange(c+p,i(e.line,0));var l=a.blockCommentLead||u.blockCommentLead;if(null!=l)for(var h=e.line+1;h<=f;++h)(h!=f||t)&&s.replaceRange(l+p,i(h,0))}else{var m=0==o(s.getCursor("to"),r),g=!s.somethingSelected();s.replaceRange(d,r),m&&s.setSelection(g?r:s.getCursor("from"),r),s.replaceRange(c,e)}}))}}else(a.lineComment||u.lineComment)&&0!=a.fullLines&&s.lineComment(e,r,a)})),e.defineExtension("uncomment",(function(e,r,o){o||(o=t);var a,s=this,u=l(s,e),c=Math.min(0!=r.ch||r.line==e.line?r.line:r.line-1,s.lastLine()),d=Math.min(e.line,c),f=o.lineComment||u.lineComment,p=[],h=null==o.padding?" ":o.padding;e:if(f){for(var m=d;m<=c;++m){var g=s.getLine(m),v=g.indexOf(f);if(v>-1&&!/comment/.test(s.getTokenTypeAt(i(m,v+1)))&&(v=-1),-1==v&&n.test(g))break e;if(v>-1&&n.test(g.slice(0,v)))break e;p.push(g)}if(s.operation((function(){for(var e=d;e<=c;++e){var t=p[e-d],n=t.indexOf(f),r=n+f.length;n<0||(t.slice(r,r+h.length)==h&&(r+=h.length),a=!0,s.replaceRange("",i(e,n),i(e,r)))}})),a)return!0}var y=o.blockCommentStart||u.blockCommentStart,b=o.blockCommentEnd||u.blockCommentEnd;if(!y||!b)return!1;var E=o.blockCommentLead||u.blockCommentLead,T=s.getLine(d),w=T.indexOf(y);if(-1==w)return!1;var C=c==d?T:s.getLine(c),S=C.indexOf(b,c==d?w+y.length:0),x=i(d,w+1),k=i(c,S+1);if(-1==S||!/comment/.test(s.getTokenTypeAt(x))||!/comment/.test(s.getTokenTypeAt(k))||s.getRange(x,k,"\n").indexOf(b)>-1)return!1;var N=T.lastIndexOf(y,e.ch),_=-1==N?-1:T.slice(0,e.ch).indexOf(b,N+y.length);if(-1!=N&&-1!=_&&_+b.length!=e.ch)return!1;_=C.indexOf(b,r.ch);var O=C.slice(r.ch).lastIndexOf(y,_-r.ch);return N=-1==_||-1==O?-1:r.ch+O,(-1==_||-1==N||N==r.ch)&&(s.operation((function(){s.replaceRange("",i(c,S-(h&&C.slice(S-h.length,S)==h?h.length:0)),i(c,S+b.length));var e=w+y.length;if(h&&T.slice(e,e+h.length)==h&&(e+=h.length),s.replaceRange("",i(d,w),i(d,e)),E)for(var t=d+1;t<=c;++t){var r=s.getLine(t),o=r.indexOf(E);if(-1!=o&&!n.test(r.slice(0,o))){var a=o+E.length;h&&r.slice(a,a+h.length)==h&&(a+=h.length),s.replaceRange("",i(t,o),i(t,a))}}})),!0)}))}(t.a.exports);var a=i({__proto__:null,default:o.exports},[o.exports]);e.c=a})?r.apply(t,i):r)||(e.exports=o)},8058:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535)],void 0===(o="function"==typeof(r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.d=e.a=void 0;var n=Object.defineProperty,r=(e,t)=>n(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};e.a=o,function(e){function t(t,n,r){var i,o=t.getWrapperElement();return(i=o.appendChild(document.createElement("div"))).className=r?"CodeMirror-dialog CodeMirror-dialog-bottom":"CodeMirror-dialog CodeMirror-dialog-top","string"==typeof n?i.innerHTML=n:i.appendChild(n),e.addClass(o,"dialog-opened"),i}function n(e,t){e.state.currentNotificationClose&&e.state.currentNotificationClose(),e.state.currentNotificationClose=t}r(t,"dialogDiv"),r(n,"closeNotification"),e.defineExtension("openDialog",(function(i,o,a){a||(a={}),n(this,null);var s=t(this,i,a.bottom),l=!1,u=this;function c(t){if("string"==typeof t)f.value=t;else{if(l)return;l=!0,e.rmClass(s.parentNode,"dialog-opened"),s.parentNode.removeChild(s),u.focus(),a.onClose&&a.onClose(s)}}r(c,"close");var d,f=s.getElementsByTagName("input")[0];return f?(f.focus(),a.value&&(f.value=a.value,!1!==a.selectValueOnOpen&&f.select()),a.onInput&&e.on(f,"input",(function(e){a.onInput(e,f.value,c)})),a.onKeyUp&&e.on(f,"keyup",(function(e){a.onKeyUp(e,f.value,c)})),e.on(f,"keydown",(function(t){a&&a.onKeyDown&&a.onKeyDown(t,f.value,c)||((27==t.keyCode||!1!==a.closeOnEnter&&13==t.keyCode)&&(f.blur(),e.e_stop(t),c()),13==t.keyCode&&o(f.value,t))})),!1!==a.closeOnBlur&&e.on(s,"focusout",(function(e){null!==e.relatedTarget&&c()}))):(d=s.getElementsByTagName("button")[0])&&(e.on(d,"click",(function(){c(),u.focus()})),!1!==a.closeOnBlur&&e.on(d,"blur",c),d.focus()),c})),e.defineExtension("openConfirm",(function(i,o,a){n(this,null);var s=t(this,i,a&&a.bottom),l=s.getElementsByTagName("button"),u=!1,c=this,d=1;function f(){u||(u=!0,e.rmClass(s.parentNode,"dialog-opened"),s.parentNode.removeChild(s),c.focus())}r(f,"close"),l[0].focus();for(var p=0;pn(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};!function(e){function t(t,i,a,s){if(a&&a.call){var l=a;a=null}else l=o(t,a,"rangeFinder");"number"==typeof i&&(i=e.Pos(i,0));var u=o(t,a,"minFoldSize");function c(e){var n=l(t,i);if(!n||n.to.line-n.from.linet.firstLine();)i=e.Pos(i.line-1,0),d=c(!1);if(d&&!d.cleared&&"unfold"!==s){var f=n(t,a,d);e.on(f,"mousedown",(function(t){p.clear(),e.e_preventDefault(t)}));var p=t.markText(d.from,d.to,{replacedWith:f,clearOnEnter:o(t,a,"clearOnEnter"),__isFold:!0});p.on("clear",(function(n,r){e.signal(t,"unfold",t,n,r)})),e.signal(t,"fold",t,d.from,d.to)}}function n(e,t,n){var r=o(e,t,"widget");if("function"==typeof r&&(r=r(n.from,n.to)),"string"==typeof r){var i=document.createTextNode(r);(r=document.createElement("span")).appendChild(i),r.className="CodeMirror-foldmarker"}else r&&(r=r.cloneNode(!0));return r}r(t,"doFold"),r(n,"makeWidget"),e.newFoldFunction=function(e,n){return function(r,i){t(r,i,{rangeFinder:e,widget:n})}},e.defineExtension("foldCode",(function(e,n,r){t(this,e,n,r)})),e.defineExtension("isFolded",(function(e){for(var t=this.findMarksAt(e),n=0;n=u){if(f&&l&&f.test(l.className))return;r=a(i.indicatorOpen)}}(r||l)&&e.setGutterMarker(n,i.gutter,r)}))}function l(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}function u(e){var t=e.getViewport(),n=e.state.foldGutter;n&&(e.operation((function(){s(e,t.from,t.to)})),n.from=t.from,n.to=t.to)}function c(e,n,r){var i=e.state.foldGutter;if(i){var a=i.options;if(r==a.gutter){var s=o(e,n);s?s.clear():e.foldCode(t(n,0),a)}}}function d(e){var t=e.state.foldGutter;if(t){var n=t.options;t.from=t.to=0,clearTimeout(t.changeUpdate),t.changeUpdate=setTimeout((function(){u(e)}),n.foldOnChangeTimeSpan||600)}}function f(e){var t=e.state.foldGutter;if(t){var n=t.options;clearTimeout(t.changeUpdate),t.changeUpdate=setTimeout((function(){var n=e.getViewport();t.from==t.to||n.from-t.to>20||t.from-n.to>20?u(e):e.operation((function(){n.fromt.to&&(s(e,t.to,n.to),t.to=n.to)}))}),n.updateViewportTimeSpan||400)}}function p(e,t){var n=e.state.foldGutter;if(n){var r=t.line;r>=n.from&&r=0;e--)t(n[e])}Object.defineProperty(e,"__esModule",{value:!0}),e.f=t,(0,Object.defineProperty)(t,"name",{value:"forEachState",configurable:!0})})?n.apply(t,[t]):n)||(e.exports=r)},7139:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(6856),n(9196),n(3573),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"Argument",{enumerable:!0,get:function(){return t.A}}),Object.defineProperty(e,"ArgumentIcon",{enumerable:!0,get:function(){return t.ac}}),Object.defineProperty(e,"Button",{enumerable:!0,get:function(){return t.aH}}),Object.defineProperty(e,"ButtonGroup",{enumerable:!0,get:function(){return t.aI}}),Object.defineProperty(e,"ChevronDownIcon",{enumerable:!0,get:function(){return t.ad}}),Object.defineProperty(e,"ChevronLeftIcon",{enumerable:!0,get:function(){return t.ae}}),Object.defineProperty(e,"ChevronUpIcon",{enumerable:!0,get:function(){return t.af}}),Object.defineProperty(e,"CloseIcon",{enumerable:!0,get:function(){return t.ag}}),Object.defineProperty(e,"CopyIcon",{enumerable:!0,get:function(){return t.ah}}),Object.defineProperty(e,"DOC_EXPLORER_PLUGIN",{enumerable:!0,get:function(){return t._}}),Object.defineProperty(e,"DefaultValue",{enumerable:!0,get:function(){return t.D}}),Object.defineProperty(e,"DeprecatedArgumentIcon",{enumerable:!0,get:function(){return t.ai}}),Object.defineProperty(e,"DeprecatedEnumValueIcon",{enumerable:!0,get:function(){return t.aj}}),Object.defineProperty(e,"DeprecatedFieldIcon",{enumerable:!0,get:function(){return t.ak}}),Object.defineProperty(e,"DeprecationReason",{enumerable:!0,get:function(){return t.w}}),Object.defineProperty(e,"Dialog",{enumerable:!0,get:function(){return t.aJ}}),Object.defineProperty(e,"Directive",{enumerable:!0,get:function(){return t.x}}),Object.defineProperty(e,"DirectiveIcon",{enumerable:!0,get:function(){return t.al}}),Object.defineProperty(e,"DocExplorer",{enumerable:!0,get:function(){return t.y}}),Object.defineProperty(e,"DocsFilledIcon",{enumerable:!0,get:function(){return t.am}}),Object.defineProperty(e,"DocsIcon",{enumerable:!0,get:function(){return t.an}}),Object.defineProperty(e,"EditorContext",{enumerable:!0,get:function(){return t.E}}),Object.defineProperty(e,"EditorContextProvider",{enumerable:!0,get:function(){return t.d}}),Object.defineProperty(e,"EnumValueIcon",{enumerable:!0,get:function(){return t.ao}}),Object.defineProperty(e,"ExecuteButton",{enumerable:!0,get:function(){return t.aS}}),Object.defineProperty(e,"ExecutionContext",{enumerable:!0,get:function(){return t.r}}),Object.defineProperty(e,"ExecutionContextProvider",{enumerable:!0,get:function(){return t.s}}),Object.defineProperty(e,"ExplorerContext",{enumerable:!0,get:function(){return t.z}}),Object.defineProperty(e,"ExplorerContextProvider",{enumerable:!0,get:function(){return t.B}}),Object.defineProperty(e,"ExplorerSection",{enumerable:!0,get:function(){return t.F}}),Object.defineProperty(e,"FieldDocumentation",{enumerable:!0,get:function(){return t.G}}),Object.defineProperty(e,"FieldIcon",{enumerable:!0,get:function(){return t.ap}}),Object.defineProperty(e,"FieldLink",{enumerable:!0,get:function(){return t.J}}),Object.defineProperty(e,"GraphiQLProvider",{enumerable:!0,get:function(){return t.a3}}),Object.defineProperty(e,"HISTORY_PLUGIN",{enumerable:!0,get:function(){return t.$}}),Object.defineProperty(e,"HeaderEditor",{enumerable:!0,get:function(){return t.H}}),Object.defineProperty(e,"History",{enumerable:!0,get:function(){return t.W}}),Object.defineProperty(e,"HistoryContext",{enumerable:!0,get:function(){return t.X}}),Object.defineProperty(e,"HistoryContextProvider",{enumerable:!0,get:function(){return t.Y}}),Object.defineProperty(e,"HistoryIcon",{enumerable:!0,get:function(){return t.aq}}),Object.defineProperty(e,"ImagePreview",{enumerable:!0,get:function(){return t.I}}),Object.defineProperty(e,"ImplementsIcon",{enumerable:!0,get:function(){return t.ar}}),Object.defineProperty(e,"KeyboardShortcutIcon",{enumerable:!0,get:function(){return t.as}}),Object.defineProperty(e,"Listbox",{enumerable:!0,get:function(){return t.aL}}),Object.defineProperty(e,"MagnifyingGlassIcon",{enumerable:!0,get:function(){return t.at}}),Object.defineProperty(e,"MarkdownContent",{enumerable:!0,get:function(){return t.aM}}),Object.defineProperty(e,"Menu",{enumerable:!0,get:function(){return t.aK}}),Object.defineProperty(e,"MergeIcon",{enumerable:!0,get:function(){return t.au}}),Object.defineProperty(e,"PenIcon",{enumerable:!0,get:function(){return t.av}}),Object.defineProperty(e,"PlayIcon",{enumerable:!0,get:function(){return t.aw}}),Object.defineProperty(e,"PluginContext",{enumerable:!0,get:function(){return t.a0}}),Object.defineProperty(e,"PluginContextProvider",{enumerable:!0,get:function(){return t.a1}}),Object.defineProperty(e,"PlusIcon",{enumerable:!0,get:function(){return t.ax}}),Object.defineProperty(e,"PrettifyIcon",{enumerable:!0,get:function(){return t.ay}}),Object.defineProperty(e,"QueryEditor",{enumerable:!0,get:function(){return t.Q}}),Object.defineProperty(e,"ReloadIcon",{enumerable:!0,get:function(){return t.az}}),Object.defineProperty(e,"ResponseEditor",{enumerable:!0,get:function(){return t.R}}),Object.defineProperty(e,"RootTypeIcon",{enumerable:!0,get:function(){return t.aA}}),Object.defineProperty(e,"SchemaContext",{enumerable:!0,get:function(){return t.a4}}),Object.defineProperty(e,"SchemaContextProvider",{enumerable:!0,get:function(){return t.a5}}),Object.defineProperty(e,"SchemaDocumentation",{enumerable:!0,get:function(){return t.K}}),Object.defineProperty(e,"Search",{enumerable:!0,get:function(){return t.M}}),Object.defineProperty(e,"SettingsIcon",{enumerable:!0,get:function(){return t.aB}}),Object.defineProperty(e,"Spinner",{enumerable:!0,get:function(){return t.aN}}),Object.defineProperty(e,"StarFilledIcon",{enumerable:!0,get:function(){return t.aC}}),Object.defineProperty(e,"StarIcon",{enumerable:!0,get:function(){return t.aD}}),Object.defineProperty(e,"StopIcon",{enumerable:!0,get:function(){return t.aE}}),Object.defineProperty(e,"StorageContext",{enumerable:!0,get:function(){return t.a7}}),Object.defineProperty(e,"StorageContextProvider",{enumerable:!0,get:function(){return t.a8}}),Object.defineProperty(e,"Tab",{enumerable:!0,get:function(){return t.aO}}),Object.defineProperty(e,"Tabs",{enumerable:!0,get:function(){return t.aP}}),Object.defineProperty(e,"ToolbarButton",{enumerable:!0,get:function(){return t.aR}}),Object.defineProperty(e,"ToolbarListbox",{enumerable:!0,get:function(){return t.aT}}),Object.defineProperty(e,"ToolbarMenu",{enumerable:!0,get:function(){return t.aU}}),Object.defineProperty(e,"Tooltip",{enumerable:!0,get:function(){return t.aQ}}),Object.defineProperty(e,"TypeDocumentation",{enumerable:!0,get:function(){return t.N}}),Object.defineProperty(e,"TypeIcon",{enumerable:!0,get:function(){return t.aF}}),Object.defineProperty(e,"TypeLink",{enumerable:!0,get:function(){return t.O}}),Object.defineProperty(e,"UnStyledButton",{enumerable:!0,get:function(){return t.aG}}),Object.defineProperty(e,"VariableEditor",{enumerable:!0,get:function(){return t.V}}),Object.defineProperty(e,"useAutoCompleteLeafs",{enumerable:!0,get:function(){return t.u}}),Object.defineProperty(e,"useCopyQuery",{enumerable:!0,get:function(){return t.e}}),Object.defineProperty(e,"useDragResize",{enumerable:!0,get:function(){return t.ab}}),Object.defineProperty(e,"useEditorContext",{enumerable:!0,get:function(){return t.f}}),Object.defineProperty(e,"useExecutionContext",{enumerable:!0,get:function(){return t.v}}),Object.defineProperty(e,"useExplorerContext",{enumerable:!0,get:function(){return t.U}}),Object.defineProperty(e,"useHeaderEditor",{enumerable:!0,get:function(){return t.h}}),Object.defineProperty(e,"useHistoryContext",{enumerable:!0,get:function(){return t.Z}}),Object.defineProperty(e,"useMergeQuery",{enumerable:!0,get:function(){return t.j}}),Object.defineProperty(e,"usePluginContext",{enumerable:!0,get:function(){return t.a2}}),Object.defineProperty(e,"usePrettifyEditors",{enumerable:!0,get:function(){return t.k}}),Object.defineProperty(e,"useQueryEditor",{enumerable:!0,get:function(){return t.m}}),Object.defineProperty(e,"useResponseEditor",{enumerable:!0,get:function(){return t.n}}),Object.defineProperty(e,"useSchemaContext",{enumerable:!0,get:function(){return t.a6}}),Object.defineProperty(e,"useStorageContext",{enumerable:!0,get:function(){return t.a9}}),Object.defineProperty(e,"useTheme",{enumerable:!0,get:function(){return t.aa}}),Object.defineProperty(e,"useVariableEditor",{enumerable:!0,get:function(){return t.q}})})?r.apply(t,i):r)||(e.exports=o)},4840:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(6980),n(3573),n(6856),n(5609),n(9196),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i,o,a){"use strict";e.C.registerHelper("hint","graphql",((t,n)=>{const{schema:o,externalFragments:a}=n;if(!o)return;const s=t.getCursor(),l=t.getTokenAt(s),u=null!==l.type&&/"|\w/.test(l.string[0])?l.start:l.end,c=new i.P(s.line,u),d={list:(0,r.g)(o,t.getValue(),c,l,a).map((e=>({text:e.label,type:e.type,description:e.documentation,isDeprecated:e.isDeprecated,deprecationReason:e.deprecationReason}))),from:{line:s.line,ch:u},to:{line:s.line,ch:l.end}};return(null==d?void 0:d.list)&&d.list.length>0&&(d.from=e.C.Pos(d.from.line,d.from.ch),d.to=e.C.Pos(d.to.line,d.to.ch),e.C.signal(t,"hasCompletion",t,d,l)),d}))})?r.apply(t,i):r)||(e.exports=o)},4712:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(3573),n(2635),n(6856),n(9196),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i,o){"use strict";var a=Object.defineProperty,s=(e,t)=>a(e,"name",{value:t,configurable:!0});function l(e,t,n){const r=u(n,d(t.string));if(!r)return;const i=null!==t.type&&/"|\w/.test(t.string[0])?t.start:t.end;return{list:r,from:{line:e.line,ch:i},to:{line:e.line,ch:t.end}}}function u(e,t){return t?c(c(e.map((e=>({proximity:f(d(e.text),t),entry:e}))),(e=>e.proximity<=2)),(e=>!e.entry.isDeprecated)).sort(((e,t)=>(e.entry.isDeprecated?1:0)-(t.entry.isDeprecated?1:0)||e.proximity-t.proximity||e.entry.text.length-t.entry.text.length)).map((e=>e.entry)):c(e,(e=>!e.isDeprecated))}function c(e,t){const n=e.filter(t);return 0===n.length?e:n}function d(e){return e.toLowerCase().replaceAll(/\W/g,"")}function f(e,t){let n=p(t,e);return e.length>t.length&&(n-=e.length-t.length-1,n+=0===e.indexOf(t)?0:.5),n}function p(e,t){let n,r;const i=[],o=e.length,a=t.length;for(n=0;n<=o;n++)i[n]=[n];for(r=1;r<=a;r++)i[0][r]=r;for(n=1;n<=o;n++)for(r=1;r<=a;r++){const o=e[n-1]===t[r-1]?0:1;i[n][r]=Math.min(i[n-1][r]+1,i[n][r-1]+1,i[n-1][r-1]+o),n>1&&r>1&&e[n-1]===t[r-2]&&e[n-2]===t[r-1]&&(i[n][r]=Math.min(i[n][r],i[n-2][r-2]+o))}return i[o][a]}function h(e,n,r){const i="Invalid"===n.state.kind?n.state.prevState:n.state,{kind:o,step:a}=i;if("Document"===o&&0===a)return l(e,n,[{text:"{"}]);const{variableToType:s}=r;if(!s)return;const u=m(s,n.state);if("Document"===o||"Variable"===o&&0===a)return l(e,n,Object.keys(s).map((e=>({text:`"${e}": `,type:s[e]}))));if(("ObjectValue"===o||"ObjectField"===o&&0===a)&&u.fields)return l(e,n,Object.keys(u.fields).map((e=>u.fields[e])).map((e=>({text:`"${e.name}": `,type:e.type,description:e.description}))));if("StringValue"===o||"NumberValue"===o||"BooleanValue"===o||"NullValue"===o||"ListValue"===o&&1===a||"ObjectField"===o&&2===a||"Variable"===o&&2===a){const r=u.type?(0,t.getNamedType)(u.type):void 0;if(r instanceof t.GraphQLInputObjectType)return l(e,n,[{text:"{"}]);if(r instanceof t.GraphQLEnumType)return l(e,n,r.getValues().map((e=>({text:`"${e.name}"`,type:r,description:e.description}))));if(r===t.GraphQLBoolean)return l(e,n,[{text:"true",type:t.GraphQLBoolean,description:"Not false."},{text:"false",type:t.GraphQLBoolean,description:"Not true."}])}}function m(e,r){const i={type:null,fields:null};return(0,n.f)(r,(n=>{switch(n.kind){case"Variable":i.type=e[n.name];break;case"ListValue":{const e=i.type?(0,t.getNullableType)(i.type):void 0;i.type=e instanceof t.GraphQLList?e.ofType:null;break}case"ObjectValue":{const e=i.type?(0,t.getNamedType)(i.type):void 0;i.fields=e instanceof t.GraphQLInputObjectType?e.getFields():null;break}case"ObjectField":{const e=n.name&&i.fields?i.fields[n.name]:null;i.type=null==e?void 0:e.type;break}}})),i}s(l,"hintList"),s(u,"filterAndSortList"),s(c,"filterNonEmpty"),s(d,"normalizeText"),s(f,"getProximity"),s(p,"lexicalDistance"),e.C.registerHelper("hint","graphql-variables",((t,n)=>{const r=t.getCursor(),i=t.getTokenAt(r),o=h(r,i,n);return(null==o?void 0:o.list)&&o.list.length>0&&(o.from=e.C.Pos(o.from.line,o.from.ch),o.to=e.C.Pos(o.to.line,o.to.ch),e.C.signal(t,"hasCompletion",t,o,i)),o})),s(h,"getVariablesHint"),s(m,"getTypeInfo")})?r.apply(t,i):r)||(e.exports=o)},6856:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(9196),n(3573),n(1850)],r=function(e,t,r,i){"use strict";function o(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(o=function(e){return e?n:t})(e)}function a(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=o(t);if(n&&n.has(e))return n.get(e);var r={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var s=i?Object.getOwnPropertyDescriptor(e,a):null;s&&(s.get||s.set)?Object.defineProperty(r,a,s):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}Object.defineProperty(e,"__esModule",{value:!0}),e.$=void 0,e.A=JE,e.B=$E,e.C=void 0,e.D=IE,e.E=void 0,e.F=sT,e.G=dT,e.H=cS,e.I=pS,e.J=Lw,e.K=gT,e.L=void 0,e.M=xw,e.N=Rw,e.O=QE,e.P=void 0,e.Q=yS,e.R=SS,e.U=e.T=e.S=void 0,e.V=NS,e.W=oE,e.X=void 0,e.Y=eE,e.a0=e.a=e._=e.Z=void 0,e.a1=Xw,e.a2=void 0,e.a3=IS,e.a4=void 0,e.a5=ME,e.a7=e.a6=void 0,e.a8=ve,e.aR=e.aQ=e.aP=e.aO=e.aN=e.aM=e.aL=e.aK=e.aJ=e.aI=e.aH=e.aG=e.aF=e.aE=e.aD=e.aC=e.aB=e.aA=e.a9=void 0,e.aS=HS,e.aU=e.aT=void 0,e.aa=AS,e.ab=PS,e.az=e.ay=e.ax=e.aw=e.av=e.au=e.at=e.as=e.ar=e.aq=e.ap=e.ao=e.an=e.am=e.al=e.ak=e.aj=e.ai=e.ah=e.ag=e.af=e.ae=e.ad=e.ac=void 0,e.b=_i,e.c=void 0,e.d=iS,e.e=uC,e.f=void 0,e.g=eo,e.h=mC,e.i=void 0,e.j=cC,e.k=dC,e.l=Oi,e.m=SC,e.n=TS,e.o=Vi,e.p=Li,e.q=ZC,e.r=void 0,e.s=dE,e.t=Di,e.u=fC,e.v=void 0,e.w=tT,e.x=iT,e.y=Hw,e.z=void 0,t=a(t),i=a(i);var s=Object.defineProperty,l=Object.defineProperties,u=Object.getOwnPropertyDescriptors,c=Object.getOwnPropertySymbols,d=Object.prototype.hasOwnProperty,f=Object.prototype.propertyIsEnumerable,p=(e,t,n)=>t in e?s(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,h=(e,t)=>{for(var n in t||(t={}))d.call(t,n)&&p(e,n,t[n]);if(c)for(var n of c(t))f.call(t,n)&&p(e,n,t[n]);return e},m=(e,t)=>l(e,u(t)),g=(e,t)=>s(e,"name",{value:t,configurable:!0}),v=(e,t)=>{var n={};for(var r in e)d.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(null!=e&&c)for(var r of c(e))t.indexOf(r)<0&&f.call(e,r)&&(n[r]=e[r]);return n};function y(e){var t,n,r="";if("string"==typeof e||"number"==typeof e)r+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t{const r=e.subscribe({next:e=>{t(e),r.unsubscribe()},error:n,complete:()=>{n(new Error("no value resolved"))}})}))}function C(e){return"object"==typeof e&&null!==e&&"subscribe"in e&&"function"==typeof e.subscribe}function S(e){return"object"==typeof e&&null!==e&&("AsyncGenerator"===e[Symbol.toStringTag]||Symbol.asyncIterator in e)}function x(e){var t;return E(this,void 0,void 0,(function*(){const n=null===(t=("return"in e?e:e[Symbol.asyncIterator]()).return)||void 0===t?void 0:t.bind(e),r=("next"in e?e:e[Symbol.asyncIterator]()).next.bind(e),i=yield r();return null==n||n(),i.value}))}function k(e){return E(this,void 0,void 0,(function*(){const t=yield e;return S(t)?x(t):C(t)?w(t):t}))}g(T,"isPromise"),g(w,"observableToPromise"),g(C,"isObservable"),g(S,"isAsyncIterable"),g(x,"asyncIterableToPromise"),g(k,"fetcherReturnToPromise"),globalThis&&globalThis.__awaiter;var N=globalThis&&globalThis.__await||function(e){return this instanceof N?(this.v=e,this):new N(e)};function _(e){return JSON.stringify(e,null,2)}function O(e){return Object.assign(Object.assign({},e),{message:e.message,stack:e.stack})}function I(e){return e instanceof Error?O(e):e}function D(e){return Array.isArray(e)?_({errors:e.map((e=>I(e)))}):_({errors:[I(e)]})}function L(e){return _(e)}function A(e,t,n){const i=[];if(!e||!t)return{insertions:i,result:t};let o;try{o=(0,r.parse)(t)}catch(e){return{insertions:i,result:t}}const a=n||M,s=new r.TypeInfo(e);return(0,r.visit)(o,{leave(e){s.leave(e)},enter(e){if(s.enter(e),"Field"===e.kind&&!e.selectionSet){const n=R(j(s.getType()),a);if(n&&e.loc){const o=P(t,e.loc.start);i.push({index:e.loc.end,string:" "+(0,r.print)(n).replaceAll("\n","\n"+o)})}}}}),{insertions:i,result:F(t,i)}}function M(e){if(!("getFields"in e))return[];const t=e.getFields();if(t.id)return["id"];if(t.edges)return["edges"];if(t.node)return["node"];const n=[];for(const e of Object.keys(t))(0,r.isLeafType)(t[e].type)&&n.push(e);return n}function R(e,t){const n=(0,r.getNamedType)(e);if(!e||(0,r.isLeafType)(e))return;const i=t(n);return Array.isArray(i)&&0!==i.length&&"getFields"in n?{kind:r.Kind.SELECTION_SET,selections:i.map((e=>{const i=n.getFields()[e],o=i?i.type:null;return{kind:r.Kind.FIELD,name:{kind:r.Kind.NAME,value:e},selectionSet:R(o,t)}}))}:void 0}function F(e,t){if(0===t.length)return e;let n="",r=0;for(const{index:i,string:o}of t)n+=e.slice(r,i)+o,r=i;return n+=e.slice(r),n}function P(e,t){let n=t,r=t;for(;n;){const t=e.charCodeAt(n-1);if(10===t||13===t||8232===t||8233===t)break;n--,9!==t&&11!==t&&12!==t&&32!==t&&160!==t&&(r=n)}return e.slice(n,r)}function j(e){if(e)return e}function V(e,t){var n;const r=new Map,i=[];for(const o of e)if("Field"===o.kind){const e=t(o),a=r.get(e);if(null===(n=o.directives)||void 0===n?void 0:n.length){const e=Object.assign({},o);i.push(e)}else if((null==a?void 0:a.selectionSet)&&o.selectionSet)a.selectionSet.selections=[...a.selectionSet.selections,...o.selectionSet.selections];else if(!a){const t=Object.assign({},o);r.set(e,t),i.push(t)}}else i.push(o);return i}function U(e,t,n){var i;const o=n?(0,r.getNamedType)(n).name:null,a=[],s=[];for(let l of t){if("FragmentSpread"===l.kind){const t=l.name.value;if(!l.directives||0===l.directives.length){if(s.includes(t))continue;s.push(t)}const n=e[l.name.value];if(n){const{typeCondition:e,directives:t,selectionSet:i}=n;l={kind:r.Kind.INLINE_FRAGMENT,typeCondition:e,directives:t,selectionSet:i}}}if(l.kind===r.Kind.INLINE_FRAGMENT&&(!l.directives||0===(null===(i=l.directives)||void 0===i?void 0:i.length))){const t=l.typeCondition?l.typeCondition.name.value:null;if(!t||t===o){a.push(...U(e,l.selectionSet.selections,n));continue}}a.push(l)}return a}function B(e,t){const n=t?new r.TypeInfo(t):null,i=Object.create(null);for(const t of e.definitions)t.kind===r.Kind.FRAGMENT_DEFINITION&&(i[t.name.value]=t);const o={SelectionSet(e){const t=n?n.getParentType():null;let{selections:r}=e;return r=U(i,r,t),r=V(r,(e=>e.alias?e.alias.value:e.name.value)),Object.assign(Object.assign({},e),{selections:r})},FragmentDefinition(){return null}};return(0,r.visit)(e,n?(0,r.visitWithTypeInfo)(n,o):o)}function $(e,t,n){if(!n||n.length<1)return;const r=n.map((e=>{var t;return null===(t=e.name)||void 0===t?void 0:t.value}));if(t&&r.includes(t))return t;if(t&&e){const n=e.map((e=>{var t;return null===(t=e.name)||void 0===t?void 0:t.value})).indexOf(t);if(-1!==n&&n{for(const e in window.localStorage)0===e.indexOf(`${G}:`)&&window.localStorage.removeItem(e)}}}get(e){if(!this.storage)return null;const t=`${G}:${e}`,n=this.storage.getItem(t);return"null"===n||"undefined"===n?(this.storage.removeItem(t),null):n||null}set(e,t){let n=!1,r=null;if(this.storage){const i=`${G}:${e}`;if(t)try{this.storage.setItem(i,t)}catch(e){r=e instanceof Error?e:new Error(`${e}`),n=q(this.storage,e)}else this.storage.removeItem(i)}return{isQuotaError:n,error:r}}clear(){this.storage&&this.storage.clear()}}g(H,"StorageAPI");const G="graphiql";class z{constructor(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;this.key=e,this.storage=t,this.maxSize=n,this.items=this.fetchAll()}get length(){return this.items.length}contains(e){return this.items.some((t=>t.query===e.query&&t.variables===e.variables&&t.headers===e.headers&&t.operationName===e.operationName))}edit(e){const t=this.items.findIndex((t=>t.query===e.query&&t.variables===e.variables&&t.headers===e.headers&&t.operationName===e.operationName));-1!==t&&(this.items.splice(t,1,e),this.save())}delete(e){const t=this.items.findIndex((t=>t.query===e.query&&t.variables===e.variables&&t.headers===e.headers&&t.operationName===e.operationName));-1!==t&&(this.items.splice(t,1),this.save())}fetchRecent(){return this.items.at(-1)}fetchAll(){const e=this.storage.get(this.key);return e?JSON.parse(e)[this.key]:[]}push(e){const t=[...this.items,e];this.maxSize&&t.length>this.maxSize&&t.shift();for(let e=0;e<5;e++){const e=this.storage.set(this.key,JSON.stringify({[this.key]:t}));if(null==e?void 0:e.error){if(!e.isQuotaError||!this.maxSize)return;t.shift()}else this.items=t}}save(){this.storage.set(this.key,JSON.stringify({[this.key]:this.items}))}}g(z,"QueryStore");class W{constructor(e,t){this.storage=e,this.maxHistoryLength=t,this.updateHistory=(e,t,n,r)=>{if(this.shouldSaveQuery(e,t,n,this.history.fetchRecent())){this.history.push({query:e,variables:t,headers:n,operationName:r});const i=this.history.items,o=this.favorite.items;this.queries=i.concat(o)}},this.history=new z("queries",this.storage,this.maxHistoryLength),this.favorite=new z("favorites",this.storage,null),this.queries=[...this.history.fetchAll(),...this.favorite.fetchAll()]}shouldSaveQuery(e,t,n,i){if(!e)return!1;try{(0,r.parse)(e)}catch(e){return!1}if(e.length>1e5)return!1;if(!i)return!0;if(JSON.stringify(e)===JSON.stringify(i.query)){if(JSON.stringify(t)===JSON.stringify(i.variables)){if(JSON.stringify(n)===JSON.stringify(i.headers))return!1;if(n&&!i.headers)return!1}if(t&&!i.variables)return!1}return!0}toggleFavorite(e,t,n,r,i,o){const a={query:e,variables:t,headers:n,operationName:r,label:i};this.favorite.contains(a)?o&&(a.favorite=!1,this.favorite.delete(a)):(a.favorite=!0,this.favorite.push(a)),this.queries=[...this.history.items,...this.favorite.items]}editLabel(e,t,n,r,i,o){const a={query:e,variables:t,headers:n,operationName:r,label:i};o?this.favorite.edit(Object.assign(Object.assign({},a),{favorite:o})):this.history.edit(a),this.queries=[...this.history.items,...this.favorite.items]}}g(W,"HistoryStore");var K=Object.defineProperty,Q=g(((e,t)=>K(e,"name",{value:t,configurable:!0})),"__name$G");function X(e){const n=(0,t.createContext)(null);return n.displayName=e,n}function Y(e){function n(r){var i;const o=(0,t.useContext)(e);if(null===o&&(null==r?void 0:r.nonNull))throw new Error(`Tried to use \`${(null==(i=r.caller)?void 0:i.name)||n.caller.name}\` without the necessary context. Make sure to render the \`${e.displayName}Provider\` component higher up the tree.`);return o}return g(n,"useGivenContext"),Q(n,"useGivenContext"),Object.defineProperty(n,"name",{value:`use${e.displayName}`}),n}g(X,"createNullableContext"),Q(X,"createNullableContext"),g(Y,"createContextHook"),Q(Y,"createContextHook");var J="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:"undefined"!=typeof self?self:{};function Z(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function ee(e){if(e.__esModule)return e;var t=Object.defineProperty({},"__esModule",{value:!0});return Object.keys(e).forEach((function(n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})})),t}e.c=J,g(Z,"getDefaultExportFromCjs"),g(ee,"getAugmentedNamespace");var te={exports:{}},ne={};function re(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}Object.getOwnPropertySymbols,Object.prototype.hasOwnProperty,Object.prototype.propertyIsEnumerable,g((function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}),"toObject"),g(re,"shouldUseNative"),re()&&Object.assign;var ie=t.default,oe=60103;if(ne.Fragment=60107,"function"==typeof Symbol&&Symbol.for){var ae=Symbol.for;oe=ae("react.element"),ne.Fragment=ae("react.fragment")}var se=ie.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,le=Object.prototype.hasOwnProperty,ue={key:!0,ref:!0,__self:!0,__source:!0};function ce(e,t,n){var r,i={},o=null,a=null;for(r in void 0!==n&&(o=""+n),void 0!==t.key&&(o=""+t.key),void 0!==t.ref&&(a=t.ref),t)le.call(t,r)&&!ue.hasOwnProperty(r)&&(i[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps)void 0===i[r]&&(i[r]=t[r]);return{$$typeof:oe,type:e,key:o,ref:a,props:i,_owner:se.current}}g(ce,"q$1"),ne.jsx=ce,ne.jsxs=ce,te.exports=ne;const de=te.exports.jsx,fe=te.exports.jsxs,pe=te.exports.Fragment;var he=Object.defineProperty,me=g(((e,t)=>he(e,"name",{value:t,configurable:!0})),"__name$F");const ge=X("StorageContext");function ve(e){const n=(0,t.useRef)(!0),[r,i]=(0,t.useState)(new H(e.storage));return(0,t.useEffect)((()=>{n.current?n.current=!1:i(new H(e.storage))}),[e.storage]),de(ge.Provider,{value:r,children:e.children})}e.a7=ge,g(ve,"StorageContextProvider"),me(ve,"StorageContextProvider");const ye=Y(ge);e.a9=ye;const be=10,Ee=2;function Te(e){return we(e,[])}function we(e,t){switch(typeof e){case"string":return JSON.stringify(e);case"function":return e.name?`[function ${e.name}]`:"[function]";case"object":return Ce(e,t);default:return String(e)}}function Ce(e,t){if(null===e)return"null";if(t.includes(e))return"[Circular]";const n=[...t,e];if(Se(e)){const t=e.toJSON();if(t!==e)return"string"==typeof t?t:we(t,n)}else if(Array.isArray(e))return ke(e,n);return xe(e,n)}function Se(e){return"function"==typeof e.toJSON}function xe(e,t){const n=Object.entries(e);return 0===n.length?"{}":t.length>Ee?"["+Ne(e)+"]":"{ "+n.map((e=>{let[n,r]=e;return n+": "+we(r,t)})).join(", ")+" }"}function ke(e,t){if(0===e.length)return"[]";if(t.length>Ee)return"[Array]";const n=Math.min(be,e.length),r=e.length-n,i=[];for(let r=0;r1&&i.push(`... ${r} more items`),"["+i.join(", ")+"]"}function Ne(e){const t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){const t=e.constructor.name;if("string"==typeof t&&""!==t)return t}return t}function _e(e,t){if(!Boolean(e))throw new Error(null!=t?t:"Unexpected invariant triggered.")}let Oe;function Ie(e){return 9===e||32===e}function De(e){return e>=48&&e<=57}function Le(e){return e>=97&&e<=122||e>=65&&e<=90}function Ae(e){return Le(e)||95===e}function Me(e){return Le(e)||De(e)||95===e}function Re(e,t){const n=e.replace(/"""/g,'\\"""'),r=n.split(/\r\n|[\n\r]/g),i=1===r.length,o=r.length>1&&r.slice(1).every((e=>0===e.length||Ie(e.charCodeAt(0)))),a=n.endsWith('\\"""'),s=e.endsWith('"')&&!a,l=e.endsWith("\\"),u=s||l,c=!(null!=t&&t.minimize)&&(!i||e.length>70||u||o||a);let d="";const f=i&&Ie(e.charCodeAt(0));return(c&&!f||o)&&(d+="\n"),d+=n,(c||u)&&(d+="\n"),'"""'+d+'"""'}function Fe(e){return`"${e.replace(je,Ve)}"`}var Pe;g(Te,"inspect"),g(we,"formatValue"),g(Ce,"formatObjectValue"),g(Se,"isJSONable"),g(xe,"formatObject"),g(ke,"formatArray"),g(Ne,"getObjectTag"),g(_e,"invariant"),(Pe=Oe||(Oe={})).QUERY="QUERY",Pe.MUTATION="MUTATION",Pe.SUBSCRIPTION="SUBSCRIPTION",Pe.FIELD="FIELD",Pe.FRAGMENT_DEFINITION="FRAGMENT_DEFINITION",Pe.FRAGMENT_SPREAD="FRAGMENT_SPREAD",Pe.INLINE_FRAGMENT="INLINE_FRAGMENT",Pe.VARIABLE_DEFINITION="VARIABLE_DEFINITION",Pe.SCHEMA="SCHEMA",Pe.SCALAR="SCALAR",Pe.OBJECT="OBJECT",Pe.FIELD_DEFINITION="FIELD_DEFINITION",Pe.ARGUMENT_DEFINITION="ARGUMENT_DEFINITION",Pe.INTERFACE="INTERFACE",Pe.UNION="UNION",Pe.ENUM="ENUM",Pe.ENUM_VALUE="ENUM_VALUE",Pe.INPUT_OBJECT="INPUT_OBJECT",Pe.INPUT_FIELD_DEFINITION="INPUT_FIELD_DEFINITION",g(Ie,"isWhiteSpace$2"),g(De,"isDigit$1"),g(Le,"isLetter$1"),g(Ae,"isNameStart"),g(Me,"isNameContinue"),g(Re,"printBlockString"),g(Fe,"printString");const je=/[\x00-\x1f\x22\x5c\x7f-\x9f]/g;function Ve(e){return Ue[e.charCodeAt(0)]}g(Ve,"escapedReplacer");const Ue=["\\u0000","\\u0001","\\u0002","\\u0003","\\u0004","\\u0005","\\u0006","\\u0007","\\b","\\t","\\n","\\u000B","\\f","\\r","\\u000E","\\u000F","\\u0010","\\u0011","\\u0012","\\u0013","\\u0014","\\u0015","\\u0016","\\u0017","\\u0018","\\u0019","\\u001A","\\u001B","\\u001C","\\u001D","\\u001E","\\u001F","","",'\\"',"","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","\\\\","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","\\u007F","\\u0080","\\u0081","\\u0082","\\u0083","\\u0084","\\u0085","\\u0086","\\u0087","\\u0088","\\u0089","\\u008A","\\u008B","\\u008C","\\u008D","\\u008E","\\u008F","\\u0090","\\u0091","\\u0092","\\u0093","\\u0094","\\u0095","\\u0096","\\u0097","\\u0098","\\u0099","\\u009A","\\u009B","\\u009C","\\u009D","\\u009E","\\u009F"];function Be(e,t){if(!Boolean(e))throw new Error(t)}g(Be,"devAssert");const $e={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},qe=new Set(Object.keys($e));function He(e){const t=null==e?void 0:e.kind;return"string"==typeof t&&qe.has(t)}let Ge,ze;var We,Ke;g(He,"isNode"),(Ke=Ge||(Ge={})).QUERY="query",Ke.MUTATION="mutation",Ke.SUBSCRIPTION="subscription",(We=ze||(ze={})).NAME="Name",We.DOCUMENT="Document",We.OPERATION_DEFINITION="OperationDefinition",We.VARIABLE_DEFINITION="VariableDefinition",We.SELECTION_SET="SelectionSet",We.FIELD="Field",We.ARGUMENT="Argument",We.FRAGMENT_SPREAD="FragmentSpread",We.INLINE_FRAGMENT="InlineFragment",We.FRAGMENT_DEFINITION="FragmentDefinition",We.VARIABLE="Variable",We.INT="IntValue",We.FLOAT="FloatValue",We.STRING="StringValue",We.BOOLEAN="BooleanValue",We.NULL="NullValue",We.ENUM="EnumValue",We.LIST="ListValue",We.OBJECT="ObjectValue",We.OBJECT_FIELD="ObjectField",We.DIRECTIVE="Directive",We.NAMED_TYPE="NamedType",We.LIST_TYPE="ListType",We.NON_NULL_TYPE="NonNullType",We.SCHEMA_DEFINITION="SchemaDefinition",We.OPERATION_TYPE_DEFINITION="OperationTypeDefinition",We.SCALAR_TYPE_DEFINITION="ScalarTypeDefinition",We.OBJECT_TYPE_DEFINITION="ObjectTypeDefinition",We.FIELD_DEFINITION="FieldDefinition",We.INPUT_VALUE_DEFINITION="InputValueDefinition",We.INTERFACE_TYPE_DEFINITION="InterfaceTypeDefinition",We.UNION_TYPE_DEFINITION="UnionTypeDefinition",We.ENUM_TYPE_DEFINITION="EnumTypeDefinition",We.ENUM_VALUE_DEFINITION="EnumValueDefinition",We.INPUT_OBJECT_TYPE_DEFINITION="InputObjectTypeDefinition",We.DIRECTIVE_DEFINITION="DirectiveDefinition",We.SCHEMA_EXTENSION="SchemaExtension",We.SCALAR_TYPE_EXTENSION="ScalarTypeExtension",We.OBJECT_TYPE_EXTENSION="ObjectTypeExtension",We.INTERFACE_TYPE_EXTENSION="InterfaceTypeExtension",We.UNION_TYPE_EXTENSION="UnionTypeExtension",We.ENUM_TYPE_EXTENSION="EnumTypeExtension",We.INPUT_OBJECT_TYPE_EXTENSION="InputObjectTypeExtension";const Qe=Object.freeze({});function Xe(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:$e;const r=new Map;for(const e of Object.values(ze))r.set(e,Ye(t,e));let i,o,a,s=Array.isArray(e),l=[e],u=-1,c=[],d=e;const f=[],p=[];do{u++;const e=u===l.length,v=e&&0!==c.length;if(e){if(o=0===p.length?void 0:f[f.length-1],d=a,a=p.pop(),v)if(s){d=d.slice();let e=0;for(const[t,n]of c){const r=t-e;null===n?(d.splice(r,1),e++):d[r]=n}}else{d=Object.defineProperties({},Object.getOwnPropertyDescriptors(d));for(const[e,t]of c)d[e]=t}u=i.index,l=i.keys,c=i.edits,s=i.inArray,i=i.prev}else if(a){if(o=s?u:l[u],d=a[o],null==d)continue;f.push(o)}let y;if(!Array.isArray(d)){var h,m;He(d)||Be(!1,`Invalid AST Node: ${Te(d)}.`);const n=e?null===(h=r.get(d.kind))||void 0===h?void 0:h.leave:null===(m=r.get(d.kind))||void 0===m?void 0:m.enter;if(y=null==n?void 0:n.call(t,d,o,a,f,p),y===Qe)break;if(!1===y){if(!e){f.pop();continue}}else if(void 0!==y&&(c.push([o,y]),!e)){if(!He(y)){f.pop();continue}d=y}}var g;void 0===y&&v&&c.push([o,d]),e?f.pop():(i={inArray:s,index:u,keys:l,edits:c,prev:i},s=Array.isArray(d),l=s?d:null!==(g=n[d.kind])&&void 0!==g?g:[],u=-1,c=[],a&&p.push(a),a=d)}while(void 0!==i);return 0!==c.length?c[c.length-1][1]:e}function Ye(e,t){const n=e[t];return"object"==typeof n?n:"function"==typeof n?{enter:n,leave:void 0}:{enter:e.enter,leave:e.leave}}function Je(e){return Xe(e,Ze)}g(Xe,"visit"),g(Ye,"getEnterLeaveForKind"),g(Je,"print");const Ze={Name:{leave:e=>e.value},Variable:{leave:e=>"$"+e.name},Document:{leave:e=>et(e.definitions,"\n\n")},OperationDefinition:{leave(e){const t=nt("(",et(e.variableDefinitions,", "),")"),n=et([e.operation,et([e.name,t]),et(e.directives," ")]," ");return("query"===n?"":n+" ")+e.selectionSet}},VariableDefinition:{leave:e=>{let{variable:t,type:n,defaultValue:r,directives:i}=e;return t+": "+n+nt(" = ",r)+nt(" ",et(i," "))}},SelectionSet:{leave:e=>{let{selections:t}=e;return tt(t)}},Field:{leave(e){let{alias:t,name:n,arguments:r,directives:i,selectionSet:o}=e;const a=nt("",t,": ")+n;let s=a+nt("(",et(r,", "),")");return s.length>80&&(s=a+nt("(\n",rt(et(r,"\n")),"\n)")),et([s,et(i," "),o]," ")}},Argument:{leave:e=>{let{name:t,value:n}=e;return t+": "+n}},FragmentSpread:{leave:e=>{let{name:t,directives:n}=e;return"..."+t+nt(" ",et(n," "))}},InlineFragment:{leave:e=>{let{typeCondition:t,directives:n,selectionSet:r}=e;return et(["...",nt("on ",t),et(n," "),r]," ")}},FragmentDefinition:{leave:e=>{let{name:t,typeCondition:n,variableDefinitions:r,directives:i,selectionSet:o}=e;return`fragment ${t}${nt("(",et(r,", "),")")} on ${n} ${nt("",et(i," ")," ")}`+o}},IntValue:{leave:e=>{let{value:t}=e;return t}},FloatValue:{leave:e=>{let{value:t}=e;return t}},StringValue:{leave:e=>{let{value:t,block:n}=e;return n?Re(t):Fe(t)}},BooleanValue:{leave:e=>{let{value:t}=e;return t?"true":"false"}},NullValue:{leave:()=>"null"},EnumValue:{leave:e=>{let{value:t}=e;return t}},ListValue:{leave:e=>{let{values:t}=e;return"["+et(t,", ")+"]"}},ObjectValue:{leave:e=>{let{fields:t}=e;return"{"+et(t,", ")+"}"}},ObjectField:{leave:e=>{let{name:t,value:n}=e;return t+": "+n}},Directive:{leave:e=>{let{name:t,arguments:n}=e;return"@"+t+nt("(",et(n,", "),")")}},NamedType:{leave:e=>{let{name:t}=e;return t}},ListType:{leave:e=>{let{type:t}=e;return"["+t+"]"}},NonNullType:{leave:e=>{let{type:t}=e;return t+"!"}},SchemaDefinition:{leave:e=>{let{description:t,directives:n,operationTypes:r}=e;return nt("",t,"\n")+et(["schema",et(n," "),tt(r)]," ")}},OperationTypeDefinition:{leave:e=>{let{operation:t,type:n}=e;return t+": "+n}},ScalarTypeDefinition:{leave:e=>{let{description:t,name:n,directives:r}=e;return nt("",t,"\n")+et(["scalar",n,et(r," ")]," ")}},ObjectTypeDefinition:{leave:e=>{let{description:t,name:n,interfaces:r,directives:i,fields:o}=e;return nt("",t,"\n")+et(["type",n,nt("implements ",et(r," & ")),et(i," "),tt(o)]," ")}},FieldDefinition:{leave:e=>{let{description:t,name:n,arguments:r,type:i,directives:o}=e;return nt("",t,"\n")+n+(it(r)?nt("(\n",rt(et(r,"\n")),"\n)"):nt("(",et(r,", "),")"))+": "+i+nt(" ",et(o," "))}},InputValueDefinition:{leave:e=>{let{description:t,name:n,type:r,defaultValue:i,directives:o}=e;return nt("",t,"\n")+et([n+": "+r,nt("= ",i),et(o," ")]," ")}},InterfaceTypeDefinition:{leave:e=>{let{description:t,name:n,interfaces:r,directives:i,fields:o}=e;return nt("",t,"\n")+et(["interface",n,nt("implements ",et(r," & ")),et(i," "),tt(o)]," ")}},UnionTypeDefinition:{leave:e=>{let{description:t,name:n,directives:r,types:i}=e;return nt("",t,"\n")+et(["union",n,et(r," "),nt("= ",et(i," | "))]," ")}},EnumTypeDefinition:{leave:e=>{let{description:t,name:n,directives:r,values:i}=e;return nt("",t,"\n")+et(["enum",n,et(r," "),tt(i)]," ")}},EnumValueDefinition:{leave:e=>{let{description:t,name:n,directives:r}=e;return nt("",t,"\n")+et([n,et(r," ")]," ")}},InputObjectTypeDefinition:{leave:e=>{let{description:t,name:n,directives:r,fields:i}=e;return nt("",t,"\n")+et(["input",n,et(r," "),tt(i)]," ")}},DirectiveDefinition:{leave:e=>{let{description:t,name:n,arguments:r,repeatable:i,locations:o}=e;return nt("",t,"\n")+"directive @"+n+(it(r)?nt("(\n",rt(et(r,"\n")),"\n)"):nt("(",et(r,", "),")"))+(i?" repeatable":"")+" on "+et(o," | ")}},SchemaExtension:{leave:e=>{let{directives:t,operationTypes:n}=e;return et(["extend schema",et(t," "),tt(n)]," ")}},ScalarTypeExtension:{leave:e=>{let{name:t,directives:n}=e;return et(["extend scalar",t,et(n," ")]," ")}},ObjectTypeExtension:{leave:e=>{let{name:t,interfaces:n,directives:r,fields:i}=e;return et(["extend type",t,nt("implements ",et(n," & ")),et(r," "),tt(i)]," ")}},InterfaceTypeExtension:{leave:e=>{let{name:t,interfaces:n,directives:r,fields:i}=e;return et(["extend interface",t,nt("implements ",et(n," & ")),et(r," "),tt(i)]," ")}},UnionTypeExtension:{leave:e=>{let{name:t,directives:n,types:r}=e;return et(["extend union",t,et(n," "),nt("= ",et(r," | "))]," ")}},EnumTypeExtension:{leave:e=>{let{name:t,directives:n,values:r}=e;return et(["extend enum",t,et(n," "),tt(r)]," ")}},InputObjectTypeExtension:{leave:e=>{let{name:t,directives:n,fields:r}=e;return et(["extend input",t,et(n," "),tt(r)]," ")}}};function et(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";var n;return null!==(n=null==e?void 0:e.filter((e=>e)).join(t))&&void 0!==n?n:""}function tt(e){return nt("{\n",rt(et(e,"\n")),"\n}")}function nt(e,t){return null!=t&&""!==t?e+t+(arguments.length>2&&void 0!==arguments[2]?arguments[2]:""):""}function rt(e){return nt(" ",e.replace(/\n/g,"\n "))}function it(e){var t;return null!==(t=null==e?void 0:e.some((e=>e.includes("\n"))))&&void 0!==t&&t}function ot(e){return"object"==typeof e&&"function"==typeof(null==e?void 0:e[Symbol.iterator])}function at(e){return"object"==typeof e&&null!==e}g(et,"join"),g(tt,"block$2"),g(nt,"wrap"),g(rt,"indent"),g(it,"hasMultilineItems"),g(ot,"isIterableObject"),g(at,"isObjectLike");const st=5;function lt(e,t){const[n,r]=t?[e,t]:[void 0,e];let i=" Did you mean ";n&&(i+=n+" ");const o=r.map((e=>`"${e}"`));switch(o.length){case 0:return"";case 1:return i+o[0]+"?";case 2:return i+o[0]+" or "+o[1]+"?"}const a=o.slice(0,st),s=a.pop();return i+a.join(", ")+", or "+s+"?"}function ut(e){return e}g(lt,"didYouMean"),g(ut,"identityFunc");const ct=g((function(e,t){return e instanceof t}),"instanceOf");function dt(e,t){const n=Object.create(null);for(const r of e)n[t(r)]=r;return n}function ft(e,t,n){const r=Object.create(null);for(const i of e)r[t(i)]=n(i);return r}function pt(e,t){const n=Object.create(null);for(const r of Object.keys(e))n[r]=t(e[r],r);return n}function ht(e,t){let n=0,r=0;for(;n0);let s=0;do{++r,s=10*s+o-mt,o=t.charCodeAt(r)}while(vt(o)&&s>0);if(as)return 1}else{if(io)return 1;++n,++r}}return e.length-t.length}g(dt,"keyMap"),g(ft,"keyValMap"),g(pt,"mapValue"),g(ht,"naturalCompare");const mt=48,gt=57;function vt(e){return!isNaN(e)&&mt<=e&&e<=gt}function yt(e,t){const n=Object.create(null),r=new bt(e),i=Math.floor(.4*e.length)+1;for(const e of t){const t=r.measure(e,i);void 0!==t&&(n[e]=t)}return Object.keys(n).sort(((e,t)=>{const r=n[e]-n[t];return 0!==r?r:ht(e,t)}))}g(vt,"isDigit"),g(yt,"suggestionList");class bt{constructor(e){this._input=e,this._inputLowerCase=e.toLowerCase(),this._inputArray=Et(this._inputLowerCase),this._rows=[new Array(e.length+1).fill(0),new Array(e.length+1).fill(0),new Array(e.length+1).fill(0)]}measure(e,t){if(this._input===e)return 0;const n=e.toLowerCase();if(this._inputLowerCase===n)return 1;let r=Et(n),i=this._inputArray;if(r.lengtht)return;const s=this._rows;for(let e=0;e<=a;e++)s[0][e]=e;for(let e=1;e<=o;e++){const n=s[(e-1)%3],o=s[e%3];let l=o[0]=e;for(let t=1;t<=a;t++){const a=r[e-1]===i[t-1]?0:1;let u=Math.min(n[t]+1,o[t-1]+1,n[t-1]+a);if(e>1&&t>1&&r[e-1]===i[t-2]&&r[e-2]===i[t-1]){const n=s[(e-2)%3][t-2];u=Math.min(u,n+1)}ut)return}const l=s[o%3][a];return l<=t?l:void 0}}function Et(e){const t=e.length,n=new Array(t);for(let r=0;r=t)break;n=i.index+i[0].length,r+=1}return{line:r,column:t+1-n}}function St(e){return xt(e.source,Ct(e.source,e.start))}function xt(e,t){const n=e.locationOffset.column-1,r="".padStart(n)+e.body,i=t.line-1,o=e.locationOffset.line-1,a=t.line+o,s=1===t.line?n:0,l=t.column+s,u=`${e.name}:${a}:${l}\n`,c=r.split(/\r\n|[\n\r]/g),d=c[i];if(d.length>120){const e=Math.floor(l/80),t=l%80,n=[];for(let e=0;e["|",e])),["|","^".padStart(t)],["|",n[e+1]]])}return u+kt([[a-1+" |",c[i-1]],[`${a} |`,d],["|","^".padStart(l)],[`${a+1} |`,c[i+1]]])}function kt(e){const t=e.filter((e=>{let[t,n]=e;return void 0!==n})),n=Math.max(...t.map((e=>{let[t]=e;return t.length})));return t.map((e=>{let[t,r]=e;return t.padStart(n)+(r?" "+r:"")})).join("\n")}function Nt(e){const t=e[0];return null==t||"kind"in t||"length"in t?{nodes:t,source:e[1],positions:e[2],path:e[3],originalError:e[4],extensions:e[5]}:t}g(Ct,"getLocation"),g(St,"printLocation"),g(xt,"printSourceLocation"),g(kt,"printPrefixedLines"),g(Nt,"toNormalizedOptions");class _t extends Error{constructor(e){for(var t,n,r,i=arguments.length,o=new Array(i>1?i-1:0),a=1;ae.loc)).filter((e=>null!=e)));this.source=null!=l?l:null==p||null===(n=p[0])||void 0===n?void 0:n.source,this.positions=null!=u?u:null==p?void 0:p.map((e=>e.start)),this.locations=u&&l?u.map((e=>Ct(l,e))):null==p?void 0:p.map((e=>Ct(e.source,e.start)));const h=at(null==d?void 0:d.extensions)?null==d?void 0:d.extensions:void 0;this.extensions=null!==(r=null!=f?f:h)&&void 0!==r?r:Object.create(null),Object.defineProperties(this,{message:{writable:!0,enumerable:!0},name:{enumerable:!1},nodes:{enumerable:!1},source:{enumerable:!1},positions:{enumerable:!1},originalError:{enumerable:!1}}),null!=d&&d.stack?Object.defineProperty(this,"stack",{value:d.stack,writable:!0,configurable:!0}):Error.captureStackTrace?Error.captureStackTrace(this,_t):Object.defineProperty(this,"stack",{value:Error().stack,writable:!0,configurable:!0})}get[Symbol.toStringTag](){return"GraphQLError"}toString(){let e=this.message;if(this.nodes)for(const t of this.nodes)t.loc&&(e+="\n\n"+St(t.loc));else if(this.source&&this.locations)for(const t of this.locations)e+="\n\n"+xt(this.source,t);return e}toJSON(){const e={message:this.message};return null!=this.locations&&(e.locations=this.locations),null!=this.path&&(e.path=this.path),null!=this.extensions&&Object.keys(this.extensions).length>0&&(e.extensions=this.extensions),e}}function Ot(e){return void 0===e||0===e.length?void 0:e}function It(e,t){switch(e.kind){case ze.NULL:return null;case ze.INT:return parseInt(e.value,10);case ze.FLOAT:return parseFloat(e.value);case ze.STRING:case ze.ENUM:case ze.BOOLEAN:return e.value;case ze.LIST:return e.values.map((e=>It(e,t)));case ze.OBJECT:return ft(e.fields,(e=>e.name.value),(e=>It(e.value,t)));case ze.VARIABLE:return null==t?void 0:t[e.name.value]}}function Dt(e){if(null!=e||Be(!1,"Must provide name."),"string"==typeof e||Be(!1,"Expected name to be a string."),0===e.length)throw new _t("Expected name to be a non-empty string.");for(let t=1;to(It(e,t)),this.extensions=Tt(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(i=e.extensionASTNodes)&&void 0!==i?i:[],null==e.specifiedByURL||"string"==typeof e.specifiedByURL||Be(!1,`${this.name} must provide "specifiedByURL" as a string, but got: ${Te(e.specifiedByURL)}.`),null==e.serialize||"function"==typeof e.serialize||Be(!1,`${this.name} must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.`),e.parseLiteral&&("function"==typeof e.parseValue&&"function"==typeof e.parseLiteral||Be(!1,`${this.name} must provide both "parseValue" and "parseLiteral" functions.`))}get[Symbol.toStringTag](){return"GraphQLScalarType"}toConfig(){return{name:this.name,description:this.description,specifiedByURL:this.specifiedByURL,serialize:this.serialize,parseValue:this.parseValue,parseLiteral:this.parseLiteral,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}g(Qt,"GraphQLScalarType");class Xt{constructor(e){var t;this.name=Dt(e.name),this.description=e.description,this.isTypeOf=e.isTypeOf,this.extensions=Tt(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._fields=()=>Jt(e),this._interfaces=()=>Yt(e),null==e.isTypeOf||"function"==typeof e.isTypeOf||Be(!1,`${this.name} must provide "isTypeOf" as a function, but got: ${Te(e.isTypeOf)}.`)}get[Symbol.toStringTag](){return"GraphQLObjectType"}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}getInterfaces(){return"function"==typeof this._interfaces&&(this._interfaces=this._interfaces()),this._interfaces}toConfig(){return{name:this.name,description:this.description,interfaces:this.getInterfaces(),fields:tn(this.getFields()),isTypeOf:this.isTypeOf,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function Yt(e){var t;const n=Wt(null!==(t=e.interfaces)&&void 0!==t?t:[]);return Array.isArray(n)||Be(!1,`${e.name} interfaces must be an Array or a function which returns an Array.`),n}function Jt(e){const t=Kt(e.fields);return en(t)||Be(!1,`${e.name} fields must be an object with field names as keys or a function which returns such an object.`),pt(t,((t,n)=>{var r;en(t)||Be(!1,`${e.name}.${n} field config must be an object.`),null==t.resolve||"function"==typeof t.resolve||Be(!1,`${e.name}.${n} field resolver must be a function if provided, but got: ${Te(t.resolve)}.`);const i=null!==(r=t.args)&&void 0!==r?r:{};return en(i)||Be(!1,`${e.name}.${n} args must be an object with argument names as keys.`),{name:Dt(n),description:t.description,type:t.type,args:Zt(i),resolve:t.resolve,subscribe:t.subscribe,deprecationReason:t.deprecationReason,extensions:Tt(t.extensions),astNode:t.astNode}}))}function Zt(e){return Object.entries(e).map((e=>{let[t,n]=e;return{name:Dt(t),description:n.description,type:n.type,defaultValue:n.defaultValue,deprecationReason:n.deprecationReason,extensions:Tt(n.extensions),astNode:n.astNode}}))}function en(e){return at(e)&&!Array.isArray(e)}function tn(e){return pt(e,(e=>({description:e.description,type:e.type,args:nn(e.args),resolve:e.resolve,subscribe:e.subscribe,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})))}function nn(e){return ft(e,(e=>e.name),(e=>({description:e.description,type:e.type,defaultValue:e.defaultValue,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})))}g(Xt,"GraphQLObjectType"),g(Yt,"defineInterfaces"),g(Jt,"defineFieldMap"),g(Zt,"defineArguments"),g(en,"isPlainObj"),g(tn,"fieldsToFieldsConfig"),g(nn,"argsToArgsConfig");class rn{constructor(e){var t;this.name=Dt(e.name),this.description=e.description,this.resolveType=e.resolveType,this.extensions=Tt(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._fields=Jt.bind(void 0,e),this._interfaces=Yt.bind(void 0,e),null==e.resolveType||"function"==typeof e.resolveType||Be(!1,`${this.name} must provide "resolveType" as a function, but got: ${Te(e.resolveType)}.`)}get[Symbol.toStringTag](){return"GraphQLInterfaceType"}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}getInterfaces(){return"function"==typeof this._interfaces&&(this._interfaces=this._interfaces()),this._interfaces}toConfig(){return{name:this.name,description:this.description,interfaces:this.getInterfaces(),fields:tn(this.getFields()),resolveType:this.resolveType,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}g(rn,"GraphQLInterfaceType");class on{constructor(e){var t;this.name=Dt(e.name),this.description=e.description,this.resolveType=e.resolveType,this.extensions=Tt(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._types=an.bind(void 0,e),null==e.resolveType||"function"==typeof e.resolveType||Be(!1,`${this.name} must provide "resolveType" as a function, but got: ${Te(e.resolveType)}.`)}get[Symbol.toStringTag](){return"GraphQLUnionType"}getTypes(){return"function"==typeof this._types&&(this._types=this._types()),this._types}toConfig(){return{name:this.name,description:this.description,types:this.getTypes(),resolveType:this.resolveType,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function an(e){const t=Wt(e.types);return Array.isArray(t)||Be(!1,`Must provide Array of types or a function which returns such an array for Union ${e.name}.`),t}g(on,"GraphQLUnionType"),g(an,"defineTypes");class sn{constructor(e){var t;this.name=Dt(e.name),this.description=e.description,this.extensions=Tt(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._values=un(this.name,e.values),this._valueLookup=new Map(this._values.map((e=>[e.value,e]))),this._nameLookup=dt(this._values,(e=>e.name))}get[Symbol.toStringTag](){return"GraphQLEnumType"}getValues(){return this._values}getValue(e){return this._nameLookup[e]}serialize(e){const t=this._valueLookup.get(e);if(void 0===t)throw new _t(`Enum "${this.name}" cannot represent value: ${Te(e)}`);return t.name}parseValue(e){if("string"!=typeof e){const t=Te(e);throw new _t(`Enum "${this.name}" cannot represent non-string value: ${t}.`+ln(this,t))}const t=this.getValue(e);if(null==t)throw new _t(`Value "${e}" does not exist in "${this.name}" enum.`+ln(this,e));return t.value}parseLiteral(e,t){if(e.kind!==ze.ENUM){const t=Je(e);throw new _t(`Enum "${this.name}" cannot represent non-enum value: ${t}.`+ln(this,t),{nodes:e})}const n=this.getValue(e.value);if(null==n){const t=Je(e);throw new _t(`Value "${t}" does not exist in "${this.name}" enum.`+ln(this,t),{nodes:e})}return n.value}toConfig(){const e=ft(this.getValues(),(e=>e.name),(e=>({description:e.description,value:e.value,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})));return{name:this.name,description:this.description,values:e,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function ln(e,t){return lt("the enum value",yt(t,e.getValues().map((e=>e.name))))}function un(e,t){return en(t)||Be(!1,`${e} values must be an object with value names as keys.`),Object.entries(t).map((t=>{let[n,r]=t;return en(r)||Be(!1,`${e}.${n} must refer to an object with a "value" key representing an internal value but got: ${Te(r)}.`),{name:Lt(n),description:r.description,value:void 0!==r.value?r.value:n,deprecationReason:r.deprecationReason,extensions:Tt(r.extensions),astNode:r.astNode}}))}g(sn,"GraphQLEnumType"),g(ln,"didYouMeanEnumValue"),g(un,"defineEnumValues");class cn{constructor(e){var t;this.name=Dt(e.name),this.description=e.description,this.extensions=Tt(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._fields=dn.bind(void 0,e)}get[Symbol.toStringTag](){return"GraphQLInputObjectType"}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}toConfig(){const e=pt(this.getFields(),(e=>({description:e.description,type:e.type,defaultValue:e.defaultValue,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})));return{name:this.name,description:this.description,fields:e,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function dn(e){const t=Kt(e.fields);return en(t)||Be(!1,`${e.name} fields must be an object with field names as keys or a function which returns such an object.`),pt(t,((t,n)=>(!("resolve"in t)||Be(!1,`${e.name}.${n} field has a resolve property, but Input Types cannot define resolvers.`),{name:Dt(n),description:t.description,type:t.type,defaultValue:t.defaultValue,deprecationReason:t.deprecationReason,extensions:Tt(t.extensions),astNode:t.astNode})))}g(cn,"GraphQLInputObjectType"),g(dn,"defineInputFieldMap");const fn=2147483647,pn=-2147483648,hn=new Qt({name:"Int",description:"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",serialize(e){const t=bn(e);if("boolean"==typeof t)return t?1:0;let n=t;if("string"==typeof t&&""!==t&&(n=Number(t)),"number"!=typeof n||!Number.isInteger(n))throw new _t(`Int cannot represent non-integer value: ${Te(t)}`);if(n>fn||nfn||efn||t({description:{type:gn,resolve:e=>e.description},types:{description:"A list of all types supported by this server.",type:new Gt(new Ht(new Gt(xn))),resolve(e){return Object.values(e.getTypeMap())}},queryType:{description:"The type that query operations will be rooted at.",type:new Gt(xn),resolve:e=>e.getQueryType()},mutationType:{description:"If this server supports mutation, the type that mutation operations will be rooted at.",type:xn,resolve:e=>e.getMutationType()},subscriptionType:{description:"If this server support subscription, the type that subscription operations will be rooted at.",type:xn,resolve:e=>e.getSubscriptionType()},directives:{description:"A list of all directives supported by this server.",type:new Gt(new Ht(new Gt(Cn))),resolve:e=>e.getDirectives()}})}),Cn=new Xt({name:"__Directive",description:"A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.",fields:()=>({name:{type:new Gt(gn),resolve:e=>e.name},description:{type:gn,resolve:e=>e.description},isRepeatable:{type:new Gt(vn),resolve:e=>e.isRepeatable},locations:{type:new Gt(new Ht(new Gt(Sn))),resolve:e=>e.locations},args:{type:new Gt(new Ht(new Gt(Nn))),args:{includeDeprecated:{type:vn,defaultValue:!1}},resolve(e,t){let{includeDeprecated:n}=t;return n?e.args:e.args.filter((e=>null==e.deprecationReason))}}})}),Sn=new sn({name:"__DirectiveLocation",description:"A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.",values:{QUERY:{value:Oe.QUERY,description:"Location adjacent to a query operation."},MUTATION:{value:Oe.MUTATION,description:"Location adjacent to a mutation operation."},SUBSCRIPTION:{value:Oe.SUBSCRIPTION,description:"Location adjacent to a subscription operation."},FIELD:{value:Oe.FIELD,description:"Location adjacent to a field."},FRAGMENT_DEFINITION:{value:Oe.FRAGMENT_DEFINITION,description:"Location adjacent to a fragment definition."},FRAGMENT_SPREAD:{value:Oe.FRAGMENT_SPREAD,description:"Location adjacent to a fragment spread."},INLINE_FRAGMENT:{value:Oe.INLINE_FRAGMENT,description:"Location adjacent to an inline fragment."},VARIABLE_DEFINITION:{value:Oe.VARIABLE_DEFINITION,description:"Location adjacent to a variable definition."},SCHEMA:{value:Oe.SCHEMA,description:"Location adjacent to a schema definition."},SCALAR:{value:Oe.SCALAR,description:"Location adjacent to a scalar definition."},OBJECT:{value:Oe.OBJECT,description:"Location adjacent to an object type definition."},FIELD_DEFINITION:{value:Oe.FIELD_DEFINITION,description:"Location adjacent to a field definition."},ARGUMENT_DEFINITION:{value:Oe.ARGUMENT_DEFINITION,description:"Location adjacent to an argument definition."},INTERFACE:{value:Oe.INTERFACE,description:"Location adjacent to an interface definition."},UNION:{value:Oe.UNION,description:"Location adjacent to a union definition."},ENUM:{value:Oe.ENUM,description:"Location adjacent to an enum definition."},ENUM_VALUE:{value:Oe.ENUM_VALUE,description:"Location adjacent to an enum value definition."},INPUT_OBJECT:{value:Oe.INPUT_OBJECT,description:"Location adjacent to an input object type definition."},INPUT_FIELD_DEFINITION:{value:Oe.INPUT_FIELD_DEFINITION,description:"Location adjacent to an input object field definition."}}}),xn=new Xt({name:"__Type",description:"The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional `specifiedByURL`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.",fields:()=>({kind:{type:new Gt(Dn),resolve(e){return Mt(e)?On.SCALAR:Rt(e)?On.OBJECT:Ft(e)?On.INTERFACE:Pt(e)?On.UNION:jt(e)?On.ENUM:Vt(e)?On.INPUT_OBJECT:Ut(e)?On.LIST:Bt(e)?On.NON_NULL:void _e(!1,`Unexpected type: "${Te(e)}".`)}},name:{type:gn,resolve:e=>"name"in e?e.name:void 0},description:{type:gn,resolve:e=>"description"in e?e.description:void 0},specifiedByURL:{type:gn,resolve:e=>"specifiedByURL"in e?e.specifiedByURL:void 0},fields:{type:new Ht(new Gt(kn)),args:{includeDeprecated:{type:vn,defaultValue:!1}},resolve(e,t){let{includeDeprecated:n}=t;if(Rt(e)||Ft(e)){const t=Object.values(e.getFields());return n?t:t.filter((e=>null==e.deprecationReason))}}},interfaces:{type:new Ht(new Gt(xn)),resolve(e){if(Rt(e)||Ft(e))return e.getInterfaces()}},possibleTypes:{type:new Ht(new Gt(xn)),resolve(e,t,n,r){let{schema:i}=r;if(qt(e))return i.getPossibleTypes(e)}},enumValues:{type:new Ht(new Gt(_n)),args:{includeDeprecated:{type:vn,defaultValue:!1}},resolve(e,t){let{includeDeprecated:n}=t;if(jt(e)){const t=e.getValues();return n?t:t.filter((e=>null==e.deprecationReason))}}},inputFields:{type:new Ht(new Gt(Nn)),args:{includeDeprecated:{type:vn,defaultValue:!1}},resolve(e,t){let{includeDeprecated:n}=t;if(Vt(e)){const t=Object.values(e.getFields());return n?t:t.filter((e=>null==e.deprecationReason))}}},ofType:{type:xn,resolve:e=>"ofType"in e?e.ofType:void 0}})}),kn=new Xt({name:"__Field",description:"Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.",fields:()=>({name:{type:new Gt(gn),resolve:e=>e.name},description:{type:gn,resolve:e=>e.description},args:{type:new Gt(new Ht(new Gt(Nn))),args:{includeDeprecated:{type:vn,defaultValue:!1}},resolve(e,t){let{includeDeprecated:n}=t;return n?e.args:e.args.filter((e=>null==e.deprecationReason))}},type:{type:new Gt(xn),resolve:e=>e.type},isDeprecated:{type:new Gt(vn),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:gn,resolve:e=>e.deprecationReason}})}),Nn=new Xt({name:"__InputValue",description:"Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.",fields:()=>({name:{type:new Gt(gn),resolve:e=>e.name},description:{type:gn,resolve:e=>e.description},type:{type:new Gt(xn),resolve:e=>e.type},defaultValue:{type:gn,description:"A GraphQL-formatted string representing the default value for this input value.",resolve(e){const{type:t,defaultValue:n}=e,r=En(n,t);return r?Je(r):null}},isDeprecated:{type:new Gt(vn),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:gn,resolve:e=>e.deprecationReason}})}),_n=new Xt({name:"__EnumValue",description:"One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.",fields:()=>({name:{type:new Gt(gn),resolve:e=>e.name},description:{type:gn,resolve:e=>e.description},isDeprecated:{type:new Gt(vn),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:gn,resolve:e=>e.deprecationReason}})});let On;var In;(In=On||(On={})).SCALAR="SCALAR",In.OBJECT="OBJECT",In.INTERFACE="INTERFACE",In.UNION="UNION",In.ENUM="ENUM",In.INPUT_OBJECT="INPUT_OBJECT",In.LIST="LIST",In.NON_NULL="NON_NULL";const Dn=new sn({name:"__TypeKind",description:"An enum describing what kind of type a given `__Type` is.",values:{SCALAR:{value:On.SCALAR,description:"Indicates this type is a scalar."},OBJECT:{value:On.OBJECT,description:"Indicates this type is an object. `fields` and `interfaces` are valid fields."},INTERFACE:{value:On.INTERFACE,description:"Indicates this type is an interface. `fields`, `interfaces`, and `possibleTypes` are valid fields."},UNION:{value:On.UNION,description:"Indicates this type is a union. `possibleTypes` is a valid field."},ENUM:{value:On.ENUM,description:"Indicates this type is an enum. `enumValues` is a valid field."},INPUT_OBJECT:{value:On.INPUT_OBJECT,description:"Indicates this type is an input object. `inputFields` is a valid field."},LIST:{value:On.LIST,description:"Indicates this type is a list. `ofType` is a valid field."},NON_NULL:{value:On.NON_NULL,description:"Indicates this type is a non-null. `ofType` is a valid field."}}}),Ln={name:"__schema",type:new Gt(wn),description:"Access the current type schema of this server.",args:[],resolve:(e,t,n,r)=>{let{schema:i}=r;return i},deprecationReason:void 0,extensions:Object.create(null),astNode:void 0};e.S=Ln;const An={name:"__type",type:xn,description:"Request the type information of a single type.",args:[{name:"name",description:void 0,type:new Gt(gn),defaultValue:void 0,deprecationReason:void 0,extensions:Object.create(null),astNode:void 0}],resolve:(e,t,n,r)=>{let{name:i}=t,{schema:o}=r;return o.getType(i)},deprecationReason:void 0,extensions:Object.create(null),astNode:void 0};e.T=An;const Mn={name:"__typename",type:new Gt(gn),description:"The name of the current Object type at runtime.",args:[],resolve:(e,t,n,r)=>{let{parentType:i}=r;return i.name},deprecationReason:void 0,extensions:Object.create(null),astNode:void 0};function Rn(e){let t;return Pn(e,(e=>{switch(e.kind){case"Query":case"ShortQuery":case"Mutation":case"Subscription":case"FragmentDefinition":t=e}})),t}function Fn(e,t,n){return n===Ln.name&&e.getQueryType()===t?Ln:n===An.name&&e.getQueryType()===t?An:n===Mn.name&&(0,r.isCompositeType)(t)?Mn:"getFields"in t?t.getFields()[n]:null}function Pn(e,t){const n=[];let r=e;for(;null==r?void 0:r.kind;)n.push(r),r=r.prevState;for(let e=n.length-1;e>=0;e--)t(n[e])}function jn(e){const t=Object.keys(e),n=t.length,r=new Array(n);for(let i=0;i({proximity:qn($n(e.label),t),entry:e}))),(e=>e.proximity<=2)),(e=>!e.entry.isDeprecated)).sort(((e,t)=>(e.entry.isDeprecated?1:0)-(t.entry.isDeprecated?1:0)||e.proximity-t.proximity||e.entry.label.length-t.entry.label.length)).map((e=>e.entry)):Bn(e,(e=>!e.isDeprecated))}function Bn(e,t){const n=e.filter(t);return 0===n.length?e:n}function $n(e){return e.toLowerCase().replaceAll(/\W/g,"")}function qn(e,t){let n=Hn(t,e);return e.length>t.length&&(n-=e.length-t.length-1,n+=0===e.indexOf(t)?0:.5),n}function Hn(e,t){let n,r;const i=[],o=e.length,a=t.length;for(n=0;n<=o;n++)i[n]=[n];for(r=1;r<=a;r++)i[0][r]=r;for(n=1;n<=o;n++)for(r=1;r<=a;r++){const o=e[n-1]===t[r-1]?0:1;i[n][r]=Math.min(i[n-1][r]+1,i[n][r-1]+1,i[n-1][r-1]+o),n>1&&r>1&&e[n-1]===t[r-2]&&e[n-2]===t[r-1]&&(i[n][r]=Math.min(i[n][r],i[n-2][r-2]+o))}return i[o][a]}var Gn,zn,Wn,Kn,Qn,Xn,Yn,Jn,Zn,er,tr,nr,rr,ir,or,ar,sr,lr,ur,cr,dr,fr,pr,hr,mr,gr,vr,yr,br,Er,Tr;e.a=Mn,Object.freeze([wn,Cn,Sn,xn,kn,Nn,_n,Dn]),g(Rn,"getDefinitionState"),g(Fn,"getFieldDef"),g(Pn,"forEachState"),g(jn,"objectValues"),g(Vn,"hintList"),g(Un,"filterAndSortList"),g(Bn,"filterNonEmpty"),g($n,"normalizeText"),g(qn,"getProximity"),g(Hn,"lexicalDistance"),function(e){function t(e){return"string"==typeof e}g(t,"is"),e.is=t}(Gn||(Gn={})),function(e){function t(e){return"string"==typeof e}g(t,"is"),e.is=t}(zn||(zn={})),function(e){function t(t){return"number"==typeof t&&e.MIN_VALUE<=t&&t<=e.MAX_VALUE}e.MIN_VALUE=-2147483648,e.MAX_VALUE=2147483647,g(t,"is"),e.is=t}(Wn||(Wn={})),function(e){function t(t){return"number"==typeof t&&e.MIN_VALUE<=t&&t<=e.MAX_VALUE}e.MIN_VALUE=0,e.MAX_VALUE=2147483647,g(t,"is"),e.is=t}(Kn||(Kn={})),function(e){function t(e,t){return e===Number.MAX_VALUE&&(e=Kn.MAX_VALUE),t===Number.MAX_VALUE&&(t=Kn.MAX_VALUE),{line:e,character:t}}function n(e){var t=e;return Si.objectLiteral(t)&&Si.uinteger(t.line)&&Si.uinteger(t.character)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Qn||(Qn={})),function(e){function t(e,t,n,r){if(Si.uinteger(e)&&Si.uinteger(t)&&Si.uinteger(n)&&Si.uinteger(r))return{start:Qn.create(e,t),end:Qn.create(n,r)};if(Qn.is(e)&&Qn.is(t))return{start:e,end:t};throw new Error("Range#create called with invalid arguments[".concat(e,", ").concat(t,", ").concat(n,", ").concat(r,"]"))}function n(e){var t=e;return Si.objectLiteral(t)&&Qn.is(t.start)&&Qn.is(t.end)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Xn||(Xn={})),function(e){function t(e,t){return{uri:e,range:t}}function n(e){var t=e;return Si.defined(t)&&Xn.is(t.range)&&(Si.string(t.uri)||Si.undefined(t.uri))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Yn||(Yn={})),function(e){function t(e,t,n,r){return{targetUri:e,targetRange:t,targetSelectionRange:n,originSelectionRange:r}}function n(e){var t=e;return Si.defined(t)&&Xn.is(t.targetRange)&&Si.string(t.targetUri)&&Xn.is(t.targetSelectionRange)&&(Xn.is(t.originSelectionRange)||Si.undefined(t.originSelectionRange))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Jn||(Jn={})),function(e){function t(e,t,n,r){return{red:e,green:t,blue:n,alpha:r}}function n(e){var t=e;return Si.objectLiteral(t)&&Si.numberRange(t.red,0,1)&&Si.numberRange(t.green,0,1)&&Si.numberRange(t.blue,0,1)&&Si.numberRange(t.alpha,0,1)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Zn||(Zn={})),function(e){function t(e,t){return{range:e,color:t}}function n(e){var t=e;return Si.objectLiteral(t)&&Xn.is(t.range)&&Zn.is(t.color)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(er||(er={})),function(e){function t(e,t,n){return{label:e,textEdit:t,additionalTextEdits:n}}function n(e){var t=e;return Si.objectLiteral(t)&&Si.string(t.label)&&(Si.undefined(t.textEdit)||cr.is(t))&&(Si.undefined(t.additionalTextEdits)||Si.typedArray(t.additionalTextEdits,cr.is))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(tr||(tr={})),(Tr=nr||(nr={})).Comment="comment",Tr.Imports="imports",Tr.Region="region",function(e){function t(e,t,n,r,i,o){var a={startLine:e,endLine:t};return Si.defined(n)&&(a.startCharacter=n),Si.defined(r)&&(a.endCharacter=r),Si.defined(i)&&(a.kind=i),Si.defined(o)&&(a.collapsedText=o),a}function n(e){var t=e;return Si.objectLiteral(t)&&Si.uinteger(t.startLine)&&Si.uinteger(t.startLine)&&(Si.undefined(t.startCharacter)||Si.uinteger(t.startCharacter))&&(Si.undefined(t.endCharacter)||Si.uinteger(t.endCharacter))&&(Si.undefined(t.kind)||Si.string(t.kind))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(rr||(rr={})),function(e){function t(e,t){return{location:e,message:t}}function n(e){var t=e;return Si.defined(t)&&Yn.is(t.location)&&Si.string(t.message)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(ir||(ir={})),(Er=or||(or={})).Error=1,Er.Warning=2,Er.Information=3,Er.Hint=4,(br=ar||(ar={})).Unnecessary=1,br.Deprecated=2,function(e){function t(e){var t=e;return Si.objectLiteral(t)&&Si.string(t.href)}g(t,"is"),e.is=t}(sr||(sr={})),function(e){function t(e,t,n,r,i,o){var a={range:e,message:t};return Si.defined(n)&&(a.severity=n),Si.defined(r)&&(a.code=r),Si.defined(i)&&(a.source=i),Si.defined(o)&&(a.relatedInformation=o),a}function n(e){var t,n=e;return Si.defined(n)&&Xn.is(n.range)&&Si.string(n.message)&&(Si.number(n.severity)||Si.undefined(n.severity))&&(Si.integer(n.code)||Si.string(n.code)||Si.undefined(n.code))&&(Si.undefined(n.codeDescription)||Si.string(null===(t=n.codeDescription)||void 0===t?void 0:t.href))&&(Si.string(n.source)||Si.undefined(n.source))&&(Si.undefined(n.relatedInformation)||Si.typedArray(n.relatedInformation,ir.is))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(lr||(lr={})),function(e){function t(e,t){for(var n=[],r=2;r0&&(i.arguments=n),i}function n(e){var t=e;return Si.defined(t)&&Si.string(t.title)&&Si.string(t.command)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(ur||(ur={})),function(e){function t(e,t){return{range:e,newText:t}}function n(e,t){return{range:{start:e,end:e},newText:t}}function r(e){return{range:e,newText:""}}function i(e){var t=e;return Si.objectLiteral(t)&&Si.string(t.newText)&&Xn.is(t.range)}g(t,"replace"),e.replace=t,g(n,"insert"),e.insert=n,g(r,"del"),e.del=r,g(i,"is"),e.is=i}(cr||(cr={})),function(e){function t(e,t,n){var r={label:e};return void 0!==t&&(r.needsConfirmation=t),void 0!==n&&(r.description=n),r}function n(e){var t=e;return Si.objectLiteral(t)&&Si.string(t.label)&&(Si.boolean(t.needsConfirmation)||void 0===t.needsConfirmation)&&(Si.string(t.description)||void 0===t.description)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(dr||(dr={})),function(e){function t(e){var t=e;return Si.string(t)}g(t,"is"),e.is=t}(fr||(fr={})),function(e){function t(e,t,n){return{range:e,newText:t,annotationId:n}}function n(e,t,n){return{range:{start:e,end:e},newText:t,annotationId:n}}function r(e,t){return{range:e,newText:"",annotationId:t}}function i(e){var t=e;return cr.is(t)&&(dr.is(t.annotationId)||fr.is(t.annotationId))}g(t,"replace"),e.replace=t,g(n,"insert"),e.insert=n,g(r,"del"),e.del=r,g(i,"is"),e.is=i}(pr||(pr={})),function(e){function t(e,t){return{textDocument:e,edits:t}}function n(e){var t=e;return Si.defined(t)&&Sr.is(t.textDocument)&&Array.isArray(t.edits)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(hr||(hr={})),function(e){function t(e,t,n){var r={kind:"create",uri:e};return void 0===t||void 0===t.overwrite&&void 0===t.ignoreIfExists||(r.options=t),void 0!==n&&(r.annotationId=n),r}function n(e){var t=e;return t&&"create"===t.kind&&Si.string(t.uri)&&(void 0===t.options||(void 0===t.options.overwrite||Si.boolean(t.options.overwrite))&&(void 0===t.options.ignoreIfExists||Si.boolean(t.options.ignoreIfExists)))&&(void 0===t.annotationId||fr.is(t.annotationId))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(mr||(mr={})),function(e){function t(e,t,n,r){var i={kind:"rename",oldUri:e,newUri:t};return void 0===n||void 0===n.overwrite&&void 0===n.ignoreIfExists||(i.options=n),void 0!==r&&(i.annotationId=r),i}function n(e){var t=e;return t&&"rename"===t.kind&&Si.string(t.oldUri)&&Si.string(t.newUri)&&(void 0===t.options||(void 0===t.options.overwrite||Si.boolean(t.options.overwrite))&&(void 0===t.options.ignoreIfExists||Si.boolean(t.options.ignoreIfExists)))&&(void 0===t.annotationId||fr.is(t.annotationId))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(gr||(gr={})),function(e){function t(e,t,n){var r={kind:"delete",uri:e};return void 0===t||void 0===t.recursive&&void 0===t.ignoreIfNotExists||(r.options=t),void 0!==n&&(r.annotationId=n),r}function n(e){var t=e;return t&&"delete"===t.kind&&Si.string(t.uri)&&(void 0===t.options||(void 0===t.options.recursive||Si.boolean(t.options.recursive))&&(void 0===t.options.ignoreIfNotExists||Si.boolean(t.options.ignoreIfNotExists)))&&(void 0===t.annotationId||fr.is(t.annotationId))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(vr||(vr={})),function(e){function t(e){var t=e;return t&&(void 0!==t.changes||void 0!==t.documentChanges)&&(void 0===t.documentChanges||t.documentChanges.every((function(e){return Si.string(e.kind)?mr.is(e)||gr.is(e)||vr.is(e):hr.is(e)})))}g(t,"is"),e.is=t}(yr||(yr={}));var wr,Cr,Sr,xr,kr,Nr,_r,Or,Ir,Dr,Lr,Ar,Mr,Rr,Fr,Pr,jr,Vr,Ur,Br,$r,qr,Hr,Gr,zr,Wr,Kr,Qr,Xr,Yr,Jr,Zr,ei,ti,ni,ri,ii,oi,ai,si,li,ui,ci,di,fi,pi,hi,mi,gi,vi,yi,bi,Ei,Ti,wi=function(){function e(e,t){this.edits=e,this.changeAnnotations=t}return g(e,"TextEditChangeImpl"),e.prototype.insert=function(e,t,n){var r,i;if(void 0===n?r=cr.insert(e,t):fr.is(n)?(i=n,r=pr.insert(e,t,n)):(this.assertChangeAnnotations(this.changeAnnotations),i=this.changeAnnotations.manage(n),r=pr.insert(e,t,i)),this.edits.push(r),void 0!==i)return i},e.prototype.replace=function(e,t,n){var r,i;if(void 0===n?r=cr.replace(e,t):fr.is(n)?(i=n,r=pr.replace(e,t,n)):(this.assertChangeAnnotations(this.changeAnnotations),i=this.changeAnnotations.manage(n),r=pr.replace(e,t,i)),this.edits.push(r),void 0!==i)return i},e.prototype.delete=function(e,t){var n,r;if(void 0===t?n=cr.del(e):fr.is(t)?(r=t,n=pr.del(e,t)):(this.assertChangeAnnotations(this.changeAnnotations),r=this.changeAnnotations.manage(t),n=pr.del(e,r)),this.edits.push(n),void 0!==r)return r},e.prototype.add=function(e){this.edits.push(e)},e.prototype.all=function(){return this.edits},e.prototype.clear=function(){this.edits.splice(0,this.edits.length)},e.prototype.assertChangeAnnotations=function(e){if(void 0===e)throw new Error("Text edit change is not configured to manage change annotations.")},e}(),Ci=function(){function e(e){this._annotations=void 0===e?Object.create(null):e,this._counter=0,this._size=0}return g(e,"ChangeAnnotations"),e.prototype.all=function(){return this._annotations},Object.defineProperty(e.prototype,"size",{get:function(){return this._size},enumerable:!1,configurable:!0}),e.prototype.manage=function(e,t){var n;if(fr.is(e)?n=e:(n=this.nextId(),t=e),void 0!==this._annotations[n])throw new Error("Id ".concat(n," is already in use."));if(void 0===t)throw new Error("No annotation provided for id ".concat(n));return this._annotations[n]=t,this._size++,n},e.prototype.nextId=function(){return this._counter++,this._counter.toString()},e}();(function(){function e(e){var t=this;this._textEditChanges=Object.create(null),void 0!==e?(this._workspaceEdit=e,e.documentChanges?(this._changeAnnotations=new Ci(e.changeAnnotations),e.changeAnnotations=this._changeAnnotations.all(),e.documentChanges.forEach((function(e){if(hr.is(e)){var n=new wi(e.edits,t._changeAnnotations);t._textEditChanges[e.textDocument.uri]=n}}))):e.changes&&Object.keys(e.changes).forEach((function(n){var r=new wi(e.changes[n]);t._textEditChanges[n]=r}))):this._workspaceEdit={}}g(e,"WorkspaceChange"),Object.defineProperty(e.prototype,"edit",{get:function(){return this.initDocumentChanges(),void 0!==this._changeAnnotations&&(0===this._changeAnnotations.size?this._workspaceEdit.changeAnnotations=void 0:this._workspaceEdit.changeAnnotations=this._changeAnnotations.all()),this._workspaceEdit},enumerable:!1,configurable:!0}),e.prototype.getTextEditChange=function(e){if(Sr.is(e)){if(this.initDocumentChanges(),void 0===this._workspaceEdit.documentChanges)throw new Error("Workspace edit is not configured for document changes.");var t={uri:e.uri,version:e.version};if(!(r=this._textEditChanges[t.uri])){var n={textDocument:t,edits:i=[]};this._workspaceEdit.documentChanges.push(n),r=new wi(i,this._changeAnnotations),this._textEditChanges[t.uri]=r}return r}if(this.initChanges(),void 0===this._workspaceEdit.changes)throw new Error("Workspace edit is not configured for normal text edit changes.");var r;if(!(r=this._textEditChanges[e])){var i=[];this._workspaceEdit.changes[e]=i,r=new wi(i),this._textEditChanges[e]=r}return r},e.prototype.initDocumentChanges=function(){void 0===this._workspaceEdit.documentChanges&&void 0===this._workspaceEdit.changes&&(this._changeAnnotations=new Ci,this._workspaceEdit.documentChanges=[],this._workspaceEdit.changeAnnotations=this._changeAnnotations.all())},e.prototype.initChanges=function(){void 0===this._workspaceEdit.documentChanges&&void 0===this._workspaceEdit.changes&&(this._workspaceEdit.changes=Object.create(null))},e.prototype.createFile=function(e,t,n){if(this.initDocumentChanges(),void 0===this._workspaceEdit.documentChanges)throw new Error("Workspace edit is not configured for document changes.");var r,i,o;if(dr.is(t)||fr.is(t)?r=t:n=t,void 0===r?i=mr.create(e,n):(o=fr.is(r)?r:this._changeAnnotations.manage(r),i=mr.create(e,n,o)),this._workspaceEdit.documentChanges.push(i),void 0!==o)return o},e.prototype.renameFile=function(e,t,n,r){if(this.initDocumentChanges(),void 0===this._workspaceEdit.documentChanges)throw new Error("Workspace edit is not configured for document changes.");var i,o,a;if(dr.is(n)||fr.is(n)?i=n:r=n,void 0===i?o=gr.create(e,t,r):(a=fr.is(i)?i:this._changeAnnotations.manage(i),o=gr.create(e,t,r,a)),this._workspaceEdit.documentChanges.push(o),void 0!==a)return a},e.prototype.deleteFile=function(e,t,n){if(this.initDocumentChanges(),void 0===this._workspaceEdit.documentChanges)throw new Error("Workspace edit is not configured for document changes.");var r,i,o;if(dr.is(t)||fr.is(t)?r=t:n=t,void 0===r?i=vr.create(e,n):(o=fr.is(r)?r:this._changeAnnotations.manage(r),i=vr.create(e,n,o)),this._workspaceEdit.documentChanges.push(i),void 0!==o)return o}})(),function(e){function t(e){return{uri:e}}function n(e){var t=e;return Si.defined(t)&&Si.string(t.uri)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(wr||(wr={})),function(e){function t(e,t){return{uri:e,version:t}}function n(e){var t=e;return Si.defined(t)&&Si.string(t.uri)&&Si.integer(t.version)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Cr||(Cr={})),function(e){function t(e,t){return{uri:e,version:t}}function n(e){var t=e;return Si.defined(t)&&Si.string(t.uri)&&(null===t.version||Si.integer(t.version))}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Sr||(Sr={})),function(e){function t(e,t,n,r){return{uri:e,languageId:t,version:n,text:r}}function n(e){var t=e;return Si.defined(t)&&Si.string(t.uri)&&Si.string(t.languageId)&&Si.integer(t.version)&&Si.string(t.text)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(xr||(xr={})),function(e){function t(t){var n=t;return n===e.PlainText||n===e.Markdown}e.PlainText="plaintext",e.Markdown="markdown",g(t,"is"),e.is=t}(kr||(kr={})),function(e){function t(e){var t=e;return Si.objectLiteral(e)&&kr.is(t.kind)&&Si.string(t.value)}g(t,"is"),e.is=t}(Nr||(Nr={})),(Ti=_r||(_r={})).Text=1,Ti.Method=2,Ti.Function=3,Ti.Constructor=4,Ti.Field=5,Ti.Variable=6,Ti.Class=7,Ti.Interface=8,Ti.Module=9,Ti.Property=10,Ti.Unit=11,Ti.Value=12,Ti.Enum=13,Ti.Keyword=14,Ti.Snippet=15,Ti.Color=16,Ti.File=17,Ti.Reference=18,Ti.Folder=19,Ti.EnumMember=20,Ti.Constant=21,Ti.Struct=22,Ti.Event=23,Ti.Operator=24,Ti.TypeParameter=25,(Ei=Or||(Or={})).PlainText=1,Ei.Snippet=2,(Ir||(Ir={})).Deprecated=1,function(e){function t(e,t,n){return{newText:e,insert:t,replace:n}}function n(e){var t=e;return t&&Si.string(t.newText)&&Xn.is(t.insert)&&Xn.is(t.replace)}g(t,"create"),e.create=t,g(n,"is"),e.is=n}(Dr||(Dr={})),(bi=Lr||(Lr={})).asIs=1,bi.adjustIndentation=2,function(e){function t(e){var t=e;return t&&(Si.string(t.detail)||void 0===t.detail)&&(Si.string(t.description)||void 0===t.description)}g(t,"is"),e.is=t}(Ar||(Ar={})),function(e){function t(e){return{label:e}}g(t,"create"),e.create=t}(Mr||(Mr={})),function(e){function t(e,t){return{items:e||[],isIncomplete:!!t}}g(t,"create"),e.create=t}(Rr||(Rr={})),function(e){function t(e){return e.replace(/[\\`*_{}[\]()#+\-.!]/g,"\\$&")}function n(e){var t=e;return Si.string(t)||Si.objectLiteral(t)&&Si.string(t.language)&&Si.string(t.value)}g(t,"fromPlainText"),e.fromPlainText=t,g(n,"is"),e.is=n}(Fr||(Fr={})),function(e){function t(e){var t=e;return!!t&&Si.objectLiteral(t)&&(Nr.is(t.contents)||Fr.is(t.contents)||Si.typedArray(t.contents,Fr.is))&&(void 0===e.range||Xn.is(e.range))}g(t,"is"),e.is=t}(Pr||(Pr={})),function(e){function t(e,t){return t?{label:e,documentation:t}:{label:e}}g(t,"create"),e.create=t}(jr||(jr={})),function(e){function t(e,t){for(var n=[],r=2;r=0;a--){var s=r[a],l=e.offsetAt(s.range.start),u=e.offsetAt(s.range.end);if(!(u<=o))throw new Error("Overlapping edit");n=n.substring(0,l)+s.newText+n.substring(u,n.length),o=l}return n}function i(e,t){if(e.length<=1)return e;var n=e.length/2|0,r=e.slice(0,n),o=e.slice(n);i(r,t),i(o,t);for(var a=0,s=0,l=0;a0&&e.push(t.length),this._lineOffsets=e}return this._lineOffsets},e.prototype.positionAt=function(e){e=Math.max(Math.min(e,this._content.length),0);var t=this.getLineOffsets(),n=0,r=t.length;if(0===r)return Qn.create(0,e);for(;ne?r=i:n=i+1}var o=n-1;return Qn.create(o,e-t[o])},e.prototype.offsetAt=function(e){var t=this.getLineOffsets();if(e.line>=t.length)return this._content.length;if(e.line<0)return 0;var n=t[e.line],r=e.line+1this._start,this.getCurrentPosition=()=>this._pos,this.eol=()=>this._sourceText.length===this._pos,this.sol=()=>0===this._pos,this.peek=()=>this._sourceText.charAt(this._pos)||null,this.next=()=>{const e=this._sourceText.charAt(this._pos);return this._pos++,e},this.eat=e=>{if(this._testNextCharacter(e))return this._start=this._pos,this._pos++,this._sourceText.charAt(this._pos-1)},this.eatWhile=e=>{let t=this._testNextCharacter(e),n=!1;for(t&&(n=t,this._start=this._pos);t;)this._pos++,t=this._testNextCharacter(e),n=!0;return n},this.eatSpace=()=>this.eatWhile(/[\s\u00a0]/),this.skipToEnd=()=>{this._pos=this._sourceText.length},this.skipTo=e=>{this._pos=e},this.match=function(e){let n=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],r=null,i=null;return"string"==typeof e?(i=new RegExp(e,arguments.length>2&&void 0!==arguments[2]&&arguments[2]?"i":"g").test(t._sourceText.slice(t._pos,t._pos+e.length)),r=e):e instanceof RegExp&&(i=t._sourceText.slice(t._pos).match(e),r=null==i?void 0:i[0]),!(null==i||!("string"==typeof e||i instanceof Array&&t._sourceText.startsWith(i[0],t._pos)))&&(n&&(t._start=t._pos,r&&r.length&&(t._pos+=r.length)),i)},this.backUp=e=>{this._pos-=e},this.column=()=>this._pos,this.indentation=()=>{const e=this._sourceText.match(/\s*/);let t=0;if(e&&0!==e.length){const n=e[0];let r=0;for(;n.length>r;)9===n.charCodeAt(r)?t+=2:t++,r++}return t},this.current=()=>this._sourceText.slice(this._start,this._pos),this._start=0,this._pos=0,this._sourceText=e}_testNextCharacter(e){const t=this._sourceText.charAt(this._pos);let n=!1;return n="string"==typeof e?t===e:e instanceof RegExp?e.test(t):e(t),n}}function _i(e){return{ofRule:e}}function Oi(e,t){return{ofRule:e,isList:!0,separator:t}}function Ii(e,t){const n=e.match;return e.match=e=>{let r=!1;return n&&(r=n(e)),r&&t.every((t=>t.match&&!t.match(e)))},e}function Di(e,t){return{style:t,match:t=>t.kind===e}}function Li(e,t){return{style:t||"punctuation",match:t=>"Punctuation"===t.kind&&t.value===e}}e.C=Ni,g(Ni,"CharacterStream"),g(_i,"opt"),g(Oi,"list$1"),g(Ii,"butNot"),g(Di,"t$2"),g(Li,"p$1");const Ai=g((e=>" "===e||"\t"===e||","===e||"\n"===e||"\r"===e||"\ufeff"===e||" "===e),"isIgnored");e.i=Ai;const Mi={Name:/^[_A-Za-z][_0-9A-Za-z]*/,Punctuation:/^(?:!|\$|\(|\)|\.\.\.|:|=|&|@|\[|]|\{|\||\})/,Number:/^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/,String:/^(?:"""(?:\\"""|[^"]|"[^"]|""[^"])*(?:""")?|"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?)/,Comment:/^#.*/};e.L=Mi;const Ri={Document:[Oi("Definition")],Definition(e){switch(e.value){case"{":return"ShortQuery";case"query":return"Query";case"mutation":return"Mutation";case"subscription":return"Subscription";case"fragment":return r.Kind.FRAGMENT_DEFINITION;case"schema":return"SchemaDef";case"scalar":return"ScalarDef";case"type":return"ObjectTypeDef";case"interface":return"InterfaceDef";case"union":return"UnionDef";case"enum":return"EnumDef";case"input":return"InputDef";case"extend":return"ExtendDef";case"directive":return"DirectiveDef"}},ShortQuery:["SelectionSet"],Query:[Fi("query"),_i(Pi("def")),_i("VariableDefinitions"),Oi("Directive"),"SelectionSet"],Mutation:[Fi("mutation"),_i(Pi("def")),_i("VariableDefinitions"),Oi("Directive"),"SelectionSet"],Subscription:[Fi("subscription"),_i(Pi("def")),_i("VariableDefinitions"),Oi("Directive"),"SelectionSet"],VariableDefinitions:[Li("("),Oi("VariableDefinition"),Li(")")],VariableDefinition:["Variable",Li(":"),"Type",_i("DefaultValue")],Variable:[Li("$","variable"),Pi("variable")],DefaultValue:[Li("="),"Value"],SelectionSet:[Li("{"),Oi("Selection"),Li("}")],Selection(e,t){return"..."===e.value?t.match(/[\s\u00a0,]*(on\b|@|{)/,!1)?"InlineFragment":"FragmentSpread":t.match(/[\s\u00a0,]*:/,!1)?"AliasedField":"Field"},AliasedField:[Pi("property"),Li(":"),Pi("qualifier"),_i("Arguments"),Oi("Directive"),_i("SelectionSet")],Field:[Pi("property"),_i("Arguments"),Oi("Directive"),_i("SelectionSet")],Arguments:[Li("("),Oi("Argument"),Li(")")],Argument:[Pi("attribute"),Li(":"),"Value"],FragmentSpread:[Li("..."),Pi("def"),Oi("Directive")],InlineFragment:[Li("..."),_i("TypeCondition"),Oi("Directive"),"SelectionSet"],FragmentDefinition:[Fi("fragment"),_i(Ii(Pi("def"),[Fi("on")])),"TypeCondition",Oi("Directive"),"SelectionSet"],TypeCondition:[Fi("on"),"NamedType"],Value(e){switch(e.kind){case"Number":return"NumberValue";case"String":return"StringValue";case"Punctuation":switch(e.value){case"[":return"ListValue";case"{":return"ObjectValue";case"$":return"Variable";case"&":return"NamedType"}return null;case"Name":switch(e.value){case"true":case"false":return"BooleanValue"}return"null"===e.value?"NullValue":"EnumValue"}},NumberValue:[Di("Number","number")],StringValue:[{style:"string",match:e=>"String"===e.kind,update(e,t){t.value.startsWith('"""')&&(e.inBlockstring=!t.value.slice(3).endsWith('"""'))}}],BooleanValue:[Di("Name","builtin")],NullValue:[Di("Name","keyword")],EnumValue:[Pi("string-2")],ListValue:[Li("["),Oi("Value"),Li("]")],ObjectValue:[Li("{"),Oi("ObjectField"),Li("}")],ObjectField:[Pi("attribute"),Li(":"),"Value"],Type(e){return"["===e.value?"ListType":"NonNullType"},ListType:[Li("["),"Type",Li("]"),_i(Li("!"))],NonNullType:["NamedType",_i(Li("!"))],NamedType:[ji("atom")],Directive:[Li("@","meta"),Pi("meta"),_i("Arguments")],DirectiveDef:[Fi("directive"),Li("@","meta"),Pi("meta"),_i("ArgumentsDef"),Fi("on"),Oi("DirectiveLocation",Li("|"))],InterfaceDef:[Fi("interface"),Pi("atom"),_i("Implements"),Oi("Directive"),Li("{"),Oi("FieldDef"),Li("}")],Implements:[Fi("implements"),Oi("NamedType",Li("&"))],DirectiveLocation:[Pi("string-2")],SchemaDef:[Fi("schema"),Oi("Directive"),Li("{"),Oi("OperationTypeDef"),Li("}")],OperationTypeDef:[Pi("keyword"),Li(":"),Pi("atom")],ScalarDef:[Fi("scalar"),Pi("atom"),Oi("Directive")],ObjectTypeDef:[Fi("type"),Pi("atom"),_i("Implements"),Oi("Directive"),Li("{"),Oi("FieldDef"),Li("}")],FieldDef:[Pi("property"),_i("ArgumentsDef"),Li(":"),"Type",Oi("Directive")],ArgumentsDef:[Li("("),Oi("InputValueDef"),Li(")")],InputValueDef:[Pi("attribute"),Li(":"),"Type",_i("DefaultValue"),Oi("Directive")],UnionDef:[Fi("union"),Pi("atom"),Oi("Directive"),Li("="),Oi("UnionMember",Li("|"))],UnionMember:["NamedType"],EnumDef:[Fi("enum"),Pi("atom"),Oi("Directive"),Li("{"),Oi("EnumValueDef"),Li("}")],EnumValueDef:[Pi("string-2"),Oi("Directive")],InputDef:[Fi("input"),Pi("atom"),Oi("Directive"),Li("{"),Oi("InputValueDef"),Li("}")],ExtendDef:[Fi("extend"),"ExtensionDefinition"],ExtensionDefinition(e){switch(e.value){case"schema":return r.Kind.SCHEMA_EXTENSION;case"scalar":return r.Kind.SCALAR_TYPE_EXTENSION;case"type":return r.Kind.OBJECT_TYPE_EXTENSION;case"interface":return r.Kind.INTERFACE_TYPE_EXTENSION;case"union":return r.Kind.UNION_TYPE_EXTENSION;case"enum":return r.Kind.ENUM_TYPE_EXTENSION;case"input":return r.Kind.INPUT_OBJECT_TYPE_EXTENSION}},[r.Kind.SCHEMA_EXTENSION]:["SchemaDef"],[r.Kind.SCALAR_TYPE_EXTENSION]:["ScalarDef"],[r.Kind.OBJECT_TYPE_EXTENSION]:["ObjectTypeDef"],[r.Kind.INTERFACE_TYPE_EXTENSION]:["InterfaceDef"],[r.Kind.UNION_TYPE_EXTENSION]:["UnionDef"],[r.Kind.ENUM_TYPE_EXTENSION]:["EnumDef"],[r.Kind.INPUT_OBJECT_TYPE_EXTENSION]:["InputDef"]};function Fi(e){return{style:"keyword",match:t=>"Name"===t.kind&&t.value===e}}function Pi(e){return{style:e,match:e=>"Name"===e.kind,update(e,t){e.name=t.value}}}function ji(e){return{style:e,match:e=>"Name"===e.kind,update(e,t){var n;(null===(n=e.prevState)||void 0===n?void 0:n.prevState)&&(e.name=t.value,e.prevState.prevState.type=t.value)}}}function Vi(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{eatWhitespace:e=>e.eatWhile(Ai),lexRules:Mi,parseRules:Ri,editorConfig:{}};return{startState(){const t={level:0,step:0,name:null,kind:null,type:null,rule:null,needsSeparator:!1,prevState:null};return qi(e.parseRules,t,r.Kind.DOCUMENT),t},token(t,n){return Ui(t,n,e)}}}function Ui(e,t,n){var r;if(t.inBlockstring)return e.match(/.*"""/)?(t.inBlockstring=!1,"string"):(e.skipToEnd(),"string");const{lexRules:i,parseRules:o,eatWhitespace:a,editorConfig:s}=n;if(t.rule&&0===t.rule.length?Hi(t):t.needsAdvance&&(t.needsAdvance=!1,Gi(t,!0)),e.sol()){const n=(null==s?void 0:s.tabSize)||2;t.indentLevel=Math.floor(e.indentation()/n)}if(a(e))return"ws";const l=Ki(i,e);if(!l)return e.match(/\S+/)||e.match(/\s/),qi($i,t,"Invalid"),"invalidchar";if("Comment"===l.kind)return qi($i,t,"Comment"),"comment";const u=Bi({},t);if("Punctuation"===l.kind)if(/^[{([]/.test(l.value))void 0!==t.indentLevel&&(t.levels=(t.levels||[]).concat(t.indentLevel+1));else if(/^[})\]]/.test(l.value)){const e=t.levels=(t.levels||[]).slice(0,-1);t.indentLevel&&e.length>0&&e.at(-1){const t=[];if(e)try{(0,r.visit)((0,r.parse)(e),{FragmentDefinition(e){t.push(e)}})}catch(e){return[]}return t}),"collectFragmentDefs"),Ji=[r.Kind.SCHEMA_DEFINITION,r.Kind.OPERATION_TYPE_DEFINITION,r.Kind.SCALAR_TYPE_DEFINITION,r.Kind.OBJECT_TYPE_DEFINITION,r.Kind.INTERFACE_TYPE_DEFINITION,r.Kind.UNION_TYPE_DEFINITION,r.Kind.ENUM_TYPE_DEFINITION,r.Kind.INPUT_OBJECT_TYPE_DEFINITION,r.Kind.DIRECTIVE_DEFINITION,r.Kind.SCHEMA_EXTENSION,r.Kind.SCALAR_TYPE_EXTENSION,r.Kind.OBJECT_TYPE_EXTENSION,r.Kind.INTERFACE_TYPE_EXTENSION,r.Kind.UNION_TYPE_EXTENSION,r.Kind.ENUM_TYPE_EXTENSION,r.Kind.INPUT_OBJECT_TYPE_EXTENSION],Zi=g((e=>{let t=!1;if(e)try{(0,r.visit)((0,r.parse)(e),{enter(e){if("Document"!==e.kind)return!!Ji.includes(e.kind)&&(t=!0,r.BREAK)}})}catch(e){return t}return t}),"hasTypeSystemDefinitions");function eo(e,t,n,i,o,a){var s;const l=Object.assign(Object.assign({},a),{schema:e}),u=i||vo(t,n),c="Invalid"===u.state.kind?u.state.prevState:u.state,d=(null==a?void 0:a.mode)||Co(t,null==a?void 0:a.uri);if(!c)return[];const{kind:f,step:p,prevState:h}=c,m=Eo(e,u.state);if(f===Qi.DOCUMENT)return d===To.TYPE_SYSTEM?ro(u):io(u);if(f===Qi.EXTEND_DEF)return oo(u);if((null===(s=null==h?void 0:h.prevState)||void 0===s?void 0:s.kind)===Qi.EXTENSION_DEFINITION&&c.name)return Vn(u,[]);if((null==h?void 0:h.kind)===r.Kind.SCALAR_TYPE_EXTENSION)return Vn(u,Object.values(e.getTypeMap()).filter(r.isScalarType).map((e=>({label:e.name,kind:xi.Function}))));if((null==h?void 0:h.kind)===r.Kind.OBJECT_TYPE_EXTENSION)return Vn(u,Object.values(e.getTypeMap()).filter((e=>(0,r.isObjectType)(e)&&!e.name.startsWith("__"))).map((e=>({label:e.name,kind:xi.Function}))));if((null==h?void 0:h.kind)===r.Kind.INTERFACE_TYPE_EXTENSION)return Vn(u,Object.values(e.getTypeMap()).filter(r.isInterfaceType).map((e=>({label:e.name,kind:xi.Function}))));if((null==h?void 0:h.kind)===r.Kind.UNION_TYPE_EXTENSION)return Vn(u,Object.values(e.getTypeMap()).filter(r.isUnionType).map((e=>({label:e.name,kind:xi.Function}))));if((null==h?void 0:h.kind)===r.Kind.ENUM_TYPE_EXTENSION)return Vn(u,Object.values(e.getTypeMap()).filter((e=>(0,r.isEnumType)(e)&&!e.name.startsWith("__"))).map((e=>({label:e.name,kind:xi.Function}))));if((null==h?void 0:h.kind)===r.Kind.INPUT_OBJECT_TYPE_EXTENSION)return Vn(u,Object.values(e.getTypeMap()).filter(r.isInputObjectType).map((e=>({label:e.name,kind:xi.Function}))));if(f===Qi.IMPLEMENTS||f===Qi.NAMED_TYPE&&(null==h?void 0:h.kind)===Qi.IMPLEMENTS)return lo(u,c,e,t,m);if(f===Qi.SELECTION_SET||f===Qi.FIELD||f===Qi.ALIASED_FIELD)return ao(u,m,l);if(f===Qi.ARGUMENTS||f===Qi.ARGUMENT&&0===p){const{argDefs:e}=m;if(e)return Vn(u,e.map((e=>{var t;return{label:e.name,insertText:e.name+": ",command:Xi,detail:String(e.type),documentation:null!==(t=e.description)&&void 0!==t?t:void 0,kind:xi.Variable,type:e.type}})))}if((f===Qi.OBJECT_VALUE||f===Qi.OBJECT_FIELD&&0===p)&&m.objectFieldDefs){const e=jn(m.objectFieldDefs),t=f===Qi.OBJECT_VALUE?xi.Value:xi.Field;return Vn(u,e.map((e=>{var n;return{label:e.name,detail:String(e.type),documentation:null!==(n=e.description)&&void 0!==n?n:void 0,kind:t,type:e.type}})))}if(f===Qi.ENUM_VALUE||f===Qi.LIST_VALUE&&1===p||f===Qi.OBJECT_FIELD&&2===p||f===Qi.ARGUMENT&&2===p)return so(u,m,t,e);if(f===Qi.VARIABLE&&1===p){const n=(0,r.getNamedType)(m.inputType);return Vn(u,po(t,e,u).filter((e=>e.detail===(null==n?void 0:n.name))))}if(f===Qi.TYPE_CONDITION&&1===p||f===Qi.NAMED_TYPE&&null!=h&&h.kind===Qi.TYPE_CONDITION)return uo(u,m,e);if(f===Qi.FRAGMENT_SPREAD&&1===p)return co(u,m,e,t,Array.isArray(o)?o:Yi(o));const g=So(c);if(d===To.TYPE_SYSTEM&&!g.needsAdvance&&f===Qi.NAMED_TYPE||f===Qi.LIST_TYPE){if(g.kind===Qi.FIELD_DEF)return Vn(u,Object.values(e.getTypeMap()).filter((e=>(0,r.isOutputType)(e)&&!e.name.startsWith("__"))).map((e=>({label:e.name,kind:xi.Function}))));if(g.kind===Qi.INPUT_VALUE_DEF)return Vn(u,Object.values(e.getTypeMap()).filter((e=>(0,r.isInputType)(e)&&!e.name.startsWith("__"))).map((e=>({label:e.name,kind:xi.Function}))))}return f===Qi.VARIABLE_DEFINITION&&2===p||f===Qi.LIST_TYPE&&1===p||f===Qi.NAMED_TYPE&&h&&(h.kind===Qi.VARIABLE_DEFINITION||h.kind===Qi.LIST_TYPE||h.kind===Qi.NON_NULL_TYPE)?mo(u,e):f===Qi.DIRECTIVE?go(u,c,e):[]}g(eo,"getAutocompleteSuggestions");const to=" {\n $1\n}",no=g((e=>{const{type:t}=e;if((0,r.isCompositeType)(t))return to;if((0,r.isListType)(t)&&(0,r.isCompositeType)(t.ofType))return to;if((0,r.isNonNullType)(t)){if((0,r.isCompositeType)(t.ofType))return to;if((0,r.isListType)(t.ofType)&&(0,r.isCompositeType)(t.ofType.ofType))return to}return null}),"getInsertText");function ro(e){return Vn(e,[{label:"extend",kind:xi.Function},{label:"type",kind:xi.Function},{label:"interface",kind:xi.Function},{label:"union",kind:xi.Function},{label:"input",kind:xi.Function},{label:"scalar",kind:xi.Function},{label:"schema",kind:xi.Function}])}function io(e){return Vn(e,[{label:"query",kind:xi.Function},{label:"mutation",kind:xi.Function},{label:"subscription",kind:xi.Function},{label:"fragment",kind:xi.Function},{label:"{",kind:xi.Constructor}])}function oo(e){return Vn(e,[{label:"type",kind:xi.Function},{label:"interface",kind:xi.Function},{label:"union",kind:xi.Function},{label:"input",kind:xi.Function},{label:"scalar",kind:xi.Function},{label:"schema",kind:xi.Function}])}function ao(e,t,n){var i;if(t.parentType){const{parentType:o}=t;let a=[];return"getFields"in o&&(a=jn(o.getFields())),(0,r.isCompositeType)(o)&&a.push(r.TypeNameMetaFieldDef),o===(null===(i=null==n?void 0:n.schema)||void 0===i?void 0:i.getQueryType())&&a.push(r.SchemaMetaFieldDef,r.TypeMetaFieldDef),Vn(e,a.map(((e,t)=>{var r;const i={sortText:String(t)+e.name,label:e.name,detail:String(e.type),documentation:null!==(r=e.description)&&void 0!==r?r:void 0,deprecated:Boolean(e.deprecationReason),isDeprecated:Boolean(e.deprecationReason),deprecationReason:e.deprecationReason,kind:xi.Field,type:e.type};if(null==n?void 0:n.fillLeafsOnComplete){const t=no(e);t&&(i.insertText=e.name+t,i.insertTextFormat=Or.Snippet,i.command=Xi)}return i})))}return[]}function so(e,t,n,i){const o=(0,r.getNamedType)(t.inputType),a=po(n,i,e).filter((e=>e.detail===o.name));return o instanceof r.GraphQLEnumType?Vn(e,o.getValues().map((e=>{var t;return{label:e.name,detail:String(o),documentation:null!==(t=e.description)&&void 0!==t?t:void 0,deprecated:Boolean(e.deprecationReason),isDeprecated:Boolean(e.deprecationReason),deprecationReason:e.deprecationReason,kind:xi.EnumMember,type:o}})).concat(a)):o===r.GraphQLBoolean?Vn(e,a.concat([{label:"true",detail:String(r.GraphQLBoolean),documentation:"Not false.",kind:xi.Variable,type:r.GraphQLBoolean},{label:"false",detail:String(r.GraphQLBoolean),documentation:"Not true.",kind:xi.Variable,type:r.GraphQLBoolean}])):a}function lo(e,t,n,i,o){if(t.needsSeparator)return[];const a=jn(n.getTypeMap()).filter(r.isInterfaceType),s=a.map((e=>{let{name:t}=e;return t})),l=new Set;yo(i,((e,t)=>{var i,a,u,c,d;if(t.name&&(t.kind!==Qi.INTERFACE_DEF||s.includes(t.name)||l.add(t.name),t.kind===Qi.NAMED_TYPE&&(null===(i=t.prevState)||void 0===i?void 0:i.kind)===Qi.IMPLEMENTS))if(o.interfaceDef){if(null===(a=o.interfaceDef)||void 0===a?void 0:a.getInterfaces().find((e=>{let{name:n}=e;return n===t.name})))return;const e=n.getType(t.name),i=null===(u=o.interfaceDef)||void 0===u?void 0:u.toConfig();o.interfaceDef=new r.GraphQLInterfaceType(Object.assign(Object.assign({},i),{interfaces:[...i.interfaces,e||new r.GraphQLInterfaceType({name:t.name,fields:{}})]}))}else if(o.objectTypeDef){if(null===(c=o.objectTypeDef)||void 0===c?void 0:c.getInterfaces().find((e=>{let{name:n}=e;return n===t.name})))return;const e=n.getType(t.name),i=null===(d=o.objectTypeDef)||void 0===d?void 0:d.toConfig();o.objectTypeDef=new r.GraphQLObjectType(Object.assign(Object.assign({},i),{interfaces:[...i.interfaces,e||new r.GraphQLInterfaceType({name:t.name,fields:{}})]}))}}));const u=o.interfaceDef||o.objectTypeDef,c=((null==u?void 0:u.getInterfaces())||[]).map((e=>{let{name:t}=e;return t}));return Vn(e,a.concat([...l].map((e=>({name:e})))).filter((e=>{let{name:t}=e;return t!==(null==u?void 0:u.name)&&!c.includes(t)})).map((e=>{const t={label:e.name,kind:xi.Interface,type:e};return(null==e?void 0:e.description)&&(t.documentation=e.description),t})))}function uo(e,t,n,i){let o;if(t.parentType)if((0,r.isAbstractType)(t.parentType)){const e=(0,r.assertAbstractType)(t.parentType),i=n.getPossibleTypes(e),a=Object.create(null);for(const e of i)for(const t of e.getInterfaces())a[t.name]=t;o=i.concat(jn(a))}else o=[t.parentType];else o=jn(n.getTypeMap()).filter((e=>(0,r.isCompositeType)(e)&&!e.name.startsWith("__")));return Vn(e,o.map((e=>{const t=(0,r.getNamedType)(e);return{label:String(e),documentation:(null==t?void 0:t.description)||"",kind:xi.Field}})))}function co(e,t,n,i,o){if(!i)return[];const a=n.getTypeMap(),s=Rn(e.state),l=ho(i);return o&&o.length>0&&l.push(...o),Vn(e,l.filter((e=>a[e.typeCondition.name.value]&&!(s&&s.kind===Qi.FRAGMENT_DEFINITION&&s.name===e.name.value)&&(0,r.isCompositeType)(t.parentType)&&(0,r.isCompositeType)(a[e.typeCondition.name.value])&&(0,r.doTypesOverlap)(n,t.parentType,a[e.typeCondition.name.value]))).map((e=>({label:e.name.value,detail:String(a[e.typeCondition.name.value]),documentation:`fragment ${e.name.value} on ${e.typeCondition.name.value}`,kind:xi.Field,type:a[e.typeCondition.name.value]}))))}g(ro,"getSuggestionsForTypeSystemDefinitions"),g(io,"getSuggestionsForExecutableDefinitions"),g(oo,"getSuggestionsForExtensionDefinitions"),g(ao,"getSuggestionsForFieldNames"),g(so,"getSuggestionsForInputValues"),g(lo,"getSuggestionsForImplements"),g(uo,"getSuggestionsForFragmentTypeConditions"),g(co,"getSuggestionsForFragmentSpread");const fo=g(((e,t)=>{var n,r,i,o,a,s,l,u,c,d;return(null===(n=e.prevState)||void 0===n?void 0:n.kind)===t?e.prevState:(null===(i=null===(r=e.prevState)||void 0===r?void 0:r.prevState)||void 0===i?void 0:i.kind)===t?e.prevState.prevState:(null===(s=null===(a=null===(o=e.prevState)||void 0===o?void 0:o.prevState)||void 0===a?void 0:a.prevState)||void 0===s?void 0:s.kind)===t?e.prevState.prevState.prevState:(null===(d=null===(c=null===(u=null===(l=e.prevState)||void 0===l?void 0:l.prevState)||void 0===u?void 0:u.prevState)||void 0===c?void 0:c.prevState)||void 0===d?void 0:d.kind)===t?e.prevState.prevState.prevState.prevState:void 0}),"getParentDefinition");function po(e,t,n){let r,i=null;const o=Object.create({});return yo(e,((e,a)=>{if((null==a?void 0:a.kind)===Qi.VARIABLE&&a.name&&(i=a.name),(null==a?void 0:a.kind)===Qi.NAMED_TYPE&&i){const e=fo(a,Qi.TYPE);(null==e?void 0:e.type)&&(r=t.getType(null==e?void 0:e.type))}i&&r&&!o[i]&&(o[i]={detail:r.toString(),insertText:"$"===n.string?i:"$"+i,label:i,type:r,kind:xi.Variable},i=null,r=null)})),jn(o)}function ho(e){const t=[];return yo(e,((e,n)=>{n.kind===Qi.FRAGMENT_DEFINITION&&n.name&&n.type&&t.push({kind:Qi.FRAGMENT_DEFINITION,name:{kind:r.Kind.NAME,value:n.name},selectionSet:{kind:Qi.SELECTION_SET,selections:[]},typeCondition:{kind:Qi.NAMED_TYPE,name:{kind:r.Kind.NAME,value:n.type}}})})),t}function mo(e,t,n){return Vn(e,jn(t.getTypeMap()).filter(r.isInputType).map((e=>({label:e.name,documentation:e.description,kind:xi.Variable}))))}function go(e,t,n,r){var i;return(null===(i=t.prevState)||void 0===i?void 0:i.kind)?Vn(e,n.getDirectives().filter((e=>bo(t.prevState,e))).map((e=>({label:e.name,documentation:e.description||"",kind:xi.Function})))):[]}function vo(e,t){let n=null,r=null,i=null;const o=yo(e,((e,o,a,s)=>{if(s===t.line&&e.getCurrentPosition()>=t.character)return n=a,r=Object.assign({},o),i=e.current(),"BREAK"}));return{start:o.start,end:o.end,string:i||o.string,state:r||o.state,style:n||o.style}}function yo(e,t){const n=e.split("\n"),r=Vi();let i=r.startState(),o="",a=new Ni("");for(let e=0;e{var h;switch(t.kind){case Qi.QUERY:case"ShortQuery":f=e.getQueryType();break;case Qi.MUTATION:f=e.getMutationType();break;case Qi.SUBSCRIPTION:f=e.getSubscriptionType();break;case Qi.INLINE_FRAGMENT:case Qi.FRAGMENT_DEFINITION:t.type&&(f=e.getType(t.type));break;case Qi.FIELD:case Qi.ALIASED_FIELD:f&&t.name?(s=d?Fn(e,d,t.name):null,f=s?s.type:null):s=null;break;case Qi.SELECTION_SET:d=(0,r.getNamedType)(f);break;case Qi.DIRECTIVE:o=t.name?e.getDirective(t.name):null;break;case Qi.INTERFACE_DEF:t.name&&(u=null,p=new r.GraphQLInterfaceType({name:t.name,interfaces:[],fields:{}}));break;case Qi.OBJECT_TYPE_DEF:t.name&&(p=null,u=new r.GraphQLObjectType({name:t.name,interfaces:[],fields:{}}));break;case Qi.ARGUMENTS:if(t.prevState)switch(t.prevState.kind){case Qi.FIELD:i=s&&s.args;break;case Qi.DIRECTIVE:i=o&&o.args;break;case Qi.ALIASED_FIELD:{const n=null===(h=t.prevState)||void 0===h?void 0:h.name;if(!n){i=null;break}const r=d?Fn(e,d,n):null;if(!r){i=null;break}i=r.args;break}default:i=null}else i=null;break;case Qi.ARGUMENT:if(i)for(let e=0;ee.value===t.name)):null;break;case Qi.LIST_VALUE:const g=(0,r.getNullableType)(l);l=g instanceof r.GraphQLList?g.ofType:null;break;case Qi.OBJECT_VALUE:const v=(0,r.getNamedType)(l);c=v instanceof r.GraphQLInputObjectType?v.getFields():null;break;case Qi.OBJECT_FIELD:const y=t.name&&c?c[t.name]:null;l=null==y?void 0:y.type;break;case Qi.NAMED_TYPE:t.name&&(f=e.getType(t.name))}})),{argDef:n,argDefs:i,directiveDef:o,enumValue:a,fieldDef:s,inputType:l,objectFieldDefs:c,parentType:d,type:f,interfaceDef:p,objectTypeDef:u}}var To,wo;function Co(e,t){return(null==t?void 0:t.endsWith(".graphqls"))||Zi(e)?To.TYPE_SYSTEM:To.EXECUTABLE}function So(e){return e.prevState&&e.kind&&[Qi.NAMED_TYPE,Qi.LIST_TYPE,Qi.TYPE,Qi.NON_NULL_TYPE].includes(e.kind)?So(e.prevState):e}g(po,"getVariableCompletions"),g(ho,"getFragmentDefinitions"),g(mo,"getSuggestionsForVariableDefinition"),g(go,"getSuggestionsForDirective"),g(vo,"getTokenAtPosition"),g(yo,"runOnlineParser"),g(bo,"canUseDirective"),g(Eo,"getTypeInfo"),(wo=To||(To={})).TYPE_SYSTEM="TYPE_SYSTEM",wo.EXECUTABLE="EXECUTABLE",g(Co,"getDocumentMode"),g(So,"unwrapType");var xo={exports:{}};function ko(e,t){if(null!=e)return e;var n=new Error(void 0!==t?t:"Got unexpected "+e);throw n.framesToPop=1,n}g(ko,"nullthrows"),xo.exports=ko,xo.exports.default=ko,Object.defineProperty(xo.exports,"__esModule",{value:!0});var No=Z(xo.exports);const _o=g(((e,t)=>{if(!t)return[];const n=new Map,i=new Set;(0,r.visit)(e,{FragmentDefinition(e){n.set(e.name.value,!0)},FragmentSpread(e){i.has(e.name.value)||i.add(e.name.value)}});const o=new Set;for(const e of i)!n.has(e)&&t.has(e)&&o.add(No(t.get(e)));const a=[];for(const e of o)(0,r.visit)(e,{FragmentSpread(e){!i.has(e.name.value)&&t.get(e.name.value)&&(o.add(No(t.get(e.name.value))),i.add(e.name.value))}}),n.has(e.name.value)||a.push(e);return a}),"getFragmentDependenciesForAST");function Oo(e,t){const n=Object.create(null);for(const i of t.definitions)if("OperationDefinition"===i.kind){const{variableDefinitions:t}=i;if(t)for(const{variable:i,type:o}of t){const t=(0,r.typeFromAST)(e,o);t?n[i.name.value]=t:o.kind===r.Kind.NAMED_TYPE&&"Float"===o.name.value&&(n[i.name.value]=r.GraphQLFloat)}}return n}function Io(e,t){const n=t?Oo(t,e):void 0,i=[];return(0,r.visit)(e,{OperationDefinition(e){i.push(e)}}),{variableToType:n,operations:i}}function Do(e,t){if(t)try{const n=(0,r.parse)(t);return Object.assign(Object.assign({},Io(n,e)),{documentAST:n})}catch(e){return}}g(Oo,"collectVariables"),g(Io,"getOperationASTFacts"),g(Do,"getOperationFacts"),globalThis&&globalThis.__awaiter;var Lo=g((function(e){return"object"==typeof e?null===e:"function"!=typeof e}),"isPrimitive"),Ao=g((function(e){return null!=e&&"object"==typeof e&&!1===Array.isArray(e)}),"isObject");function Mo(e){return!0===Ao(e)&&"[object Object]"===Object.prototype.toString.call(e)}g(Mo,"isObjectObject");var Ro=g((function(e){var t,n;return!1!==Mo(e)&&"function"==typeof(t=e.constructor)&&!1!==Mo(n=t.prototype)&&!1!==n.hasOwnProperty("isPrototypeOf")}),"isPlainObject");const{deleteProperty:Fo}=Reflect,Po=Lo,jo=Ro,Vo=g((e=>"object"==typeof e&&null!==e||"function"==typeof e),"isObject$1"),Uo=g((e=>"__proto__"===e||"constructor"===e||"prototype"===e),"isUnsafeKey"),Bo=g((e=>{if(!Po(e))throw new TypeError("Object keys must be strings or symbols");if(Uo(e))throw new Error(`Cannot set unsafe key: "${e}"`)}),"validateKey"),$o=g((e=>Array.isArray(e)?e.flat().map(String).join(","):e),"toStringKey"),qo=g(((e,t)=>{if("string"!=typeof e||!t)return e;let n=e+";";return void 0!==t.arrays&&(n+=`arrays=${t.arrays};`),void 0!==t.separator&&(n+=`separator=${t.separator};`),void 0!==t.split&&(n+=`split=${t.split};`),void 0!==t.merge&&(n+=`merge=${t.merge};`),void 0!==t.preservePaths&&(n+=`preservePaths=${t.preservePaths};`),n}),"createMemoKey"),Ho=g(((e,t,n)=>{const r=$o(t?qo(e,t):e);Bo(r);const i=Ko.cache.get(r)||n();return Ko.cache.set(r,i),i}),"memoize"),Go=g((function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const n=t.separator||".",r="/"!==n&&t.preservePaths;if("string"==typeof e&&!1!==r&&/\//.test(e))return[e];const i=[];let o="";const a=g((e=>{let t;""!==e.trim()&&Number.isInteger(t=Number(e))?i.push(t):i.push(e)}),"push");for(let t=0;tt&&"function"==typeof t.split?t.split(e):"symbol"==typeof e?[e]:Array.isArray(e)?e:Ho(e,t,(()=>Go(e,t)))),"split"),Wo=g(((e,t,n,r)=>{if(Bo(t),void 0===n)Fo(e,t);else if(r&&r.merge){const i="function"===r.merge?r.merge:Object.assign;i&&jo(e[t])&&jo(n)?e[t]=i(e[t],n):e[t]=n}else e[t]=n;return e}),"assignProp"),Ko=g(((e,t,n,r)=>{if(!t||!Vo(e))return e;const i=zo(t,r);let o=e;for(let e=0;e{Ko.cache=new Map};var Qo=Ko;function Xo(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M5.0484 1.40838C6.12624 0.33054 7.87376 0.330541 8.9516 1.40838L12.5916 5.0484C13.6695 6.12624 13.6695 7.87376 12.5916 8.9516L8.9516 12.5916C7.87376 13.6695 6.12624 13.6695 5.0484 12.5916L1.40838 8.9516C0.33054 7.87376 0.330541 6.12624 1.40838 5.0484L5.0484 1.40838Z",stroke:"currentColor",strokeWidth:1.2}),t.createElement("rect",{x:6,y:6,width:2,height:2,rx:1,fill:"currentColor"}))}function Yo(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 9",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M1 1L7 7L13 1",stroke:"currentColor",strokeWidth:1.5}))}function Jo(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 7 10",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M6 1.04819L2 5.04819L6 9.04819",stroke:"currentColor",strokeWidth:1.75}))}function Zo(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 9",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M13 8L7 2L1 8",stroke:"currentColor",strokeWidth:1.5}))}function ea(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M1 1L12.9998 12.9997",stroke:"currentColor",strokeWidth:1.5}),t.createElement("path",{d:"M13 1L1.00079 13.0003",stroke:"currentColor",strokeWidth:1.5}))}function ta(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"-2 -2 22 22",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M11.25 14.2105V15.235C11.25 16.3479 10.3479 17.25 9.23501 17.25H2.76499C1.65214 17.25 0.75 16.3479 0.75 15.235L0.75 8.76499C0.75 7.65214 1.65214 6.75 2.76499 6.75L3.78947 6.75",stroke:"currentColor",strokeWidth:1.5}),t.createElement("rect",{x:6.75,y:.75,width:10.5,height:10.5,rx:2.2069,stroke:"currentColor",strokeWidth:1.5}))}function na(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M5.0484 1.40838C6.12624 0.33054 7.87376 0.330541 8.9516 1.40838L12.5916 5.0484C13.6695 6.12624 13.6695 7.87376 12.5916 8.9516L8.9516 12.5916C7.87376 13.6695 6.12624 13.6695 5.0484 12.5916L1.40838 8.9516C0.33054 7.87376 0.330541 6.12624 1.40838 5.0484L5.0484 1.40838Z",stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{d:"M5 9L9 5",stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{d:"M5 5L9 9",stroke:"currentColor",strokeWidth:1.2}))}function ra(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 12 12",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M4 8L8 4",stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{d:"M4 4L8 8",stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M8.5 1.2H9C9.99411 1.2 10.8 2.00589 10.8 3V9C10.8 9.99411 9.99411 10.8 9 10.8H8.5V12H9C10.6569 12 12 10.6569 12 9V3C12 1.34315 10.6569 0 9 0H8.5V1.2ZM3.5 1.2V0H3C1.34315 0 0 1.34315 0 3V9C0 10.6569 1.34315 12 3 12H3.5V10.8H3C2.00589 10.8 1.2 9.99411 1.2 9V3C1.2 2.00589 2.00589 1.2 3 1.2H3.5Z",fill:"currentColor"}))}function ia(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 12 12",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{x:.6,y:.6,width:10.8,height:10.8,rx:3.4,stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{d:"M4 8L8 4",stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{d:"M4 4L8 8",stroke:"currentColor",strokeWidth:1.2}))}function oa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0.5 12 12",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{x:7,y:5.5,width:2,height:2,rx:1,transform:"rotate(90 7 5.5)",fill:"currentColor"}),t.createElement("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M10.8 9L10.8 9.5C10.8 10.4941 9.99411 11.3 9 11.3L3 11.3C2.00589 11.3 1.2 10.4941 1.2 9.5L1.2 9L-3.71547e-07 9L-3.93402e-07 9.5C-4.65826e-07 11.1569 1.34314 12.5 3 12.5L9 12.5C10.6569 12.5 12 11.1569 12 9.5L12 9L10.8 9ZM10.8 4L12 4L12 3.5C12 1.84315 10.6569 0.5 9 0.5L3 0.5C1.34315 0.5 -5.87117e-08 1.84315 -1.31135e-07 3.5L-1.5299e-07 4L1.2 4L1.2 3.5C1.2 2.50589 2.00589 1.7 3 1.7L9 1.7C9.99411 1.7 10.8 2.50589 10.8 3.5L10.8 4Z",fill:"currentColor"}))}function aa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 20 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M0.75 3C0.75 1.75736 1.75736 0.75 3 0.75H17.25C17.8023 0.75 18.25 1.19772 18.25 1.75V5.25",stroke:"currentColor",strokeWidth:1.5}),t.createElement("path",{d:"M0.75 3C0.75 4.24264 1.75736 5.25 3 5.25H18.25C18.8023 5.25 19.25 5.69771 19.25 6.25V22.25C19.25 22.8023 18.8023 23.25 18.25 23.25H3C1.75736 23.25 0.75 22.2426 0.75 21V3Z",stroke:"currentColor",strokeWidth:1.5}),t.createElement("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M3 5.25C1.75736 5.25 0.75 4.24264 0.75 3V21C0.75 22.2426 1.75736 23.25 3 23.25H18.25C18.8023 23.25 19.25 22.8023 19.25 22.25V6.25C19.25 5.69771 18.8023 5.25 18.25 5.25H3ZM13 11L6 11V12.5L13 12.5V11Z",fill:"currentColor"}))}function sa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 20 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M0.75 3C0.75 4.24264 1.75736 5.25 3 5.25H17.25M0.75 3C0.75 1.75736 1.75736 0.75 3 0.75H16.25C16.8023 0.75 17.25 1.19772 17.25 1.75V5.25M0.75 3V21C0.75 22.2426 1.75736 23.25 3 23.25H18.25C18.8023 23.25 19.25 22.8023 19.25 22.25V6.25C19.25 5.69771 18.8023 5.25 18.25 5.25H17.25",stroke:"currentColor",strokeWidth:1.5}),t.createElement("line",{x1:13,y1:11.75,x2:6,y2:11.75,stroke:"currentColor",strokeWidth:1.5}))}function la(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 12 12",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{x:5,y:5,width:2,height:2,rx:1,fill:"currentColor"}),t.createElement("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M8.5 1.2H9C9.99411 1.2 10.8 2.00589 10.8 3V9C10.8 9.99411 9.99411 10.8 9 10.8H8.5V12H9C10.6569 12 12 10.6569 12 9V3C12 1.34315 10.6569 0 9 0H8.5V1.2ZM3.5 1.2V0H3C1.34315 0 0 1.34315 0 3V9C0 10.6569 1.34315 12 3 12H3.5V10.8H3C2.00589 10.8 1.2 9.99411 1.2 9V3C1.2 2.00589 2.00589 1.2 3 1.2H3.5Z",fill:"currentColor"}))}function ua(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 12 13",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{x:.6,y:1.1,width:10.8,height:10.8,rx:2.4,stroke:"currentColor",strokeWidth:1.2}),t.createElement("rect",{x:5,y:5.5,width:2,height:2,rx:1,fill:"currentColor"}))}function ca(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 24 20",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M1.59375 9.52344L4.87259 12.9944L8.07872 9.41249",stroke:"currentColor",strokeWidth:1.5,strokeLinecap:"square"}),t.createElement("path",{d:"M13.75 5.25V10.75H18.75",stroke:"currentColor",strokeWidth:1.5,strokeLinecap:"square"}),t.createElement("path",{d:"M4.95427 11.9332C4.55457 10.0629 4.74441 8.11477 5.49765 6.35686C6.25089 4.59894 7.5305 3.11772 9.16034 2.11709C10.7902 1.11647 12.6901 0.645626 14.5986 0.769388C16.5071 0.893151 18.3303 1.60543 19.8172 2.80818C21.3042 4.01093 22.3818 5.64501 22.9017 7.48548C23.4216 9.32595 23.3582 11.2823 22.7203 13.0853C22.0824 14.8883 20.9013 16.4492 19.3396 17.5532C17.778 18.6572 15.9125 19.25 14 19.25",stroke:"currentColor",strokeWidth:1.5}))}function da(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 12 12",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("circle",{cx:6,cy:6,r:5.4,stroke:"currentColor",strokeWidth:1.2,strokeDasharray:"4.241025 4.241025",transform:"rotate(22.5)","transform-origin":"center"}),t.createElement("circle",{cx:6,cy:6,r:1,fill:"currentColor"}))}function fa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 19 18",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M1.5 14.5653C1.5 15.211 1.75652 15.8303 2.21314 16.2869C2.66975 16.7435 3.28905 17 3.9348 17C4.58054 17 5.19984 16.7435 5.65646 16.2869C6.11307 15.8303 6.36959 15.211 6.36959 14.5653V12.1305H3.9348C3.28905 12.1305 2.66975 12.387 2.21314 12.8437C1.75652 13.3003 1.5 13.9195 1.5 14.5653Z",stroke:"currentColor",strokeWidth:1.125,strokeLinecap:"round",strokeLinejoin:"round"}),t.createElement("path",{d:"M3.9348 1.00063C3.28905 1.00063 2.66975 1.25715 2.21314 1.71375C1.75652 2.17035 1.5 2.78964 1.5 3.43537C1.5 4.0811 1.75652 4.70038 2.21314 5.15698C2.66975 5.61358 3.28905 5.8701 3.9348 5.8701H6.36959V3.43537C6.36959 2.78964 6.11307 2.17035 5.65646 1.71375C5.19984 1.25715 4.58054 1.00063 3.9348 1.00063Z",stroke:"currentColor",strokeWidth:1.125,strokeLinecap:"round",strokeLinejoin:"round"}),t.createElement("path",{d:"M15.0652 12.1305H12.6304V14.5653C12.6304 15.0468 12.7732 15.5175 13.0407 15.9179C13.3083 16.3183 13.6885 16.6304 14.1334 16.8147C14.5783 16.9989 15.0679 17.0472 15.5402 16.9532C16.0125 16.8593 16.4464 16.6274 16.7869 16.2869C17.1274 15.9464 17.3593 15.5126 17.4532 15.0403C17.5472 14.568 17.4989 14.0784 17.3147 13.6335C17.1304 13.1886 16.8183 12.8084 16.4179 12.5409C16.0175 12.2733 15.5468 12.1305 15.0652 12.1305Z",stroke:"currentColor",strokeWidth:1.125,strokeLinecap:"round",strokeLinejoin:"round"}),t.createElement("path",{d:"M12.6318 5.86775H6.36955V12.1285H12.6318V5.86775Z",stroke:"currentColor",strokeWidth:1.125,strokeLinecap:"round",strokeLinejoin:"round"}),t.createElement("path",{d:"M17.5 3.43473C17.5 2.789 17.2435 2.16972 16.7869 1.71312C16.3303 1.25652 15.711 1 15.0652 1C14.4195 1 13.8002 1.25652 13.3435 1.71312C12.8869 2.16972 12.6304 2.789 12.6304 3.43473V5.86946H15.0652C15.711 5.86946 16.3303 5.61295 16.7869 5.15635C17.2435 4.69975 17.5 4.08046 17.5 3.43473Z",stroke:"currentColor",strokeWidth:1.125,strokeLinecap:"round",strokeLinejoin:"round"}))}function pa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 13 13",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("circle",{cx:5,cy:5,r:4.35,stroke:"currentColor",strokeWidth:1.3}),t.createElement("line",{x1:8.45962,y1:8.54038,x2:11.7525,y2:11.8333,stroke:"currentColor",strokeWidth:1.3}))}function ha(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"-2 -2 22 22",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M17.2492 6V2.9569C17.2492 1.73806 16.2611 0.75 15.0423 0.75L2.9569 0.75C1.73806 0.75 0.75 1.73806 0.75 2.9569L0.75 6",stroke:"currentColor",strokeWidth:1.5}),t.createElement("path",{d:"M0.749873 12V15.0431C0.749873 16.2619 1.73794 17.25 2.95677 17.25H15.0421C16.261 17.25 17.249 16.2619 17.249 15.0431V12",stroke:"currentColor",strokeWidth:1.5}),t.createElement("path",{d:"M6 4.5L9 7.5L12 4.5",stroke:"currentColor",strokeWidth:1.5}),t.createElement("path",{d:"M12 13.5L9 10.5L6 13.5",stroke:"currentColor",strokeWidth:1.5}))}function ma(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M0.75 13.25L0.0554307 12.967C-0.0593528 13.2488 0.00743073 13.5719 0.224488 13.7851C0.441545 13.9983 0.765869 14.0592 1.04549 13.9393L0.75 13.25ZM12.8214 1.83253L12.2911 2.36286L12.2911 2.36286L12.8214 1.83253ZM12.8214 3.90194L13.3517 4.43227L12.8214 3.90194ZM10.0981 1.17859L9.56773 0.648259L10.0981 1.17859ZM12.1675 1.17859L12.6978 0.648258L12.6978 0.648257L12.1675 1.17859ZM2.58049 8.75697L3.27506 9.03994L2.58049 8.75697ZM2.70066 8.57599L3.23099 9.10632L2.70066 8.57599ZM5.2479 11.4195L4.95355 10.7297L5.2479 11.4195ZM5.42036 11.303L4.89003 10.7727L5.42036 11.303ZM4.95355 10.7297C4.08882 11.0987 3.41842 11.362 2.73535 11.6308C2.05146 11.9 1.35588 12.1743 0.454511 12.5607L1.04549 13.9393C1.92476 13.5624 2.60256 13.2951 3.28469 13.0266C3.96762 12.7578 4.65585 12.4876 5.54225 12.1093L4.95355 10.7297ZM1.44457 13.533L3.27506 9.03994L1.88592 8.474L0.0554307 12.967L1.44457 13.533ZM3.23099 9.10632L10.6284 1.70892L9.56773 0.648259L2.17033 8.04566L3.23099 9.10632ZM11.6371 1.70892L12.2911 2.36286L13.3517 1.3022L12.6978 0.648258L11.6371 1.70892ZM12.2911 3.37161L4.89003 10.7727L5.95069 11.8333L13.3517 4.43227L12.2911 3.37161ZM12.2911 2.36286C12.5696 2.64142 12.5696 3.09305 12.2911 3.37161L13.3517 4.43227C14.2161 3.56792 14.2161 2.16654 13.3517 1.3022L12.2911 2.36286ZM10.6284 1.70892C10.9069 1.43036 11.3586 1.43036 11.6371 1.70892L12.6978 0.648257C11.8335 -0.216088 10.4321 -0.216084 9.56773 0.648259L10.6284 1.70892ZM3.27506 9.03994C3.26494 9.06479 3.24996 9.08735 3.23099 9.10632L2.17033 8.04566C2.04793 8.16806 1.95123 8.31369 1.88592 8.474L3.27506 9.03994ZM5.54225 12.1093C5.69431 12.0444 5.83339 11.9506 5.95069 11.8333L4.89003 10.7727C4.90863 10.7541 4.92988 10.7398 4.95355 10.7297L5.54225 12.1093Z",fill:"currentColor"}),t.createElement("path",{d:"M11.5 4.5L9.5 2.5",stroke:"currentColor",strokeWidth:1.4026,strokeLinecap:"round",strokeLinejoin:"round"}),t.createElement("path",{d:"M5.5 10.5L3.5 8.5",stroke:"currentColor",strokeWidth:1.4026,strokeLinecap:"round",strokeLinejoin:"round"}))}function ga(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 16 18",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M1.32226e-07 1.6609C7.22332e-08 0.907329 0.801887 0.424528 1.46789 0.777117L15.3306 8.11621C16.0401 8.49182 16.0401 9.50818 15.3306 9.88379L1.46789 17.2229C0.801886 17.5755 1.36076e-06 17.0927 1.30077e-06 16.3391L1.32226e-07 1.6609Z",fill:"currentColor"}))}function va(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 10 16",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M4.25 9.25V13.5H5.75V9.25L10 9.25V7.75L5.75 7.75V3.5H4.25V7.75L0 7.75V9.25L4.25 9.25Z",fill:"currentColor"}))}function ya(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({width:25,height:25,viewBox:"0 0 25 25",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M10.2852 24.0745L13.7139 18.0742",stroke:"currentColor",strokeWidth:1.5625}),t.createElement("path",{d:"M14.5742 24.0749L17.1457 19.7891",stroke:"currentColor",strokeWidth:1.5625}),t.createElement("path",{d:"M19.4868 24.0735L20.7229 21.7523C21.3259 20.6143 21.5457 19.3122 21.3496 18.0394C21.1535 16.7666 20.5519 15.591 19.6342 14.6874L23.7984 6.87853C24.0123 6.47728 24.0581 6.00748 23.9256 5.57249C23.7932 5.1375 23.4933 4.77294 23.0921 4.55901C22.6908 4.34509 22.221 4.29932 21.7861 4.43178C21.3511 4.56424 20.9865 4.86408 20.7726 5.26533L16.6084 13.0742C15.3474 12.8142 14.0362 12.9683 12.8699 13.5135C11.7035 14.0586 10.7443 14.9658 10.135 16.1L6 24.0735",stroke:"currentColor",strokeWidth:1.5625}),t.createElement("path",{d:"M4 15L5 13L7 12L5 11L4 9L3 11L1 12L3 13L4 15Z",stroke:"currentColor",strokeWidth:1.5625,strokeLinejoin:"round"}),t.createElement("path",{d:"M11.5 8L12.6662 5.6662L15 4.5L12.6662 3.3338L11.5 1L10.3338 3.3338L8 4.5L10.3338 5.6662L11.5 8Z",stroke:"currentColor",strokeWidth:1.5625,strokeLinejoin:"round"}))}function ba(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 16 16",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M4.75 9.25H1.25V12.75",stroke:"currentColor",strokeWidth:1,strokeLinecap:"square"}),t.createElement("path",{d:"M11.25 6.75H14.75V3.25",stroke:"currentColor",strokeWidth:1,strokeLinecap:"square"}),t.createElement("path",{d:"M14.1036 6.65539C13.8 5.27698 13.0387 4.04193 11.9437 3.15131C10.8487 2.26069 9.48447 1.76694 8.0731 1.75043C6.66173 1.73392 5.28633 2.19563 4.17079 3.0604C3.05526 3.92516 2.26529 5.14206 1.92947 6.513",stroke:"currentColor",strokeWidth:1}),t.createElement("path",{d:"M1.89635 9.34461C2.20001 10.723 2.96131 11.9581 4.05631 12.8487C5.15131 13.7393 6.51553 14.2331 7.9269 14.2496C9.33827 14.2661 10.7137 13.8044 11.8292 12.9396C12.9447 12.0748 13.7347 10.8579 14.0705 9.487",stroke:"currentColor",strokeWidth:1}))}function Ea(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 13 13",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{x:.6,y:.6,width:11.8,height:11.8,rx:5.9,stroke:"currentColor",strokeWidth:1.2}),t.createElement("path",{d:"M4.25 7.5C4.25 6 5.75 5 6.5 6.5C7.25 8 8.75 7 8.75 5.5",stroke:"currentColor",strokeWidth:1.2}))}function Ta(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 21 20",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M9.29186 1.92702C9.06924 1.82745 8.87014 1.68202 8.70757 1.50024L7.86631 0.574931C7.62496 0.309957 7.30773 0.12592 6.95791 0.0479385C6.60809 -0.0300431 6.24274 0.00182978 5.91171 0.139208C5.58068 0.276585 5.3001 0.512774 5.10828 0.815537C4.91645 1.1183 4.82272 1.47288 4.83989 1.83089L4.90388 3.08019C4.91612 3.32348 4.87721 3.56662 4.78968 3.79394C4.70215 4.02126 4.56794 4.2277 4.39571 4.39994C4.22347 4.57219 4.01704 4.7064 3.78974 4.79394C3.56243 4.88147 3.3193 4.92038 3.07603 4.90814L1.8308 4.84414C1.47162 4.82563 1.11553 4.91881 0.811445 5.11086C0.507359 5.30292 0.270203 5.58443 0.132561 5.91671C-0.00508149 6.249 -0.0364554 6.61576 0.0427496 6.9666C0.121955 7.31744 0.307852 7.63514 0.5749 7.87606L1.50016 8.71204C1.68193 8.87461 1.82735 9.07373 1.92692 9.29636C2.02648 9.51898 2.07794 9.76012 2.07794 10.004C2.07794 10.2479 2.02648 10.489 1.92692 10.7116C1.82735 10.9343 1.68193 11.1334 1.50016 11.296L0.5749 12.1319C0.309856 12.3729 0.125575 12.6898 0.0471809 13.0393C-0.0312128 13.3888 9.64098e-05 13.754 0.13684 14.0851C0.273583 14.4162 0.509106 14.6971 0.811296 14.8894C1.11349 15.0817 1.46764 15.1762 1.82546 15.1599L3.0707 15.0959C3.31397 15.0836 3.5571 15.1225 3.7844 15.2101C4.01171 15.2976 4.21814 15.4318 4.39037 15.6041C4.56261 15.7763 4.69682 15.9827 4.78435 16.2101C4.87188 16.4374 4.91078 16.6805 4.89855 16.9238L4.83455 18.1691C4.81605 18.5283 4.90921 18.8844 5.10126 19.1885C5.2933 19.4926 5.5748 19.7298 5.90707 19.8674C6.23934 20.0051 6.60608 20.0365 6.9569 19.9572C7.30772 19.878 7.6254 19.6921 7.86631 19.4251L8.7129 18.4998C8.87547 18.318 9.07458 18.1725 9.29719 18.073C9.51981 17.9734 9.76093 17.9219 10.0048 17.9219C10.2487 17.9219 10.4898 17.9734 10.7124 18.073C10.935 18.1725 11.1341 18.318 11.2967 18.4998L12.1326 19.4251C12.3735 19.6921 12.6912 19.878 13.042 19.9572C13.3929 20.0365 13.7596 20.0051 14.0919 19.8674C14.4241 19.7298 14.7056 19.4926 14.8977 19.1885C15.0897 18.8844 15.1829 18.5283 15.1644 18.1691L15.1004 16.9238C15.0882 16.6805 15.1271 16.4374 15.2146 16.2101C15.3021 15.9827 15.4363 15.7763 15.6086 15.6041C15.7808 15.4318 15.9872 15.2976 16.2145 15.2101C16.4418 15.1225 16.685 15.0836 16.9282 15.0959L18.1735 15.1599C18.5326 15.1784 18.8887 15.0852 19.1928 14.8931C19.4969 14.7011 19.7341 14.4196 19.8717 14.0873C20.0093 13.755 20.0407 13.3882 19.9615 13.0374C19.8823 12.6866 19.6964 12.3689 19.4294 12.1279L18.5041 11.292C18.3223 11.1294 18.1769 10.9303 18.0774 10.7076C17.9778 10.485 17.9263 10.2439 17.9263 10C17.9263 9.75612 17.9778 9.51499 18.0774 9.29236C18.1769 9.06973 18.3223 8.87062 18.5041 8.70804L19.4294 7.87206C19.6964 7.63114 19.8823 7.31344 19.9615 6.9626C20.0407 6.61176 20.0093 6.245 19.8717 5.91271C19.7341 5.58043 19.4969 5.29892 19.1928 5.10686C18.8887 4.91481 18.5326 4.82163 18.1735 4.84014L16.9282 4.90414C16.685 4.91638 16.4418 4.87747 16.2145 4.78994C15.9872 4.7024 15.7808 4.56818 15.6086 4.39594C15.4363 4.2237 15.3021 4.01726 15.2146 3.78994C15.1271 3.56262 15.0882 3.31948 15.1004 3.07619L15.1644 1.83089C15.1829 1.4717 15.0897 1.11559 14.8977 0.811487C14.7056 0.507385 14.4241 0.270217 14.0919 0.132568C13.7596 -0.00508182 13.3929 -0.0364573 13.042 0.0427519C12.6912 0.121961 12.3735 0.307869 12.1326 0.574931L11.2914 1.50024C11.1288 1.68202 10.9297 1.82745 10.7071 1.92702C10.4845 2.02659 10.2433 2.07805 9.99947 2.07805C9.7556 2.07805 9.51448 2.02659 9.29186 1.92702ZM14.3745 10C14.3745 12.4162 12.4159 14.375 9.99977 14.375C7.58365 14.375 5.625 12.4162 5.625 10C5.625 7.58375 7.58365 5.625 9.99977 5.625C12.4159 5.625 14.3745 7.58375 14.3745 10Z",fill:"currentColor"}))}function wa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M6.5782 1.07092C6.71096 0.643026 7.28904 0.643027 7.4218 1.07092L8.59318 4.84622C8.65255 5.03758 8.82284 5.16714 9.01498 5.16714L12.8056 5.16714C13.2353 5.16714 13.4139 5.74287 13.0663 6.00732L9.99962 8.34058C9.84418 8.45885 9.77913 8.66848 9.83851 8.85984L11.0099 12.6351C11.1426 13.063 10.675 13.4189 10.3274 13.1544L7.26069 10.8211C7.10524 10.7029 6.89476 10.7029 6.73931 10.8211L3.6726 13.1544C3.32502 13.4189 2.85735 13.063 2.99012 12.6351L4.16149 8.85984C4.22087 8.66848 4.15582 8.45885 4.00038 8.34058L0.933671 6.00732C0.586087 5.74287 0.764722 5.16714 1.19436 5.16714L4.98502 5.16714C5.17716 5.16714 5.34745 5.03758 5.40682 4.84622L6.5782 1.07092Z",fill:"currentColor",stroke:"currentColor"}))}function Ca(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("path",{d:"M6.5782 1.07092C6.71096 0.643026 7.28904 0.643027 7.4218 1.07092L8.59318 4.84622C8.65255 5.03758 8.82284 5.16714 9.01498 5.16714L12.8056 5.16714C13.2353 5.16714 13.4139 5.74287 13.0663 6.00732L9.99962 8.34058C9.84418 8.45885 9.77913 8.66848 9.83851 8.85984L11.0099 12.6351C11.1426 13.063 10.675 13.4189 10.3274 13.1544L7.26069 10.8211C7.10524 10.7029 6.89476 10.7029 6.73931 10.8211L3.6726 13.1544C3.32502 13.4189 2.85735 13.063 2.99012 12.6351L4.16149 8.85984C4.22087 8.66848 4.15582 8.45885 4.00038 8.34058L0.933671 6.00732C0.586087 5.74287 0.764722 5.16714 1.19436 5.16714L4.98502 5.16714C5.17716 5.16714 5.34745 5.03758 5.40682 4.84622L6.5782 1.07092Z",stroke:"currentColor",strokeWidth:1.5}))}function Sa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 16 16",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{width:16,height:16,rx:2,fill:"currentColor"}))}function xa(e){var n=e,{title:r,titleId:i}=n,o=v(n,["title","titleId"]);return t.createElement("svg",Object.assign({height:"1em",viewBox:"0 0 13 13",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-labelledby":i},o),r?t.createElement("title",{id:i},r):null,t.createElement("rect",{x:.6,y:.6,width:11.8,height:11.8,rx:5.9,stroke:"currentColor",strokeWidth:1.2}),t.createElement("rect",{x:5.5,y:5.5,width:2,height:2,rx:1,fill:"currentColor"}))}g(Xo,"SvgArgument"),g(Yo,"SvgChevronDown"),g(Jo,"SvgChevronLeft"),g(Zo,"SvgChevronUp"),g(ea,"SvgClose"),g(ta,"SvgCopy"),g(na,"SvgDeprecatedArgument"),g(ra,"SvgDeprecatedEnumValue"),g(ia,"SvgDeprecatedField"),g(oa,"SvgDirective"),g(aa,"SvgDocsFilled"),g(sa,"SvgDocs"),g(la,"SvgEnumValue"),g(ua,"SvgField"),g(ca,"SvgHistory"),g(da,"SvgImplements"),g(fa,"SvgKeyboardShortcut"),g(pa,"SvgMagnifyingGlass"),g(ha,"SvgMerge"),g(ma,"SvgPen"),g(ga,"SvgPlay"),g(va,"SvgPlus"),g(ya,"SvgPrettify"),g(ba,"SvgReload"),g(Ea,"SvgRootType"),g(Ta,"SvgSettings"),g(wa,"SvgStarFilled"),g(Ca,"SvgStar"),g(Sa,"SvgStop"),g(xa,"SvgType");var ka=Object.defineProperty,Na=g(((e,t)=>ka(e,"name",{value:t,configurable:!0})),"__name$E");const _a=is(Xo,"argument icon");e.ac=_a;const Oa=is(Yo,"chevron down icon");e.ad=Oa;const Ia=is(Jo,"chevron left icon");e.ae=Ia;const Da=is(Zo,"chevron up icon");e.af=Da;const La=is(ea,"close icon");e.ag=La;const Aa=is(ta,"copy icon");e.ah=Aa;const Ma=is(na,"deprecated argument icon");e.ai=Ma;const Ra=is(ra,"deprecated enum value icon");e.aj=Ra;const Fa=is(ia,"deprecated field icon");e.ak=Fa;const Pa=is(oa,"directive icon");e.al=Pa;const ja=is(aa,"filled docs icon");e.am=ja;const Va=is(sa,"docs icon");e.an=Va;const Ua=is(la,"enum value icon");e.ao=Ua;const Ba=is(ua,"field icon");e.ap=Ba;const $a=is(ca,"history icon");e.aq=$a;const qa=is(da,"implements icon");e.ar=qa;const Ha=is(fa,"keyboard shortcut icon");e.as=Ha;const Ga=is(pa,"magnifying glass icon");e.at=Ga;const za=is(ha,"merge icon");e.au=za;const Wa=is(ma,"pen icon");e.av=Wa;const Ka=is(ga,"play icon");e.aw=Ka;const Qa=is(va,"plus icon");e.ax=Qa;const Xa=is(ya,"prettify icon");e.ay=Xa;const Ya=is(ba,"reload icon");e.az=Ya;const Ja=is(Ea,"root type icon");e.aA=Ja;const Za=is(Ta,"settings icon");e.aB=Za;const es=is(wa,"filled star icon");e.aC=es;const ts=is(Ca,"star icon");e.aD=ts;const ns=is(Sa,"stop icon");e.aE=ns;const rs=is(xa,"type icon");function is(e,t){const n=Na(g((function(n){return de(e,m(h({},n),{title:t}))}),"IconComponent"),"IconComponent");return Object.defineProperty(n,"name",{value:e.name}),n}e.aF=rs,g(is,"generateIcon"),Na(is,"generateIcon");const os=(0,t.forwardRef)(((e,t)=>de("button",m(h({},e),{ref:t,className:b("graphiql-un-styled",e.className)}))));e.aG=os,os.displayName="UnStyledButton";const as=(0,t.forwardRef)(((e,t)=>de("button",m(h({},e),{ref:t,className:b("graphiql-button",{success:"graphiql-button-success",error:"graphiql-button-error"}[e.state],e.className)}))));e.aH=as,as.displayName="Button";const ss=(0,t.forwardRef)(((e,t)=>de("div",m(h({},e),{ref:t,className:b("graphiql-button-group",e.className)}))));function ls(){return!("undefined"==typeof window||!window.document||!window.document.createElement)}e.aI=ss,ss.displayName="ButtonGroup",g(ls,"canUseDOM");var us=ls()?t.useLayoutEffect:t.useEffect;function cs(){var e=(0,t.useState)(Object.create(null))[1];return(0,t.useCallback)((function(){e(Object.create(null))}),[])}function ds(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}g(cs,"useForceUpdate"),g(ds,"_objectWithoutPropertiesLoose$b");var fs=["unstable_skipInitialRender"],ps=g((function(e){var n=e.children,r=e.type,o=void 0===r?"reach-portal":r,a=e.containerRef,s=(0,t.useRef)(null),l=(0,t.useRef)(null),u=cs();return us((function(){if(s.current){var e=s.current.ownerDocument,t=(null==a?void 0:a.current)||e.body;return l.current=null==e?void 0:e.createElement(o),t.appendChild(l.current),u(),function(){l.current&&t&&t.removeChild(l.current)}}}),[o,u,a]),l.current?(0,i.createPortal)(n,l.current):(0,t.createElement)("span",{ref:s})}),"PortalImpl"),hs=g((function(e){var n=e.unstable_skipInitialRender,r=ds(e,fs),i=(0,t.useState)(!1),o=i[0],a=i[1];return(0,t.useEffect)((function(){n&&a(!0)}),[n]),n&&!o?null:(0,t.createElement)(ps,r)}),"Portal");function ms(e){return ls()?e?e.ownerDocument:document:null}function gs(e){return"boolean"==typeof e}function vs(e){return!(!e||"[object Function]"!={}.toString.call(e))}function ys(e){return"string"==typeof e}function bs(){}function Es(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(n=e[Symbol.iterator]()).next.bind(n)}function Cs(e,t){if(null!=e)if(vs(e))e(t);else try{e.current=t}catch(n){throw new Error('Cannot assign value "'+t+'" to ref "'+e+'"')}}function Ss(){for(var e=arguments.length,n=new Array(e),r=0;r=0||(i[n]=e[n]);return i}function Ns(){return Ns=Object.assign?Object.assign.bind():function(e){for(var t=1;t=0})).sort(Tl)}),"orderByTabIndex"),Cl=["button:enabled","select:enabled","textarea:enabled","input:enabled","a[href]","area[href]","summary","iframe","object","embed","audio[controls]","video[controls]","[tabindex]","[contenteditable]","[autofocus]"].join(","),Sl="".concat(Cl,", [data-focus-guard]"),xl=g((function(e,t){var n;return rl((null===(n=e.shadowRoot)||void 0===n?void 0:n.children)||e.children).reduce((function(e,n){return e.concat(n.matches(t?Sl:Cl)?[n]:[],xl(n))}),[])}),"getFocusablesWithShadowDom"),kl=g((function(e,t){return e.reduce((function(e,n){return e.concat(xl(n,t),n.parentNode?rl(n.parentNode.querySelectorAll(Cl)).filter((function(e){return e===n})):[])}),[])}),"getFocusables"),Nl=g((function(e){var t=e.querySelectorAll("[".concat("data-autofocus-inside","]"));return rl(t).map((function(e){return kl([e])})).reduce((function(e,t){return e.concat(t)}),[])}),"getParentAutofocusables"),_l=g((function(e,t){return rl(e).filter((function(e){return ul(t,e)})).filter((function(e){return gl(e)}))}),"filterFocusable"),Ol=g((function(e,t){return void 0===t&&(t=new Map),rl(e).filter((function(e){return dl(t,e)}))}),"filterAutoFocusable"),Il=g((function(e,t,n){return wl(_l(kl(e,n),t),!0,n)}),"getTabbableNodes"),Dl=g((function(e,t){return wl(_l(kl(e),t),!1)}),"getAllTabbableNodes"),Ll=g((function(e,t){return _l(Nl(e),t)}),"parentAutofocusables"),Al=g((function(e,t){return(e.shadowRoot?Al(e.shadowRoot,t):Object.getPrototypeOf(e).contains.call(e,t))||rl(e.children).some((function(e){return Al(e,t)}))}),"contains"),Ml=g((function(e){for(var t=new Set,n=e.length,r=0;r0&&t.add(i),(o&Node.DOCUMENT_POSITION_CONTAINS)>0&&t.add(r)}return e.filter((function(e,n){return!t.has(n)}))}),"filterNested"),Rl=g((function(e){return e.parentNode?Rl(e.parentNode):e}),"getTopParent"),Fl=g((function(e){return il(e).filter(Boolean).reduce((function(e,t){var n=t.getAttribute(Ds);return e.push.apply(e,n?Ml(rl(Rl(t).querySelectorAll("[".concat(Ds,'="').concat(n,'"]:not([').concat(Ls,'="disabled"])')))):[t]),e}),[])}),"getAllAffectedNodes"),Pl=g((function(e){return e.activeElement?e.activeElement.shadowRoot?Pl(e.activeElement.shadowRoot):e.activeElement:void 0}),"getNestedShadowActiveElement"),jl=g((function(){return document.activeElement?document.activeElement.shadowRoot?Pl(document.activeElement.shadowRoot):document.activeElement:void 0}),"getActiveElement"),Vl=g((function(e){return e===document.activeElement}),"focusInFrame"),Ul=g((function(e){return Boolean(rl(e.querySelectorAll("iframe")).some((function(e){return Vl(e)})))}),"focusInsideIframe"),Bl=g((function(e){var t=document&&jl();return!(!t||t.dataset&&t.dataset.focusGuard)&&Fl(e).some((function(e){return Al(e,t)||Ul(e)}))}),"focusInside"),$l=g((function(){var e=document&&jl();return!!e&&rl(document.querySelectorAll("[".concat("data-no-focus-lock","]"))).some((function(t){return Al(t,e)}))}),"focusIsHidden"),ql=g((function(e,t){return t.filter(ml).filter((function(t){return t.name===e.name})).filter((function(e){return e.checked}))[0]||e}),"findSelectedRadio"),Hl=g((function(e,t){return ml(e)&&e.name?ql(e,t):e}),"correctNode"),Gl=g((function(e){var t=new Set;return e.forEach((function(n){return t.add(Hl(n,e))})),e.filter((function(e){return t.has(e)}))}),"correctNodes"),zl=g((function(e){return e[0]&&e.length>1?Hl(e[0],e):e[0]}),"pickFirstFocus"),Wl=g((function(e,t){return e.length>1?e.indexOf(Hl(e[t],e)):t}),"pickFocusable"),Kl="NEW_FOCUS",Ql=g((function(e,t,n,r){var i=e.length,o=e[0],a=e[i-1],s=yl(n);if(!(n&&e.indexOf(n)>=0)){var l=void 0!==n?t.indexOf(n):-1,u=r?t.indexOf(r):l,c=r?e.indexOf(r):-1,d=l-u,f=t.indexOf(o),p=t.indexOf(a),h=Gl(t),m=(void 0!==n?h.indexOf(n):-1)-(r?h.indexOf(r):l),g=Wl(e,0),v=Wl(e,i-1);return-1===l||-1===c?Kl:!d&&c>=0?c:l<=f&&s&&Math.abs(d)>1?v:l>=p&&s&&Math.abs(d)>1?g:d&&Math.abs(m)>1?c:l<=f?v:l>p?g:d?Math.abs(d)>1?c:(i+c+d)%i:void 0}}),"newFocus"),Xl=g((function(e,t){return void 0===t&&(t=[]),t.push(e),e.parentNode&&Xl(e.parentNode.host||e.parentNode,t),t}),"getParents"),Yl=g((function(e,t){for(var n=Xl(e),r=Xl(t),i=0;i=0)return o}return!1}),"getCommonParent"),Jl=g((function(e,t,n){var r=il(e),i=il(t),o=r[0],a=!1;return i.filter(Boolean).forEach((function(e){a=Yl(a||e,e)||a,n.filter(Boolean).forEach((function(e){var t=Yl(o,e);t&&(a=!a||Al(t,a)?t:Yl(t,a))}))})),a}),"getTopCommonParent"),Zl=g((function(e,t){return e.reduce((function(e,n){return e.concat(Ll(n,t))}),[])}),"allParentAutofocusables"),eu=g((function(e){return function(t){var n;return t.autofocus||!!(null===(n=fl(t))||void 0===n?void 0:n.autofocus)||e.indexOf(t)>=0}}),"findAutoFocused"),tu=g((function(e,t){var n=new Map;return t.forEach((function(e){return n.set(e.node,e)})),e.map((function(e){return n.get(e)})).filter(El)}),"reorderNodes"),nu=g((function(e,t){var n=document&&jl(),r=Fl(e).filter(bl),i=Jl(n||e,e,r),o=new Map,a=Dl(r,o),s=Il(r,o).filter((function(e){var t=e.node;return bl(t)}));if(s[0]||(s=a)[0]){var l=Dl([i],o).map((function(e){return e.node})),u=tu(l,s),c=u.map((function(e){return e.node})),d=Ql(c,l,n,t);if(d===Kl){var f=Ol(a.map((function(e){return e.node}))).filter(eu(Zl(r,o)));return{node:f&&f.length?zl(f):zl(Ol(c))}}return void 0===d?d:u[d]}}),"getFocusMerge"),ru=g((function(e){var t=Fl(e).filter(bl),n=Jl(e,e,t),r=new Map,i=Il([n],r,!0),o=Il(t,r).filter((function(e){var t=e.node;return bl(t)})).map((function(e){return e.node}));return i.map((function(e){var t=e.node;return{node:t,index:e.index,lockItem:o.indexOf(t)>=0,guard:yl(t)}}))}),"getFocusabledIn"),iu=g((function(e,t){"focus"in e&&e.focus(t),"contentWindow"in e&&e.contentWindow&&e.contentWindow.focus()}),"focusOn"),ou=0,au=!1,su=g((function(e,t,n){void 0===n&&(n={});var r=nu(e,t);if(!au&&r){if(ou>2)return console.error("FocusLock: focus-fighting detected. Only one focus management system could be active. See https://github.com/theKashey/focus-lock/#focus-fighting"),au=!0,void setTimeout((function(){au=!1}),1);ou++,iu(r.node,n.focusOptions),ou--}}),"setFocus");function lu(e){var t=window.setImmediate;void 0!==t?t(e):setTimeout(e,1)}g(lu,"deferAction");var uu=g((function(){return document&&document.activeElement===document.body}),"focusOnBody"),cu=g((function(){return uu()||$l()}),"isFreeFocus"),du=null,fu=null,pu=null,hu=!1,mu=g((function(){return!0}),"defaultWhitelist"),gu=g((function(e){return(du.whiteList||mu)(e)}),"focusWhitelisted"),vu=g((function(e,t){pu={observerNode:e,portaledElement:t}}),"recordPortal"),yu=g((function(e){return pu&&pu.portaledElement===e}),"focusIsPortaledPair");function bu(e,t,n,r){var i=null,o=e;do{var a=r[o];if(a.guard)a.node.dataset.focusAutoGuard&&(i=a);else{if(!a.lockItem)break;if(o!==e)return;i=null}}while((o+=n)!==t);i&&(i.node.tabIndex=0)}g(bu,"autoGuard");var Eu=g((function(e){return e&&"current"in e?e.current:e}),"extractRef"),Tu=g((function(e){return e?Boolean(hu):"meanwhile"===hu}),"focusWasOutside"),wu=g((function e(t,n,r){return n&&(n.host===t&&(!n.activeElement||r.contains(n.activeElement))||n.parentNode&&e(t,n.parentNode,r))}),"checkInHost"),Cu=g((function(e,t){return t.some((function(t){return wu(e,t,t)}))}),"withinHost"),Su=g((function(){var e=!1;if(du){var t=du,n=t.observed,r=t.persistentFocus,i=t.autoFocus,o=t.shards,a=t.crossFrame,s=t.focusOptions,l=n||pu&&pu.portaledElement,u=document&&document.activeElement;if(l){var c=[l].concat(o.map(Eu).filter(Boolean));if(u&&!gu(u)||(r||Tu(a)||!cu()||!fu&&i)&&(l&&!(Bl(c)||u&&Cu(u,c)||yu(u))&&(document&&!fu&&u&&!i?(u.blur&&u.blur(),document.body.focus()):(e=su(c,fu,{focusOptions:s}),pu={})),hu=!1,fu=document&&document.activeElement),document){var d=document&&document.activeElement,f=ru(c),p=f.map((function(e){return e.node})).indexOf(d);p>-1&&(f.filter((function(e){var t=e.guard,n=e.node;return t&&n.dataset.focusAutoGuard})).forEach((function(e){return e.node.removeAttribute("tabIndex")})),bu(p,f.length,1,f),bu(p,-1,-1,f))}}}return e}),"activateTrap"),xu=g((function(e){Su()&&e&&(e.stopPropagation(),e.preventDefault())}),"onTrap"),ku=g((function(){return lu(Su)}),"onBlur"),Nu=g((function(e){var t=e.target,n=e.currentTarget;n.contains(t)||vu(n,t)}),"onFocus"),_u=g((function(){return null}),"FocusWatcher"),Ou=g((function(){hu="just",setTimeout((function(){hu="meanwhile"}),0)}),"onWindowBlur"),Iu=g((function(){document.addEventListener("focusin",xu),document.addEventListener("focusout",ku),window.addEventListener("blur",Ou)}),"attachHandler"),Du=g((function(){document.removeEventListener("focusin",xu),document.removeEventListener("focusout",ku),window.removeEventListener("blur",Ou)}),"detachHandler");function Lu(e){return e.filter((function(e){return!e.disabled}))}function Au(e){var t=e.slice(-1)[0];t&&!du&&Iu();var n=du,r=n&&t&&t.id===n.id;du=t,n&&!r&&(n.onDeactivation(),e.filter((function(e){return e.id===n.id})).length||n.returnFocus(!t)),t?(fu=null,r&&n.observed===t.observed||t.onActivation(),Su(),lu(Su)):(Du(),fu=null)}g(Lu,"reducePropsToState"),g(Au,"handleStateChangeOnClient"),zs.assignSyncMedium(Nu),Ws.assignMedium(ku),Ks.assignMedium((function(e){return e({moveFocusInside:su,focusInside:Bl})}));var Mu=nl(Lu,Au)(_u),Ru=t.forwardRef(g((function(e,n){return t.createElement(Js,Ns({sideCar:Mu,ref:n},e))}),"FocusLockUICombination")),Fu=Js.propTypes||{};Fu.sideCar,ks(Fu,["sideCar"]),Ru.propTypes={};var Pu=Ru,ju="right-scroll-bar-position",Vu="width-before-scroll-bar",Uu=qs(),Bu=g((function(){}),"nothing"),$u=t.forwardRef((function(e,n){var r=t.useRef(null),i=t.useState({onScrollCapture:Bu,onWheelCapture:Bu,onTouchMoveCapture:Bu}),o=i[0],a=i[1],s=e.forwardProps,l=e.children,u=e.className,c=e.removeScrollBar,d=e.enabled,f=e.shards,p=e.sideCar,h=e.noIsolation,m=e.inert,g=e.allowPinchZoom,v=e.as,y=void 0===v?"div":v,b=js(e,["forwardProps","children","className","removeScrollBar","enabled","shards","sideCar","noIsolation","inert","allowPinchZoom","as"]),E=p,T=Rs([r,n]),w=Ps(Ps({},b),o);return t.createElement(t.Fragment,null,d&&t.createElement(E,{sideCar:Uu,removeScrollBar:c,shards:f,noIsolation:h,inert:m,setCallbacks:a,allowPinchZoom:!!g,lockRef:r}),s?t.cloneElement(t.Children.only(l),Ps(Ps({},w),{ref:T})):t.createElement(y,Ps({},w,{className:u,ref:T}),l))}));$u.defaultProps={enabled:!0,removeScrollBar:!0,inert:!1},$u.classNames={fullWidth:Vu,zeroRight:ju};var qu=g((function(){return n.nc}),"getNonce");function Hu(){if(!document)return null;var e=document.createElement("style");e.type="text/css";var t=qu();return t&&e.setAttribute("nonce",t),e}function Gu(e,t){e.styleSheet?e.styleSheet.cssText=t:e.appendChild(document.createTextNode(t))}function zu(e){(document.head||document.getElementsByTagName("head")[0]).appendChild(e)}g(Hu,"makeStyleTag"),g(Gu,"injectStyles"),g(zu,"insertStyleTag");var Wu=g((function(){var e=0,t=null;return{add:function(n){0==e&&(t=Hu())&&(Gu(t,n),zu(t)),e++},remove:function(){!--e&&t&&(t.parentNode&&t.parentNode.removeChild(t),t=null)}}}),"stylesheetSingleton"),Ku=g((function(){var e=Wu();return function(n,r){t.useEffect((function(){return e.add(n),function(){e.remove()}}),[n&&r])}}),"styleHookSingleton"),Qu=g((function(){var e=Ku();return g((function(t){var n=t.styles,r=t.dynamic;return e(n,r),null}),"Sheet")}),"styleSingleton"),Xu={left:0,top:0,right:0,gap:0},Yu=g((function(e){return parseInt(e||"",10)||0}),"parse$1"),Ju=g((function(e){var t=window.getComputedStyle(document.body),n=t["padding"===e?"paddingLeft":"marginLeft"],r=t["padding"===e?"paddingTop":"marginTop"],i=t["padding"===e?"paddingRight":"marginRight"];return[Yu(n),Yu(r),Yu(i)]}),"getOffset"),Zu=g((function(e){if(void 0===e&&(e="margin"),"undefined"==typeof window)return Xu;var t=Ju(e),n=document.documentElement.clientWidth,r=window.innerWidth;return{left:t[0],top:t[1],right:t[2],gap:Math.max(0,r-n+t[2]-t[0])}}),"getGapWidth"),ec=Qu(),tc=g((function(e,t,n,r){var i=e.left,o=e.top,a=e.right,s=e.gap;return void 0===n&&(n="margin"),"\n .".concat("with-scroll-bars-hidden"," {\n overflow: hidden ").concat(r,";\n padding-right: ").concat(s,"px ").concat(r,";\n }\n body {\n overflow: hidden ").concat(r,";\n overscroll-behavior: contain;\n ").concat([t&&"position: relative ".concat(r,";"),"margin"===n&&"\n padding-left: ".concat(i,"px;\n padding-top: ").concat(o,"px;\n padding-right: ").concat(a,"px;\n margin-left:0;\n margin-top:0;\n margin-right: ").concat(s,"px ").concat(r,";\n "),"padding"===n&&"padding-right: ".concat(s,"px ").concat(r,";")].filter(Boolean).join(""),"\n }\n \n .").concat(ju," {\n right: ").concat(s,"px ").concat(r,";\n }\n \n .").concat(Vu," {\n margin-right: ").concat(s,"px ").concat(r,";\n }\n \n .").concat(ju," .").concat(ju," {\n right: 0 ").concat(r,";\n }\n \n .").concat(Vu," .").concat(Vu," {\n margin-right: 0 ").concat(r,";\n }\n \n body {\n ").concat("--removed-body-scroll-bar-size",": ").concat(s,"px;\n }\n")}),"getStyles$2"),nc=g((function(e){var n=e.noRelative,r=e.noImportant,i=e.gapMode,o=void 0===i?"margin":i,a=t.useMemo((function(){return Zu(o)}),[o]);return t.createElement(ec,{styles:tc(a,!n,o,r?"":"!important")})}),"RemoveScrollBar"),rc=!1;if("undefined"!=typeof window)try{var ic=Object.defineProperty({},"passive",{get:function(){return rc=!0,!0}});window.addEventListener("test",ic,ic),window.removeEventListener("test",ic,ic)}catch(e){rc=!1}var oc=!!rc&&{passive:!1},ac=g((function(e){return"TEXTAREA"===e.tagName}),"alwaysContainsScroll"),sc=g((function(e,t){var n=window.getComputedStyle(e);return"hidden"!==n[t]&&!(n.overflowY===n.overflowX&&!ac(e)&&"visible"===n[t])}),"elementCanBeScrolled"),lc=g((function(e){return sc(e,"overflowY")}),"elementCouldBeVScrolled"),uc=g((function(e){return sc(e,"overflowX")}),"elementCouldBeHScrolled"),cc=g((function(e,t){var n=t;do{if("undefined"!=typeof ShadowRoot&&n instanceof ShadowRoot&&(n=n.host),pc(e,n)){var r=hc(e,n);if(r[1]>r[2])return!0}n=n.parentNode}while(n&&n!==document.body);return!1}),"locationCouldBeScrolled"),dc=g((function(e){return[e.scrollTop,e.scrollHeight,e.clientHeight]}),"getVScrollVariables"),fc=g((function(e){return[e.scrollLeft,e.scrollWidth,e.clientWidth]}),"getHScrollVariables"),pc=g((function(e,t){return"v"===e?lc(t):uc(t)}),"elementCouldBeScrolled"),hc=g((function(e,t){return"v"===e?dc(t):fc(t)}),"getScrollVariables"),mc=g((function(e,t){return"h"===e&&"rtl"===t?-1:1}),"getDirectionFactor"),gc=g((function(e,t,n,r,i){var o=mc(e,window.getComputedStyle(t).direction),a=o*r,s=n.target,l=t.contains(s),u=!1,c=a>0,d=0,f=0;do{var p=hc(e,s),h=p[0],m=p[1]-p[2]-o*h;(h||m)&&pc(e,s)&&(d+=m,f+=h),s=s.parentNode}while(!l&&s!==document.body||l&&(t.contains(s)||t===s));return(c&&(i&&0===d||!i&&a>d)||!c&&(i&&0===f||!i&&-a>f))&&(u=!0),u}),"handleScroll"),vc=g((function(e){return"changedTouches"in e?[e.changedTouches[0].clientX,e.changedTouches[0].clientY]:[0,0]}),"getTouchXY"),yc=g((function(e){return[e.deltaX,e.deltaY]}),"getDeltaXY"),bc=g((function(e){return e&&"current"in e?e.current:e}),"extractRef"),Ec=g((function(e,t){return e[0]===t[0]&&e[1]===t[1]}),"deltaCompare"),Tc=g((function(e){return"\n .block-interactivity-".concat(e," {pointer-events: none;}\n .allow-interactivity-").concat(e," {pointer-events: all;}\n")}),"generateStyle"),wc=0,Cc=[];function Sc(e){var n=t.useRef([]),r=t.useRef([0,0]),i=t.useRef(),o=t.useState(wc++)[0],a=t.useState((function(){return Qu()}))[0],s=t.useRef(e);t.useEffect((function(){s.current=e}),[e]),t.useEffect((function(){if(e.inert){document.body.classList.add("block-interactivity-".concat(o));var t=Vs([e.lockRef.current],(e.shards||[]).map(bc),!0).filter(Boolean);return t.forEach((function(e){return e.classList.add("allow-interactivity-".concat(o))})),function(){document.body.classList.remove("block-interactivity-".concat(o)),t.forEach((function(e){return e.classList.remove("allow-interactivity-".concat(o))}))}}}),[e.inert,e.lockRef.current,e.shards]);var l=t.useCallback((function(e,t){if("touches"in e&&2===e.touches.length)return!s.current.allowPinchZoom;var n,o=vc(e),a=r.current,l="deltaX"in e?e.deltaX:a[0]-o[0],u="deltaY"in e?e.deltaY:a[1]-o[1],c=e.target,d=Math.abs(l)>Math.abs(u)?"h":"v";if("touches"in e&&"h"===d&&"range"===c.type)return!1;var f=cc(d,c);if(!f)return!0;if(f?n=d:(n="v"===d?"h":"v",f=cc(d,c)),!f)return!1;if(!i.current&&"changedTouches"in e&&(l||u)&&(i.current=n),!n)return!0;var p=i.current||n;return gc(p,t,e,"h"===p?l:u,!0)}),[]),u=t.useCallback((function(e){var t=e;if(Cc.length&&Cc[Cc.length-1]===a){var r="deltaY"in t?yc(t):vc(t),i=n.current.filter((function(e){return e.name===t.type&&e.target===t.target&&Ec(e.delta,r)}))[0];if(i&&i.should)t.cancelable&&t.preventDefault();else if(!i){var o=(s.current.shards||[]).map(bc).filter(Boolean).filter((function(e){return e.contains(t.target)}));(o.length>0?l(t,o[0]):!s.current.noIsolation)&&t.cancelable&&t.preventDefault()}}}),[]),c=t.useCallback((function(e,t,r,i){var o={name:e,delta:t,target:r,should:i};n.current.push(o),setTimeout((function(){n.current=n.current.filter((function(e){return e!==o}))}),1)}),[]),d=t.useCallback((function(e){r.current=vc(e),i.current=void 0}),[]),f=t.useCallback((function(t){c(t.type,yc(t),t.target,l(t,e.lockRef.current))}),[]),p=t.useCallback((function(t){c(t.type,vc(t),t.target,l(t,e.lockRef.current))}),[]);t.useEffect((function(){return Cc.push(a),e.setCallbacks({onScrollCapture:f,onWheelCapture:f,onTouchMoveCapture:p}),document.addEventListener("wheel",u,oc),document.addEventListener("touchmove",u,oc),document.addEventListener("touchstart",d,oc),function(){Cc=Cc.filter((function(e){return e!==a})),document.removeEventListener("wheel",u,oc),document.removeEventListener("touchmove",u,oc),document.removeEventListener("touchstart",d,oc)}}),[]);var h=e.removeScrollBar,m=e.inert;return t.createElement(t.Fragment,null,m?t.createElement(a,{styles:Tc(o)}):null,h?t.createElement(nc,{gapMode:"margin"}):null)}g(Sc,"RemoveScrollSideCar");var xc=Gs(Uu,Sc),kc=t.forwardRef((function(e,n){return t.createElement($u,Ps({},e,{ref:n,sideCar:xc}))}));kc.classNames=$u.classNames;var Nc=kc,_c={exports:{}},Oc="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";function Ic(){}function Dc(){}g(Ic,"emptyFunction"),g(Dc,"emptyFunctionWithReset"),Dc.resetWarningCache=Ic;var Lc=g((function(){function e(e,t,n,r,i,o){if(o!==Oc){var a=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw a.name="Invariant Violation",a}}function t(){return e}g(e,"shim"),e.isRequired=e,g(t,"getShim");var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:Dc,resetWarningCache:Ic};return n.PropTypes=n,n}),"factoryWithThrowingShims");_c.exports=Lc();var Ac=_c.exports;function Mc(){return Mc=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}g(Mc,"_extends$9"),g(Rc,"_objectWithoutPropertiesLoose$9");var Fc=["as","isOpen"],Pc=["allowPinchZoom","as","dangerouslyBypassFocusLock","dangerouslyBypassScrollLock","initialFocusRef","onClick","onDismiss","onKeyDown","onMouseDown","unstable_lockFocusAcrossFrames"],jc=["as","onClick","onKeyDown"],Vc=["allowPinchZoom","initialFocusRef","isOpen","onDismiss"];Ac.bool,Ac.bool,Ac.bool,Ac.func;var Uc=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"div":r,o=e.isOpen,a=void 0===o||o,s=Rc(e,Fc);return(0,t.useEffect)((function(){a?window.__REACH_DISABLE_TOOLTIPS=!0:window.requestAnimationFrame((function(){window.__REACH_DISABLE_TOOLTIPS=!1}))}),[a]),a?(0,t.createElement)(hs,{"data-reach-dialog-wrapper":""},(0,t.createElement)(Bc,Mc({ref:n,as:i},s))):null}),"DialogOverlay")),Bc=(0,t.forwardRef)(g((function(e,n){var r=e.allowPinchZoom,i=e.as,o=void 0===i?"div":i,a=e.dangerouslyBypassFocusLock,s=void 0!==a&&a,l=e.dangerouslyBypassScrollLock,u=void 0!==l&&l,c=e.initialFocusRef,d=e.onClick,f=e.onDismiss,p=void 0===f?bs:f,h=e.onKeyDown,m=e.onMouseDown,v=e.unstable_lockFocusAcrossFrames,y=Rc(e,Pc),b=(0,t.useRef)(null),E=(0,t.useRef)(null),T=Ss(E,n),w=(0,t.useCallback)((function(){c&&c.current&&c.current.focus()}),[c]);function C(e){b.current===e.target&&(e.stopPropagation(),p(e))}function S(e){"Escape"===e.key&&(e.stopPropagation(),p(e))}function x(e){b.current=e.target}return g(C,"handleClick"),g(S,"handleKeyDown"),g(x,"handleMouseDown"),(0,t.useEffect)((function(){return E.current?Hc(E.current):void 0}),[]),(0,t.createElement)(Pu,{autoFocus:!0,returnFocus:!0,onActivation:w,disabled:s,crossFrame:null==v||v},(0,t.createElement)(Nc,{allowPinchZoom:r,enabled:!u},(0,t.createElement)(o,Mc({},y,{ref:T,"data-reach-dialog-overlay":"",onClick:xs(d,C),onKeyDown:xs(h,S),onMouseDown:xs(m,x)}))))}),"DialogInner")),$c=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"div":r,o=e.onClick;e.onKeyDown;var a=Rc(e,jc);return(0,t.createElement)(i,Mc({"aria-modal":"true",role:"dialog",tabIndex:-1},a,{ref:n,"data-reach-dialog-content":"",onClick:xs(o,(function(e){e.stopPropagation()}))}))}),"DialogContent")),qc=(0,t.forwardRef)(g((function(e,n){var r=e.allowPinchZoom,i=void 0!==r&&r,o=e.initialFocusRef,a=e.isOpen,s=e.onDismiss,l=void 0===s?bs:s,u=Rc(e,Vc);return(0,t.createElement)(Uc,{allowPinchZoom:i,initialFocusRef:o,isOpen:a,onDismiss:l},(0,t.createElement)($c,Mc({ref:n},u)))}),"Dialog"));function Hc(e){var t=[],n=[],r=ms(e);return e?(Array.prototype.forEach.call(r.querySelectorAll("body > *"),(function(r){var i,o;if(r!==(null==(i=e.parentNode)||null==(o=i.parentNode)?void 0:o.parentNode)){var a=r.getAttribute("aria-hidden");null!==a&&"false"!==a||(t.push(a),n.push(r),r.setAttribute("aria-hidden","true"))}})),function(){n.forEach((function(e,n){var r=t[n];null===r?e.removeAttribute("aria-hidden"):e.setAttribute("aria-hidden",r)}))}):bs}function Gc(){return Gc=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}g(Hc,"createAriaHider"),g(Gc,"_extends$8"),g(zc,"_objectWithoutPropertiesLoose$8");var Wc=["as","style"],Kc=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"span":r,o=e.style,a=void 0===o?{}:o,s=zc(e,Wc);return(0,t.createElement)(i,Gc({ref:n,style:Gc({border:0,clip:"rect(0 0 0 0)",height:"1px",margin:"-1px",overflow:"hidden",padding:0,position:"absolute",width:"1px",whiteSpace:"nowrap",wordWrap:"normal"},a)},s))}),"VisuallyHidden")),Qc=Object.defineProperty;const Xc=g(((e,t)=>Qc(e,"name",{value:t,configurable:!0})),"__name$D")(((e,t)=>Object.entries(t).reduce(((e,t)=>{let[n,r]=t;return e[n]=r,e}),e)),"createComponentGroup"),Yc=(0,t.forwardRef)(((e,t)=>de(qc,m(h({},e),{ref:t}))));Yc.displayName="Dialog";const Jc=(0,t.forwardRef)(((e,t)=>fe(os,m(h({},e),{ref:t,type:"button",className:b("graphiql-dialog-close",e.className),children:[de(Kc,{children:"Close dialog"}),de(La,{})]}))));Jc.displayName="Dialog.Close";const Zc=Xc(Yc,{Close:Jc});e.aJ=Zc;var ed=!1,td=0;function nd(){return++td}function rd(e){var n;if("function"==typeof t.useId){var r=(0,t.useId)(e);return null!=e?e:r}var i=null!=e?e:ed?nd():null,o=(0,t.useState)(i),a=o[0],s=o[1];return us((function(){null===a&&s(nd())}),[]),(0,t.useEffect)((function(){!1===ed&&(ed=!0)}),[]),null!=(n=null!=e?e:a)?n:void 0}g(nd,"genId"),g(rd,"useId");var id,od=["bottom","height","left","right","top","width"],ad=g((function(e,t){return void 0===e&&(e={}),void 0===t&&(t={}),od.some((function(n){return e[n]!==t[n]}))}),"rectChanged"),sd=new Map,ld=g((function e(){var t=[];sd.forEach((function(e,n){var r=n.getBoundingClientRect();ad(r,e.rect)&&(e.rect=r,t.push(e))})),t.forEach((function(e){e.callbacks.forEach((function(t){return t(e.rect)}))})),id=window.requestAnimationFrame(e)}),"run");function ud(e,t){return{observe:g((function(){var n=0===sd.size;sd.has(e)?sd.get(e).callbacks.push(t):sd.set(e,{rect:void 0,hasRectChanged:!1,callbacks:[t]}),n&&ld()}),"observe"),unobserve:g((function(){var n=sd.get(e);if(n){var r=n.callbacks.indexOf(t);r>=0&&n.callbacks.splice(r,1),n.callbacks.length||sd.delete(e),sd.size||cancelAnimationFrame(id)}}),"unobserve")}}function cd(e,n,r){var i,o,a;gs(n)?i=n:(i=null==(a=null==n?void 0:n.observe)||a,o=null==n?void 0:n.onChange),vs(r)&&(o=r);var s=(0,t.useState)(e.current),l=s[0],u=s[1],c=(0,t.useRef)(!1),d=(0,t.useRef)(!1),f=(0,t.useState)(null),p=f[0],h=f[1],m=(0,t.useRef)(o);return us((function(){m.current=o,e.current!==l&&u(e.current)})),us((function(){l&&!c.current&&(c.current=!0,h(l.getBoundingClientRect()))}),[l]),us((function(){if(i){var t=l;if(d.current||(d.current=!0,t=e.current),t){var n=ud(t,(function(e){null==m.current||m.current(e),h(e)}));return n.observe(),function(){n.unobserve()}}}}),[i,l,e]),p}g(ud,"observeRect"),g(cd,"useRect");var dd=["input","select","textarea","a[href]","button","[tabindex]","audio[controls]","video[controls]",'[contenteditable]:not([contenteditable="false"])'],fd=dd.join(","),pd="undefined"==typeof Element?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector;function hd(e,t){t=t||{};var n,r,i,o=[],a=[],s=e.querySelectorAll(fd);for(t.includeContainer&&pd.call(e,fd)&&(s=Array.prototype.slice.apply(s)).unshift(e),n=0;n=0||(i[n]=e[n]);return i}g(Dd,"_extends$7"),g(Ld,"_objectWithoutPropertiesLoose$7");var Ad=["unstable_skipInitialPortalRender"],Md=["as","targetRef","position","unstable_observableRefs"],Rd=(0,t.forwardRef)(g((function(e,n){var r=e.unstable_skipInitialPortalRender,i=Ld(e,Ad);return(0,t.createElement)(hs,{unstable_skipInitialRender:r},(0,t.createElement)(Fd,Dd({ref:n},i)))}),"Popover")),Fd=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"div":r,o=e.targetRef,a=e.position,s=void 0===a?Vd:a,l=e.unstable_observableRefs,u=void 0===l?[]:l,c=Ld(e,Md),d=(0,t.useRef)(null),f=cd(d,{observe:!c.hidden}),p=cd(o,{observe:!c.hidden}),h=Ss(d,n);return $d(o,d),(0,t.createElement)(i,Dd({"data-reach-popover":"",ref:h},c,{style:Dd({position:"absolute"},Pd.apply(void 0,[s,p,f].concat(u)),c.style)}))}),"PopoverImpl"));function Pd(e,t,n){for(var r=arguments.length,i=new Array(r>3?r-3:0),o=3;o=0||(i[n]=e[n]);return i}function Hd(){return Hd=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}g(zd,"createDescendantContext"),g(Wd,"useDescendant"),g(Kd,"useDescendantsInit"),g(Qd,"useDescendants"),g(Xd,"DescendantProvider"),g(Yd,"useDescendantKeyDown"),g(Jd,"isRightClick"),g(Zd,"createStableCallbackHook"),g(ef,"useStableCallback"),g(tf,"_objectWithoutPropertiesLoose$5");var nf,rf,of=["children"];function af(e,n){return(0,t.createContext)(n)}function sf(e,n){var r=(0,t.createContext)(n);function i(e){var n=e.children,i=tf(e,of),o=(0,t.useMemo)((function(){return i}),Object.values(i));return(0,t.createElement)(r.Provider,{value:o},n)}function o(i){var o=(0,t.useContext)(r);if(o)return o;if(n)return n;throw Error(i+" must be rendered inside of a "+e+" component.")}return g(i,"Provider"),g(o,"useContext$1"),[i,o]}function lf(){for(var e=arguments.length,t=new Array(e),n=0;n0||m,matches:hf(o)}}}}),"x");try{for(var p=function(e){var t="function"==typeof Symbol&&e[Symbol.iterator],n=0;return t?t.call(e):{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}}}(d),h=p.next();!h.done;h=p.next()){var m=f(h.value);if("object"==typeof m)return m.value}}catch(e){i={error:e}}finally{try{h&&!h.done&&(o=p.return)&&o.call(p)}finally{if(i)throw i.error}}}return gf(s,l)}};return n}g(df,"e$1"),g(ff,"r$1"),g(pf,"i$1"),g(hf,"o"),g(mf,"a"),g(gf,"u"),g(vf,"c$1");var yf=g((function(e,t){return e.actions.forEach((function(n){var r=n.exec;return r&&r(e.context,t)}))}),"s");function bf(e){var t=e.initialState,n=nf.NotStarted,r=new Set,i={_machine:e,send:function(i){n===nf.Running&&(t=e.transition(t,i),yf(t,mf(i)),r.forEach((function(e){return e(t)})))},subscribe:function(e){return r.add(e),e(t),{unsubscribe:function(){return r.delete(e)}}},start:function(){return n=nf.Running,yf(t,cf),i},stop:function(){return n=nf.Stopped,r.clear(),i},get state(){return t},get status(){return n}};return i}function Ef(e){var n=(0,t.useRef)();return n.current||(n.current={v:e()}),n.current.v}function Tf(){return Tf=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}g(_f,"useMachine"),g(Of,"unwrapRefs"),g(If,"useCreateMachine"),g(Df,"_extends$4"),g(Lf,"_objectWithoutPropertiesLoose$4"),(kf=Cf||(Cf={})).Idle="IDLE",kf.Open="OPEN",kf.Navigating="NAVIGATING",kf.Dragging="DRAGGING",kf.Interacting="INTERACTING",(xf=Sf||(Sf={})).ButtonMouseDown="BUTTON_MOUSE_DOWN",xf.ButtonMouseUp="BUTTON_MOUSE_UP",xf.Blur="BLUR",xf.ClearNavSelection="CLEAR_NAV_SELECTION",xf.ClearTypeahead="CLEAR_TYPEAHEAD",xf.GetDerivedData="GET_DERIVED_DATA",xf.KeyDownEscape="KEY_DOWN_ESCAPE",xf.KeyDownEnter="KEY_DOWN_ENTER",xf.KeyDownSpace="KEY_DOWN_SPACE",xf.KeyDownNavigate="KEY_DOWN_NAVIGATE",xf.KeyDownSearch="KEY_DOWN_SEARCH",xf.KeyDownTab="KEY_DOWN_TAB",xf.KeyDownShiftTab="KEY_DOWN_SHIFT_TAB",xf.OptionTouchStart="OPTION_TOUCH_START",xf.OptionMouseMove="OPTION_MOUSE_MOVE",xf.OptionMouseEnter="OPTION_MOUSE_ENTER",xf.OptionMouseDown="OPTION_MOUSE_DOWN",xf.OptionMouseUp="OPTION_MOUSE_UP",xf.OptionClick="OPTION_CLICK",xf.ListMouseUp="LIST_MOUSE_UP",xf.OptionPress="OPTION_PRESS",xf.OutsideMouseDown="OUTSIDE_MOUSE_DOWN",xf.OutsideMouseUp="OUTSIDE_MOUSE_UP",xf.ValueChange="VALUE_CHANGE",xf.PopoverPointerDown="POPOVER_POINTER_DOWN",xf.PopoverPointerUp="POPOVER_POINTER_UP",xf.UpdateAfterTypeahead="UPDATE_AFTER_TYPEAHEAD";var Af=ff({navigationValue:null}),Mf=ff({typeaheadQuery:null}),Rf=ff({value:g((function(e,t){return t.value}),"value")}),Ff=ff({navigationValue:g((function(e,t){return t.value}),"navigationValue")}),Pf=ff({navigationValue:g((function(e){var t,n=tp(e.value,e.options);return n&&!n.disabled?e.value:(null==(t=e.options.find((function(e){return!e.disabled})))?void 0:t.value)||null}),"navigationValue")});function jf(e,t){if(t.type===Sf.Blur){var n=t.refs,r=n.list,i=n.popover,o=t.relatedTarget,a=ms(i);return!((null==a?void 0:a.activeElement)===r||!i||i.contains(o||(null==a?void 0:a.activeElement)))}return!1}function Vf(e,t){if(t.type===Sf.OutsideMouseDown||t.type===Sf.OutsideMouseUp){var n=t.refs,r=n.button,i=n.popover,o=t.relatedTarget;return!(o===r||!r||r.contains(o)||!i||i.contains(o))}return!1}function Uf(e,t){return!!e.options.find((function(t){return t.value===e.navigationValue}))}function Bf(e,t){var n=t.refs,r=n.popover,i=n.list,o=t.relatedTarget;return!(r&&o&&r.contains(o)&&o!==i)&&Uf(e)}function $f(e,t){requestAnimationFrame((function(){t.refs.list&&t.refs.list.focus()}))}function qf(e,t){t.refs.button&&t.refs.button.focus()}function Hf(e,t){return!t.disabled}function Gf(e,t){return t.type!==Sf.OptionTouchStart||!t||!t.disabled}function zf(e,t){return!("disabled"in t&&t.disabled||("value"in t?null==t.value:null==e.navigationValue))}function Wf(e,t){t.callback&&t.callback(t.value)}function Kf(e,t){if(t.type===Sf.KeyDownEnter){var n=t.refs.hiddenInput;if(n&&n.form){var r=n.form.querySelector("button:not([type]),[type='submit']");r&&r.click()}}}g(jf,"listboxLostFocus"),g(Vf,"clickedOutsideOfListbox"),g(Uf,"optionIsActive"),g(Bf,"shouldNavigate"),g($f,"focusList"),g(qf,"focusButton"),g(Hf,"listboxIsNotDisabled"),g(Gf,"optionIsNavigable"),g(zf,"optionIsSelectable"),g(Wf,"selectOption"),g(Kf,"submitForm");var Qf=ff({typeaheadQuery:g((function(e,t){return(e.typeaheadQuery||"")+t.query}),"typeaheadQuery")}),Xf=ff({value:g((function(e,t){if(t.type===Sf.UpdateAfterTypeahead&&t.query){var n=ep(e.options,t.query);if(n&&!n.disabled)return t.callback&&t.callback(n.value),n.value}return e.value}),"value")}),Yf=ff({navigationValue:g((function(e,t){if(t.type===Sf.UpdateAfterTypeahead&&t.query){var n=ep(e.options,t.query);if(n&&!n.disabled)return n.value}return e.navigationValue}),"navigationValue")}),Jf=((wf={})[Sf.GetDerivedData]={actions:ff((function(e,t){return Df({},e,t.data)}))},wf[Sf.ValueChange]={actions:[Rf,Wf]},wf),Zf=g((function(e){var t,n,r,i,o,a,s=e.value;return{id:"listbox",initial:Cf.Idle,context:{value:s,options:[],navigationValue:null,typeaheadQuery:null},states:(a={},a[Cf.Idle]={on:Df({},Jf,(t={},t[Sf.ButtonMouseDown]={target:Cf.Open,actions:[Pf],cond:Hf},t[Sf.KeyDownSpace]={target:Cf.Navigating,actions:[Pf,$f],cond:Hf},t[Sf.KeyDownSearch]={target:Cf.Idle,actions:Qf,cond:Hf},t[Sf.UpdateAfterTypeahead]={target:Cf.Idle,actions:[Xf],cond:Hf},t[Sf.ClearTypeahead]={target:Cf.Idle,actions:Mf},t[Sf.KeyDownNavigate]={target:Cf.Navigating,actions:[Pf,Mf,$f],cond:Hf},t[Sf.KeyDownEnter]={actions:[Kf],cond:Hf},t))},a[Cf.Interacting]={entry:[Af],on:Df({},Jf,(n={},n[Sf.ClearNavSelection]={actions:[Af,$f]},n[Sf.KeyDownEnter]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},n[Sf.KeyDownSpace]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},n[Sf.ButtonMouseDown]={target:Cf.Idle,actions:[qf]},n[Sf.KeyDownEscape]={target:Cf.Idle,actions:[qf]},n[Sf.OptionMouseDown]={target:Cf.Dragging},n[Sf.OutsideMouseDown]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Dragging,actions:Mf,cond:Uf}],n[Sf.OutsideMouseUp]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Navigating,cond:Uf},{target:Cf.Interacting,actions:Mf}],n[Sf.KeyDownEnter]=Cf.Interacting,n[Sf.Blur]=[{target:Cf.Idle,cond:jf,actions:Mf},{target:Cf.Navigating,cond:Bf},{target:Cf.Interacting,actions:Mf}],n[Sf.OptionTouchStart]={target:Cf.Navigating,actions:[Ff,Mf],cond:Gf},n[Sf.OptionClick]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},n[Sf.OptionPress]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},n[Sf.OptionMouseEnter]={target:Cf.Navigating,actions:[Ff,Mf],cond:Gf},n[Sf.KeyDownNavigate]={target:Cf.Navigating,actions:[Ff,Mf,$f]},n))},a[Cf.Open]={on:Df({},Jf,(r={},r[Sf.ClearNavSelection]={actions:[Af]},r[Sf.KeyDownEnter]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},r[Sf.KeyDownSpace]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},r[Sf.ButtonMouseDown]={target:Cf.Idle,actions:[qf]},r[Sf.KeyDownEscape]={target:Cf.Idle,actions:[qf]},r[Sf.OptionMouseDown]={target:Cf.Dragging},r[Sf.OutsideMouseDown]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Dragging,cond:Uf},{target:Cf.Interacting,actions:Mf}],r[Sf.OutsideMouseUp]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Navigating,cond:Uf},{target:Cf.Interacting,actions:Mf}],r[Sf.Blur]=[{target:Cf.Idle,cond:jf,actions:Mf},{target:Cf.Navigating,cond:Bf},{target:Cf.Interacting,actions:Mf}],r[Sf.ButtonMouseUp]={target:Cf.Navigating,actions:[Pf,$f]},r[Sf.ListMouseUp]={target:Cf.Navigating,actions:[Pf,$f]},r[Sf.OptionTouchStart]={target:Cf.Navigating,actions:[Ff,Mf],cond:Gf},r[Sf.OptionClick]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},r[Sf.OptionPress]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},r[Sf.KeyDownNavigate]={target:Cf.Navigating,actions:[Ff,Mf,$f]},r[Sf.KeyDownSearch]={target:Cf.Navigating,actions:Qf},r[Sf.UpdateAfterTypeahead]={actions:[Yf]},r[Sf.ClearTypeahead]={actions:Mf},r[Sf.OptionMouseMove]=[{target:Cf.Dragging,actions:[Ff],cond:Gf},{target:Cf.Dragging}],r))},a[Cf.Dragging]={on:Df({},Jf,(i={},i[Sf.ClearNavSelection]={actions:[Af]},i[Sf.KeyDownEnter]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},i[Sf.KeyDownSpace]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},i[Sf.ButtonMouseDown]={target:Cf.Idle,actions:[qf]},i[Sf.KeyDownEscape]={target:Cf.Idle,actions:[qf]},i[Sf.OptionMouseDown]={target:Cf.Dragging},i[Sf.OutsideMouseDown]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Navigating,cond:Uf},{target:Cf.Interacting,actions:Mf}],i[Sf.OutsideMouseUp]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Navigating,cond:Uf,actions:$f},{target:Cf.Interacting,actions:[Mf,$f]}],i[Sf.Blur]=[{target:Cf.Idle,cond:jf,actions:Mf},{target:Cf.Navigating,cond:Bf},{target:Cf.Interacting,actions:Mf}],i[Sf.ButtonMouseUp]={target:Cf.Navigating,actions:[Pf,$f]},i[Sf.OptionTouchStart]={target:Cf.Navigating,actions:[Ff,Mf],cond:Gf},i[Sf.OptionClick]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},i[Sf.OptionPress]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},i[Sf.OptionMouseEnter]={target:Cf.Dragging,actions:[Ff,Mf],cond:Gf},i[Sf.KeyDownNavigate]={target:Cf.Navigating,actions:[Ff,Mf,$f]},i[Sf.KeyDownSearch]={target:Cf.Navigating,actions:Qf},i[Sf.UpdateAfterTypeahead]={actions:[Yf]},i[Sf.ClearTypeahead]={actions:Mf},i[Sf.OptionMouseMove]=[{target:Cf.Navigating,actions:[Ff],cond:Gf},{target:Cf.Navigating}],i[Sf.OptionMouseUp]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},i))},a[Cf.Navigating]={on:Df({},Jf,(o={},o[Sf.ClearNavSelection]={actions:[Af,$f]},o[Sf.KeyDownEnter]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},o[Sf.KeyDownSpace]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},o[Sf.ButtonMouseDown]={target:Cf.Idle,actions:[qf]},o[Sf.KeyDownEscape]={target:Cf.Idle,actions:[qf]},o[Sf.OptionMouseDown]={target:Cf.Dragging},o[Sf.OutsideMouseDown]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Navigating,cond:Uf},{target:Cf.Interacting,actions:Mf}],o[Sf.OutsideMouseUp]=[{target:Cf.Idle,cond:Vf,actions:Mf},{target:Cf.Navigating,cond:Uf},{target:Cf.Interacting,actions:Mf}],o[Sf.Blur]=[{target:Cf.Idle,cond:jf,actions:Mf},{target:Cf.Navigating,cond:Bf},{target:Cf.Interacting,actions:Mf}],o[Sf.ButtonMouseUp]={target:Cf.Navigating,actions:[Pf,$f]},o[Sf.OptionTouchStart]={target:Cf.Navigating,actions:[Ff,Mf],cond:Gf},o[Sf.OptionClick]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},o[Sf.OptionPress]={target:Cf.Idle,actions:[Rf,Mf,qf,Wf],cond:zf},o[Sf.OptionMouseEnter]={target:Cf.Navigating,actions:[Ff,Mf],cond:Gf},o[Sf.KeyDownNavigate]={target:Cf.Navigating,actions:[Ff,Mf,$f]},o[Sf.KeyDownSearch]={target:Cf.Navigating,actions:Qf},o[Sf.UpdateAfterTypeahead]={actions:[Yf]},o[Sf.ClearTypeahead]={actions:Mf},o[Sf.OptionMouseMove]=[{target:Cf.Navigating,actions:[Ff],cond:Gf},{target:Cf.Navigating}],o))},a)}}),"createMachineDefinition");function ep(e,t){return void 0===t&&(t=""),t&&e.find((function(e){return!e.disabled&&e.label&&e.label.toLowerCase().startsWith(t.toLowerCase())}))||null}function tp(e,t){return e?t.find((function(t){return t.value===e})):void 0}g(ep,"findOptionFromTypeahead"),g(tp,"findOptionFromValue");var np=["as","aria-labelledby","aria-label","children","defaultValue","disabled","form","name","onChange","required","value","__componentName"],rp=["arrow","button","children","portal"],ip=["aria-label","arrow","as","children","onKeyDown","onMouseDown","onMouseUp"],op=["as","children"],ap=["as","position","onBlur","onKeyDown","onMouseUp","portal","unstable_observableRefs"],sp=["as"],lp=["as","children","disabled","index","label","onClick","onMouseDown","onMouseEnter","onMouseLeave","onMouseMove","onMouseUp","onTouchStart","value"],up=zd(),cp=af(0,{}),dp=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"div":r,o=e["aria-labelledby"],a=e["aria-label"],s=e.children,l=e.defaultValue,u=e.disabled,c=void 0!==u&&u,d=e.form,f=e.name,p=e.onChange,h=e.required,m=e.value;e.__componentName;var v=Lf(e,np),y=(0,t.useRef)(null!=m),b=Kd(),E=b[0],T=b[1],w=(0,t.useRef)(null),C=(0,t.useRef)(null),S=(0,t.useRef)(null),x=(0,t.useRef)(null),k=(0,t.useRef)(null),N=(0,t.useRef)(null),_=(0,t.useRef)(null),O=_f(If(Zf({value:(y.current?m:l)||null})),{button:w,hiddenInput:C,highlightedOption:S,input:x,list:k,popover:N,selectedOption:_},false),I=O[0],D=O[1];function L(e){e!==I.context.value&&(null==p||p(e))}g(L,"handleValueChange");var A=rd(v.id),M=v.id||lf("listbox-input",A),R=Ss(x,n),F=(0,t.useMemo)((function(){var e=E.find((function(e){return e.value===I.context.value}));return e?e.label:null}),[E,I.context.value]),P=Tp(I.value),j={ariaLabel:a,ariaLabelledBy:o,buttonRef:w,disabled:c,highlightedOptionRef:S,isExpanded:P,listboxId:M,listboxValueLabel:F,listRef:k,onValueChange:L,popoverRef:N,selectedOptionRef:_,send:D,state:I.value,stateData:I.context},V=(0,t.useRef)(!1);if(!y.current&&null==l&&!V.current&&E.length){V.current=!0;var U=E.find((function(e){return!e.disabled}));U&&U.value&&D({type:Sf.ValueChange,value:U.value})}return xp(m,I.context.value,(function(){D({type:Sf.ValueChange,value:m})})),us((function(){D({type:Sf.GetDerivedData,data:{options:E}})}),[E,D]),(0,t.useEffect)((function(){function e(e){var t=e.target,n=e.relatedTarget;Sp(N.current,t)||D({type:Sf.OutsideMouseDown,relatedTarget:n||t})}return g(e,"handleMouseDown"),P&&window.addEventListener("mousedown",e),function(){window.removeEventListener("mousedown",e)}}),[D,P]),(0,t.useEffect)((function(){function e(e){var t=e.target,n=e.relatedTarget;Sp(N.current,t)||D({type:Sf.OutsideMouseUp,relatedTarget:n||t})}return g(e,"handleMouseUp"),P&&window.addEventListener("mouseup",e),function(){window.removeEventListener("mouseup",e)}}),[D,P]),(0,t.createElement)(i,Df({},v,{ref:R,"data-reach-listbox-input":"","data-state":P?"expanded":"closed","data-value":I.context.value,id:M}),(0,t.createElement)(cp.Provider,{value:j},(0,t.createElement)(Xd,{context:up,items:E,set:T},vs(s)?s({id:M,isExpanded:P,value:I.context.value,selectedOptionRef:_,highlightedOptionRef:S,valueLabel:F,expanded:P}):s,(d||f||h)&&(0,t.createElement)("input",{ref:C,"data-reach-listbox-hidden-input":"",disabled:c,form:d,name:f,readOnly:!0,required:h,tabIndex:-1,type:"hidden",value:I.context.value||""}))))}),"ListboxInput")),fp=(0,t.forwardRef)(g((function(e,n){var r=e.arrow,i=void 0===r?"â–¼":r,o=e.button,a=e.children,s=e.portal,l=void 0===s||s,u=Lf(e,rp);return(0,t.createElement)(dp,Df({},u,{__componentName:"Listbox",ref:n}),(function(e){var n=e.value,r=e.valueLabel;return(0,t.createElement)(t.Fragment,null,(0,t.createElement)(hp,{arrow:i,children:o?vs(o)?o({value:n,label:r}):o:void 0}),(0,t.createElement)(yp,{portal:l},(0,t.createElement)(bp,null,a)))}))}),"Listbox")),pp=(0,t.forwardRef)(g((function(e,n){var r=e["aria-label"],i=e.arrow,o=void 0!==i&&i,a=e.as,s=void 0===a?"span":a,l=e.children,u=e.onKeyDown,c=e.onMouseDown,d=e.onMouseUp,f=Lf(e,ip),p=(0,t.useContext)(cp),h=p.buttonRef,m=p.send,v=p.ariaLabelledBy,y=p.disabled,b=p.isExpanded,E=p.listboxId,T=p.stateData,w=p.listboxValueLabel,C=T.value,S=Ss(h,n),x=wp();function k(e){Jd(e.nativeEvent)||(e.preventDefault(),e.stopPropagation(),m({type:Sf.ButtonMouseDown,disabled:y}))}function N(e){Jd(e.nativeEvent)||(e.preventDefault(),e.stopPropagation(),m({type:Sf.ButtonMouseUp}))}g(k,"handleMouseDown"),g(N,"handleMouseUp");var _=lf("button",E),O=(0,t.useMemo)((function(){return l?vs(l)?l({isExpanded:b,label:w,value:C,expanded:b}):l:w}),[l,w,b,C]);return(0,t.createElement)(s,Df({"aria-disabled":y||void 0,"aria-expanded":b||void 0,"aria-haspopup":"listbox","aria-labelledby":r?void 0:[v,_].filter(Boolean).join(" "),"aria-label":r,role:"button",tabIndex:y?-1:0},f,{ref:S,"data-reach-listbox-button":"",id:_,onKeyDown:xs(u,x),onMouseDown:xs(c,k),onMouseUp:xs(d,N)}),O,o&&(0,t.createElement)(gp,null,gs(o)?null:o))}),"ListboxButton")),hp=(0,t.memo)(pp),mp=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"span":r,o=e.children,a=Lf(e,op),s=(0,t.useContext)(cp).isExpanded;return(0,t.createElement)(i,Df({"aria-hidden":!0},a,{ref:n,"data-reach-listbox-arrow":"","data-expanded":s?"":void 0}),vs(o)?o({isExpanded:s,expanded:s}):o||"â–¼")}),"ListboxArrow")),gp=(0,t.memo)(mp),vp=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"div":r,o=e.position,a=void 0===o?Ud:o,s=e.onBlur,l=e.onKeyDown,u=e.onMouseUp,c=e.portal,d=void 0===c||c,f=e.unstable_observableRefs,p=Lf(e,ap),h=(0,t.useContext)(cp),m=h.isExpanded,v=h.buttonRef,y=h.popoverRef,b=h.send,E=Ss(y,n),T=wp();function w(){b({type:Sf.ListMouseUp})}g(w,"handleMouseUp");var C=Df({hidden:!m,tabIndex:-1},p,{ref:E,"data-reach-listbox-popover":"",onMouseUp:xs(u,w),onBlur:xs(s,S),onKeyDown:xs(l,T)});function S(e){var t=e.nativeEvent;requestAnimationFrame((function(){b({type:Sf.Blur,relatedTarget:t.relatedTarget||t.target})}))}return g(S,"handleBlur"),d?(0,t.createElement)(Rd,Df({},C,{as:i,targetRef:v,position:a,unstable_observableRefs:f,unstable_skipInitialPortalRender:!0})):(0,t.createElement)(i,C)}),"ListboxPopover")),yp=(0,t.memo)(vp),bp=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"ul":r,o=Lf(e,sp),a=(0,t.useContext)(cp),s=a.listRef,l=a.ariaLabel,u=a.ariaLabelledBy,c=a.isExpanded,d=a.listboxId,f=a.stateData,p=f.value,h=f.navigationValue,m=Ss(n,s);return(0,t.createElement)(i,Df({"aria-activedescendant":Cp(c?h:p),"aria-labelledby":l?void 0:u,"aria-label":l,role:"listbox",tabIndex:-1},o,{ref:m,"data-reach-listbox-list":"",id:lf("listbox",d)}))}),"ListboxList")),Ep=(0,t.forwardRef)(g((function(e,n){var r=e.as,i=void 0===r?"li":r,o=e.children,a=e.disabled,s=e.index,l=e.label,u=e.onClick,c=e.onMouseDown,d=e.onMouseEnter,f=e.onMouseLeave,p=e.onMouseMove,h=e.onMouseUp,m=e.onTouchStart,v=e.value,y=Lf(e,lp),b=(0,t.useContext)(cp),E=b.highlightedOptionRef,T=b.selectedOptionRef,w=b.send,C=b.isExpanded,S=b.onValueChange,x=b.state,k=b.stateData,N=k.value,_=k.navigationValue,O=(0,t.useState)(l),I=O[0],D=O[1],L=l||I||"",A=uf((0,t.useRef)(null),null),M=A[0],R=A[1];Wd((0,t.useMemo)((function(){return{element:M,value:v,label:L,disabled:!!a}}),[a,M,L,v]),up,s);var F=(0,t.useCallback)((function(e){!l&&e&&D((function(t){return e.textContent&&t!==e.textContent?e.textContent:t||""}))}),[l]),P=!!_&&_===v,j=N===v,V=Ss(F,n,R,j?T:null,P?E:null);function U(){w({type:Sf.OptionMouseEnter,value:v,disabled:!!a})}function B(){w({type:Sf.OptionTouchStart,value:v,disabled:!!a})}function $(){w({type:Sf.ClearNavSelection})}function q(e){Jd(e.nativeEvent)||(e.preventDefault(),w({type:Sf.OptionMouseDown}))}function H(e){Jd(e.nativeEvent)||w({type:Sf.OptionMouseUp,value:v,callback:S,disabled:!!a})}function G(e){Jd(e.nativeEvent)||w({type:Sf.OptionClick,value:v,callback:S,disabled:!!a})}function z(){x!==Cf.Open&&_===v||w({type:Sf.OptionMouseMove,value:v,disabled:!!a})}return g(U,"handleMouseEnter"),g(B,"handleTouchStart"),g($,"handleMouseLeave"),g(q,"handleMouseDown"),g(H,"handleMouseUp"),g(G,"handleClick"),g(z,"handleMouseMove"),(0,t.createElement)(i,Df({"aria-selected":(C?P:j)||void 0,"aria-disabled":a||void 0,role:"option"},y,{ref:V,id:Cp(v),"data-reach-listbox-option":"","data-current-nav":P?"":void 0,"data-current-selected":j?"":void 0,"data-label":L,"data-value":v,onClick:xs(u,G),onMouseDown:xs(c,q),onMouseEnter:xs(d,U),onMouseLeave:xs(f,$),onMouseMove:xs(p,z),onMouseUp:xs(h,H),onTouchStart:xs(m,B)}),o)}),"ListboxOption"));function Tp(e){return[Cf.Navigating,Cf.Open,Cf.Dragging,Cf.Interacting].includes(e)}function wp(){var e=(0,t.useContext)(cp),n=e.send,r=e.disabled,i=e.onValueChange,o=e.stateData,a=o.navigationValue,s=o.typeaheadQuery,l=Qd(up),u=ef(i);(0,t.useEffect)((function(){s&&n({type:Sf.UpdateAfterTypeahead,query:s,callback:u});var e=window.setTimeout((function(){null!=s&&n({type:Sf.ClearTypeahead})}),1e3);return function(){window.clearTimeout(e)}}),[u,n,s]);var c=l.findIndex((function(e){return e.value===a}));return xs((function(e){var t=e.key,o=ys(t)&&1===t.length,s=l.find((function(e){return e.value===a}));switch(t){case"Enter":return void n({type:Sf.KeyDownEnter,value:a,callback:i,disabled:!!(null!=s&&s.disabled||r)});case" ":return e.preventDefault(),void n({type:Sf.KeyDownSpace,value:a,callback:i,disabled:!!(null!=s&&s.disabled||r)});case"Escape":return void n({type:Sf.KeyDownEscape});case"Tab":var u=e.shiftKey?Sf.KeyDownShiftTab:Sf.KeyDownTab;return void n({type:u});default:return void(o&&n({type:Sf.KeyDownSearch,query:t,disabled:r}))}}),Yd(up,{currentIndex:c,orientation:"vertical",key:"index",rotate:!0,filter:g((function(e){return!e.disabled}),"filter"),callback:g((function(e){n({type:Sf.KeyDownNavigate,value:l[e].value,disabled:r})}),"callback")}))}function Cp(e){var n=(0,t.useContext)(cp).listboxId;return e?lf("option-"+e,n):void 0}function Sp(e,t){return!(!e||!e.contains(t))}function xp(e,n,r){(0,t.useRef)(null!=e).current&&e!==n&&r()}function kp(e){var n=(0,t.useRef)(null);return(0,t.useEffect)((function(){n.current=e}),[e]),n.current}function Np(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}function _p(){return _p=Object.assign||function(e){for(var t=1;t8||n>8)&&(C.current=!0)}V||null==j||p||E({type:Up,payload:{index:j,dropdownRef:T}})}function K(){C.current=!0,V||null==j||p||E({type:Up,payload:{index:j}})}function Q(e){Jd(e.nativeEvent)||(C.current?i?M.current?M.current=!1:O.current&&O.current.click():p||B():C.current=!0)}return S.current[j]=f,g(B,"select"),g($,"handleClick"),g(q,"handleDragStart"),g(H,"handleMouseDown"),g(G,"handleMouseEnter"),g(z,"handleMouseLeave"),g(W,"handleMouseMove"),g(K,"handleFocus"),g(Q,"handleMouseUp"),(0,t.useEffect)((function(){if(_){var e=window.setTimeout((function(){C.current=!0}),400);return function(){window.clearTimeout(e)}}C.current=!1}),[_,C]),(0,t.useEffect)((function(){var e=ms(O.current);return e.addEventListener("mouseup",t),function(){e.removeEventListener("mouseup",t)};function t(){M.current=!1}}),[]),{data:{disabled:p},props:_p({id:Zp(j),tabIndex:-1},y,{ref:U,"data-disabled":p?"":void 0,"data-selected":V?"":void 0,"data-valuetext":D,onClick:xs(o,$),onDragStart:xs(a,q),onMouseDown:xs(s,H),onMouseEnter:xs(l,G),onMouseLeave:xs(u,z),onMouseMove:xs(c,W),onFocus:xs(h,K),onMouseUp:xs(d,Q)})}}function Xp(e){e.id;var n=e.onKeyDown,r=e.ref,i=Np(e,Dp),o=Gp("useDropdownItems"),a=o.dispatch,s=o.triggerRef,l=o.dropdownRef,u=o.selectCallbacks,c=o.dropdownId,d=o.state,f=d.isExpanded,p=d.triggerId,h=d.selectionIndex,m=d.typeaheadQuery,v=rh(),y=Ss(l,r);(0,t.useEffect)((function(){var e=Jp(v,m);m&&null!=e&&a({type:Up,payload:{index:e,dropdownRef:l}});var t=window.setTimeout((function(){return m&&a({type:Vp,payload:""})}),1e3);return function(){return window.clearTimeout(t)}}),[a,v,m,l]);var b=kp(v.length),E=kp(v[h]),T=kp(h);(0,t.useEffect)((function(){h>v.length-1?a({type:Up,payload:{index:v.length-1,dropdownRef:l}}):b!==v.length&&h>-1&&E&&T===h&&v[h]!==E&&a({type:Up,payload:{index:v.findIndex((function(e){return e.key===(null==E?void 0:E.key)})),dropdownRef:l}})}),[l,a,v,b,E,T,h]);var w=xs(g((function(e){var t=e.key;if(f)switch(t){case"Enter":case" ":var n=v.find((function(e){return e.index===h}));n&&!n.disabled&&(e.preventDefault(),n.isLink&&n.element?n.element.click():(eh(s.current),u.current[n.index]&&u.current[n.index](),a({type:Mp})));break;case"Escape":eh(s.current),a({type:Rp});break;case"Tab":e.preventDefault();break;default:if(ys(t)&&1===t.length){var r=m+t.toLowerCase();a({type:Vp,payload:r})}}}),"handleKeyDown"),Yd($p,{currentIndex:h,orientation:"vertical",rotate:!1,filter:g((function(e){return!e.disabled}),"filter"),callback:g((function(e){a({type:Up,payload:{index:e,dropdownRef:l}})}),"callback"),key:"index"}));return{data:{activeDescendant:Zp(h)||void 0,triggerId:p},props:_p({tabIndex:-1},i,{ref:y,id:c,onKeyDown:xs(n,w)})}}function Yp(e){var n=e.onBlur,r=e.portal,i=void 0===r||r,o=e.position,a=e.ref,s=Np(e,Lp),l=Gp("useDropdownPopover"),u=l.triggerRef,c=l.triggerClickedRef,d=l.dispatch,f=l.dropdownRef,p=l.popoverRef,h=l.state.isExpanded,m=Ss(p,a);return(0,t.useEffect)((function(){if(h){var e=ms(p.current);return g(t,"listener"),e.addEventListener("mousedown",t),function(){e.removeEventListener("mousedown",t)}}function t(e){c.current?c.current=!1:th(p.current,e.target)||d({type:Rp})}}),[c,u,d,f,p,h]),{data:{portal:i,position:o,targetRef:u,isExpanded:h},props:_p({ref:m,hidden:!h,onBlur:xs(n,(function(e){e.currentTarget.contains(e.relatedTarget)||d({type:Rp})}))},s)}}function Jp(e,t){if(void 0===t&&(t=""),!t)return null;var n=e.find((function(e){var n,r,i;return!e.disabled&&(null==(n=e.element)||null==(r=n.dataset)||null==(i=r.valuetext)?void 0:i.toLowerCase().startsWith(t))}));return n?e.indexOf(n):null}function Zp(e){var t=Gp("useItemId").dropdownId;return null!=e&&e>-1?lf("option-"+e,t):void 0}function eh(e){e&&e.focus()}function th(e,t){return!(!e||!e.contains(t))}function nh(e,t){switch(void 0===t&&(t={}),t.type){case Mp:case Rp:return _p({},e,{isExpanded:!1,selectionIndex:-1});case Fp:return _p({},e,{isExpanded:!0,selectionIndex:0});case Pp:return _p({},e,{isExpanded:!0,selectionIndex:t.payload.index});case jp:return _p({},e,{isExpanded:!0,selectionIndex:-1});case Up:var n=t.payload.dropdownRef,r=void 0===n?{current:null}:n;if(t.payload.index>=0&&t.payload.index!==e.selectionIndex){if(r.current){var i=ms(r.current);r.current!==(null==i?void 0:i.activeElement)&&r.current.focus()}return _p({},e,{selectionIndex:null!=t.payload.max?Math.min(Math.max(t.payload.index,0),t.payload.max):Math.max(t.payload.index,0)})}return e;case Ap:return _p({},e,{selectionIndex:-1});case Bp:return _p({},e,{triggerId:t.payload});case Vp:return void 0!==t.payload?_p({},e,{typeaheadQuery:t.payload}):e;default:return e}}function rh(){return Qd($p)}g(Kp,"useDropdownTrigger"),g(Qp,"useDropdownItem"),g(Xp,"useDropdownItems"),g(Yp,"useDropdownPopover"),g(Jp,"findItemFromTypeahead"),g(Zp,"useItemId"),g(eh,"focus"),g(th,"popoverContainsEventTarget"),g(nh,"reducer$1"),g(rh,"useDropdownDescendants");var ih={exports:{}},oh={},ah="function"==typeof Symbol&&Symbol.for,sh=ah?Symbol.for("react.element"):60103,lh=ah?Symbol.for("react.portal"):60106,uh=ah?Symbol.for("react.fragment"):60107,ch=ah?Symbol.for("react.strict_mode"):60108,dh=ah?Symbol.for("react.profiler"):60114,fh=ah?Symbol.for("react.provider"):60109,ph=ah?Symbol.for("react.context"):60110,hh=ah?Symbol.for("react.async_mode"):60111,mh=ah?Symbol.for("react.concurrent_mode"):60111,gh=ah?Symbol.for("react.forward_ref"):60112,vh=ah?Symbol.for("react.suspense"):60113,yh=ah?Symbol.for("react.suspense_list"):60120,bh=ah?Symbol.for("react.memo"):60115,Eh=ah?Symbol.for("react.lazy"):60116,Th=ah?Symbol.for("react.block"):60121,wh=ah?Symbol.for("react.fundamental"):60117,Ch=ah?Symbol.for("react.responder"):60118,Sh=ah?Symbol.for("react.scope"):60119;function xh(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case sh:switch(e=e.type){case hh:case mh:case uh:case dh:case ch:case vh:return e;default:switch(e=e&&e.$$typeof){case ph:case gh:case Eh:case bh:case fh:return e;default:return t}}case lh:return t}}}function kh(e){return xh(e)===mh}function Nh(){return Nh=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}g(xh,"z"),g(kh,"A"),oh.AsyncMode=hh,oh.ConcurrentMode=mh,oh.ContextConsumer=ph,oh.ContextProvider=fh,oh.Element=sh,oh.ForwardRef=gh,oh.Fragment=uh,oh.Lazy=Eh,oh.Memo=bh,oh.Portal=lh,oh.Profiler=dh,oh.StrictMode=ch,oh.Suspense=vh,oh.isAsyncMode=function(e){return kh(e)||xh(e)===hh},oh.isConcurrentMode=kh,oh.isContextConsumer=function(e){return xh(e)===ph},oh.isContextProvider=function(e){return xh(e)===fh},oh.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===sh},oh.isForwardRef=function(e){return xh(e)===gh},oh.isFragment=function(e){return xh(e)===uh},oh.isLazy=function(e){return xh(e)===Eh},oh.isMemo=function(e){return xh(e)===bh},oh.isPortal=function(e){return xh(e)===lh},oh.isProfiler=function(e){return xh(e)===dh},oh.isStrictMode=function(e){return xh(e)===ch},oh.isSuspense=function(e){return xh(e)===vh},oh.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===uh||e===mh||e===dh||e===ch||e===vh||e===yh||"object"==typeof e&&null!==e&&(e.$$typeof===Eh||e.$$typeof===bh||e.$$typeof===fh||e.$$typeof===ph||e.$$typeof===gh||e.$$typeof===wh||e.$$typeof===Ch||e.$$typeof===Sh||e.$$typeof===Th)},oh.typeOf=xh,ih.exports=oh,g(Nh,"_extends$2"),g(_h,"_objectWithoutPropertiesLoose$2");var Oh=["as","id","children"],Ih=["as"],Dh=["as"],Lh=["as"],Ah=["as"],Mh=["portal"],Rh=["as"],Fh=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?t.Fragment:r,o=e.id,a=e.children,s=_h(e,Oh),l=(0,t.useMemo)((function(){try{return ih.exports.isFragment((0,t.createElement)(i,null))}catch(e){return!1}}),[i])?{}:Nh({ref:n,id:o,"data-reach-menu":""},s);return(0,t.createElement)(i,l,(0,t.createElement)(Wp,{id:o,children:a}))})),Ph=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"button":r,o=Kp(Nh({},_h(e,Ih),{ref:n})),a=o.data,s=a.isExpanded,l=a.controls,u=o.props;return(0,t.createElement)(i,Nh({"aria-expanded":!!s||void 0,"aria-haspopup":!0,"aria-controls":l},u,{"data-reach-menu-button":""}))})),jh=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"div":r,o=Qp(Nh({},_h(e,Dh),{ref:n})),a=o.data.disabled,s=o.props;return(0,t.createElement)(i,Nh({role:"menuitem"},s,{"aria-disabled":a||void 0,"data-reach-menu-item":""}))})),Vh=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"div":r,o=_h(e,Lh);return(0,t.createElement)(jh,Nh({},o,{ref:n,as:i}))})),Uh=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"div":r,o=Xp(Nh({},_h(e,Ah),{ref:n})),a=o.data,s=a.activeDescendant,l=a.triggerId,u=o.props;return(0,t.createElement)(i,Nh({"aria-activedescendant":s,"aria-labelledby":l||void 0,role:"menu"},u,{"data-reach-menu-items":""}))})),Bh=(0,t.forwardRef)((function(e,n){var r=e.portal,i=void 0===r||r,o=_h(e,Mh);return(0,t.createElement)($h,{portal:i},(0,t.createElement)(Uh,Nh({},o,{ref:n,"data-reach-menu-list":""})))})),$h=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"div":r,o=Yp(Nh({},_h(e,Rh),{ref:n})),a=o.data,s=a.portal,l=a.targetRef,u=a.position,c=o.props,d={"data-reach-menu-popover":""};return s?(0,t.createElement)(Rd,Nh({},c,d,{as:i,targetRef:l,position:u,unstable_skipInitialPortalRender:!0})):(0,t.createElement)(i,Nh({},c,d))}));const qh=(0,t.forwardRef)(((e,t)=>de(Ph,m(h({},e),{ref:t,className:b("graphiql-un-styled",e.className)}))));qh.displayName="MenuButton";const Hh=Xc(Fh,{Button:qh,Item:Vh,List:Bh});e.aK=Hh;const Gh=(0,t.forwardRef)(((e,t)=>de(hp,m(h({},e),{ref:t,className:b("graphiql-un-styled",e.className)}))));Gh.displayName="ListboxButton";const zh=Xc(fp,{Button:Gh,Input:dp,Option:Ep,Popover:yp});e.aL=zh;var Wh={};var Kh={Aacute:"Ã",aacute:"á",Abreve:"Ä‚",abreve:"ă",ac:"∾",acd:"∿",acE:"∾̳",Acirc:"Â",acirc:"â",acute:"´",Acy:"Ð",acy:"а",AElig:"Æ",aelig:"æ",af:"â¡",Afr:"ð”„",afr:"ð”ž",Agrave:"À",agrave:"à",alefsym:"ℵ",aleph:"ℵ",Alpha:"Α",alpha:"α",Amacr:"Ä€",amacr:"Ä",amalg:"⨿",amp:"&",AMP:"&",andand:"â©•",And:"â©“",and:"∧",andd:"â©œ",andslope:"⩘",andv:"â©š",ang:"∠",ange:"⦤",angle:"∠",angmsdaa:"⦨",angmsdab:"⦩",angmsdac:"⦪",angmsdad:"⦫",angmsdae:"⦬",angmsdaf:"⦭",angmsdag:"⦮",angmsdah:"⦯",angmsd:"∡",angrt:"∟",angrtvb:"⊾",angrtvbd:"â¦",angsph:"∢",angst:"Ã…",angzarr:"â¼",Aogon:"Ä„",aogon:"Ä…",Aopf:"ð”¸",aopf:"ð•’",apacir:"⩯",ap:"≈",apE:"â©°",ape:"≊",apid:"≋",apos:"'",ApplyFunction:"â¡",approx:"≈",approxeq:"≊",Aring:"Ã…",aring:"Ã¥",Ascr:"ð’œ",ascr:"ð’¶",Assign:"≔",ast:"*",asymp:"≈",asympeq:"â‰",Atilde:"Ã",atilde:"ã",Auml:"Ä",auml:"ä",awconint:"∳",awint:"⨑",backcong:"≌",backepsilon:"϶",backprime:"‵",backsim:"∽",backsimeq:"â‹",Backslash:"∖",Barv:"⫧",barvee:"⊽",barwed:"⌅",Barwed:"⌆",barwedge:"⌅",bbrk:"⎵",bbrktbrk:"⎶",bcong:"≌",Bcy:"Б",bcy:"б",bdquo:"„",becaus:"∵",because:"∵",Because:"∵",bemptyv:"⦰",bepsi:"϶",bernou:"ℬ",Bernoullis:"ℬ",Beta:"Î’",beta:"β",beth:"ℶ",between:"≬",Bfr:"ð”…",bfr:"ð”Ÿ",bigcap:"â‹‚",bigcirc:"â—¯",bigcup:"⋃",bigodot:"⨀",bigoplus:"â¨",bigotimes:"⨂",bigsqcup:"⨆",bigstar:"★",bigtriangledown:"â–½",bigtriangleup:"â–³",biguplus:"⨄",bigvee:"â‹",bigwedge:"â‹€",bkarow:"â¤",blacklozenge:"⧫",blacksquare:"â–ª",blacktriangle:"â–´",blacktriangledown:"â–¾",blacktriangleleft:"â—‚",blacktriangleright:"â–¸",blank:"â£",blk12:"â–’",blk14:"â–‘",blk34:"â–“",block:"â–ˆ",bne:"=⃥",bnequiv:"≡⃥",bNot:"â«­",bnot:"âŒ",Bopf:"ð”¹",bopf:"ð•“",bot:"⊥",bottom:"⊥",bowtie:"⋈",boxbox:"⧉",boxdl:"â”",boxdL:"â••",boxDl:"â•–",boxDL:"â•—",boxdr:"┌",boxdR:"â•’",boxDr:"â•“",boxDR:"â•”",boxh:"─",boxH:"â•",boxhd:"┬",boxHd:"╤",boxhD:"â•¥",boxHD:"╦",boxhu:"â”´",boxHu:"╧",boxhU:"╨",boxHU:"â•©",boxminus:"⊟",boxplus:"⊞",boxtimes:"⊠",boxul:"┘",boxuL:"â•›",boxUl:"â•œ",boxUL:"â•",boxur:"â””",boxuR:"╘",boxUr:"â•™",boxUR:"â•š",boxv:"│",boxV:"â•‘",boxvh:"┼",boxvH:"╪",boxVh:"â•«",boxVH:"╬",boxvl:"┤",boxvL:"â•¡",boxVl:"â•¢",boxVL:"â•£",boxvr:"├",boxvR:"â•ž",boxVr:"â•Ÿ",boxVR:"â• ",bprime:"‵",breve:"˘",Breve:"˘",brvbar:"¦",bscr:"ð’·",Bscr:"ℬ",bsemi:"â",bsim:"∽",bsime:"â‹",bsolb:"⧅",bsol:"\\",bsolhsub:"⟈",bull:"•",bullet:"•",bump:"≎",bumpE:"⪮",bumpe:"â‰",Bumpeq:"≎",bumpeq:"â‰",Cacute:"Ć",cacute:"ć",capand:"â©„",capbrcup:"⩉",capcap:"â©‹",cap:"∩",Cap:"â‹’",capcup:"⩇",capdot:"â©€",CapitalDifferentialD:"â……",caps:"∩︀",caret:"â",caron:"ˇ",Cayleys:"â„­",ccaps:"â©",Ccaron:"ÄŒ",ccaron:"Ä",Ccedil:"Ç",ccedil:"ç",Ccirc:"Ĉ",ccirc:"ĉ",Cconint:"∰",ccups:"â©Œ",ccupssm:"â©",Cdot:"ÄŠ",cdot:"Ä‹",cedil:"¸",Cedilla:"¸",cemptyv:"⦲",cent:"¢",centerdot:"·",CenterDot:"·",cfr:"ð” ",Cfr:"â„­",CHcy:"Ч",chcy:"ч",check:"✓",checkmark:"✓",Chi:"Χ",chi:"χ",circ:"ˆ",circeq:"≗",circlearrowleft:"↺",circlearrowright:"↻",circledast:"⊛",circledcirc:"⊚",circleddash:"âŠ",CircleDot:"⊙",circledR:"®",circledS:"Ⓢ",CircleMinus:"⊖",CirclePlus:"⊕",CircleTimes:"⊗",cir:"â—‹",cirE:"⧃",cire:"≗",cirfnint:"â¨",cirmid:"⫯",cirscir:"⧂",ClockwiseContourIntegral:"∲",CloseCurlyDoubleQuote:"â€",CloseCurlyQuote:"’",clubs:"♣",clubsuit:"♣",colon:":",Colon:"∷",Colone:"â©´",colone:"≔",coloneq:"≔",comma:",",commat:"@",comp:"âˆ",compfn:"∘",complement:"âˆ",complexes:"â„‚",cong:"≅",congdot:"â©­",Congruent:"≡",conint:"∮",Conint:"∯",ContourIntegral:"∮",copf:"ð•”",Copf:"â„‚",coprod:"âˆ",Coproduct:"âˆ",copy:"©",COPY:"©",copysr:"â„—",CounterClockwiseContourIntegral:"∳",crarr:"↵",cross:"✗",Cross:"⨯",Cscr:"ð’ž",cscr:"ð’¸",csub:"â«",csube:"â«‘",csup:"â«",csupe:"â«’",ctdot:"⋯",cudarrl:"⤸",cudarrr:"⤵",cuepr:"â‹ž",cuesc:"â‹Ÿ",cularr:"↶",cularrp:"⤽",cupbrcap:"⩈",cupcap:"⩆",CupCap:"â‰",cup:"∪",Cup:"â‹“",cupcup:"â©Š",cupdot:"âŠ",cupor:"â©…",cups:"∪︀",curarr:"↷",curarrm:"⤼",curlyeqprec:"â‹ž",curlyeqsucc:"â‹Ÿ",curlyvee:"â‹Ž",curlywedge:"â‹",curren:"¤",curvearrowleft:"↶",curvearrowright:"↷",cuvee:"â‹Ž",cuwed:"â‹",cwconint:"∲",cwint:"∱",cylcty:"⌭",dagger:"†",Dagger:"‡",daleth:"ℸ",darr:"↓",Darr:"↡",dArr:"⇓",dash:"â€",Dashv:"⫤",dashv:"⊣",dbkarow:"â¤",dblac:"Ë",Dcaron:"ÄŽ",dcaron:"Ä",Dcy:"Д",dcy:"д",ddagger:"‡",ddarr:"⇊",DD:"â……",dd:"â…†",DDotrahd:"⤑",ddotseq:"â©·",deg:"°",Del:"∇",Delta:"Δ",delta:"δ",demptyv:"⦱",dfisht:"⥿",Dfr:"ð”‡",dfr:"ð”¡",dHar:"⥥",dharl:"⇃",dharr:"⇂",DiacriticalAcute:"´",DiacriticalDot:"Ë™",DiacriticalDoubleAcute:"Ë",DiacriticalGrave:"`",DiacriticalTilde:"Ëœ",diam:"â‹„",diamond:"â‹„",Diamond:"â‹„",diamondsuit:"♦",diams:"♦",die:"¨",DifferentialD:"â…†",digamma:"Ï",disin:"⋲",div:"÷",divide:"÷",divideontimes:"⋇",divonx:"⋇",DJcy:"Ђ",djcy:"Ñ’",dlcorn:"⌞",dlcrop:"âŒ",dollar:"$",Dopf:"ð”»",dopf:"ð••",Dot:"¨",dot:"Ë™",DotDot:"⃜",doteq:"â‰",doteqdot:"≑",DotEqual:"â‰",dotminus:"∸",dotplus:"∔",dotsquare:"⊡",doublebarwedge:"⌆",DoubleContourIntegral:"∯",DoubleDot:"¨",DoubleDownArrow:"⇓",DoubleLeftArrow:"â‡",DoubleLeftRightArrow:"⇔",DoubleLeftTee:"⫤",DoubleLongLeftArrow:"⟸",DoubleLongLeftRightArrow:"⟺",DoubleLongRightArrow:"⟹",DoubleRightArrow:"⇒",DoubleRightTee:"⊨",DoubleUpArrow:"⇑",DoubleUpDownArrow:"⇕",DoubleVerticalBar:"∥",DownArrowBar:"⤓",downarrow:"↓",DownArrow:"↓",Downarrow:"⇓",DownArrowUpArrow:"⇵",DownBreve:"Ì‘",downdownarrows:"⇊",downharpoonleft:"⇃",downharpoonright:"⇂",DownLeftRightVector:"â¥",DownLeftTeeVector:"⥞",DownLeftVectorBar:"⥖",DownLeftVector:"↽",DownRightTeeVector:"⥟",DownRightVectorBar:"⥗",DownRightVector:"â‡",DownTeeArrow:"↧",DownTee:"⊤",drbkarow:"â¤",drcorn:"⌟",drcrop:"⌌",Dscr:"ð’Ÿ",dscr:"ð’¹",DScy:"Ð…",dscy:"Ñ•",dsol:"⧶",Dstrok:"Ä",dstrok:"Ä‘",dtdot:"⋱",dtri:"â–¿",dtrif:"â–¾",duarr:"⇵",duhar:"⥯",dwangle:"⦦",DZcy:"Ð",dzcy:"ÑŸ",dzigrarr:"⟿",Eacute:"É",eacute:"é",easter:"â©®",Ecaron:"Äš",ecaron:"Ä›",Ecirc:"Ê",ecirc:"ê",ecir:"≖",ecolon:"≕",Ecy:"Э",ecy:"Ñ",eDDot:"â©·",Edot:"Ä–",edot:"Ä—",eDot:"≑",ee:"â…‡",efDot:"≒",Efr:"ð”ˆ",efr:"ð”¢",eg:"⪚",Egrave:"È",egrave:"è",egs:"⪖",egsdot:"⪘",el:"⪙",Element:"∈",elinters:"â§",ell:"â„“",els:"⪕",elsdot:"⪗",Emacr:"Ä’",emacr:"Ä“",empty:"∅",emptyset:"∅",EmptySmallSquare:"â—»",emptyv:"∅",EmptyVerySmallSquare:"â–«",emsp13:" ",emsp14:" ",emsp:" ",ENG:"ÅŠ",eng:"Å‹",ensp:" ",Eogon:"Ę",eogon:"Ä™",Eopf:"ð”¼",eopf:"ð•–",epar:"â‹•",eparsl:"⧣",eplus:"⩱",epsi:"ε",Epsilon:"Ε",epsilon:"ε",epsiv:"ϵ",eqcirc:"≖",eqcolon:"≕",eqsim:"≂",eqslantgtr:"⪖",eqslantless:"⪕",Equal:"⩵",equals:"=",EqualTilde:"≂",equest:"≟",Equilibrium:"⇌",equiv:"≡",equivDD:"⩸",eqvparsl:"⧥",erarr:"⥱",erDot:"≓",escr:"ℯ",Escr:"â„°",esdot:"â‰",Esim:"⩳",esim:"≂",Eta:"Η",eta:"η",ETH:"Ã",eth:"ð",Euml:"Ë",euml:"ë",euro:"€",excl:"!",exist:"∃",Exists:"∃",expectation:"â„°",exponentiale:"â…‡",ExponentialE:"â…‡",fallingdotseq:"≒",Fcy:"Ф",fcy:"Ñ„",female:"♀",ffilig:"ffi",fflig:"ff",ffllig:"ffl",Ffr:"ð”‰",ffr:"ð”£",filig:"ï¬",FilledSmallSquare:"â—¼",FilledVerySmallSquare:"â–ª",fjlig:"fj",flat:"â™­",fllig:"fl",fltns:"â–±",fnof:"Æ’",Fopf:"ð”½",fopf:"ð•—",forall:"∀",ForAll:"∀",fork:"â‹”",forkv:"â«™",Fouriertrf:"ℱ",fpartint:"â¨",frac12:"½",frac13:"â…“",frac14:"¼",frac15:"â…•",frac16:"â…™",frac18:"â…›",frac23:"â…”",frac25:"â…–",frac34:"¾",frac35:"â…—",frac38:"â…œ",frac45:"â…˜",frac56:"â…š",frac58:"â…",frac78:"â…ž",frasl:"â„",frown:"⌢",fscr:"ð’»",Fscr:"ℱ",gacute:"ǵ",Gamma:"Γ",gamma:"γ",Gammad:"Ïœ",gammad:"Ï",gap:"⪆",Gbreve:"Äž",gbreve:"ÄŸ",Gcedil:"Ä¢",Gcirc:"Äœ",gcirc:"Ä",Gcy:"Г",gcy:"г",Gdot:"Ä ",gdot:"Ä¡",ge:"≥",gE:"≧",gEl:"⪌",gel:"â‹›",geq:"≥",geqq:"≧",geqslant:"⩾",gescc:"⪩",ges:"⩾",gesdot:"⪀",gesdoto:"⪂",gesdotol:"⪄",gesl:"⋛︀",gesles:"⪔",Gfr:"ð”Š",gfr:"ð”¤",gg:"≫",Gg:"â‹™",ggg:"â‹™",gimel:"â„·",GJcy:"Ѓ",gjcy:"Ñ“",gla:"⪥",gl:"≷",glE:"⪒",glj:"⪤",gnap:"⪊",gnapprox:"⪊",gne:"⪈",gnE:"≩",gneq:"⪈",gneqq:"≩",gnsim:"⋧",Gopf:"ð”¾",gopf:"ð•˜",grave:"`",GreaterEqual:"≥",GreaterEqualLess:"â‹›",GreaterFullEqual:"≧",GreaterGreater:"⪢",GreaterLess:"≷",GreaterSlantEqual:"⩾",GreaterTilde:"≳",Gscr:"ð’¢",gscr:"â„Š",gsim:"≳",gsime:"⪎",gsiml:"âª",gtcc:"⪧",gtcir:"⩺",gt:">",GT:">",Gt:"≫",gtdot:"â‹—",gtlPar:"⦕",gtquest:"⩼",gtrapprox:"⪆",gtrarr:"⥸",gtrdot:"â‹—",gtreqless:"â‹›",gtreqqless:"⪌",gtrless:"≷",gtrsim:"≳",gvertneqq:"≩︀",gvnE:"≩︀",Hacek:"ˇ",hairsp:" ",half:"½",hamilt:"â„‹",HARDcy:"Ъ",hardcy:"ÑŠ",harrcir:"⥈",harr:"↔",hArr:"⇔",harrw:"↭",Hat:"^",hbar:"â„",Hcirc:"Ĥ",hcirc:"Ä¥",hearts:"♥",heartsuit:"♥",hellip:"…",hercon:"⊹",hfr:"ð”¥",Hfr:"â„Œ",HilbertSpace:"â„‹",hksearow:"⤥",hkswarow:"⤦",hoarr:"⇿",homtht:"∻",hookleftarrow:"↩",hookrightarrow:"↪",hopf:"ð•™",Hopf:"â„",horbar:"―",HorizontalLine:"─",hscr:"ð’½",Hscr:"â„‹",hslash:"â„",Hstrok:"Ħ",hstrok:"ħ",HumpDownHump:"≎",HumpEqual:"â‰",hybull:"âƒ",hyphen:"â€",Iacute:"Ã",iacute:"í",ic:"â£",Icirc:"ÃŽ",icirc:"î",Icy:"И",icy:"и",Idot:"Ä°",IEcy:"Е",iecy:"е",iexcl:"¡",iff:"⇔",ifr:"ð”¦",Ifr:"â„‘",Igrave:"ÃŒ",igrave:"ì",ii:"â…ˆ",iiiint:"⨌",iiint:"∭",iinfin:"⧜",iiota:"â„©",IJlig:"IJ",ijlig:"ij",Imacr:"Ī",imacr:"Ä«",image:"â„‘",ImaginaryI:"â…ˆ",imagline:"â„",imagpart:"â„‘",imath:"ı",Im:"â„‘",imof:"⊷",imped:"Ƶ",Implies:"⇒",incare:"â„…",in:"∈",infin:"∞",infintie:"â§",inodot:"ı",intcal:"⊺",int:"∫",Int:"∬",integers:"ℤ",Integral:"∫",intercal:"⊺",Intersection:"â‹‚",intlarhk:"⨗",intprod:"⨼",InvisibleComma:"â£",InvisibleTimes:"â¢",IOcy:"Ð",iocy:"Ñ‘",Iogon:"Ä®",iogon:"į",Iopf:"ð•€",iopf:"ð•š",Iota:"Ι",iota:"ι",iprod:"⨼",iquest:"¿",iscr:"ð’¾",Iscr:"â„",isin:"∈",isindot:"⋵",isinE:"⋹",isins:"â‹´",isinsv:"⋳",isinv:"∈",it:"â¢",Itilde:"Ĩ",itilde:"Ä©",Iukcy:"І",iukcy:"Ñ–",Iuml:"Ã",iuml:"ï",Jcirc:"Ä´",jcirc:"ĵ",Jcy:"Й",jcy:"й",Jfr:"ð”",jfr:"ð”§",jmath:"È·",Jopf:"ð•",jopf:"ð•›",Jscr:"ð’¥",jscr:"ð’¿",Jsercy:"Ј",jsercy:"ј",Jukcy:"Є",jukcy:"Ñ”",Kappa:"Κ",kappa:"κ",kappav:"Ï°",Kcedil:"Ķ",kcedil:"Ä·",Kcy:"К",kcy:"к",Kfr:"ð”Ž",kfr:"ð”¨",kgreen:"ĸ",KHcy:"Ð¥",khcy:"Ñ…",KJcy:"ÐŒ",kjcy:"Ñœ",Kopf:"ð•‚",kopf:"ð•œ",Kscr:"ð’¦",kscr:"ð“€",lAarr:"⇚",Lacute:"Ĺ",lacute:"ĺ",laemptyv:"⦴",lagran:"â„’",Lambda:"Λ",lambda:"λ",lang:"⟨",Lang:"⟪",langd:"⦑",langle:"⟨",lap:"⪅",Laplacetrf:"â„’",laquo:"«",larrb:"⇤",larrbfs:"⤟",larr:"â†",Larr:"↞",lArr:"â‡",larrfs:"â¤",larrhk:"↩",larrlp:"↫",larrpl:"⤹",larrsim:"⥳",larrtl:"↢",latail:"⤙",lAtail:"⤛",lat:"⪫",late:"⪭",lates:"⪭︀",lbarr:"⤌",lBarr:"⤎",lbbrk:"â²",lbrace:"{",lbrack:"[",lbrke:"⦋",lbrksld:"â¦",lbrkslu:"â¦",Lcaron:"Ľ",lcaron:"ľ",Lcedil:"Ä»",lcedil:"ļ",lceil:"⌈",lcub:"{",Lcy:"Л",lcy:"л",ldca:"⤶",ldquo:"“",ldquor:"„",ldrdhar:"⥧",ldrushar:"⥋",ldsh:"↲",le:"≤",lE:"≦",LeftAngleBracket:"⟨",LeftArrowBar:"⇤",leftarrow:"â†",LeftArrow:"â†",Leftarrow:"â‡",LeftArrowRightArrow:"⇆",leftarrowtail:"↢",LeftCeiling:"⌈",LeftDoubleBracket:"⟦",LeftDownTeeVector:"⥡",LeftDownVectorBar:"⥙",LeftDownVector:"⇃",LeftFloor:"⌊",leftharpoondown:"↽",leftharpoonup:"↼",leftleftarrows:"⇇",leftrightarrow:"↔",LeftRightArrow:"↔",Leftrightarrow:"⇔",leftrightarrows:"⇆",leftrightharpoons:"⇋",leftrightsquigarrow:"↭",LeftRightVector:"⥎",LeftTeeArrow:"↤",LeftTee:"⊣",LeftTeeVector:"⥚",leftthreetimes:"â‹‹",LeftTriangleBar:"â§",LeftTriangle:"⊲",LeftTriangleEqual:"⊴",LeftUpDownVector:"⥑",LeftUpTeeVector:"⥠",LeftUpVectorBar:"⥘",LeftUpVector:"↿",LeftVectorBar:"⥒",LeftVector:"↼",lEg:"⪋",leg:"â‹š",leq:"≤",leqq:"≦",leqslant:"⩽",lescc:"⪨",les:"⩽",lesdot:"â©¿",lesdoto:"âª",lesdotor:"⪃",lesg:"⋚︀",lesges:"⪓",lessapprox:"⪅",lessdot:"â‹–",lesseqgtr:"â‹š",lesseqqgtr:"⪋",LessEqualGreater:"â‹š",LessFullEqual:"≦",LessGreater:"≶",lessgtr:"≶",LessLess:"⪡",lesssim:"≲",LessSlantEqual:"⩽",LessTilde:"≲",lfisht:"⥼",lfloor:"⌊",Lfr:"ð”",lfr:"ð”©",lg:"≶",lgE:"⪑",lHar:"⥢",lhard:"↽",lharu:"↼",lharul:"⥪",lhblk:"â–„",LJcy:"Љ",ljcy:"Ñ™",llarr:"⇇",ll:"≪",Ll:"⋘",llcorner:"⌞",Lleftarrow:"⇚",llhard:"⥫",lltri:"â—º",Lmidot:"Ä¿",lmidot:"Å€",lmoustache:"⎰",lmoust:"⎰",lnap:"⪉",lnapprox:"⪉",lne:"⪇",lnE:"≨",lneq:"⪇",lneqq:"≨",lnsim:"⋦",loang:"⟬",loarr:"⇽",lobrk:"⟦",longleftarrow:"⟵",LongLeftArrow:"⟵",Longleftarrow:"⟸",longleftrightarrow:"⟷",LongLeftRightArrow:"⟷",Longleftrightarrow:"⟺",longmapsto:"⟼",longrightarrow:"⟶",LongRightArrow:"⟶",Longrightarrow:"⟹",looparrowleft:"↫",looparrowright:"↬",lopar:"⦅",Lopf:"ð•ƒ",lopf:"ð•",loplus:"⨭",lotimes:"⨴",lowast:"∗",lowbar:"_",LowerLeftArrow:"↙",LowerRightArrow:"↘",loz:"â—Š",lozenge:"â—Š",lozf:"⧫",lpar:"(",lparlt:"⦓",lrarr:"⇆",lrcorner:"⌟",lrhar:"⇋",lrhard:"⥭",lrm:"‎",lrtri:"⊿",lsaquo:"‹",lscr:"ð“",Lscr:"â„’",lsh:"↰",Lsh:"↰",lsim:"≲",lsime:"âª",lsimg:"âª",lsqb:"[",lsquo:"‘",lsquor:"‚",Lstrok:"Å",lstrok:"Å‚",ltcc:"⪦",ltcir:"⩹",lt:"<",LT:"<",Lt:"≪",ltdot:"â‹–",lthree:"â‹‹",ltimes:"⋉",ltlarr:"⥶",ltquest:"â©»",ltri:"â—ƒ",ltrie:"⊴",ltrif:"â—‚",ltrPar:"⦖",lurdshar:"⥊",luruhar:"⥦",lvertneqq:"≨︀",lvnE:"≨︀",macr:"¯",male:"♂",malt:"✠",maltese:"✠",Map:"⤅",map:"↦",mapsto:"↦",mapstodown:"↧",mapstoleft:"↤",mapstoup:"↥",marker:"â–®",mcomma:"⨩",Mcy:"Ðœ",mcy:"м",mdash:"—",mDDot:"∺",measuredangle:"∡",MediumSpace:"âŸ",Mellintrf:"ℳ",Mfr:"ð”",mfr:"ð”ª",mho:"℧",micro:"µ",midast:"*",midcir:"â«°",mid:"∣",middot:"·",minusb:"⊟",minus:"−",minusd:"∸",minusdu:"⨪",MinusPlus:"∓",mlcp:"â«›",mldr:"…",mnplus:"∓",models:"⊧",Mopf:"ð•„",mopf:"ð•ž",mp:"∓",mscr:"ð“‚",Mscr:"ℳ",mstpos:"∾",Mu:"Îœ",mu:"μ",multimap:"⊸",mumap:"⊸",nabla:"∇",Nacute:"Ń",nacute:"Å„",nang:"∠⃒",nap:"≉",napE:"⩰̸",napid:"≋̸",napos:"ʼn",napprox:"≉",natural:"â™®",naturals:"â„•",natur:"â™®",nbsp:" ",nbump:"≎̸",nbumpe:"â‰Ì¸",ncap:"⩃",Ncaron:"Ň",ncaron:"ň",Ncedil:"Å…",ncedil:"ņ",ncong:"≇",ncongdot:"⩭̸",ncup:"â©‚",Ncy:"Ð",ncy:"н",ndash:"–",nearhk:"⤤",nearr:"↗",neArr:"⇗",nearrow:"↗",ne:"≠",nedot:"â‰Ì¸",NegativeMediumSpace:"​",NegativeThickSpace:"​",NegativeThinSpace:"​",NegativeVeryThinSpace:"​",nequiv:"≢",nesear:"⤨",nesim:"≂̸",NestedGreaterGreater:"≫",NestedLessLess:"≪",NewLine:"\n",nexist:"∄",nexists:"∄",Nfr:"ð”‘",nfr:"ð”«",ngE:"≧̸",nge:"≱",ngeq:"≱",ngeqq:"≧̸",ngeqslant:"⩾̸",nges:"⩾̸",nGg:"⋙̸",ngsim:"≵",nGt:"≫⃒",ngt:"≯",ngtr:"≯",nGtv:"≫̸",nharr:"↮",nhArr:"⇎",nhpar:"⫲",ni:"∋",nis:"⋼",nisd:"⋺",niv:"∋",NJcy:"Њ",njcy:"Ñš",nlarr:"↚",nlArr:"â‡",nldr:"‥",nlE:"≦̸",nle:"≰",nleftarrow:"↚",nLeftarrow:"â‡",nleftrightarrow:"↮",nLeftrightarrow:"⇎",nleq:"≰",nleqq:"≦̸",nleqslant:"⩽̸",nles:"⩽̸",nless:"≮",nLl:"⋘̸",nlsim:"≴",nLt:"≪⃒",nlt:"≮",nltri:"⋪",nltrie:"⋬",nLtv:"≪̸",nmid:"∤",NoBreak:"â ",NonBreakingSpace:" ",nopf:"ð•Ÿ",Nopf:"â„•",Not:"⫬",not:"¬",NotCongruent:"≢",NotCupCap:"≭",NotDoubleVerticalBar:"∦",NotElement:"∉",NotEqual:"≠",NotEqualTilde:"≂̸",NotExists:"∄",NotGreater:"≯",NotGreaterEqual:"≱",NotGreaterFullEqual:"≧̸",NotGreaterGreater:"≫̸",NotGreaterLess:"≹",NotGreaterSlantEqual:"⩾̸",NotGreaterTilde:"≵",NotHumpDownHump:"≎̸",NotHumpEqual:"â‰Ì¸",notin:"∉",notindot:"⋵̸",notinE:"⋹̸",notinva:"∉",notinvb:"â‹·",notinvc:"⋶",NotLeftTriangleBar:"â§Ì¸",NotLeftTriangle:"⋪",NotLeftTriangleEqual:"⋬",NotLess:"≮",NotLessEqual:"≰",NotLessGreater:"≸",NotLessLess:"≪̸",NotLessSlantEqual:"⩽̸",NotLessTilde:"≴",NotNestedGreaterGreater:"⪢̸",NotNestedLessLess:"⪡̸",notni:"∌",notniva:"∌",notnivb:"⋾",notnivc:"⋽",NotPrecedes:"⊀",NotPrecedesEqual:"⪯̸",NotPrecedesSlantEqual:"â‹ ",NotReverseElement:"∌",NotRightTriangleBar:"â§Ì¸",NotRightTriangle:"â‹«",NotRightTriangleEqual:"â‹­",NotSquareSubset:"âŠÌ¸",NotSquareSubsetEqual:"â‹¢",NotSquareSuperset:"âŠÌ¸",NotSquareSupersetEqual:"â‹£",NotSubset:"⊂⃒",NotSubsetEqual:"⊈",NotSucceeds:"âŠ",NotSucceedsEqual:"⪰̸",NotSucceedsSlantEqual:"â‹¡",NotSucceedsTilde:"≿̸",NotSuperset:"⊃⃒",NotSupersetEqual:"⊉",NotTilde:"â‰",NotTildeEqual:"≄",NotTildeFullEqual:"≇",NotTildeTilde:"≉",NotVerticalBar:"∤",nparallel:"∦",npar:"∦",nparsl:"⫽⃥",npart:"∂̸",npolint:"⨔",npr:"⊀",nprcue:"â‹ ",nprec:"⊀",npreceq:"⪯̸",npre:"⪯̸",nrarrc:"⤳̸",nrarr:"↛",nrArr:"â‡",nrarrw:"â†Ì¸",nrightarrow:"↛",nRightarrow:"â‡",nrtri:"â‹«",nrtrie:"â‹­",nsc:"âŠ",nsccue:"â‹¡",nsce:"⪰̸",Nscr:"ð’©",nscr:"ð“ƒ",nshortmid:"∤",nshortparallel:"∦",nsim:"â‰",nsime:"≄",nsimeq:"≄",nsmid:"∤",nspar:"∦",nsqsube:"â‹¢",nsqsupe:"â‹£",nsub:"⊄",nsubE:"⫅̸",nsube:"⊈",nsubset:"⊂⃒",nsubseteq:"⊈",nsubseteqq:"⫅̸",nsucc:"âŠ",nsucceq:"⪰̸",nsup:"⊅",nsupE:"⫆̸",nsupe:"⊉",nsupset:"⊃⃒",nsupseteq:"⊉",nsupseteqq:"⫆̸",ntgl:"≹",Ntilde:"Ñ",ntilde:"ñ",ntlg:"≸",ntriangleleft:"⋪",ntrianglelefteq:"⋬",ntriangleright:"â‹«",ntrianglerighteq:"â‹­",Nu:"Î",nu:"ν",num:"#",numero:"â„–",numsp:" ",nvap:"â‰âƒ’",nvdash:"⊬",nvDash:"⊭",nVdash:"⊮",nVDash:"⊯",nvge:"≥⃒",nvgt:">⃒",nvHarr:"⤄",nvinfin:"⧞",nvlArr:"⤂",nvle:"≤⃒",nvlt:"<⃒",nvltrie:"⊴⃒",nvrArr:"⤃",nvrtrie:"⊵⃒",nvsim:"∼⃒",nwarhk:"⤣",nwarr:"↖",nwArr:"⇖",nwarrow:"↖",nwnear:"⤧",Oacute:"Ó",oacute:"ó",oast:"⊛",Ocirc:"Ô",ocirc:"ô",ocir:"⊚",Ocy:"О",ocy:"о",odash:"âŠ",Odblac:"Å",odblac:"Å‘",odiv:"⨸",odot:"⊙",odsold:"⦼",OElig:"Å’",oelig:"Å“",ofcir:"⦿",Ofr:"ð”’",ofr:"ð”¬",ogon:"Ë›",Ograve:"Ã’",ograve:"ò",ogt:"â§",ohbar:"⦵",ohm:"Ω",oint:"∮",olarr:"↺",olcir:"⦾",olcross:"⦻",oline:"‾",olt:"⧀",Omacr:"ÅŒ",omacr:"Å",Omega:"Ω",omega:"ω",Omicron:"Ο",omicron:"ο",omid:"⦶",ominus:"⊖",Oopf:"ð•†",oopf:"ð• ",opar:"⦷",OpenCurlyDoubleQuote:"“",OpenCurlyQuote:"‘",operp:"⦹",oplus:"⊕",orarr:"↻",Or:"â©”",or:"∨",ord:"â©",order:"â„´",orderof:"â„´",ordf:"ª",ordm:"º",origof:"⊶",oror:"â©–",orslope:"â©—",orv:"â©›",oS:"Ⓢ",Oscr:"ð’ª",oscr:"â„´",Oslash:"Ø",oslash:"ø",osol:"⊘",Otilde:"Õ",otilde:"õ",otimesas:"⨶",Otimes:"⨷",otimes:"⊗",Ouml:"Ö",ouml:"ö",ovbar:"⌽",OverBar:"‾",OverBrace:"âž",OverBracket:"⎴",OverParenthesis:"âœ",para:"¶",parallel:"∥",par:"∥",parsim:"⫳",parsl:"⫽",part:"∂",PartialD:"∂",Pcy:"П",pcy:"п",percnt:"%",period:".",permil:"‰",perp:"⊥",pertenk:"‱",Pfr:"ð”“",pfr:"ð”­",Phi:"Φ",phi:"φ",phiv:"Ï•",phmmat:"ℳ",phone:"☎",Pi:"Π",pi:"Ï€",pitchfork:"â‹”",piv:"Ï–",planck:"â„",planckh:"â„Ž",plankv:"â„",plusacir:"⨣",plusb:"⊞",pluscir:"⨢",plus:"+",plusdo:"∔",plusdu:"⨥",pluse:"⩲",PlusMinus:"±",plusmn:"±",plussim:"⨦",plustwo:"⨧",pm:"±",Poincareplane:"â„Œ",pointint:"⨕",popf:"ð•¡",Popf:"â„™",pound:"£",prap:"⪷",Pr:"⪻",pr:"≺",prcue:"≼",precapprox:"⪷",prec:"≺",preccurlyeq:"≼",Precedes:"≺",PrecedesEqual:"⪯",PrecedesSlantEqual:"≼",PrecedesTilde:"≾",preceq:"⪯",precnapprox:"⪹",precneqq:"⪵",precnsim:"⋨",pre:"⪯",prE:"⪳",precsim:"≾",prime:"′",Prime:"″",primes:"â„™",prnap:"⪹",prnE:"⪵",prnsim:"⋨",prod:"âˆ",Product:"âˆ",profalar:"⌮",profline:"⌒",profsurf:"⌓",prop:"âˆ",Proportional:"âˆ",Proportion:"∷",propto:"âˆ",prsim:"≾",prurel:"⊰",Pscr:"ð’«",pscr:"ð“…",Psi:"Ψ",psi:"ψ",puncsp:" ",Qfr:"ð””",qfr:"ð”®",qint:"⨌",qopf:"ð•¢",Qopf:"â„š",qprime:"â—",Qscr:"ð’¬",qscr:"ð“†",quaternions:"â„",quatint:"⨖",quest:"?",questeq:"≟",quot:'"',QUOT:'"',rAarr:"⇛",race:"∽̱",Racute:"Å”",racute:"Å•",radic:"√",raemptyv:"⦳",rang:"⟩",Rang:"⟫",rangd:"⦒",range:"⦥",rangle:"⟩",raquo:"»",rarrap:"⥵",rarrb:"⇥",rarrbfs:"⤠",rarrc:"⤳",rarr:"→",Rarr:"↠",rArr:"⇒",rarrfs:"⤞",rarrhk:"↪",rarrlp:"↬",rarrpl:"⥅",rarrsim:"⥴",Rarrtl:"⤖",rarrtl:"↣",rarrw:"â†",ratail:"⤚",rAtail:"⤜",ratio:"∶",rationals:"â„š",rbarr:"â¤",rBarr:"â¤",RBarr:"â¤",rbbrk:"â³",rbrace:"}",rbrack:"]",rbrke:"⦌",rbrksld:"⦎",rbrkslu:"â¦",Rcaron:"Ř",rcaron:"Å™",Rcedil:"Å–",rcedil:"Å—",rceil:"⌉",rcub:"}",Rcy:"Р",rcy:"Ñ€",rdca:"⤷",rdldhar:"⥩",rdquo:"â€",rdquor:"â€",rdsh:"↳",real:"â„œ",realine:"â„›",realpart:"â„œ",reals:"â„",Re:"â„œ",rect:"â–­",reg:"®",REG:"®",ReverseElement:"∋",ReverseEquilibrium:"⇋",ReverseUpEquilibrium:"⥯",rfisht:"⥽",rfloor:"⌋",rfr:"ð”¯",Rfr:"â„œ",rHar:"⥤",rhard:"â‡",rharu:"⇀",rharul:"⥬",Rho:"Ρ",rho:"Ï",rhov:"ϱ",RightAngleBracket:"⟩",RightArrowBar:"⇥",rightarrow:"→",RightArrow:"→",Rightarrow:"⇒",RightArrowLeftArrow:"⇄",rightarrowtail:"↣",RightCeiling:"⌉",RightDoubleBracket:"⟧",RightDownTeeVector:"â¥",RightDownVectorBar:"⥕",RightDownVector:"⇂",RightFloor:"⌋",rightharpoondown:"â‡",rightharpoonup:"⇀",rightleftarrows:"⇄",rightleftharpoons:"⇌",rightrightarrows:"⇉",rightsquigarrow:"â†",RightTeeArrow:"↦",RightTee:"⊢",RightTeeVector:"⥛",rightthreetimes:"â‹Œ",RightTriangleBar:"â§",RightTriangle:"⊳",RightTriangleEqual:"⊵",RightUpDownVector:"â¥",RightUpTeeVector:"⥜",RightUpVectorBar:"⥔",RightUpVector:"↾",RightVectorBar:"⥓",RightVector:"⇀",ring:"Ëš",risingdotseq:"≓",rlarr:"⇄",rlhar:"⇌",rlm:"â€",rmoustache:"⎱",rmoust:"⎱",rnmid:"â«®",roang:"⟭",roarr:"⇾",robrk:"⟧",ropar:"⦆",ropf:"ð•£",Ropf:"â„",roplus:"⨮",rotimes:"⨵",RoundImplies:"⥰",rpar:")",rpargt:"⦔",rppolint:"⨒",rrarr:"⇉",Rrightarrow:"⇛",rsaquo:"›",rscr:"ð“‡",Rscr:"â„›",rsh:"↱",Rsh:"↱",rsqb:"]",rsquo:"’",rsquor:"’",rthree:"â‹Œ",rtimes:"â‹Š",rtri:"â–¹",rtrie:"⊵",rtrif:"â–¸",rtriltri:"⧎",RuleDelayed:"⧴",ruluhar:"⥨",rx:"â„ž",Sacute:"Åš",sacute:"Å›",sbquo:"‚",scap:"⪸",Scaron:"Å ",scaron:"Å¡",Sc:"⪼",sc:"≻",sccue:"≽",sce:"⪰",scE:"⪴",Scedil:"Åž",scedil:"ÅŸ",Scirc:"Åœ",scirc:"Å",scnap:"⪺",scnE:"⪶",scnsim:"â‹©",scpolint:"⨓",scsim:"≿",Scy:"С",scy:"Ñ",sdotb:"⊡",sdot:"â‹…",sdote:"⩦",searhk:"⤥",searr:"↘",seArr:"⇘",searrow:"↘",sect:"§",semi:";",seswar:"⤩",setminus:"∖",setmn:"∖",sext:"✶",Sfr:"ð”–",sfr:"ð”°",sfrown:"⌢",sharp:"♯",SHCHcy:"Щ",shchcy:"щ",SHcy:"Ш",shcy:"ш",ShortDownArrow:"↓",ShortLeftArrow:"â†",shortmid:"∣",shortparallel:"∥",ShortRightArrow:"→",ShortUpArrow:"↑",shy:"­",Sigma:"Σ",sigma:"σ",sigmaf:"Ï‚",sigmav:"Ï‚",sim:"∼",simdot:"⩪",sime:"≃",simeq:"≃",simg:"⪞",simgE:"⪠",siml:"âª",simlE:"⪟",simne:"≆",simplus:"⨤",simrarr:"⥲",slarr:"â†",SmallCircle:"∘",smallsetminus:"∖",smashp:"⨳",smeparsl:"⧤",smid:"∣",smile:"⌣",smt:"⪪",smte:"⪬",smtes:"⪬︀",SOFTcy:"Ь",softcy:"ÑŒ",solbar:"⌿",solb:"⧄",sol:"/",Sopf:"ð•Š",sopf:"ð•¤",spades:"â™ ",spadesuit:"â™ ",spar:"∥",sqcap:"⊓",sqcaps:"⊓︀",sqcup:"⊔",sqcups:"⊔︀",Sqrt:"√",sqsub:"âŠ",sqsube:"⊑",sqsubset:"âŠ",sqsubseteq:"⊑",sqsup:"âŠ",sqsupe:"⊒",sqsupset:"âŠ",sqsupseteq:"⊒",square:"â–¡",Square:"â–¡",SquareIntersection:"⊓",SquareSubset:"âŠ",SquareSubsetEqual:"⊑",SquareSuperset:"âŠ",SquareSupersetEqual:"⊒",SquareUnion:"⊔",squarf:"â–ª",squ:"â–¡",squf:"â–ª",srarr:"→",Sscr:"ð’®",sscr:"ð“ˆ",ssetmn:"∖",ssmile:"⌣",sstarf:"⋆",Star:"⋆",star:"☆",starf:"★",straightepsilon:"ϵ",straightphi:"Ï•",strns:"¯",sub:"⊂",Sub:"â‹",subdot:"⪽",subE:"â«…",sube:"⊆",subedot:"⫃",submult:"â«",subnE:"â«‹",subne:"⊊",subplus:"⪿",subrarr:"⥹",subset:"⊂",Subset:"â‹",subseteq:"⊆",subseteqq:"â«…",SubsetEqual:"⊆",subsetneq:"⊊",subsetneqq:"â«‹",subsim:"⫇",subsub:"â«•",subsup:"â«“",succapprox:"⪸",succ:"≻",succcurlyeq:"≽",Succeeds:"≻",SucceedsEqual:"⪰",SucceedsSlantEqual:"≽",SucceedsTilde:"≿",succeq:"⪰",succnapprox:"⪺",succneqq:"⪶",succnsim:"â‹©",succsim:"≿",SuchThat:"∋",sum:"∑",Sum:"∑",sung:"♪",sup1:"¹",sup2:"²",sup3:"³",sup:"⊃",Sup:"â‹‘",supdot:"⪾",supdsub:"⫘",supE:"⫆",supe:"⊇",supedot:"â«„",Superset:"⊃",SupersetEqual:"⊇",suphsol:"⟉",suphsub:"â«—",suplarr:"⥻",supmult:"â«‚",supnE:"â«Œ",supne:"⊋",supplus:"â«€",supset:"⊃",Supset:"â‹‘",supseteq:"⊇",supseteqq:"⫆",supsetneq:"⊋",supsetneqq:"â«Œ",supsim:"⫈",supsub:"â«”",supsup:"â«–",swarhk:"⤦",swarr:"↙",swArr:"⇙",swarrow:"↙",swnwar:"⤪",szlig:"ß",Tab:"\t",target:"⌖",Tau:"Τ",tau:"Ï„",tbrk:"⎴",Tcaron:"Ť",tcaron:"Å¥",Tcedil:"Å¢",tcedil:"Å£",Tcy:"Т",tcy:"Ñ‚",tdot:"⃛",telrec:"⌕",Tfr:"ð”—",tfr:"ð”±",there4:"∴",therefore:"∴",Therefore:"∴",Theta:"Θ",theta:"θ",thetasym:"Ï‘",thetav:"Ï‘",thickapprox:"≈",thicksim:"∼",ThickSpace:"âŸâ€Š",ThinSpace:" ",thinsp:" ",thkap:"≈",thksim:"∼",THORN:"Þ",thorn:"þ",tilde:"Ëœ",Tilde:"∼",TildeEqual:"≃",TildeFullEqual:"≅",TildeTilde:"≈",timesbar:"⨱",timesb:"⊠",times:"×",timesd:"⨰",tint:"∭",toea:"⤨",topbot:"⌶",topcir:"⫱",top:"⊤",Topf:"ð•‹",topf:"ð•¥",topfork:"â«š",tosa:"⤩",tprime:"‴",trade:"â„¢",TRADE:"â„¢",triangle:"â–µ",triangledown:"â–¿",triangleleft:"â—ƒ",trianglelefteq:"⊴",triangleq:"≜",triangleright:"â–¹",trianglerighteq:"⊵",tridot:"â—¬",trie:"≜",triminus:"⨺",TripleDot:"⃛",triplus:"⨹",trisb:"â§",tritime:"⨻",trpezium:"â¢",Tscr:"ð’¯",tscr:"ð“‰",TScy:"Ц",tscy:"ц",TSHcy:"Ћ",tshcy:"Ñ›",Tstrok:"Ŧ",tstrok:"ŧ",twixt:"≬",twoheadleftarrow:"↞",twoheadrightarrow:"↠",Uacute:"Ú",uacute:"ú",uarr:"↑",Uarr:"↟",uArr:"⇑",Uarrocir:"⥉",Ubrcy:"ÐŽ",ubrcy:"Ñž",Ubreve:"Ŭ",ubreve:"Å­",Ucirc:"Û",ucirc:"û",Ucy:"У",ucy:"у",udarr:"⇅",Udblac:"Å°",udblac:"ű",udhar:"⥮",ufisht:"⥾",Ufr:"ð”˜",ufr:"ð”²",Ugrave:"Ù",ugrave:"ù",uHar:"⥣",uharl:"↿",uharr:"↾",uhblk:"â–€",ulcorn:"⌜",ulcorner:"⌜",ulcrop:"âŒ",ultri:"â—¸",Umacr:"Ū",umacr:"Å«",uml:"¨",UnderBar:"_",UnderBrace:"âŸ",UnderBracket:"⎵",UnderParenthesis:"â",Union:"⋃",UnionPlus:"⊎",Uogon:"Ų",uogon:"ų",Uopf:"ð•Œ",uopf:"ð•¦",UpArrowBar:"⤒",uparrow:"↑",UpArrow:"↑",Uparrow:"⇑",UpArrowDownArrow:"⇅",updownarrow:"↕",UpDownArrow:"↕",Updownarrow:"⇕",UpEquilibrium:"⥮",upharpoonleft:"↿",upharpoonright:"↾",uplus:"⊎",UpperLeftArrow:"↖",UpperRightArrow:"↗",upsi:"Ï…",Upsi:"Ï’",upsih:"Ï’",Upsilon:"Î¥",upsilon:"Ï…",UpTeeArrow:"↥",UpTee:"⊥",upuparrows:"⇈",urcorn:"âŒ",urcorner:"âŒ",urcrop:"⌎",Uring:"Å®",uring:"ů",urtri:"â—¹",Uscr:"ð’°",uscr:"ð“Š",utdot:"â‹°",Utilde:"Ũ",utilde:"Å©",utri:"â–µ",utrif:"â–´",uuarr:"⇈",Uuml:"Ãœ",uuml:"ü",uwangle:"⦧",vangrt:"⦜",varepsilon:"ϵ",varkappa:"Ï°",varnothing:"∅",varphi:"Ï•",varpi:"Ï–",varpropto:"âˆ",varr:"↕",vArr:"⇕",varrho:"ϱ",varsigma:"Ï‚",varsubsetneq:"⊊︀",varsubsetneqq:"⫋︀",varsupsetneq:"⊋︀",varsupsetneqq:"⫌︀",vartheta:"Ï‘",vartriangleleft:"⊲",vartriangleright:"⊳",vBar:"⫨",Vbar:"â««",vBarv:"â«©",Vcy:"Ð’",vcy:"в",vdash:"⊢",vDash:"⊨",Vdash:"⊩",VDash:"⊫",Vdashl:"⫦",veebar:"⊻",vee:"∨",Vee:"â‹",veeeq:"≚",vellip:"â‹®",verbar:"|",Verbar:"‖",vert:"|",Vert:"‖",VerticalBar:"∣",VerticalLine:"|",VerticalSeparator:"â˜",VerticalTilde:"≀",VeryThinSpace:" ",Vfr:"ð”™",vfr:"ð”³",vltri:"⊲",vnsub:"⊂⃒",vnsup:"⊃⃒",Vopf:"ð•",vopf:"ð•§",vprop:"âˆ",vrtri:"⊳",Vscr:"ð’±",vscr:"ð“‹",vsubnE:"⫋︀",vsubne:"⊊︀",vsupnE:"⫌︀",vsupne:"⊋︀",Vvdash:"⊪",vzigzag:"⦚",Wcirc:"Å´",wcirc:"ŵ",wedbar:"â©Ÿ",wedge:"∧",Wedge:"â‹€",wedgeq:"≙",weierp:"℘",Wfr:"ð”š",wfr:"ð”´",Wopf:"ð•Ž",wopf:"ð•¨",wp:"℘",wr:"≀",wreath:"≀",Wscr:"ð’²",wscr:"ð“Œ",xcap:"â‹‚",xcirc:"â—¯",xcup:"⋃",xdtri:"â–½",Xfr:"ð”›",xfr:"ð”µ",xharr:"⟷",xhArr:"⟺",Xi:"Ξ",xi:"ξ",xlarr:"⟵",xlArr:"⟸",xmap:"⟼",xnis:"â‹»",xodot:"⨀",Xopf:"ð•",xopf:"ð•©",xoplus:"â¨",xotime:"⨂",xrarr:"⟶",xrArr:"⟹",Xscr:"ð’³",xscr:"ð“",xsqcup:"⨆",xuplus:"⨄",xutri:"â–³",xvee:"â‹",xwedge:"â‹€",Yacute:"Ã",yacute:"ý",YAcy:"Я",yacy:"Ñ",Ycirc:"Ŷ",ycirc:"Å·",Ycy:"Ы",ycy:"Ñ‹",yen:"Â¥",Yfr:"ð”œ",yfr:"ð”¶",YIcy:"Ї",yicy:"Ñ—",Yopf:"ð•",yopf:"ð•ª",Yscr:"ð’´",yscr:"ð“Ž",YUcy:"Ю",yucy:"ÑŽ",yuml:"ÿ",Yuml:"Ÿ",Zacute:"Ź",zacute:"ź",Zcaron:"Ž",zcaron:"ž",Zcy:"З",zcy:"з",Zdot:"Å»",zdot:"ż",zeetrf:"ℨ",ZeroWidthSpace:"​",Zeta:"Ζ",zeta:"ζ",zfr:"ð”·",Zfr:"ℨ",ZHcy:"Ж",zhcy:"ж",zigrarr:"â‡",zopf:"ð•«",Zopf:"ℤ",Zscr:"ð’µ",zscr:"ð“",zwj:"â€",zwnj:"‌"},Qh=/[!-#%-\*,-\/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E4E\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD803[\uDF55-\uDF59]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC8\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD806[\uDC3B\uDE3F-\uDE46\uDE9A-\uDE9C\uDE9E-\uDEA2]|\uD807[\uDC41-\uDC45\uDC70\uDC71\uDEF7\uDEF8]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD81B[\uDE97-\uDE9A]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/,Xh={},Yh={};function Jh(e){var t,n,r=Yh[e];if(r)return r;for(r=Yh[e]=[],t=0;t<128;t++)n=String.fromCharCode(t),/^[0-9a-z]$/i.test(n)?r.push(n):r.push("%"+("0"+t.toString(16).toUpperCase()).slice(-2));for(t=0;t=55296&&o<=57343){if(o>=55296&&o<=56319&&r+1=56320&&a<=57343){l+=encodeURIComponent(e[r]+e[r+1]),r++;continue}l+="%EF%BF%BD"}else l+=encodeURIComponent(e[r]);return l}g(Jh,"getEncodeCache"),g(Zh,"encode$1"),Zh.defaultChars=";/?:@&=+$,-_.!~*'()#",Zh.componentChars="-_.!~*'()";var em=Zh,tm={};function nm(e){var t,n,r=tm[e];if(r)return r;for(r=tm[e]=[],t=0;t<128;t++)n=String.fromCharCode(t),r.push(n);for(t=0;t=55296&&l<=57343?"���":String.fromCharCode(l),t+=6):240==(248&i)&&t+91114111?u+="����":(l-=65536,u+=String.fromCharCode(55296+(l>>10),56320+(1023&l))),t+=9):u+="�";return u}))}g(nm,"getDecodeCache"),g(rm,"decode$1"),rm.defaultChars=";/?:@&=+$,#",rm.componentChars="";var im=rm,om=g((function(e){var t="";return t+=e.protocol||"",t+=e.slashes?"//":"",t+=e.auth?e.auth+"@":"",e.hostname&&-1!==e.hostname.indexOf(":")?t+="["+e.hostname+"]":t+=e.hostname||"",t+=e.port?":"+e.port:"",t+=e.pathname||"",(t+=e.search||"")+(e.hash||"")}),"format");function am(){this.protocol=null,this.slashes=null,this.auth=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.pathname=null}g(am,"Url");var sm=/^([a-z0-9.+-]+:)/i,lm=/:[0-9]*$/,um=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,cm=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),dm=["'"].concat(cm),fm=["%","/","?",";","#"].concat(dm),pm=["/","?","#"],hm=/^[+a-z0-9A-Z_-]{0,63}$/,mm=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,gm={javascript:!0,"javascript:":!0},vm={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0};function ym(e,t){if(e&&e instanceof am)return e;var n=new am;return n.parse(e,t),n}g(ym,"urlParse"),am.prototype.parse=function(e,t){var n,r,i,o,a,s=e;if(s=s.trim(),!t&&1===e.split("#").length){var l=um.exec(s);if(l)return this.pathname=l[1],l[2]&&(this.search=l[2]),this}var u=sm.exec(s);if(u&&(i=(u=u[0]).toLowerCase(),this.protocol=u,s=s.substr(u.length)),(t||u||s.match(/^\/\/[^@\/]+@[^@\/]+/))&&(!(a="//"===s.substr(0,2))||u&&gm[u]||(s=s.substr(2),this.slashes=!0)),!gm[u]&&(a||u&&!vm[u])){var c,d,f=-1;for(n=0;n127?v+="x":v+=g[y];if(!v.match(hm)){var E=m.slice(0,n),T=m.slice(n+1),w=g.match(mm);w&&(E.push(w[1]),T.unshift(w[2])),T.length&&(s=T.join(".")+s),this.hostname=E.join(".");break}}}}this.hostname.length>255&&(this.hostname=""),h&&(this.hostname=this.hostname.substr(1,this.hostname.length-2))}var C=s.indexOf("#");-1!==C&&(this.hash=s.substr(C),s=s.slice(0,C));var S=s.indexOf("?");return-1!==S&&(this.search=s.substr(S),s=s.slice(0,S)),s&&(this.pathname=s),vm[i]&&this.hostname&&!this.pathname&&(this.pathname=""),this},am.prototype.parseHost=function(e){var t=lm.exec(e);t&&(":"!==(t=t[0])&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)};var bm=ym;Xh.encode=em,Xh.decode=im,Xh.format=om,Xh.parse=bm;var Em={},Tm=/[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,wm=/[\0-\x1F\x7F-\x9F]/,Cm=/[ \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]/;Em.Any=Tm,Em.Cc=wm,Em.Cf=/[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804[\uDCBD\uDCCD]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/,Em.P=Qh,Em.Z=Cm,function(e){function t(e){return Object.prototype.toString.call(e)}function n(e){return"[object String]"===t(e)}g(t,"_class"),g(n,"isString");var r=Object.prototype.hasOwnProperty;function i(e,t){return r.call(e,t)}function o(e){return Array.prototype.slice.call(arguments,1).forEach((function(t){if(t){if("object"!=typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach((function(n){e[n]=t[n]}))}})),e}function a(e,t,n){return[].concat(e.slice(0,t),n,e.slice(t+1))}function s(e){return!(e>=55296&&e<=57343||e>=64976&&e<=65007||65535==(65535&e)||65534==(65535&e)||e>=0&&e<=8||11===e||e>=14&&e<=31||e>=127&&e<=159||e>1114111)}function l(e){if(e>65535){var t=55296+((e-=65536)>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}g(i,"has"),g(o,"assign"),g(a,"arrayReplaceAt"),g(s,"isValidEntityCode"),g(l,"fromCodePoint");var u=/\\([!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~])/g,c=new RegExp(u.source+"|"+/&([a-z#][a-z0-9]{1,31});/gi.source,"gi"),d=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,f=Kh;function p(e,t){var n=0;return i(f,t)?f[t]:35===t.charCodeAt(0)&&d.test(t)&&s(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10))?l(n):e}function h(e){return e.indexOf("\\")<0?e:e.replace(u,"$1")}function m(e){return e.indexOf("\\")<0&&e.indexOf("&")<0?e:e.replace(c,(function(e,t,n){return t||p(e,n)}))}g(p,"replaceEntityPattern"),g(h,"unescapeMd"),g(m,"unescapeAll");var v=/[&<>"]/,y=/[&<>"]/g,b={"&":"&","<":"<",">":">",'"':"""};function E(e){return b[e]}function T(e){return v.test(e)?e.replace(y,E):e}g(E,"replaceUnsafeChar"),g(T,"escapeHtml");var w=/[.?*+^$[\]\\(){}|-]/g;function C(e){return e.replace(w,"\\$&")}function S(e){switch(e){case 9:case 32:return!0}return!1}function x(e){if(e>=8192&&e<=8202)return!0;switch(e){case 9:case 10:case 11:case 12:case 13:case 32:case 160:case 5760:case 8239:case 8287:case 12288:return!0}return!1}g(C,"escapeRE"),g(S,"isSpace"),g(x,"isWhiteSpace");var k=Qh;function N(e){return k.test(e)}function _(e){switch(e){case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:case 58:case 59:case 60:case 61:case 62:case 63:case 64:case 91:case 92:case 93:case 94:case 95:case 96:case 123:case 124:case 125:case 126:return!0;default:return!1}}function O(e){return e=e.trim().replace(/\s+/g," "),"á¹¾"==="ẞ".toLowerCase()&&(e=e.replace(/ẞ/g,"ß")),e.toLowerCase().toUpperCase()}g(N,"isPunctChar"),g(_,"isMdAsciiPunct"),g(O,"normalizeReference"),e.lib={},e.lib.mdurl=Xh,e.lib.ucmicro=Em,e.assign=o,e.isString=n,e.has=i,e.unescapeMd=h,e.unescapeAll=m,e.isValidEntityCode=s,e.fromCodePoint=l,e.escapeHtml=T,e.arrayReplaceAt=a,e.isSpace=S,e.isWhiteSpace=x,e.isMdAsciiPunct=_,e.isPunctChar=N,e.escapeRE=C,e.normalizeReference=O}(Wh);var Sm={},xm=g((function(e,t,n){var r,i,o,a,s=-1,l=e.posMax,u=e.pos;for(e.pos=t+1,r=1;e.pos32)return a;if(41===r){if(0===i)break;i--}t++}return o===t||0!==i||(a.str=km(e.slice(o,t)),a.lines=0,a.pos=t,a.ok=!0),a}),"parseLinkDestination"),_m=Wh.unescapeAll,Om=g((function(e,t,n){var r,i,o=0,a=t,s={ok:!1,pos:0,lines:0,str:""};if(t>=n)return s;if(34!==(i=e.charCodeAt(t))&&39!==i&&40!==i)return s;for(t++,40===i&&(i=41);t"+Lm(e[t].content)+""},Am.code_block=function(e,t,n,r,i){var o=e[t];return""+Lm(e[t].content)+"\n"},Am.fence=function(e,t,n,r,i){var o,a,s,l,u,c=e[t],d=c.info?Dm(c.info).trim():"",f="",p="";return d&&(f=(s=d.split(/(\s+)/g))[0],p=s.slice(2).join("")),0===(o=n.highlight&&n.highlight(c.content,f,p)||Lm(c.content)).indexOf(""+o+"\n"):"
"+o+"
\n"},Am.image=function(e,t,n,r,i){var o=e[t];return o.attrs[o.attrIndex("alt")][1]=i.renderInlineAsText(o.children,n,r),i.renderToken(e,t,n)},Am.hardbreak=function(e,t,n){return n.xhtmlOut?"
\n":"
\n"},Am.softbreak=function(e,t,n){return n.breaks?n.xhtmlOut?"
\n":"
\n":"\n"},Am.text=function(e,t){return Lm(e[t].content)},Am.html_block=function(e,t){return e[t].content},Am.html_inline=function(e,t){return e[t].content},g(Mm,"Renderer$1"),Mm.prototype.renderAttrs=g((function(e){var t,n,r;if(!e.attrs)return"";for(r="",t=0,n=e.attrs.length;t\n":">")}),"renderToken"),Mm.prototype.renderInline=function(e,t,n){for(var r,i="",o=this.rules,a=0,s=e.length;a\s]/i.test(e)}function Gm(e){return/^<\/a\s*>/i.test(e)}g(Hm,"isLinkOpen"),g(Gm,"isLinkClose");var zm=g((function(e){var t,n,r,i,o,a,s,l,u,c,d,f,p,h,m,g,v,y=e.tokens;if(e.md.options.linkify)for(n=0,r=y.length;n=0;t--)if("link_close"!==(a=i[t]).type){if("html_inline"===a.type&&(Hm(a.content)&&p>0&&p--,Gm(a.content)&&p++),!(p>0)&&"text"===a.type&&e.md.linkify.test(a.content)){for(u=a.content,v=e.md.linkify.match(u),s=[],f=a.level,d=0,l=0;ld&&((o=new e.Token("text","",0)).content=u.slice(d,c),o.level=f,s.push(o)),(o=new e.Token("link_open","a",1)).attrs=[["href",m]],o.level=f++,o.markup="linkify",o.info="auto",s.push(o),(o=new e.Token("text","",0)).content=g,o.level=f,s.push(o),(o=new e.Token("link_close","a",-1)).level=--f,o.markup="linkify",o.info="auto",s.push(o),d=v[l].lastIndex);d=0;t--)"text"!==(n=e[t]).type||r||(n.content=n.content.replace(Qm,Ym)),"link_open"===n.type&&"auto"===n.info&&r--,"link_close"===n.type&&"auto"===n.info&&r++}function Zm(e){var t,n,r=0;for(t=e.length-1;t>=0;t--)"text"!==(n=e[t]).type||r||Wm.test(n.content)&&(n.content=n.content.replace(/\+-/g,"±").replace(/\.{2,}/g,"…").replace(/([?!])…/g,"$1..").replace(/([?!]){4,}/g,"$1$1$1").replace(/,{2,}/g,",").replace(/(^|[^-])---(?=[^-]|$)/gm,"$1—").replace(/(^|\s)--(?=\s|$)/gm,"$1–").replace(/(^|[^-\s])--(?=[^-\s]|$)/gm,"$1–")),"link_open"===n.type&&"auto"===n.info&&r--,"link_close"===n.type&&"auto"===n.info&&r++}g(Ym,"replaceFn"),g(Jm,"replace_scoped"),g(Zm,"replace_rare");var eg=g((function(e){var t;if(e.md.options.typographer)for(t=e.tokens.length-1;t>=0;t--)"inline"===e.tokens[t].type&&(Km.test(e.tokens[t].content)&&Jm(e.tokens[t].children),Wm.test(e.tokens[t].content)&&Zm(e.tokens[t].children))}),"replace"),tg=Wh.isWhiteSpace,ng=Wh.isPunctChar,rg=Wh.isMdAsciiPunct,ig=/['"]/,og=/['"]/g,ag="’";function sg(e,t,n){return e.substr(0,t)+n+e.substr(t+1)}function lg(e,t){var n,r,i,o,a,s,l,u,c,d,f,p,h,m,g,v,y,b,E,T,w;for(E=[],n=0;n=0&&!(E[y].level<=l);y--);if(E.length=y+1,"text"===r.type){a=0,s=(i=r.content).length;e:for(;a=0)c=i.charCodeAt(o.index-1);else for(y=n-1;y>=0&&"softbreak"!==e[y].type&&"hardbreak"!==e[y].type;y--)if(e[y].content){c=e[y].content.charCodeAt(e[y].content.length-1);break}if(d=32,a=48&&c<=57&&(v=g=!1),g&&v&&(g=f,v=p),g||v){if(v)for(y=E.length-1;y>=0&&(u=E[y],!(E[y].level=0;t--)"inline"===e.tokens[t].type&&ig.test(e.tokens[t].content)&&lg(e.tokens[t].children,e)}),"smartquotes");function cg(e,t,n){this.type=e,this.tag=t,this.attrs=null,this.map=null,this.nesting=n,this.level=0,this.children=null,this.content="",this.markup="",this.info="",this.meta=null,this.block=!1,this.hidden=!1}g(cg,"Token$3"),cg.prototype.attrIndex=g((function(e){var t,n,r;if(!this.attrs)return-1;for(n=0,r=(t=this.attrs).length;n=0&&(n=this.attrs[t][1]),n}),"attrGet"),cg.prototype.attrJoin=g((function(e,t){var n=this.attrIndex(e);n<0?this.attrPush([e,t]):this.attrs[n][1]=this.attrs[n][1]+" "+t}),"attrJoin");var dg=cg,fg=dg;function pg(e,t,n){this.src=e,this.env=n,this.tokens=[],this.inlineMode=!1,this.md=t}g(pg,"StateCore"),pg.prototype.Token=fg;var hg=pg,mg=Pm,gg=[["normalize",Um],["block",Bm],["inline",$m],["linkify",zm],["replacements",eg],["smartquotes",ug]];function vg(){this.ruler=new mg;for(var e=0;en)return!1;if(u=t+1,e.sCount[u]=4)return!1;if((a=e.bMarks[u]+e.tShift[u])>=e.eMarks[u])return!1;if(124!==(E=e.src.charCodeAt(a++))&&45!==E&&58!==E)return!1;if(a>=e.eMarks[u])return!1;if(124!==(T=e.src.charCodeAt(a++))&&45!==T&&58!==T&&!bg(T))return!1;if(45===E&&bg(T))return!1;for(;a=4)return!1;if((c=Tg(o)).length&&""===c[0]&&c.shift(),c.length&&""===c[c.length-1]&&c.pop(),0===(d=c.length)||d!==p.length)return!1;if(r)return!0;for(v=e.parentType,e.parentType="table",b=e.md.block.ruler.getRules("blockquote"),(f=e.push("table_open","table",1)).map=m=[t,0],(f=e.push("thead_open","thead",1)).map=[t,t+1],(f=e.push("tr_open","tr",1)).map=[t,t+1],s=0;s=4)break;for((c=Tg(o)).length&&""===c[0]&&c.shift(),c.length&&""===c[c.length-1]&&c.pop(),u===t+2&&((f=e.push("tbody_open","tbody",1)).map=g=[t+2,0]),(f=e.push("tr_open","tr",1)).map=[u,u+1],s=0;s=4))break;i=++r}return e.line=i,(o=e.push("code_block","code",0)).content=e.getLines(t,i,4+e.blkIndent,!1)+"\n",o.map=[t,e.line],!0}),"code"),Sg=g((function(e,t,n,r){var i,o,a,s,l,u,c,d=!1,f=e.bMarks[t]+e.tShift[t],p=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(f+3>p)return!1;if(126!==(i=e.src.charCodeAt(f))&&96!==i)return!1;if(l=f,(o=(f=e.skipChars(f,i))-l)<3)return!1;if(c=e.src.slice(l,f),a=e.src.slice(f,p),96===i&&a.indexOf(String.fromCharCode(i))>=0)return!1;if(r)return!0;for(s=t;!(++s>=n||(f=l=e.bMarks[s]+e.tShift[s])<(p=e.eMarks[s])&&e.sCount[s]=4||(f=e.skipChars(f,i))-l=4)return!1;if(62!==e.src.charCodeAt(x++))return!1;if(r)return!0;for(s=f=e.sCount[t]+1,32===e.src.charCodeAt(x)?(x++,s++,f++,i=!1,b=!0):9===e.src.charCodeAt(x)?(b=!0,(e.bsCount[t]+f)%4==3?(x++,s++,f++,i=!1):i=!0):b=!1,p=[e.bMarks[t]],e.bMarks[t]=x;x=k,v=[e.sCount[t]],e.sCount[t]=f-s,y=[e.tShift[t]],e.tShift[t]=x-e.bMarks[t],T=e.md.block.ruler.getRules("blockquote"),g=e.parentType,e.parentType="blockquote",d=t+1;d=(k=e.eMarks[d])));d++)if(62!==e.src.charCodeAt(x++)||C){if(u)break;for(E=!1,a=0,l=T.length;a=k,h.push(e.bsCount[d]),e.bsCount[d]=e.sCount[d]+1+(b?1:0),v.push(e.sCount[d]),e.sCount[d]=f-s,y.push(e.tShift[d]),e.tShift[d]=x-e.bMarks[d]}for(m=e.blkIndent,e.blkIndent=0,(w=e.push("blockquote_open","blockquote",1)).markup=">",w.map=c=[t,0],e.md.block.tokenize(e,t,d),(w=e.push("blockquote_close","blockquote",-1)).markup=">",e.lineMax=S,e.parentType=g,c[1]=e.line,a=0;a=4)return!1;if(42!==(i=e.src.charCodeAt(l++))&&45!==i&&95!==i)return!1;for(o=1;l=o)return-1;if((n=e.src.charCodeAt(i++))<48||n>57)return-1;for(;;){if(i>=o)return-1;if(!((n=e.src.charCodeAt(i++))>=48&&n<=57)){if(41===n||46===n)break;return-1}if(i-r>=10)return-1}return i=4)return!1;if(e.listIndent>=0&&e.sCount[t]-e.listIndent>=4&&e.sCount[t]=e.blkIndent&&(L=!0),(k=Dg(e,t))>=0){if(c=!0,_=e.bMarks[t]+e.tShift[t],g=Number(e.src.slice(_,k-1)),L&&1!==g)return!1}else{if(!((k=Ig(e,t))>=0))return!1;c=!1}if(L&&e.skipSpaces(k)>=e.eMarks[t])return!1;if(m=e.src.charCodeAt(k-1),r)return!0;for(h=e.tokens.length,c?(D=e.push("ordered_list_open","ol",1),1!==g&&(D.attrs=[["start",g]])):D=e.push("bullet_list_open","ul",1),D.map=p=[t,0],D.markup=String.fromCharCode(m),y=t,N=!1,I=e.md.block.ruler.getRules("list"),T=e.parentType,e.parentType="list";y=v?1:b-u)>4&&(l=1),s=u+l,(D=e.push("list_item_open","li",1)).markup=String.fromCharCode(m),D.map=d=[t,0],c&&(D.info=e.src.slice(_,k-1)),S=e.tight,C=e.tShift[t],w=e.sCount[t],E=e.listIndent,e.listIndent=e.blkIndent,e.blkIndent=s,e.tight=!0,e.tShift[t]=o-e.bMarks[t],e.sCount[t]=b,o>=v&&e.isEmpty(t+1)?e.line=Math.min(e.line+2,n):e.md.block.tokenize(e,t,n,!0),e.tight&&!N||(A=!1),N=e.line-t>1&&e.isEmpty(e.line-1),e.blkIndent=e.listIndent,e.listIndent=E,e.tShift[t]=C,e.sCount[t]=w,e.tight=S,(D=e.push("list_item_close","li",-1)).markup=String.fromCharCode(m),y=t=e.line,d[1]=y,o=e.bMarks[t],y>=n)break;if(e.sCount[y]=4)break;for(O=!1,a=0,f=I.length;a=4)return!1;if(91!==e.src.charCodeAt(T))return!1;for(;++T3||e.sCount[C]<0)){for(v=!1,u=0,c=y.length;u`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*\\/?>",Vg="<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>",Ug=new RegExp("^(?:"+jg+"|"+Vg+"|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|<[?][\\s\\S]*?[?]>|]*>|)"),Bg=new RegExp("^(?:"+jg+"|"+Vg+")");Pg.HTML_TAG_RE=Ug,Pg.HTML_OPEN_CLOSE_TAG_RE=Bg;var $g=["address","article","aside","base","basefont","blockquote","body","caption","center","col","colgroup","dd","details","dialog","dir","div","dl","dt","fieldset","figcaption","figure","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hr","html","iframe","legend","li","link","main","menu","menuitem","nav","noframes","ol","optgroup","option","p","param","section","source","summary","table","tbody","td","tfoot","th","thead","title","tr","track","ul"],qg=Pg.HTML_OPEN_CLOSE_TAG_RE,Hg=[[/^<(script|pre|style|textarea)(?=(\s|>|$))/i,/<\/(script|pre|style|textarea)>/i,!0],[/^/,!0],[/^<\?/,/\?>/,!0],[/^/,!0],[/^/,!0],[new RegExp("^|$))","i"),/^$/,!0],[new RegExp(qg.source+"\\s*$"),/^$/,!1]],Gg=g((function(e,t,n,r){var i,o,a,s,l=e.bMarks[t]+e.tShift[t],u=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(!e.md.options.html)return!1;if(60!==e.src.charCodeAt(l))return!1;for(s=e.src.slice(l,u),i=0;i=4)return!1;if(35!==(i=e.src.charCodeAt(l))||l>=u)return!1;for(o=1,i=e.src.charCodeAt(++l);35===i&&l6||ll&&zg(e.src.charCodeAt(a-1))&&(u=a),e.line=t+1,(s=e.push("heading_open","h"+String(o),1)).markup="########".slice(0,o),s.map=[t,e.line],(s=e.push("inline","",0)).content=e.src.slice(l,u).trim(),s.map=[t,e.line],s.children=[],(s=e.push("heading_close","h"+String(o),-1)).markup="########".slice(0,o)),0))}),"heading"),Kg=g((function(e,t,n){var r,i,o,a,s,l,u,c,d,f,p=t+1,h=e.md.block.ruler.getRules("paragraph");if(e.sCount[t]-e.blkIndent>=4)return!1;for(f=e.parentType,e.parentType="paragraph";p3)){if(e.sCount[p]>=e.blkIndent&&(l=e.bMarks[p]+e.tShift[p])<(u=e.eMarks[p])&&(45===(d=e.src.charCodeAt(l))||61===d)&&(l=e.skipChars(l,d),(l=e.skipSpaces(l))>=u)){c=61===d?1:2;break}if(!(e.sCount[p]<0)){for(i=!1,o=0,a=h.length;o3||e.sCount[l]<0)){for(r=!1,i=0,o=u.length;i0&&this.level++,this.tokens.push(r),r},Jg.prototype.isEmpty=g((function(e){return this.bMarks[e]+this.tShift[e]>=this.eMarks[e]}),"isEmpty"),Jg.prototype.skipEmptyLines=g((function(e){for(var t=this.lineMax;et;)if(!Yg(this.src.charCodeAt(--e)))return e+1;return e}),"skipSpacesBack"),Jg.prototype.skipChars=g((function(e,t){for(var n=this.src.length;en;)if(t!==this.src.charCodeAt(--e))return e+1;return e}),"skipCharsBack"),Jg.prototype.getLines=g((function(e,t,n,r){var i,o,a,s,l,u,c,d=e;if(e>=t)return"";for(u=new Array(t-e),i=0;dn?new Array(o-n+1).join(" ")+this.src.slice(s,l):this.src.slice(s,l)}return u.join("")}),"getLines"),Jg.prototype.Token=Xg;var Zg=Jg,ev=Pm,tv=[["table",wg,["paragraph","reference"]],["code",Cg],["fence",Sg,["paragraph","reference","blockquote","list"]],["blockquote",kg,["paragraph","reference","blockquote","list"]],["hr",_g,["paragraph","reference","blockquote","list"]],["list",Ag,["paragraph","reference","blockquote"]],["reference",Fg],["html_block",Gg,["paragraph","reference","blockquote"]],["heading",Wg,["paragraph","reference","blockquote"]],["lheading",Kg],["paragraph",Qg]];function nv(){this.ruler=new ev;for(var e=0;e=n))&&!(e.sCount[a]=l){e.line=n;break}for(r=0;r=0&&32===e.pending.charCodeAt(n)?n>=1&&32===e.pending.charCodeAt(n-1)?(e.pending=e.pending.replace(/ +$/,""),e.push("hardbreak","br",0)):(e.pending=e.pending.slice(0,-1),e.push("softbreak","br",0)):e.push("softbreak","br",0)),i++;i?@[]^_`{|}~-".split("").forEach((function(e){uv[e.charCodeAt(0)]=1}));var dv=g((function(e,t){var n,r=e.pos,i=e.posMax;if(92!==e.src.charCodeAt(r))return!1;if(++r=0;n--)95!==(r=t[n]).marker&&42!==r.marker||-1!==r.end&&(i=t[r.end],s=n>0&&t[n-1].end===r.end+1&&t[n-1].token===r.token-1&&t[r.end+1].token===i.token+1&&t[n-1].marker===r.marker,a=String.fromCharCode(r.marker),(o=e.tokens[r.token]).type=s?"strong_open":"em_open",o.tag=s?"strong":"em",o.nesting=1,o.markup=s?a+a:a,o.content="",(o=e.tokens[i.token]).type=s?"strong_close":"em_close",o.tag=s?"strong":"em",o.nesting=-1,o.markup=s?a+a:a,o.content="",s&&(e.tokens[t[n-1].token].content="",e.tokens[t[r.end+1].token].content="",n--))}mv.tokenize=g((function(e,t){var n,r,i=e.pos,o=e.src.charCodeAt(i);if(t)return!1;if(95!==o&&42!==o)return!1;for(r=e.scanDelims(e.pos,42===o),n=0;n=p)return!1;if(h=s,(l=e.md.helpers.parseLinkDestination(e.src,s,e.posMax)).ok){for(c=e.md.normalizeLink(l.str),e.md.validateLink(c)?s=l.pos:c="",h=s;s=p||41!==e.src.charCodeAt(s))&&(m=!0),s++}if(m){if(void 0===e.env.references)return!1;if(s=0?i=e.src.slice(h,s++):s=o+1):s=o+1,i||(i=e.src.slice(a,o)),!(u=e.env.references[vv(i)]))return e.pos=f,!1;c=u.href,d=u.title}return t||(e.pos=a,e.posMax=o,e.push("link_open","a",1).attrs=n=[["href",c]],d&&n.push(["title",d]),e.md.inline.tokenize(e),e.push("link_close","a",-1)),e.pos=s,e.posMax=p,!0}),"link"),Ev=Wh.normalizeReference,Tv=Wh.isSpace,wv=g((function(e,t){var n,r,i,o,a,s,l,u,c,d,f,p,h,m="",g=e.pos,v=e.posMax;if(33!==e.src.charCodeAt(e.pos))return!1;if(91!==e.src.charCodeAt(e.pos+1))return!1;if(s=e.pos+2,(a=e.md.helpers.parseLinkLabel(e,e.pos+1,!1))<0)return!1;if((l=a+1)=v)return!1;for(h=l,(c=e.md.helpers.parseLinkDestination(e.src,l,e.posMax)).ok&&(m=e.md.normalizeLink(c.str),e.md.validateLink(m)?l=c.pos:m=""),h=l;l=v||41!==e.src.charCodeAt(l))return e.pos=g,!1;l++}else{if(void 0===e.env.references)return!1;if(l=0?o=e.src.slice(h,l++):l=a+1):l=a+1,o||(o=e.src.slice(s,a)),!(u=e.env.references[Ev(o)]))return e.pos=g,!1;m=u.href,d=u.title}return t||(i=e.src.slice(s,a),e.md.inline.parse(i,e.md,e.env,p=[]),(f=e.push("image","img",0)).attrs=n=[["src",m],["alt",""]],f.children=p,f.content=i,d&&n.push(["title",d])),e.pos=l,e.posMax=v,!0}),"image"),Cv=/^([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/,Sv=/^([a-zA-Z][a-zA-Z0-9+.\-]{1,31}):([^<>\x00-\x20]*)$/,xv=g((function(e,t){var n,r,i,o,a,s,l=e.pos;if(60!==e.src.charCodeAt(l))return!1;for(a=e.pos,s=e.posMax;;){if(++l>=s)return!1;if(60===(o=e.src.charCodeAt(l)))return!1;if(62===o)break}return n=e.src.slice(a+1,l),Sv.test(n)?(r=e.md.normalizeLink(n),!!e.md.validateLink(r)&&(t||((i=e.push("link_open","a",1)).attrs=[["href",r]],i.markup="autolink",i.info="auto",(i=e.push("text","",0)).content=e.md.normalizeLinkText(n),(i=e.push("link_close","a",-1)).markup="autolink",i.info="auto"),e.pos+=n.length+2,!0)):!!Cv.test(n)&&(r=e.md.normalizeLink("mailto:"+n),!!e.md.validateLink(r)&&(t||((i=e.push("link_open","a",1)).attrs=[["href",r]],i.markup="autolink",i.info="auto",(i=e.push("text","",0)).content=e.md.normalizeLinkText(n),(i=e.push("link_close","a",-1)).markup="autolink",i.info="auto"),e.pos+=n.length+2,!0))}),"autolink"),kv=Pg.HTML_TAG_RE;function Nv(e){var t=32|e;return t>=97&&t<=122}g(Nv,"isLetter");var _v=g((function(e,t){var n,r,i,o=e.pos;return!(!e.md.options.html||(i=e.posMax,60!==e.src.charCodeAt(o)||o+2>=i||33!==(n=e.src.charCodeAt(o+1))&&63!==n&&47!==n&&!Nv(n)||!(r=e.src.slice(o).match(kv))||(t||(e.push("html_inline","",0).content=e.src.slice(o,o+r[0].length)),e.pos+=r[0].length,0)))}),"html_inline"),Ov=Kh,Iv=Wh.has,Dv=Wh.isValidEntityCode,Lv=Wh.fromCodePoint,Av=/^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i,Mv=/^&([a-z][a-z0-9]{1,31});/i,Rv=g((function(e,t){var n,r,i=e.pos,o=e.posMax;if(38!==e.src.charCodeAt(i))return!1;if(i+1a;r-=o.jump+1)if((o=t[r]).marker===i.marker&&o.open&&o.end<0&&(l=!1,(o.close||i.open)&&(o.length+i.length)%3==0&&(o.length%3==0&&i.length%3==0||(l=!0)),!l)){u=r>0&&!t[r-1].open?t[r-1].jump+1:0,i.jump=n-r+u,i.open=!1,o.end=n,o.jump=u,o.close=!1,s=-1;break}-1!==s&&(c[i.marker][(i.open?3:0)+(i.length||0)%3]=s)}}g(Fv,"processDelimiters");var Pv=g((function(e){var t,n=e.tokens_meta,r=e.tokens_meta.length;for(Fv(0,e.delimiters),t=0;t0&&r++,"text"===i[t].type&&t+10&&(this.level++,this._prev_delimiters.push(this.delimiters),this.delimiters=[],i={delimiters:this.delimiters}),this.pendingLevel=this.level,this.tokens.push(r),this.tokens_meta.push(i),r},qv.prototype.scanDelims=function(e,t){var n,r,i,o,a,s,l,u,c,d=e,f=!0,p=!0,h=this.posMax,m=this.src.charCodeAt(e);for(n=e>0?this.src.charCodeAt(e-1):32;d=o)break}else e.pending+=e.src[e.pos++]}e.pending&&e.pushPending()},Kv.prototype.parse=function(e,t,n,r){var i,o,a,s=new this.State(e,t,n,r);for(this.tokenize(s),a=(o=this.ruler2.getRules("")).length,i=0;i|$))",t.tpl_email_fuzzy='(^|[><|]|"|\\(|'+t.src_ZCc+")("+t.src_email_name+"@"+t.tpl_host_fuzzy_strict+")",t.tpl_link_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`||]|"+t.src_ZPCc+"))((?![$+<=>^`||])"+t.tpl_host_port_fuzzy_strict+t.src_path+")",t.tpl_link_no_ip_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`||]|"+t.src_ZPCc+"))((?![$+<=>^`||])"+t.tpl_host_port_no_ip_fuzzy_strict+t.src_path+")",t}),"re");function Yv(e){return Array.prototype.slice.call(arguments,1).forEach((function(t){t&&Object.keys(t).forEach((function(n){e[n]=t[n]}))})),e}function Jv(e){return Object.prototype.toString.call(e)}function Zv(e){return"[object String]"===Jv(e)}function ey(e){return"[object Object]"===Jv(e)}function ty(e){return"[object RegExp]"===Jv(e)}function ny(e){return"[object Function]"===Jv(e)}function ry(e){return e.replace(/[.?*+^$[\]\\(){}|-]/g,"\\$&")}g(Yv,"assign"),g(Jv,"_class"),g(Zv,"isString"),g(ey,"isObject"),g(ty,"isRegExp"),g(ny,"isFunction"),g(ry,"escapeRE");var iy={fuzzyLink:!0,fuzzyEmail:!0,fuzzyIP:!1};function oy(e){return Object.keys(e||{}).reduce((function(e,t){return e||iy.hasOwnProperty(t)}),!1)}g(oy,"isOptionsObj");var ay={"http:":{validate:function(e,t,n){var r=e.slice(t);return n.re.http||(n.re.http=new RegExp("^\\/\\/"+n.re.src_auth+n.re.src_host_port_strict+n.re.src_path,"i")),n.re.http.test(r)?r.match(n.re.http)[0].length:0}},"https:":"http:","ftp:":"http:","//":{validate:function(e,t,n){var r=e.slice(t);return n.re.no_http||(n.re.no_http=new RegExp("^"+n.re.src_auth+"(?:localhost|(?:(?:"+n.re.src_domain+")\\.)+"+n.re.src_domain_root+")"+n.re.src_port+n.re.src_host_terminator+n.re.src_path,"i")),n.re.no_http.test(r)?t>=3&&":"===e[t-3]||t>=3&&"/"===e[t-3]?0:r.match(n.re.no_http)[0].length:0}},"mailto:":{validate:function(e,t,n){var r=e.slice(t);return n.re.mailto||(n.re.mailto=new RegExp("^"+n.re.src_email_name+"@"+n.re.src_host_strict,"i")),n.re.mailto.test(r)?r.match(n.re.mailto)[0].length:0}}},sy="a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]",ly="biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф".split("|");function uy(e){e.__index__=-1,e.__text_cache__=""}function cy(e){return function(t,n){var r=t.slice(n);return e.test(r)?r.match(e)[0].length:0}}function dy(){return function(e,t){t.normalize(e)}}function fy(e){var t=e.re=Xv(e.__opts__),n=e.__tlds__.slice();function r(e){return e.replace("%TLDS%",t.src_tlds)}e.onCompile(),e.__tlds_replaced__||n.push(sy),n.push(t.src_xn),t.src_tlds=n.join("|"),g(r,"untpl"),t.email_fuzzy=RegExp(r(t.tpl_email_fuzzy),"i"),t.link_fuzzy=RegExp(r(t.tpl_link_fuzzy),"i"),t.link_no_ip_fuzzy=RegExp(r(t.tpl_link_no_ip_fuzzy),"i"),t.host_fuzzy_test=RegExp(r(t.tpl_host_fuzzy_test),"i");var i=[];function o(e,t){throw new Error('(LinkifyIt) Invalid schema "'+e+'": '+t)}e.__compiled__={},g(o,"schemaError"),Object.keys(e.__schemas__).forEach((function(t){var n=e.__schemas__[t];if(null!==n){var r={validate:null,link:null};if(e.__compiled__[t]=r,ey(n))return ty(n.validate)?r.validate=cy(n.validate):ny(n.validate)?r.validate=n.validate:o(t,n),void(ny(n.normalize)?r.normalize=n.normalize:n.normalize?o(t,n):r.normalize=function(e,t){t.normalize(e)});Zv(n)?i.push(t):o(t,n)}})),i.forEach((function(t){e.__compiled__[e.__schemas__[t]]&&(e.__compiled__[t].validate=e.__compiled__[e.__schemas__[t]].validate,e.__compiled__[t].normalize=e.__compiled__[e.__schemas__[t]].normalize)})),e.__compiled__[""]={validate:null,normalize:function(e,t){t.normalize(e)}};var a=Object.keys(e.__compiled__).filter((function(t){return t.length>0&&e.__compiled__[t]})).map(ry).join("|");e.re.schema_test=RegExp("(^|(?!_)(?:[><|]|"+t.src_ZPCc+"))("+a+")","i"),e.re.schema_search=RegExp("(^|(?!_)(?:[><|]|"+t.src_ZPCc+"))("+a+")","ig"),e.re.pretest=RegExp("("+e.re.schema_test.source+")|("+e.re.host_fuzzy_test.source+")|@","i"),uy(e)}function py(e,t){var n=e.__index__,r=e.__last_index__,i=e.__text_cache__.slice(n,r);this.schema=e.__schema__.toLowerCase(),this.index=n+t,this.lastIndex=r+t,this.raw=i,this.text=i,this.url=i}function hy(e,t){var n=new py(e,t);return e.__compiled__[n.schema].normalize(n,e),n}function my(e,t){if(!(this instanceof my))return new my(e,t);t||oy(e)&&(t=e,e={}),this.__opts__=Yv({},iy,t),this.__index__=-1,this.__last_index__=-1,this.__schema__="",this.__text_cache__="",this.__schemas__=Yv({},ay,e),this.__compiled__={},this.__tlds__=ly,this.__tlds_replaced__=!1,this.re={},fy(this)}g(uy,"resetScanCache"),g(cy,"createValidator"),g(dy,"createNormalizer"),g(fy,"compile"),g(py,"Match"),g(hy,"createMatch"),g(my,"LinkifyIt$1"),my.prototype.add=g((function(e,t){return this.__schemas__[e]=t,fy(this),this}),"add"),my.prototype.set=g((function(e){return this.__opts__=Yv(this.__opts__,e),this}),"set"),my.prototype.test=g((function(e){if(this.__text_cache__=e,this.__index__=-1,!e.length)return!1;var t,n,r,i,o,a,s,l;if(this.re.schema_test.test(e))for((s=this.re.schema_search).lastIndex=0;null!==(t=s.exec(e));)if(i=this.testSchemaAt(e,t[2],s.lastIndex)){this.__schema__=t[2],this.__index__=t.index+t[1].length,this.__last_index__=t.index+t[0].length+i;break}return this.__opts__.fuzzyLink&&this.__compiled__["http:"]&&(l=e.search(this.re.host_fuzzy_test))>=0&&(this.__index__<0||l=0&&null!==(r=e.match(this.re.email_fuzzy))&&(o=r.index+r[1].length,a=r.index+r[0].length,(this.__index__<0||othis.__last_index__)&&(this.__schema__="mailto:",this.__index__=o,this.__last_index__=a)),this.__index__>=0}),"test"),my.prototype.pretest=g((function(e){return this.re.pretest.test(e)}),"pretest"),my.prototype.testSchemaAt=g((function(e,t,n){return this.__compiled__[t.toLowerCase()]?this.__compiled__[t.toLowerCase()].validate(e,n,this):0}),"testSchemaAt"),my.prototype.match=g((function(e){var t=0,n=[];this.__index__>=0&&this.__text_cache__===e&&(n.push(hy(this,t)),t=this.__last_index__);for(var r=t?e.slice(t):e;this.test(r);)n.push(hy(this,t)),r=r.slice(this.__last_index__),t+=this.__last_index__;return n.length?n:null}),"match"),my.prototype.tlds=g((function(e,t){return e=Array.isArray(e)?e:[e],t?(this.__tlds__=this.__tlds__.concat(e).sort().filter((function(e,t,n){return e!==n[t-1]})).reverse(),fy(this),this):(this.__tlds__=e.slice(),this.__tlds_replaced__=!0,fy(this),this)}),"tlds"),my.prototype.normalize=g((function(e){e.schema||(e.url="http://"+e.url),"mailto:"!==e.schema||/^mailto:/i.test(e.url)||(e.url="mailto:"+e.url)}),"normalize"),my.prototype.onCompile=g((function(){}),"onCompile");var gy=my;const vy=2147483647,yy=36,by=/^xn--/,Ey=/[^\0-\x7E]/,Ty=/[\x2E\u3002\uFF0E\uFF61]/g,wy={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},Cy=Math.floor,Sy=String.fromCharCode;function xy(e){throw new RangeError(wy[e])}function ky(e,t){const n=[];let r=e.length;for(;r--;)n[r]=t(e[r]);return n}function Ny(e,t){const n=e.split("@");let r="";return n.length>1&&(r=n[0]+"@",e=n[1]),r+ky((e=e.replace(Ty,".")).split("."),t).join(".")}function _y(e){const t=[];let n=0;const r=e.length;for(;n=55296&&i<=56319&&nString.fromCodePoint(...e)),"ucs2encode"),Iy=g((function(e){return e-48<10?e-22:e-65<26?e-65:e-97<26?e-97:yy}),"basicToDigit"),Dy=g((function(e,t){return e+22+75*(e<26)-((0!=t)<<5)}),"digitToBasic"),Ly=g((function(e,t,n){let r=0;for(e=n?Cy(e/700):e>>1,e+=Cy(e/t);e>455;r+=yy)e=Cy(e/35);return Cy(r+36*e/(e+38))}),"adapt"),Ay=g((function(e){const t=[],n=e.length;let r=0,i=128,o=72,a=e.lastIndexOf("-");a<0&&(a=0);for(let n=0;n=128&&xy("not-basic"),t.push(e.charCodeAt(n));for(let s=a>0?a+1:0;s=n&&xy("invalid-input");const a=Iy(e.charCodeAt(s++));(a>=yy||a>Cy((vy-r)/t))&&xy("overflow"),r+=a*t;const l=i<=o?1:i>=o+26?26:i-o;if(aCy(vy/u)&&xy("overflow"),t*=u}const l=t.length+1;o=Ly(r-a,l,0==a),Cy(r/l)>vy-i&&xy("overflow"),i+=Cy(r/l),r%=l,t.splice(r++,0,i)}return String.fromCodePoint(...t)}),"decode"),My=g((function(e){const t=[];let n=(e=_y(e)).length,r=128,i=0,o=72;for(const n of e)n<128&&t.push(Sy(n));let a=t.length,s=a;for(a&&t.push("-");s=r&&tCy((vy-i)/l)&&xy("overflow"),i+=(n-r)*l,r=n;for(const n of e)if(nvy&&xy("overflow"),n==r){let e=i;for(let n=yy;;n+=yy){const r=n<=o?1:n>=o+26?26:n-o;if(e=0))try{t.hostname=Wy.toASCII(t.hostname)}catch(e){}return zy.encode(zy.format(t))}function eb(e){var t=zy.parse(e,!0);if(t.hostname&&(!t.protocol||Jy.indexOf(t.protocol)>=0))try{t.hostname=Wy.toUnicode(t.hostname)}catch(e){}return zy.decode(zy.format(t),zy.decode.defaultChars+"%")}function tb(e,t){if(!(this instanceof tb))return new tb(e,t);t||Vy.isString(e)||(t=e||{},e="default"),this.inline=new Hy,this.block=new qy,this.core=new $y,this.renderer=new By,this.linkify=new Gy,this.validateLink=Yy,this.normalizeLink=Zy,this.normalizeLinkText=eb,this.utils=Vy,this.helpers=Vy.assign({},Uy),this.options={},this.configure(e),t&&this.set(t)}g(Zy,"normalizeLink"),g(eb,"normalizeLinkText"),g(tb,"MarkdownIt"),tb.prototype.set=function(e){return Vy.assign(this.options,e),this},tb.prototype.configure=function(e){var t,n=this;if(Vy.isString(e)&&!(e=Ky[t=e]))throw new Error('Wrong `markdown-it` preset "'+t+'", check name');if(!e)throw new Error("Wrong `markdown-it` preset, can't be empty");return e.options&&n.set(e.options),e.components&&Object.keys(e.components).forEach((function(t){e.components[t].rules&&n[t].ruler.enableOnly(e.components[t].rules),e.components[t].rules2&&n[t].ruler2.enableOnly(e.components[t].rules2)})),this},tb.prototype.enable=function(e,t){var n=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach((function(t){n=n.concat(this[t].ruler.enable(e,!0))}),this),n=n.concat(this.inline.ruler2.enable(e,!0));var r=e.filter((function(e){return n.indexOf(e)<0}));if(r.length&&!t)throw new Error("MarkdownIt. Failed to enable unknown rule(s): "+r);return this},tb.prototype.disable=function(e,t){var n=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach((function(t){n=n.concat(this[t].ruler.disable(e,!0))}),this),n=n.concat(this.inline.ruler2.disable(e,!0));var r=e.filter((function(e){return n.indexOf(e)<0}));if(r.length&&!t)throw new Error("MarkdownIt. Failed to disable unknown rule(s): "+r);return this},tb.prototype.use=function(e){var t=[this].concat(Array.prototype.slice.call(arguments,1));return e.apply(e,t),this},tb.prototype.parse=function(e,t){if("string"!=typeof e)throw new Error("Input data should be a String");var n=new this.core.State(e,this,t);return this.core.process(n),n.tokens},tb.prototype.render=function(e,t){return t=t||{},this.renderer.render(this.parse(e,t),this.options,t)},tb.prototype.parseInline=function(e,t){var n=new this.core.State(e,this,t);return n.inlineMode=!0,this.core.process(n),n.tokens},tb.prototype.renderInline=function(e,t){return t=t||{},this.renderer.render(this.parseInline(e,t),this.options,t)};const nb=new tb({breaks:!0,linkify:!0}),rb=(0,t.forwardRef)(((e,t)=>{var n=e,{children:r,onlyShowFirstChild:i,type:o}=n,a=v(n,["children","onlyShowFirstChild","type"]);return de("div",m(h({},a),{ref:t,className:b(`graphiql-markdown-${o}`,i&&"graphiql-markdown-preview",a.className),dangerouslySetInnerHTML:{__html:nb.render(r)}}))}));e.aM=rb,rb.displayName="MarkdownContent";const ib=(0,t.forwardRef)(((e,t)=>de("div",m(h({},e),{ref:t,className:b("graphiql-spinner",e.className)}))));function ob(e){var t,n,r=ms(e),i=r.defaultView||window;return r?{width:null!=(t=r.documentElement.clientWidth)?t:i.innerWidth,height:null!=(n=r.documentElement.clientHeight)?n:i.innerHeight}:{width:0,height:0}}function ab(){return ab=Object.assign||function(e){for(var t=1;t=0||(i[n]=e[n]);return i}e.aN=ib,ib.displayName="Spinner",g(ob,"getDocumentDimensions"),g(ab,"_extends$1"),g(sb,"_objectWithoutPropertiesLoose$1");var lb,ub,cb,db,fb,pb,hb,mb,gb,vb,yb=["children","label","ariaLabel","id","DEBUG_STYLE"],bb=["label","ariaLabel","isVisible","id"],Eb=["ariaLabel","aria-label","as","id","isVisible","label","position","style","triggerRect"],Tb=["type"],wb=100,Cb=500;(vb=hb||(hb={})).Idle="IDLE",vb.Focused="FOCUSED",vb.Visible="VISIBLE",vb.LeavingVisible="LEAVING_VISIBLE",vb.Dismissed="DISMISSED",(gb=mb||(mb={})).Blur="BLUR",gb.Focus="FOCUS",gb.GlobalMouseMove="GLOBAL_MOUSE_MOVE",gb.MouseDown="MOUSE_DOWN",gb.MouseEnter="MOUSE_ENTER",gb.MouseLeave="MOUSE_LEAVE",gb.MouseMove="MOUSE_MOVE",gb.Rest="REST",gb.SelectWithKeyboard="SELECT_WITH_KEYBOARD",gb.TimeComplete="TIME_COMPLETE";var Sb,xb,kb={initial:hb.Idle,states:(pb={},pb[hb.Idle]={enter:Rb,on:(lb={},lb[mb.MouseEnter]=hb.Focused,lb[mb.Focus]=hb.Visible,lb)},pb[hb.Focused]={enter:Db,leave:Lb,on:(ub={},ub[mb.MouseMove]=hb.Focused,ub[mb.MouseLeave]=hb.Idle,ub[mb.MouseDown]=hb.Dismissed,ub[mb.Blur]=hb.Idle,ub[mb.Rest]=hb.Visible,ub)},pb[hb.Visible]={on:(cb={},cb[mb.Focus]=hb.Focused,cb[mb.MouseEnter]=hb.Focused,cb[mb.MouseLeave]=hb.LeavingVisible,cb[mb.Blur]=hb.LeavingVisible,cb[mb.MouseDown]=hb.Dismissed,cb[mb.SelectWithKeyboard]=hb.Dismissed,cb[mb.GlobalMouseMove]=hb.LeavingVisible,cb)},pb[hb.LeavingVisible]={enter:Ab,leave:g((function(){Mb(),Rb()}),"leave"),on:(db={},db[mb.MouseEnter]=hb.Visible,db[mb.Focus]=hb.Visible,db[mb.TimeComplete]=hb.Idle,db)},pb[hb.Dismissed]={leave:g((function(){Rb()}),"leave"),on:(fb={},fb[mb.MouseLeave]=hb.Idle,fb[mb.Blur]=hb.Idle,fb)},pb)},Nb={value:kb.initial,context:{id:null}},_b=[];function Ob(e){return _b.push(e),function(){_b.splice(_b.indexOf(e),1)}}function Ib(){_b.forEach((function(e){return e(Nb)}))}function Db(){window.clearTimeout(Sb),Sb=window.setTimeout((function(){qb({type:mb.Rest})}),wb)}function Lb(){window.clearTimeout(Sb)}function Ab(){window.clearTimeout(xb),xb=window.setTimeout((function(){return qb({type:mb.TimeComplete})}),Cb)}function Mb(){window.clearTimeout(xb)}function Rb(){Nb.context.id=null}function Fb(e){var n=void 0===e?{}:e,r=n.id,i=n.onPointerEnter,o=n.onPointerMove,a=n.onPointerLeave,s=n.onPointerDown,l=n.onMouseEnter,u=n.onMouseMove,c=n.onMouseLeave,d=n.onMouseDown,f=n.onFocus,p=n.onBlur,h=n.onKeyDown,m=n.disabled,v=n.ref,y=n.DEBUG_STYLE,b=String(rd(r)),E=(0,t.useState)(!!y||Gb(b,!0)),T=E[0],w=E[1],C=(0,t.useRef)(null),S=Ss(v,C),x=cd(C,{observe:T});function k(e,t){return"undefined"!=typeof window&&"PointerEvent"in window?e:xs(e,t)}function N(e){return g((function(t){"mouse"===t.pointerType&&e(t)}),"onPointerEvent")}function _(){qb({type:mb.MouseEnter,id:b})}function O(){qb({type:mb.MouseMove,id:b})}function I(){qb({type:mb.MouseLeave})}function D(){Nb.context.id===b&&qb({type:mb.MouseDown})}function L(){window.__REACH_DISABLE_TOOLTIPS||qb({type:mb.Focus,id:b})}function A(){Nb.context.id===b&&qb({type:mb.Blur})}function M(e){"Enter"!==e.key&&" "!==e.key||qb({type:mb.SelectWithKeyboard})}return(0,t.useEffect)((function(){return Ob((function(){w(Gb(b))}))}),[b]),(0,t.useEffect)((function(){var e=ms(C.current);function t(e){"Escape"!==e.key&&"Esc"!==e.key||Nb.value!==hb.Visible||qb({type:mb.SelectWithKeyboard})}return g(t,"listener"),e.addEventListener("keydown",t),function(){return e.removeEventListener("keydown",t)}}),[]),$b({disabled:m,isVisible:T,ref:C}),g(k,"wrapMouseEvent"),g(N,"wrapPointerEventHandler"),g(_,"handleMouseEnter"),g(O,"handleMouseMove"),g(I,"handleMouseLeave"),g(D,"handleMouseDown"),g(L,"handleFocus"),g(A,"handleBlur"),g(M,"handleKeyDown"),[{"aria-describedby":T?lf("tooltip",b):void 0,"data-state":T?"tooltip-visible":"tooltip-hidden","data-reach-tooltip-trigger":"",ref:S,onPointerEnter:xs(i,N(_)),onPointerMove:xs(o,N(O)),onPointerLeave:xs(a,N(I)),onPointerDown:xs(s,N(D)),onMouseEnter:k(l,_),onMouseMove:k(u,O),onMouseLeave:k(c,I),onMouseDown:k(d,D),onFocus:xs(f,L),onBlur:xs(p,A),onKeyDown:xs(h,M)},{id:b,triggerRect:x,isVisible:T},T]}g(Ob,"subscribe"),g(Ib,"notify"),g(Db,"startRestTimer"),g(Lb,"clearRestTimer"),g(Ab,"startLeavingVisibleTimer"),g(Mb,"clearLeavingVisibleTimer"),g(Rb,"clearContextId"),g(Fb,"useTooltip");var Pb=(0,t.forwardRef)((function(e,n){var r=e.children,i=e.label,o=e.ariaLabel,a=e.id,s=e.DEBUG_STYLE,l=sb(e,yb),u=t.Children.only(r),c=Fb({id:a,onPointerEnter:u.props.onPointerEnter,onPointerMove:u.props.onPointerMove,onPointerLeave:u.props.onPointerLeave,onPointerDown:u.props.onPointerDown,onMouseEnter:u.props.onMouseEnter,onMouseMove:u.props.onMouseMove,onMouseLeave:u.props.onMouseLeave,onMouseDown:u.props.onMouseDown,onFocus:u.props.onFocus,onBlur:u.props.onBlur,onKeyDown:u.props.onKeyDown,disabled:u.props.disabled,ref:u.ref,DEBUG_STYLE:s}),d=c[0],f=c[1];return(0,t.createElement)(t.Fragment,null,(0,t.cloneElement)(u,d),(0,t.createElement)(jb,ab({ref:n,label:i,"aria-label":o},f,l)))}));e.aQ=Pb;var jb=(0,t.forwardRef)(g((function(e,n){var r=e.label,i=e.ariaLabel,o=e.isVisible,a=e.id,s=sb(e,bb);return o?(0,t.createElement)(hs,null,(0,t.createElement)(Vb,ab({ref:n,label:r,"aria-label":i,isVisible:o},s,{id:lf("tooltip",String(a))}))):null}),"TooltipPopup")),Vb=(0,t.forwardRef)(g((function(e,n){var r=e.ariaLabel,i=e["aria-label"],o=e.as,a=void 0===o?"div":o,s=e.id,l=e.isVisible,u=e.label,c=e.position,d=void 0===c?Bb:c,f=e.style,p=e.triggerRect,h=sb(e,Eb),m=null!=(i||r),g=(0,t.useRef)(null),v=Ss(n,g),y=cd(g,{observe:l});return(0,t.createElement)(t.Fragment,null,(0,t.createElement)(a,ab({role:m?void 0:"tooltip"},h,{ref:v,"data-reach-tooltip":"",id:m?void 0:s,style:ab({},f,Ub(d,p,y))}),u),m&&(0,t.createElement)(Kc,{role:"tooltip",id:s},i||r))}),"TooltipContent"));function Ub(e,t,n){return n?e(t,n):{visibility:"hidden"}}g(Ub,"getStyles");var Bb=g((function(e,t,n){void 0===n&&(n=8);var r=ob(),i=r.width,o=r.height;if(!e||!t)return{};var a={top:e.top-t.height<0,right:i{var n=e,{isActive:r}=n,i=v(n,["isActive"]);return de("div",m(h({},i),{ref:t,role:"tab","aria-selected":r,className:b("graphiql-tab",r&&"graphiql-tab-active",i.className),children:i.children}))}));zb.displayName="Tab";const Wb=(0,t.forwardRef)(((e,t)=>de(os,m(h({},e),{ref:t,type:"button",className:b("graphiql-tab-button",e.className),children:e.children}))));Wb.displayName="Tab.Button";const Kb=(0,t.forwardRef)(((e,t)=>de(Pb,{label:"Close Tab",children:de(os,m(h({"aria-label":"Close Tab"},e),{ref:t,type:"button",className:b("graphiql-tab-close",e.className),children:de(La,{})}))})));Kb.displayName="Tab.Close";const Qb=Xc(zb,{Button:Wb,Close:Kb});e.aO=Qb;const Xb=(0,t.forwardRef)(((e,t)=>de("div",m(h({},e),{ref:t,role:"tablist",className:b("graphiql-tabs",e.className),children:e.children}))));e.aP=Xb,Xb.displayName="Tabs";var Yb=Object.defineProperty,Jb=g(((e,t)=>Yb(e,"name",{value:t,configurable:!0})),"__name$C");const Zb=X("HistoryContext");function eE(e){var n;const r=ye(),i=(0,t.useRef)(new W(r||new H(null),e.maxHistoryLength||nE)),[o,a]=(0,t.useState)((null==(n=i.current)?void 0:n.queries)||[]),s=(0,t.useCallback)((e=>{let{query:t,variables:n,headers:r,operationName:o}=e;var s;null==(s=i.current)||s.updateHistory(t,n,r,o),a(i.current.queries)}),[]),l=(0,t.useCallback)((e=>{let{query:t,variables:n,headers:r,operationName:o,label:s,favorite:l}=e;i.current.editLabel(t,n,r,o,s,l),a(i.current.queries)}),[]),u=(0,t.useCallback)((e=>{let{query:t,variables:n,headers:r,operationName:o,label:s,favorite:l}=e;i.current.toggleFavorite(t,n,r,o,s,l),a(i.current.queries)}),[]),c=(0,t.useMemo)((()=>({addToHistory:s,editLabel:l,items:o,toggleFavorite:u})),[s,l,o,u]);return de(Zb.Provider,{value:c,children:e.children})}e.X=Zb,g(eE,"HistoryContextProvider"),Jb(eE,"HistoryContextProvider");const tE=Y(Zb);e.Z=tE;const nE=20;var rE=Object.defineProperty,iE=g(((e,t)=>rE(e,"name",{value:t,configurable:!0})),"__name$B");function oE(){const{items:e}=tE({nonNull:!0}),n=e.slice().reverse();return fe("section",{"aria-label":"History",className:"graphiql-history",children:[de("div",{className:"graphiql-history-header",children:"History"}),de("ul",{className:"graphiql-history-items",children:n.map(((e,r)=>fe(t.Fragment,{children:[de(aE,{item:e}),e.favorite&&n[r+1]&&!n[r+1].favorite?de("div",{className:"graphiql-history-item-spacer"}):null]},`${r}:${e.label||e.query}`)))})]})}function aE(e){const{editLabel:n,toggleFavorite:r}=tE({nonNull:!0,caller:aE}),{headerEditor:i,queryEditor:o,variableEditor:a}=oS({nonNull:!0,caller:aE}),s=(0,t.useRef)(null),l=(0,t.useRef)(null),[u,c]=(0,t.useState)(!1);(0,t.useEffect)((()=>{u&&s.current&&s.current.focus()}),[u]);const d=e.item.label||e.item.operationName||sE(e.item.query);return de("li",{className:b("graphiql-history-item",u&&"editable"),children:fe(pe,u?{children:[de("input",{type:"text",defaultValue:e.item.label,ref:s,onKeyDown:t=>{"Esc"===t.key?c(!1):"Enter"===t.key&&(c(!1),n(m(h({},e.item),{label:t.currentTarget.value})))},placeholder:"Type a label"}),de(os,{type:"button",ref:l,onClick:()=>{var t;c(!1),n(m(h({},e.item),{label:null==(t=s.current)?void 0:t.value}))},children:"Save"}),de(os,{type:"button",ref:l,onClick:()=>{c(!1)},children:de(La,{})})]}:{children:[de(os,{type:"button",className:"graphiql-history-item-label",onClick:()=>{var t,n,r;null==o||o.setValue(null!=(t=e.item.query)?t:""),null==a||a.setValue(null!=(n=e.item.variables)?n:""),null==i||i.setValue(null!=(r=e.item.headers)?r:"")},children:d}),de(Pb,{label:"Edit label",children:de(os,{type:"button",className:"graphiql-history-item-action",onClick:e=>{e.stopPropagation(),c(!0)},"aria-label":"Edit label",children:de(Wa,{"aria-hidden":"true"})})}),de(Pb,{label:e.item.favorite?"Remove favorite":"Add favorite",children:de(os,{type:"button",className:"graphiql-history-item-action",onClick:t=>{t.stopPropagation(),r(e.item)},"aria-label":e.item.favorite?"Remove favorite":"Add favorite",children:e.item.favorite?de(es,{"aria-hidden":"true"}):de(ts,{"aria-hidden":"true"})})})]})})}function sE(e){return null==e?void 0:e.split("\n").map((e=>e.replace(/#(.*)/,""))).join(" ").replaceAll("{"," { ").replaceAll("}"," } ").replaceAll(/[\s]{2,}/g," ")}g(oE,"History"),iE(oE,"History"),g(aE,"HistoryItem"),iE(aE,"HistoryItem"),g(sE,"formatQuery"),iE(sE,"formatQuery");var lE=Object.defineProperty,uE=g(((e,t)=>lE(e,"name",{value:t,configurable:!0})),"__name$A");const cE=X("ExecutionContext");function dE(e){let{fetcher:n,getDefaultFieldNames:i,children:o,operationName:a}=e;if(!n)throw new TypeError("The `ExecutionContextProvider` component requires a `fetcher` function to be passed as prop.");const{externalFragments:s,headerEditor:l,queryEditor:u,responseEditor:c,variableEditor:d,updateActiveTabValues:f}=oS({nonNull:!0,caller:dE}),p=tE(),m=fC({getDefaultFieldNames:i,caller:dE}),[g,y]=(0,t.useState)(!1),[b,E]=(0,t.useState)(null),T=(0,t.useRef)(0),w=(0,t.useCallback)((()=>{null==b||b.unsubscribe(),y(!1),E(null)}),[b]),x=(0,t.useCallback)((async()=>{var e,t;if(!u||!c)return;if(b)return void w();const i=uE((e=>{c.setValue(e),f({response:e})}),"setResponse");T.current+=1;const o=T.current;let g=m()||u.getValue();const x=null==d?void 0:d.getValue();let k;try{k=pE({json:x,errorMessageParse:"Variables are invalid JSON",errorMessageType:"Variables are not a JSON object."})}catch(e){return void i(e instanceof Error?e.message:`${e}`)}const N=null==l?void 0:l.getValue();let _;try{_=pE({json:N,errorMessageParse:"Headers are invalid JSON",errorMessageType:"Headers are not a JSON object."})}catch(e){return void i(e instanceof Error?e.message:`${e}`)}if(s){const e=u.documentAST?_o(u.documentAST,s):[];e.length>0&&(g+="\n"+e.map((e=>(0,r.print)(e))).join("\n"))}i(""),y(!0);const O=null!=(e=null!=a?a:u.operationName)?e:void 0;null==p||p.addToHistory({query:g,variables:x,headers:N,operationName:O});try{let e={data:{}};const r=uE((t=>{if(o!==T.current)return;let n=!!Array.isArray(t)&&t;if(!n&&"object"==typeof t&&null!==t&&"hasNext"in t&&(n=[t]),n){const t={data:e.data},r=[...(null==e?void 0:e.errors)||[],...n.flatMap((e=>e.errors)).filter(Boolean)];r.length&&(t.errors=r);for(const r of n){const n=r,{path:i,data:o,errors:a}=n,s=v(n,["path","data","errors"]);if(i){if(!o)throw new Error(`Expected part to contain a data property, but got ${r}`);Qo(t.data,i,o,{merge:!0})}else o&&(t.data=o);e=h(h({},t),s)}y(!1),i(L(e))}else{const e=L(t);y(!1),i(e)}}),"handleResponse"),a=n({query:g,variables:k,operationName:O},{headers:null!=_?_:void 0,documentAST:null!=(t=u.documentAST)?t:void 0}),s=await Promise.resolve(a);if(C(s))E(s.subscribe({next(e){r(e)},error(e){y(!1),e&&i(D(e)),E(null)},complete(){y(!1),E(null)}}));else if(S(s)){E({unsubscribe:()=>{var e,t;return null==(t=(e=s[Symbol.asyncIterator]()).return)?void 0:t.call(e)}});for await(const e of s)r(e);y(!1),E(null)}else r(s)}catch(e){y(!1),i(D(e)),E(null)}}),[m,s,n,l,p,a,u,c,w,b,f,d]),k=Boolean(b),N=(0,t.useMemo)((()=>({isFetching:g,isSubscribed:k,operationName:null!=a?a:null,run:x,stop:w})),[g,k,a,x,w]);return de(cE.Provider,{value:N,children:o})}e.r=cE,g(dE,"ExecutionContextProvider"),uE(dE,"ExecutionContextProvider");const fE=Y(cE);function pE(e){let t,{json:n,errorMessageParse:r,errorMessageType:i}=e;try{t=n&&""!==n.trim()?JSON.parse(n):void 0}catch(e){throw new Error(`${r}: ${e instanceof Error?e.message:e}.`)}const o="object"==typeof t&&null!==t&&!Array.isArray(t);if(void 0!==t&&!o)throw new Error(i);return t}e.v=fE,g(pE,"tryParseJsonObject"),uE(pE,"tryParseJsonObject");var hE=Object.defineProperty,mE=g(((e,t)=>hE(e,"name",{value:t,configurable:!0})),"__name$z");const gE="graphiql",vE="sublime";let yE=!1;"object"==typeof window&&(yE=0===window.navigator.platform.toLowerCase().indexOf("mac"));const bE={[yE?"Cmd-F":"Ctrl-F"]:"findPersistent","Cmd-G":"findPersistent","Ctrl-G":"findPersistent","Ctrl-Left":"goSubwordLeft","Ctrl-Right":"goSubwordRight","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight"};async function EE(e,t){const r=await Promise.resolve().then(n.t.bind(n,535,23)).then((function(e){return e.c})).then((e=>"function"==typeof e?e:e.default));return await Promise.all(!1===(null==t?void 0:t.useCommonAddons)?e:[Promise.resolve().then(n.t.bind(n,6980,23)).then((function(e){return e.s})),Promise.resolve().then(n.t.bind(n,9171,23)).then((function(e){return e.m})),Promise.resolve().then(n.t.bind(n,5728,23)).then((function(e){return e.c})),Promise.resolve().then(n.t.bind(n,4468,23)).then((function(e){return e.b})),Promise.resolve().then(n.t.bind(n,8419,23)).then((function(e){return e.f})),Promise.resolve().then(n.t.bind(n,4054,23)).then((function(e){return e.l})),Promise.resolve().then(n.t.bind(n,9407,23)).then((function(e){return e.s})),Promise.resolve().then(n.t.bind(n,4471,23)).then((function(e){return e.j})),Promise.resolve().then(n.t.bind(n,8058,23)).then((function(e){return e.d})),Promise.resolve().then(n.t.bind(n,2568,23)).then((function(e){return e.s})),...e]),r}g(EE,"importCodeMirror"),mE(EE,"importCodeMirror");var TE=g((function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;rNE(e,"name",{value:t,configurable:!0})),"__name$y");const OE=_E((e=>e?(0,r.print)(e):""),"printDefault");function IE(e){let{field:t}=e;if(!("defaultValue"in t)||void 0===t.defaultValue)return null;const n=(0,r.astFromValue)(t.defaultValue,t.type);return n?fe(pe,{children:[" = ",de("span",{className:"graphiql-doc-explorer-default-value",children:OE(n)})]}):null}g(IE,"DefaultValue"),_E(IE,"DefaultValue");var DE=Object.defineProperty,LE=g(((e,t)=>DE(e,"name",{value:t,configurable:!0})),"__name$x");const AE=X("SchemaContext");function ME(e){if(!e.fetcher)throw new TypeError("The `SchemaContextProvider` component requires a `fetcher` function to be passed as prop.");const{initialHeaders:n,headerEditor:i}=oS({nonNull:!0,caller:ME}),[o,a]=(0,t.useState)(),[s,l]=(0,t.useState)(!1),[u,c]=(0,t.useState)(null),d=(0,t.useRef)(0);(0,t.useEffect)((()=>{a((0,r.isSchema)(e.schema)||null===e.schema||void 0===e.schema?e.schema:void 0),d.current++}),[e.schema]);const f=(0,t.useRef)(n);(0,t.useEffect)((()=>{i&&(f.current=i.getValue())}));const{introspectionQuery:p,introspectionQueryName:h,introspectionQuerySansSubscriptions:m}=FE({inputValueDeprecation:e.inputValueDeprecation,introspectionQueryName:e.introspectionQueryName,schemaDescription:e.schemaDescription}),{fetcher:v,onSchemaChange:y,dangerouslyAssumeSchemaIsValid:b,children:E}=e,w=(0,t.useCallback)((()=>{if((0,r.isSchema)(e.schema)||null===e.schema)return;const t=++d.current,n=e.schema;async function i(){if(n)return n;const e=PE(f.current);if(!e.isValidJSON)return void c("Introspection failed as headers are invalid.");const t=e.headers?{headers:e.headers}:{},r=k(v({query:p,operationName:h},t));if(!T(r))return void c("Fetcher did not return a Promise for introspection.");l(!0),c(null);let i=await r;if("object"!=typeof i||null===i||!("data"in i)){const e=k(v({query:m,operationName:h},t));if(!T(e))throw new Error("Fetcher did not return a Promise for introspection.");i=await e}if(l(!1),(null==i?void 0:i.data)&&"__schema"in i.data)return i.data;const o="string"==typeof i?i:L(i);c(o)}g(i,"fetchIntrospectionData"),LE(i,"fetchIntrospectionData"),i().then((e=>{if(t===d.current&&e)try{const t=(0,r.buildClientSchema)(e);a(t),null==y||y(t)}catch(e){c(D(e))}})).catch((e=>{t===d.current&&(c(D(e)),l(!1))}))}),[v,h,p,m,y,e.schema]);(0,t.useEffect)((()=>{w()}),[w]),(0,t.useEffect)((()=>{function e(e){e.ctrlKey&&"R"===e.key&&w()}return g(e,"triggerIntrospection"),LE(e,"triggerIntrospection"),window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)}));const C=(0,t.useMemo)((()=>!o||b?[]:(0,r.validateSchema)(o)),[o,b]),S=(0,t.useMemo)((()=>({fetchError:u,introspect:w,isFetching:s,schema:o,validationErrors:C})),[u,w,s,o,C]);return de(AE.Provider,{value:S,children:E})}e.a4=AE,g(ME,"SchemaContextProvider"),LE(ME,"SchemaContextProvider");const RE=Y(AE);function FE(e){let{inputValueDeprecation:n,introspectionQueryName:i,schemaDescription:o}=e;return(0,t.useMemo)((()=>{const e=i||"IntrospectionQuery";let t=(0,r.getIntrospectionQuery)({inputValueDeprecation:n,schemaDescription:o});i&&(t=t.replace("query IntrospectionQuery",`query ${e}`));const a=t.replace("subscriptionType { name }","");return{introspectionQueryName:e,introspectionQuery:t,introspectionQuerySansSubscriptions:a}}),[n,i,o])}function PE(e){let t=null,n=!0;try{e&&(t=JSON.parse(e))}catch{n=!1}return{headers:t,isValidJSON:n}}e.a6=RE,g(FE,"useIntrospectionQuery"),LE(FE,"useIntrospectionQuery"),g(PE,"parseHeaderString"),LE(PE,"parseHeaderString");var jE=Object.defineProperty,VE=g(((e,t)=>jE(e,"name",{value:t,configurable:!0})),"__name$w");const UE={name:"Docs"},BE=X("ExplorerContext");function $E(e){const{schema:n,validationErrors:i}=RE({nonNull:!0,caller:$E}),[o,a]=(0,t.useState)([UE]),s=(0,t.useCallback)((e=>{a((t=>t.at(-1).def===e.def?t:[...t,e]))}),[]),l=(0,t.useCallback)((()=>{a((e=>e.length>1?e.slice(0,-1):e))}),[]),u=(0,t.useCallback)((()=>{a((e=>1===e.length?e:[UE]))}),[]);(0,t.useEffect)((()=>{null==n||i.length>0?u():a((e=>{if(1===e.length)return e;const t=[UE];let i=null;for(const o of e)if(o!==UE)if(o.def)if((0,r.isNamedType)(o.def)){const e=n.getType(o.def.name);if(!e)break;t.push({name:o.name,def:e}),i=e}else{if(null===i)break;if((0,r.isObjectType)(i)||(0,r.isInputObjectType)(i)){const e=i.getFields()[o.name];if(!e)break;t.push({name:o.name,def:e})}else{if((0,r.isScalarType)(i)||(0,r.isEnumType)(i)||(0,r.isInterfaceType)(i)||(0,r.isUnionType)(i))break;{const e=i;if(!e.args.find((e=>e.name===o.name)))break;t.push({name:o.name,def:e})}}}else i=null,t.push(o);return t}))}),[u,n,i]);const c=(0,t.useMemo)((()=>({explorerNavStack:o,push:s,pop:l,reset:u})),[o,s,l,u]);return de(BE.Provider,{value:c,children:e.children})}e.z=BE,g($E,"ExplorerContextProvider"),VE($E,"ExplorerContextProvider");const qE=Y(BE);e.U=qE;var HE=Object.defineProperty,GE=g(((e,t)=>HE(e,"name",{value:t,configurable:!0})),"__name$v");function zE(e,t){return(0,r.isNonNullType)(e)?fe(pe,{children:[zE(e.ofType,t),"!"]}):(0,r.isListType)(e)?fe(pe,{children:["[",zE(e.ofType,t),"]"]}):t(e)}g(zE,"renderType"),GE(zE,"renderType");var WE=Object.defineProperty,KE=g(((e,t)=>WE(e,"name",{value:t,configurable:!0})),"__name$u");function QE(e){const{push:t}=qE({nonNull:!0,caller:QE});return e.type?zE(e.type,(e=>de("a",{className:"graphiql-doc-explorer-type-name",onClick:n=>{n.preventDefault(),t({name:e.name,def:e})},href:"#",children:e.name}))):null}g(QE,"TypeLink"),KE(QE,"TypeLink");var XE=Object.defineProperty,YE=g(((e,t)=>XE(e,"name",{value:t,configurable:!0})),"__name$t");function JE(e){let{arg:t,showDefaultValue:n,inline:r}=e;const i=fe("span",{children:[de("span",{className:"graphiql-doc-explorer-argument-name",children:t.name}),": ",de(QE,{type:t.type}),!1!==n&&de(IE,{field:t})]});return r?i:fe("div",{className:"graphiql-doc-explorer-argument",children:[i,t.description?de(rb,{type:"description",children:t.description}):null,t.deprecationReason?fe("div",{className:"graphiql-doc-explorer-argument-deprecation",children:[de("div",{className:"graphiql-doc-explorer-argument-deprecation-label",children:"Deprecated"}),de(rb,{type:"deprecation",children:t.deprecationReason})]}):null]})}g(JE,"Argument"),YE(JE,"Argument");var ZE=Object.defineProperty,eT=g(((e,t)=>ZE(e,"name",{value:t,configurable:!0})),"__name$s");function tT(e){return e.children?fe("div",{className:"graphiql-doc-explorer-deprecation",children:[de("div",{className:"graphiql-doc-explorer-deprecation-label",children:"Deprecated"}),de(rb,{type:"deprecation",onlyShowFirstChild:!0,children:e.children})]}):null}g(tT,"DeprecationReason"),eT(tT,"DeprecationReason");var nT=Object.defineProperty,rT=g(((e,t)=>nT(e,"name",{value:t,configurable:!0})),"__name$r");function iT(e){let{directive:t}=e;return fe("span",{className:"graphiql-doc-explorer-directive",children:["@",t.name.value]})}g(iT,"Directive"),rT(iT,"Directive");var oT=Object.defineProperty,aT=g(((e,t)=>oT(e,"name",{value:t,configurable:!0})),"__name$q");function sT(e){const t=lT[e.title];return fe("div",{children:[fe("div",{className:"graphiql-doc-explorer-section-title",children:[de(t,{}),e.title]}),de("div",{className:"graphiql-doc-explorer-section-content",children:e.children})]})}g(sT,"ExplorerSection"),aT(sT,"ExplorerSection");const lT={Arguments:_a,"Deprecated Arguments":Ma,"Deprecated Enum Values":Ra,"Deprecated Fields":Fa,Directives:Pa,"Enum Values":Ua,Fields:Ba,Implements:qa,Implementations:rs,"Possible Types":rs,"Root Types":Ja,Type:rs,"All Schema Types":rs};var uT=Object.defineProperty,cT=g(((e,t)=>uT(e,"name",{value:t,configurable:!0})),"__name$p");function dT(e){return fe(pe,{children:[e.field.description?de(rb,{type:"description",children:e.field.description}):null,de(tT,{children:e.field.deprecationReason}),de(sT,{title:"Type",children:de(QE,{type:e.field.type})}),de(fT,{field:e.field}),de(pT,{field:e.field})]})}function fT(e){let{field:n}=e;const[r,i]=(0,t.useState)(!1);if(!("args"in n))return null;const o=[],a=[];for(const e of n.args)e.deprecationReason?a.push(e):o.push(e);return fe(pe,{children:[o.length>0?de(sT,{title:"Arguments",children:o.map((e=>de(JE,{arg:e},e.name)))}):null,a.length>0?r||0===o.length?de(sT,{title:"Deprecated Arguments",children:a.map((e=>de(JE,{arg:e},e.name)))}):de(as,{type:"button",onClick:()=>{i(!0)},children:"Show Deprecated Arguments"}):null]})}function pT(e){let{field:t}=e;var n;const r=(null==(n=t.astNode)?void 0:n.directives)||[];return r&&0!==r.length?de(sT,{title:"Directives",children:r.map((e=>de("div",{children:de(iT,{directive:e})},e.name.value)))}):null}g(dT,"FieldDocumentation"),cT(dT,"FieldDocumentation"),g(fT,"Arguments"),cT(fT,"Arguments"),g(pT,"Directives"),cT(pT,"Directives");var hT=Object.defineProperty,mT=g(((e,t)=>hT(e,"name",{value:t,configurable:!0})),"__name$o");function gT(e){var t,n,r,i;const o=e.schema.getQueryType(),a=null==(n=(t=e.schema).getMutationType)?void 0:n.call(t),s=null==(i=(r=e.schema).getSubscriptionType)?void 0:i.call(r),l=e.schema.getTypeMap(),u=[null==o?void 0:o.name,null==a?void 0:a.name,null==s?void 0:s.name];return fe(pe,{children:[de(rb,{type:"description",children:e.schema.description||"A GraphQL schema provides a root type for each kind of operation."}),fe(sT,{title:"Root Types",children:[o?fe("div",{children:[de("span",{className:"graphiql-doc-explorer-root-type",children:"query"}),": ",de(QE,{type:o})]}):null,a&&fe("div",{children:[de("span",{className:"graphiql-doc-explorer-root-type",children:"mutation"}),": ",de(QE,{type:a})]}),s&&fe("div",{children:[de("span",{className:"graphiql-doc-explorer-root-type",children:"subscription"}),": ",de(QE,{type:s})]})]}),de(sT,{title:"All Schema Types",children:l&&de("div",{children:Object.values(l).map((e=>u.includes(e.name)||e.name.startsWith("__")?null:de("div",{children:de(QE,{type:e})},e.name)))})})]})}function vT(e,n){var r=(0,t.useRef)(!1);(0,t.useEffect)((function(){r.current?e():r.current=!0}),n)}function yT(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}function bT(){return bT=Object.assign||function(e){for(var t=1;tl&&e.push({highlight:!1,start:l,end:u}),o.index===s.lastIndex&&s.lastIndex++}return e}),[])}function CT(e){var t=e.chunksToHighlight,n=e.totalLength,r=[];if(0===t.length)o(0,n,!1);else{var i=0;t.forEach((function(e){o(i,e.start,!1),o(e.start,e.end,!0),i=e.end})),o(i,n,!1)}return r;function o(e,t,n){t-e>0&&r.push({start:e,end:t,highlight:n})}}function ST(e){return e}function xT(e){return e.replace(/[-[\]/{}()*+?.\\^$|]/g,"\\$&")}g(gT,"SchemaDocumentation"),mT(gT,"SchemaDocumentation"),g(vT,"useUpdateEffect"),g(yT,"_objectWithoutPropertiesLoose"),g(bT,"_extends"),g(ET,"findAll"),g(TT,"combineChunks"),g(wT,"defaultFindChunks"),g(CT,"fillInChunks"),g(ST,"defaultSanitize"),g(xT,"escapeRegExpFn");var kT,NT,_T,OT,IT,DT={combineChunks:TT,fillInChunks:CT,findAll:ET,findChunks:wT},LT=["onSelect","openOnFocus","children","as","aria-label","aria-labelledby"],AT=["as","selectOnClick","autocomplete","onClick","onChange","onKeyDown","onBlur","onFocus","value"],MT=["as","children","portal","onKeyDown","onBlur","position"],RT=["persistSelection","as"],FT=["as","children","index","value","onClick"],PT="IDLE",jT="SUGGESTING",VT="NAVIGATING",UT="INTERACTING",BT="CLEAR",$T="CHANGE",qT="INITIAL_CHANGE",HT="NAVIGATE",GT="SELECT_WITH_KEYBOARD",zT="SELECT_WITH_CLICK",WT="ESCAPE",KT="BLUR",QT="INTERACT",XT="FOCUS",YT="OPEN_WITH_BUTTON",JT="OPEN_WITH_INPUT_CLICK",ZT="CLOSE_WITH_BUTTON",ew={initial:PT,states:(IT={},IT[PT]={on:(kT={},kT[KT]=PT,kT[BT]=PT,kT[$T]=jT,kT[qT]=PT,kT[XT]=jT,kT[HT]=VT,kT[YT]=jT,kT[JT]=jT,kT)},IT[jT]={on:(NT={},NT[$T]=jT,NT[XT]=jT,NT[HT]=VT,NT[BT]=PT,NT[WT]=PT,NT[KT]=PT,NT[zT]=PT,NT[QT]=UT,NT[ZT]=PT,NT)},IT[VT]={on:(_T={},_T[$T]=jT,_T[XT]=jT,_T[BT]=PT,_T[KT]=PT,_T[WT]=PT,_T[HT]=VT,_T[zT]=PT,_T[GT]=PT,_T[ZT]=PT,_T[QT]=UT,_T)},IT[UT]={on:(OT={},OT[BT]=PT,OT[$T]=jT,OT[XT]=jT,OT[KT]=PT,OT[WT]=PT,OT[HT]=VT,OT[ZT]=PT,OT[zT]=PT,OT)},IT)},tw=g((function(e,t){var n=bT({},e,{lastEventType:t.type});switch(t.type){case $T:case qT:return bT({},n,{navigationValue:null,value:t.value});case HT:case YT:case JT:return bT({},n,{navigationValue:rw(n,t)});case BT:return bT({},n,{value:"",navigationValue:null});case KT:case WT:return bT({},n,{navigationValue:null});case zT:return bT({},n,{value:t.isControlled?e.value:t.value,navigationValue:null});case GT:return bT({},n,{value:t.isControlled?e.value:e.navigationValue,navigationValue:null});case ZT:return bT({},n,{navigationValue:null});case QT:return n;case XT:return bT({},n,{navigationValue:rw(n,t)});default:return n}}),"reducer");function nw(e){return[jT,VT,UT].includes(e)}function rw(e,t){return t.value?t.value:t.persistSelection?e.value:null}g(nw,"popoverIsExpanded"),g(rw,"findNavigationValue");var iw=zd(),ow=af(0,{}),aw=af(0,{}),sw=(0,t.forwardRef)((function(e,n){var r,i=e.onSelect,o=e.openOnFocus,a=void 0!==o&&o,s=e.children,l=e.as,u=void 0===l?"div":l,c=e["aria-label"],d=e["aria-labelledby"],f=yT(e,LT),p=Kd(),h=p[0],m=p[1],g=(0,t.useRef)(),v=(0,t.useRef)(),y=(0,t.useRef)(),b=(0,t.useRef)(!1),E=(0,t.useRef)(!1),T=gw(ew,tw,{value:"",navigationValue:null}),w=T[0],C=T[1],S=T[2];pw(C.lastEventType,g);var x=rd(f.id),k=x?lf("listbox",x):"listbox",N=(0,t.useRef)(!1),_=nw(w),O={ariaLabel:c,ariaLabelledby:d,autocompletePropRef:b,buttonRef:y,comboboxId:x,data:C,inputRef:g,isExpanded:_,listboxId:k,onSelect:i||bs,openOnFocus:a,persistSelectionRef:E,popoverRef:v,state:w,transition:S,isControlledRef:N};return(0,t.createElement)(Xd,{context:iw,items:h,set:m},(0,t.createElement)(ow.Provider,{value:O},(0,t.createElement)(u,bT({},f,{"data-reach-combobox":"","data-state":yw(w),"data-expanded":_||void 0,ref:n}),vs(s)?s({id:x,isExpanded:_,navigationValue:null!=(r=C.navigationValue)?r:null,state:w}):s)))})),lw=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"input":r,o=e.selectOnClick,a=void 0!==o&&o,s=e.autocomplete,l=void 0===s||s,u=e.onClick,c=e.onChange,d=e.onKeyDown,f=e.onBlur,p=e.onFocus,h=e.value,m=yT(e,AT),v=(0,t.useRef)(h).current,y=(0,t.useRef)(!1);vT((function(){y.current=!0}),[h]);var b=(0,t.useContext)(ow),E=b.data,T=E.navigationValue,w=E.value,C=E.lastEventType,S=b.inputRef,x=b.state,k=b.transition,N=b.listboxId,_=b.autocompletePropRef,O=b.openOnFocus,I=b.isExpanded,D=b.ariaLabel,L=b.ariaLabelledby,A=b.persistSelectionRef,M=b.isControlledRef,R=Ss(S,n),F=(0,t.useRef)(!1),P=hw(),j=mw(),V=void 0!==h;(0,t.useEffect)((function(){M.current=V}),[V]),us((function(){_.current=l}),[l,_]);var U=(0,t.useCallback)((function(e){""===e.trim()?k(BT,{isControlled:V}):e!==v||y.current?k($T,{value:e}):k(qT,{value:e})}),[v,k,V]);function B(e){var t=e.target.value;V||U(t)}function $(){a&&(F.current=!0),O&&C!==zT&&k(XT,{persistSelection:A.current})}function q(){var e;F.current&&(F.current=!1,null==(e=S.current)||e.select()),O&&x===PT&&k(JT)}(0,t.useEffect)((function(){!V||h===w||""===h.trim()&&""===(w||"").trim()||U(h)}),[h,U,V,w]),g(B,"handleChange"),g($,"handleFocus"),g(q,"handleClick");var H=!l||x!==VT&&x!==UT?h||w:T||h||w;return(0,t.createElement)(i,bT({"aria-activedescendant":T?String(vw(T)):void 0,"aria-autocomplete":"both","aria-controls":N,"aria-expanded":I,"aria-haspopup":"listbox","aria-label":D,"aria-labelledby":D?void 0:L,role:"combobox"},m,{"data-reach-combobox-input":"","data-state":yw(x),ref:R,onBlur:xs(f,j),onChange:xs(c,B),onClick:xs(u,q),onFocus:xs(p,$),onKeyDown:xs(d,P),value:H||""}))})),uw=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"div":r,o=e.children,a=e.portal,s=void 0===a||a,l=e.onKeyDown,u=e.onBlur,c=e.position,d=void 0===c?Ud:c,f=yT(e,MT),p=(0,t.useContext)(ow),h=p.popoverRef,m=p.inputRef,g=p.isExpanded,v=p.state,y=Ss(h,n),b=hw(),E=mw(),T={"data-reach-combobox-popover":"","data-state":yw(v),onKeyDown:xs(l,b),onBlur:xs(u,E),hidden:!g,tabIndex:-1,children:o};return s?(0,t.createElement)(Rd,bT({as:i},f,{ref:y,"data-expanded":g||void 0,position:d,targetRef:m,unstable_skipInitialPortalRender:!0},T)):(0,t.createElement)(i,bT({ref:y},f,T))})),cw=(0,t.forwardRef)((function(e,n){var r=e.persistSelection,i=void 0!==r&&r,o=e.as,a=void 0===o?"ul":o,s=yT(e,RT),l=(0,t.useContext)(ow),u=l.persistSelectionRef,c=l.listboxId;return i&&(u.current=!0),(0,t.createElement)(a,bT({role:"listbox"},s,{ref:n,"data-reach-combobox-list":"",id:c}))})),dw=(0,t.forwardRef)((function(e,n){var r=e.as,i=void 0===r?"li":r,o=e.children,a=e.index,s=e.value,l=e.onClick,u=yT(e,FT),c=(0,t.useContext)(ow),d=c.onSelect,f=c.data.navigationValue,p=c.transition,h=c.isControlledRef,m=uf((0,t.useRef)(null),null),v=m[0],y=m[1],b=Wd((0,t.useMemo)((function(){return{element:v,value:s}}),[s,v]),iw,a),E=Ss(n,y),T=f===s,w=g((function(){d&&d(s),p(zT,{value:s,isControlled:h.current})}),"handleClick");return(0,t.createElement)(aw.Provider,{value:{value:s,index:b}},(0,t.createElement)(i,bT({"aria-selected":T,role:"option"},u,{"data-reach-combobox-option":"",ref:E,id:String(vw(s)),"data-highlighted":T?"":void 0,tabIndex:-1,onClick:xs(l,w)}),o?vs(o)?o({value:s,index:b}):o:(0,t.createElement)(fw,null)))}));function fw(){var e=(0,t.useContext)(aw).value,n=(0,t.useContext)(ow).data.value,r=(0,t.useMemo)((function(){return DT.findAll({searchWords:bw(n||"").split(/\s+/),textToHighlight:e})}),[n,e]);return(0,t.createElement)(t.Fragment,null,r.length?r.map((function(n,r){var i=e.slice(n.start,n.end);return(0,t.createElement)("span",{key:r,"data-reach-combobox-option-text":"","data-user-value":!!n.highlight||void 0,"data-suggested-value":!n.highlight||void 0},i)})):e)}function pw(e,t){us((function(){var n;e!==HT&&e!==WT&&e!==zT&&e!==YT||null==(n=t.current)||n.focus()}),[t,e])}function hw(){var e=(0,t.useContext)(ow),n=e.data.navigationValue,r=e.onSelect,i=e.state,o=e.transition,a=e.autocompletePropRef,s=e.persistSelectionRef,l=e.isControlledRef,u=Qd(iw);return g((function(e){var t=u.findIndex((function(e){return e.value===n}));function c(){return t===u.length-1?a.current?null:f():u[(t+1)%u.length]}function d(){return 0===t?a.current?null:p():-1===t?p():u[(t-1+u.length)%u.length]}function f(){return u[0]}function p(){return u[u.length-1]}switch(g(c,"getNextOption"),g(d,"getPreviousOption"),g(f,"getFirstOption"),g(p,"getLastOption"),e.key){case"ArrowDown":if(e.preventDefault(),!u||!u.length)return;if(i===PT)o(HT,{persistSelection:s.current});else{var h=c();o(HT,{value:h?h.value:null})}break;case"ArrowUp":if(e.preventDefault(),!u||0===u.length)return;if(i===PT)o(HT);else{var m=d();o(HT,{value:m?m.value:null})}break;case"Home":case"PageUp":if(e.preventDefault(),!u||0===u.length)return;i===PT?o(HT):o(HT,{value:f().value});break;case"End":case"PageDown":if(e.preventDefault(),!u||0===u.length)return;i===PT?o(HT):o(HT,{value:p().value});break;case"Escape":i!==PT&&o(WT);break;case"Enter":i===VT&&null!==n&&(e.preventDefault(),r&&r(n),o(GT,{isControlled:l.current}))}}),"handleKeyDown")}function mw(){var e=(0,t.useContext)(ow),n=e.state,r=e.transition,i=e.popoverRef,o=e.inputRef,a=e.buttonRef;return g((function(e){var t=i.current,s=o.current,l=a.current,u=e.relatedTarget;u!==s&&u!==l&&t&&(t.contains(u)?n!==UT&&r(QT):r(KT))}),"handleBlur")}function gw(e,n,r){var i=(0,t.useState)(e.initial),o=i[0],a=i[1],s=(0,t.useReducer)(n,r),l=s[0],u=s[1];return[o,l,g((function(t,n){void 0===n&&(n={});var r=e.states[o],i=r&&r.on[t];if(i)return u(bT({type:t,state:o,nextState:o},n)),void a(i)}),"transition")]}function vw(e){var t=0;if(0===e.length)return t;for(var n=0;nEw(e,"name",{value:t,configurable:!0})),"__name$n");function ww(e,t){let n;return function(){for(var r=arguments.length,i=new Array(r),o=0;o{n=null,t(...i)}),e)}}g(ww,"debounce"),Tw(ww,"debounce");var Cw=Object.defineProperty,Sw=g(((e,t)=>Cw(e,"name",{value:t,configurable:!0})),"__name$m");function xw(){const{explorerNavStack:e,push:n}=qE({nonNull:!0,caller:xw}),i=(0,t.useRef)(null),o=(0,t.useRef)(null),a=kw(),[s,l]=(0,t.useState)(""),[u,c]=(0,t.useState)(a(s)),d=(0,t.useMemo)((()=>ww(200,(e=>{c(a(e))}))),[a]);(0,t.useEffect)((()=>{d(s)}),[d,s]),(0,t.useEffect)((()=>{function e(e){var t;e.metaKey&&"k"===e.key&&(null==(t=i.current)||t.focus())}return g(e,"handleKeyDown"),Sw(e,"handleKeyDown"),window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)}),[]);const f=e.at(-1);return 1===e.length||(0,r.isObjectType)(f.def)||(0,r.isInterfaceType)(f.def)||(0,r.isInputObjectType)(f.def)?fe(sw,{"aria-label":`Search ${f.name}...`,onSelect:e=>{const t=e;n("field"in t?{name:t.field.name,def:t.field}:{name:t.type.name,def:t.type})},children:[fe("div",{className:"graphiql-doc-explorer-search-input",onClick:()=>{i.current&&i.current.focus()},children:[de(Ga,{}),de(lw,{autocomplete:!1,onChange:e=>{l(e.target.value)},onKeyDown:e=>{if(!e.isDefaultPrevented()){const e=o.current;if(!e)return;window.requestAnimationFrame((()=>{const t=e.querySelector("[aria-selected=true]");if(!(t instanceof HTMLElement))return;const n=t.offsetTop-e.scrollTop,r=e.scrollTop+e.clientHeight-(t.offsetTop+t.clientHeight);r<0&&(e.scrollTop-=r),n<0&&(e.scrollTop+=n)}))}e.stopPropagation()},placeholder:"⌘ K",ref:i,value:s})]}),de(uw,{portal:!1,ref:o,children:fe(cw,{children:[u.within.map(((e,t)=>de(dw,{index:t,value:e,children:de(Ow,{field:e.field,argument:e.argument})},`within-${t}`))),u.within.length>0&&u.types.length+u.fields.length>0?de("div",{className:"graphiql-doc-explorer-search-divider",children:"Other results"}):null,u.types.map(((e,t)=>de(dw,{index:u.within.length+t,value:e,children:de(_w,{type:e.type})},`type-${t}`))),u.fields.map(((e,t)=>fe(dw,{index:u.within.length+u.types.length+t,value:e,children:[de(_w,{type:e.type}),".",de(Ow,{field:e.field,argument:e.argument})]},`field-${t}`))),u.within.length+u.types.length+u.fields.length===0?de("div",{className:"graphiql-doc-explorer-search-empty",children:"No results found"}):null]})})]}):null}function kw(e){const{explorerNavStack:n}=qE({nonNull:!0,caller:e||kw}),{schema:i}=RE({nonNull:!0,caller:e||kw}),o=n.at(-1);return(0,t.useCallback)((e=>{const t={within:[],types:[],fields:[]};if(!i)return t;const n=o.def,a=i.getTypeMap();let s=Object.keys(a);n&&(s=s.filter((e=>e!==n.name)),s.unshift(n.name));for(const i of s){if(t.within.length+t.types.length+t.fields.length>=100)break;const o=a[i];if(n!==o&&Nw(i,e)&&t.types.push({type:o}),!(0,r.isObjectType)(o)&&!(0,r.isInterfaceType)(o)&&!(0,r.isInputObjectType)(o))continue;const s=o.getFields();for(const r in s){const i=s[r];let a;if(!Nw(r,e)){if(!("args"in i))continue;if(a=i.args.filter((t=>Nw(t.name,e))),0===a.length)continue}t[n===o?"within":"fields"].push(...a?a.map((e=>({type:o,field:i,argument:e}))):[{type:o,field:i}])}}return t}),[o.def,i])}function Nw(e,t){try{const n=t.replaceAll(/[^_0-9A-Za-z]/g,(e=>"\\"+e));return-1!==e.search(new RegExp(n,"i"))}catch{return e.toLowerCase().includes(t.toLowerCase())}}function _w(e){return de("span",{className:"graphiql-doc-explorer-search-type",children:e.type.name})}function Ow(e){return fe(pe,{children:[de("span",{className:"graphiql-doc-explorer-search-field",children:e.field.name}),e.argument?fe(pe,{children:["(",de("span",{className:"graphiql-doc-explorer-search-argument",children:e.argument.name}),":"," ",zE(e.argument.type,(e=>de(_w,{type:e}))),")"]}):null]})}g(xw,"Search"),Sw(xw,"Search"),g(kw,"useSearchResults"),Sw(kw,"useSearchResults"),g(Nw,"isMatch"),Sw(Nw,"isMatch"),g(_w,"Type"),Sw(_w,"Type"),g(Ow,"Field$1"),Sw(Ow,"Field");var Iw=Object.defineProperty,Dw=g(((e,t)=>Iw(e,"name",{value:t,configurable:!0})),"__name$l");function Lw(e){const{push:t}=qE({nonNull:!0});return de("a",{className:"graphiql-doc-explorer-field-name",onClick:n=>{n.preventDefault(),t({name:e.field.name,def:e.field})},href:"#",children:e.field.name})}g(Lw,"FieldLink"),Dw(Lw,"FieldLink");var Aw=Object.defineProperty,Mw=g(((e,t)=>Aw(e,"name",{value:t,configurable:!0})),"__name$k");function Rw(e){return(0,r.isNamedType)(e.type)?fe(pe,{children:[e.type.description?de(rb,{type:"description",children:e.type.description}):null,de(Fw,{type:e.type}),de(Pw,{type:e.type}),de(Vw,{type:e.type}),de(Bw,{type:e.type})]}):null}function Fw(e){let{type:t}=e;return(0,r.isObjectType)(t)&&t.getInterfaces().length>0?de(sT,{title:"Implements",children:t.getInterfaces().map((e=>de("div",{children:de(QE,{type:e})},e.name)))}):null}function Pw(e){let{type:n}=e;const[i,o]=(0,t.useState)(!1);if(!(0,r.isObjectType)(n)&&!(0,r.isInterfaceType)(n)&&!(0,r.isInputObjectType)(n))return null;const a=n.getFields(),s=[],l=[];for(const e of Object.keys(a).map((e=>a[e])))e.deprecationReason?l.push(e):s.push(e);return fe(pe,{children:[s.length>0?de(sT,{title:"Fields",children:s.map((e=>de(jw,{field:e},e.name)))}):null,l.length>0?i||0===s.length?de(sT,{title:"Deprecated Fields",children:l.map((e=>de(jw,{field:e},e.name)))}):de(as,{type:"button",onClick:()=>{o(!0)},children:"Show Deprecated Fields"}):null]})}function jw(e){let{field:t}=e;const n="args"in t?t.args.filter((e=>!e.deprecationReason)):[];return fe("div",{className:"graphiql-doc-explorer-item",children:[fe("div",{children:[de(Lw,{field:t}),n.length>0?fe(pe,{children:["(",de("span",{children:n.map((e=>1===n.length?de(JE,{arg:e,inline:!0},e.name):de("div",{className:"graphiql-doc-explorer-argument-multiple",children:de(JE,{arg:e,inline:!0})},e.name)))}),")"]}):null,": ",de(QE,{type:t.type}),de(IE,{field:t})]}),t.description?de(rb,{type:"description",onlyShowFirstChild:!0,children:t.description}):null,de(tT,{children:t.deprecationReason})]})}function Vw(e){let{type:n}=e;const[i,o]=(0,t.useState)(!1);if(!(0,r.isEnumType)(n))return null;const a=[],s=[];for(const e of n.getValues())e.deprecationReason?s.push(e):a.push(e);return fe(pe,{children:[a.length>0?de(sT,{title:"Enum Values",children:a.map((e=>de(Uw,{value:e},e.name)))}):null,s.length>0?i||0===a.length?de(sT,{title:"Deprecated Enum Values",children:s.map((e=>de(Uw,{value:e},e.name)))}):de(as,{type:"button",onClick:()=>{o(!0)},children:"Show Deprecated Values"}):null]})}function Uw(e){let{value:t}=e;return fe("div",{className:"graphiql-doc-explorer-item",children:[de("div",{className:"graphiql-doc-explorer-enum-value",children:t.name}),t.description?de(rb,{type:"description",children:t.description}):null,t.deprecationReason?de(rb,{type:"deprecation",children:t.deprecationReason}):null]})}function Bw(e){let{type:t}=e;const{schema:n}=RE({nonNull:!0});return n&&(0,r.isAbstractType)(t)?de(sT,{title:(0,r.isInterfaceType)(t)?"Implementations":"Possible Types",children:n.getPossibleTypes(t).map((e=>de("div",{children:de(QE,{type:e})},e.name)))}):null}g(Rw,"TypeDocumentation"),Mw(Rw,"TypeDocumentation"),g(Fw,"ImplementsInterfaces"),Mw(Fw,"ImplementsInterfaces"),g(Pw,"Fields"),Mw(Pw,"Fields"),g(jw,"Field"),Mw(jw,"Field"),g(Vw,"EnumValues"),Mw(Vw,"EnumValues"),g(Uw,"EnumValue"),Mw(Uw,"EnumValue"),g(Bw,"PossibleTypes"),Mw(Bw,"PossibleTypes");var $w=Object.defineProperty,qw=g(((e,t)=>$w(e,"name",{value:t,configurable:!0})),"__name$j");function Hw(){const{fetchError:e,isFetching:t,schema:n,validationErrors:i}=RE({nonNull:!0,caller:Hw}),{explorerNavStack:o,pop:a}=qE({nonNull:!0,caller:Hw}),s=o.at(-1);let l,u=null;return e?u=de("div",{className:"graphiql-doc-explorer-error",children:"Error fetching schema"}):i.length>0?u=fe("div",{className:"graphiql-doc-explorer-error",children:["Schema is invalid: ",i[0].message]}):t?u=de(ib,{}):n?1===o.length?u=de(gT,{schema:n}):(0,r.isType)(s.def)?u=de(Rw,{type:s.def}):s.def&&(u=de(dT,{field:s.def})):u=de("div",{className:"graphiql-doc-explorer-error",children:"No GraphQL schema available"}),o.length>1&&(l=o.at(-2).name),fe("section",{className:"graphiql-doc-explorer","aria-label":"Documentation Explorer",children:[fe("div",{className:"graphiql-doc-explorer-header",children:[fe("div",{className:"graphiql-doc-explorer-header-content",children:[l&&fe("a",{href:"#",className:"graphiql-doc-explorer-back",onClick:e=>{e.preventDefault(),a()},"aria-label":`Go back to ${l}`,children:[de(Ia,{}),l]}),de("div",{className:"graphiql-doc-explorer-title",children:s.name})]}),de("div",{className:"graphiql-doc-explorer-search",children:de(xw,{},s.name)})]}),de("div",{className:"graphiql-doc-explorer-content",children:u})]})}g(Hw,"DocExplorer"),qw(Hw,"DocExplorer");var Gw=Object.defineProperty,zw=g(((e,t)=>Gw(e,"name",{value:t,configurable:!0})),"__name$i");const Ww={title:"Documentation Explorer",icon:zw(g((function(){const e=Yw();return(null==e?void 0:e.visiblePlugin)===Ww?de(ja,{}):de(Va,{})}),"Icon"),"Icon"),content:Hw};e._=Ww;const Kw={title:"History",icon:$a,content:oE};e.$=Kw;const Qw=X("PluginContext");function Xw(e){const n=ye(),r=qE(),i=tE(),o=Boolean(r),a=Boolean(i),s=(0,t.useMemo)((()=>{const t=[],n={};o&&(t.push(Ww),n[Ww.title]=!0),a&&(t.push(Kw),n[Kw.title]=!0);for(const r of e.plugins||[]){if("string"!=typeof r.title||!r.title)throw new Error("All GraphiQL plugins must have a unique title");if(n[r.title])throw new Error(`All GraphiQL plugins must have a unique title, found two plugins with the title '${r.title}'`);t.push(r),n[r.title]=!0}return t}),[o,a,e.plugins]),[l,u]=(0,t.useState)((()=>{const t=null==n?void 0:n.get(Jw);return s.find((e=>e.title===t))||(t&&(null==n||n.set(Jw,"")),e.visiblePlugin&&s.find((t=>("string"==typeof e.visiblePlugin?t.title:t)===e.visiblePlugin))||null)})),{onTogglePluginVisibility:c,children:d}=e,f=(0,t.useCallback)((e=>{const t=e&&s.find((t=>("string"==typeof e?t.title:t)===e))||null;u((e=>t===e?e:(null==c||c(t),t)))}),[c,s]);(0,t.useEffect)((()=>{e.visiblePlugin&&f(e.visiblePlugin)}),[s,e.visiblePlugin,f]);const p=(0,t.useMemo)((()=>({plugins:s,setVisiblePlugin:f,visiblePlugin:l})),[s,f,l]);return de(Qw.Provider,{value:p,children:d})}e.a0=Qw,g(Xw,"PluginContextProvider"),zw(Xw,"PluginContextProvider");const Yw=Y(Qw);e.a2=Yw;const Jw="visiblePlugin";var Zw=Object.defineProperty,eC=g(((e,t)=>Zw(e,"name",{value:t,configurable:!0})),"__name$h");function tC(e,t,n,i,o,a){function s(e){if(!(n&&i&&o&&e.currentTarget instanceof HTMLElement))return;const t=e.currentTarget.innerText,r=n.getType(t);r&&(o.setVisiblePlugin(Ww),i.push({name:r.name,def:r}),null==a||a(r))}EE([],{useCommonAddons:!1}).then((e=>{let n,i,o,a,l,u,c,d,f;e.on(t,"select",((e,t)=>{if(!n){const e=t.parentNode;n=document.createElement("div"),n.className="CodeMirror-hint-information",e.append(n);const r=document.createElement("header");r.className="CodeMirror-hint-information-header",n.append(r),i=document.createElement("span"),i.className="CodeMirror-hint-information-field-name",r.append(i),o=document.createElement("span"),o.className="CodeMirror-hint-information-type-name-pill",r.append(o),a=document.createElement("span"),o.append(a),l=document.createElement("a"),l.className="CodeMirror-hint-information-type-name",l.href="javascript:void 0",l.addEventListener("click",s),o.append(l),u=document.createElement("span"),o.append(u),c=document.createElement("div"),c.className="CodeMirror-hint-information-description",n.append(c),d=document.createElement("div"),d.className="CodeMirror-hint-information-deprecation",n.append(d);const p=document.createElement("span");p.className="CodeMirror-hint-information-deprecation-label",p.innerText="Deprecated",d.append(p),f=document.createElement("div"),f.className="CodeMirror-hint-information-deprecation-reason",d.append(f);const h=parseInt(window.getComputedStyle(n).paddingBottom.replace(/px$/,""),10)||0,m=parseInt(window.getComputedStyle(n).maxHeight.replace(/px$/,""),10)||0,g=eC((()=>{n&&(n.style.paddingTop=e.scrollTop+h+"px",n.style.maxHeight=e.scrollTop+m+"px")}),"handleScroll");let v;e.addEventListener("scroll",g),e.addEventListener("DOMNodeRemoved",v=eC((t=>{t.target===e&&(e.removeEventListener("scroll",g),e.removeEventListener("DOMNodeRemoved",v),n&&n.removeEventListener("click",s),n=null,i=null,o=null,a=null,l=null,u=null,c=null,d=null,f=null,v=null)}),"onRemoveFn"))}if(i&&(i.innerText=e.text),o&&a&&l&&u)if(e.type){o.style.display="inline";const t=eC((e=>{(0,r.isNonNullType)(e)?(u.innerText="!"+u.innerText,t(e.ofType)):(0,r.isListType)(e)?(a.innerText+="[",u.innerText="]"+u.innerText,t(e.ofType)):l.innerText=e.name}),"renderType");a.innerText="",u.innerText="",t(e.type)}else a.innerText="",l.innerText="",u.innerText="",o.style.display="none";c&&(e.description?(c.style.display="block",c.innerHTML=nb.render(e.description)):(c.style.display="none",c.innerHTML="")),d&&f&&(e.deprecationReason?(d.style.display="block",f.innerHTML=nb.render(e.deprecationReason)):(d.style.display="none",f.innerHTML=""))}))})),g(s,"onClickHintInformation"),eC(s,"onClickHintInformation")}g(tC,"onHasCompletion"),eC(tC,"onHasCompletion");var nC=Object.defineProperty,rC=g(((e,t)=>nC(e,"name",{value:t,configurable:!0})),"__name$g");function iC(e,n){(0,t.useEffect)((()=>{e&&"string"==typeof n&&n!==e.getValue()&&e.setValue(n)}),[e,n])}function oC(e,n,r){(0,t.useEffect)((()=>{e&&e.setOption(n,r)}),[e,n,r])}function aC(e,n,r,i,o){const{updateActiveTabValues:a}=oS({nonNull:!0,caller:o}),s=ye();(0,t.useEffect)((()=>{if(!e)return;const t=ww(500,(e=>{s&&null!==r&&s.set(r,e)})),o=ww(100,(e=>{a({[i]:e})})),l=rC(((e,r)=>{if(!r)return;const i=e.getValue();t(i),o(i),null==n||n(i)}),"handleChange");return e.on("change",l),()=>e.off("change",l)}),[n,e,s,r,i,a])}function sC(e,n,r){const{schema:i}=RE({nonNull:!0,caller:r}),o=qE(),a=Yw();(0,t.useEffect)((()=>{if(!e)return;const t=rC(((e,t)=>{tC(0,t,i,o,a,(e=>{null==n||n({kind:"Type",type:e,schema:i||void 0})}))}),"handleCompletion");return e.on("hasCompletion",t),()=>e.off("hasCompletion",t)}),[n,e,o,a,i])}function lC(e,n,r){(0,t.useEffect)((()=>{if(e){for(const t of n)e.removeKeyMap(t);if(r){const t={};for(const e of n)t[e]=()=>r();e.addKeyMap(t)}}}),[e,n,r])}function uC(){let{caller:e,onCopyQuery:n}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const{queryEditor:r}=oS({nonNull:!0,caller:e||uC});return(0,t.useCallback)((()=>{if(!r)return;const e=r.getValue();kE(e),null==n||n(e)}),[r,n])}function cC(){let{caller:e}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const{queryEditor:n}=oS({nonNull:!0,caller:e||cC}),{schema:i}=RE({nonNull:!0,caller:cC});return(0,t.useCallback)((()=>{const e=null==n?void 0:n.documentAST,t=null==n?void 0:n.getValue();e&&t&&n.setValue((0,r.print)(B(e,i)))}),[n,i])}function dC(){let{caller:e}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const{queryEditor:n,headerEditor:i,variableEditor:o}=oS({nonNull:!0,caller:e||dC});return(0,t.useCallback)((()=>{if(o){const e=o.getValue();try{const t=JSON.stringify(JSON.parse(e),null,2);t!==e&&o.setValue(t)}catch{}}if(i){const e=i.getValue();try{const t=JSON.stringify(JSON.parse(e),null,2);t!==e&&i.setValue(t)}catch{}}if(n){const e=n.getValue(),t=(0,r.print)((0,r.parse)(e));t!==e&&n.setValue(t)}}),[n,o,i])}function fC(){let{getDefaultFieldNames:e,caller:n}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const{schema:r}=RE({nonNull:!0,caller:n||fC}),{queryEditor:i}=oS({nonNull:!0,caller:n||fC});return(0,t.useCallback)((()=>{if(!i)return;const t=i.getValue(),{insertions:n,result:o}=A(r,t,e);return n&&n.length>0&&i.operation((()=>{const e=i.getCursor(),t=i.indexFromPos(e);i.setValue(o||"");let r=0;const a=n.map((e=>{let{index:t,string:n}=e;return i.markText(i.posFromIndex(t+r),i.posFromIndex(t+(r+=n.length)),{className:"auto-inserted-leaf",clearOnEnter:!0,title:"Automatically added leaf fields"})}));setTimeout((()=>{for(const e of a)e.clear()}),7e3);let s=t;for(const{index:e,string:r}of n)epC(e,"name",{value:t,configurable:!0})),"__name$f");function mC(){let{editorTheme:e=gE,keyMap:r=vE,onEdit:i,readOnly:o=!1}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},a=arguments.length>1?arguments[1]:void 0;const{initialHeaders:s,headerEditor:l,setHeaderEditor:u,shouldPersistHeaders:c}=oS({nonNull:!0,caller:a||mC}),d=fE(),f=cC({caller:a||mC}),p=dC({caller:a||mC}),h=(0,t.useRef)(null);return(0,t.useEffect)((()=>{let t=!0;return EE([Promise.resolve().then(n.t.bind(n,8888,23)).then((function(e){return e.j}))]).then((n=>{if(!t)return;const r=h.current;if(!r)return;const i=n(r,{value:s,lineNumbers:!0,tabSize:2,mode:{name:"javascript",json:!0},theme:e,autoCloseBrackets:!0,matchBrackets:!0,showCursorWhenSelecting:!0,readOnly:!!o&&"nocursor",foldGutter:!0,gutters:["CodeMirror-linenumbers","CodeMirror-foldgutter"],extraKeys:bE});i.addKeyMap({"Cmd-Space"(){i.showHint({completeSingle:!1,container:r})},"Ctrl-Space"(){i.showHint({completeSingle:!1,container:r})},"Alt-Space"(){i.showHint({completeSingle:!1,container:r})},"Shift-Space"(){i.showHint({completeSingle:!1,container:r})}}),i.on("keyup",((e,t)=>{const{keyCode:n,key:r,shiftKey:i}=t;(n>=65&&n<=90||!i&&n>=48&&n<=57||"_"===r||'"'===r)&&e.execCommand("autocomplete")})),u(i)})),()=>{t=!1}}),[e,s,o,u]),oC(l,"keyMap",r),aC(l,i,c?gC:null,"headers",mC),lC(l,["Cmd-Enter","Ctrl-Enter"],null==d?void 0:d.run),lC(l,["Shift-Ctrl-P"],p),lC(l,["Shift-Ctrl-M"],f),h}g(mC,"useHeaderEditor"),hC(mC,"useHeaderEditor");const gC="headers";var vC=Object.defineProperty,yC=g(((e,t)=>vC(e,"name",{value:t,configurable:!0})),"__name$e");const bC=Array.from({length:11},((e,t)=>String.fromCharCode(8192+t))).concat(["\u2028","\u2029"," "," "]),EC=new RegExp("["+bC.join("")+"]","g");function TC(e){return e.replace(EC," ")}g(TC,"normalizeWhitespace"),yC(TC,"normalizeWhitespace");var wC=Object.defineProperty,CC=g(((e,t)=>wC(e,"name",{value:t,configurable:!0})),"__name$d");function SC(){let{editorTheme:e=gE,keyMap:r=vE,onClickReference:i,onCopyQuery:o,onEdit:a,readOnly:s=!1}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},l=arguments.length>1?arguments[1]:void 0;const{schema:u}=RE({nonNull:!0,caller:l||SC}),{externalFragments:c,initialQuery:d,queryEditor:f,setOperationName:p,setQueryEditor:v,validationRules:y,variableEditor:b,updateActiveTabValues:E}=oS({nonNull:!0,caller:l||SC}),T=fE(),w=ye(),C=qE(),S=Yw(),x=uC({caller:l||SC,onCopyQuery:o}),k=cC({caller:l||SC}),N=dC({caller:l||SC}),_=(0,t.useRef)(null),O=(0,t.useRef)(),I=(0,t.useRef)((()=>{}));(0,t.useEffect)((()=>{I.current=e=>{if(C&&S){switch(S.setVisiblePlugin(Ww),e.kind){case"Type":C.push({name:e.type.name,def:e.type});break;case"Field":C.push({name:e.field.name,def:e.field});break;case"Argument":e.field&&C.push({name:e.field.name,def:e.field});break;case"EnumValue":e.type&&C.push({name:e.type.name,def:e.type})}null==i||i(e)}}}),[C,i,S]),(0,t.useEffect)((()=>{let t=!0;return EE([Promise.resolve().then(n.t.bind(n,6754,23)).then((function(e){return e.c})),Promise.resolve().then(n.t.bind(n,9509,23)).then((function(e){return e.s})),Promise.resolve().then(n.t.bind(n,4840,23)),Promise.resolve().then(n.t.bind(n,9444,23)),Promise.resolve().then(n.t.bind(n,9890,23)),Promise.resolve().then(n.t.bind(n,5980,23)),Promise.resolve().then(n.t.bind(n,9863,23))]).then((n=>{if(!t)return;O.current=n;const r=_.current;if(!r)return;const i=n(r,{value:d,lineNumbers:!0,tabSize:2,foldGutter:!0,mode:"graphql",theme:e,autoCloseBrackets:!0,matchBrackets:!0,showCursorWhenSelecting:!0,readOnly:!!s&&"nocursor",lint:{schema:void 0,validationRules:null,externalFragments:void 0},hintOptions:{schema:void 0,closeOnUnfocus:!1,completeSingle:!1,container:r,externalFragments:void 0},info:{schema:void 0,renderDescription:e=>nb.render(e),onClick:e=>{I.current(e)}},jump:{schema:void 0,onClick:e=>{I.current(e)}},gutters:["CodeMirror-linenumbers","CodeMirror-foldgutter"],extraKeys:m(h({},bE),{"Cmd-S"(){},"Ctrl-S"(){}})});i.addKeyMap({"Cmd-Space"(){i.showHint({completeSingle:!0,container:r})},"Ctrl-Space"(){i.showHint({completeSingle:!0,container:r})},"Alt-Space"(){i.showHint({completeSingle:!0,container:r})},"Shift-Space"(){i.showHint({completeSingle:!0,container:r})},"Shift-Alt-Space"(){i.showHint({completeSingle:!0,container:r})}}),i.on("keyup",((e,t)=>{_C.test(t.key)&&e.execCommand("autocomplete")}));let o=!1;i.on("startCompletion",(()=>{o=!0})),i.on("endCompletion",(()=>{o=!1})),i.on("keydown",((e,t)=>{"Escape"===t.key&&o&&t.stopPropagation()})),i.on("beforeChange",((e,t)=>{var n;if("paste"===t.origin){const e=t.text.map(TC);null==(n=t.update)||n.call(t,t.from,t.to,e)}})),i.documentAST=null,i.operationName=null,i.operations=null,i.variableToType=null,v(i)})),()=>{t=!1}}),[e,d,s,v]),oC(f,"keyMap",r),(0,t.useEffect)((()=>{if(!f)return;function e(e){var t,n,r,i,o;const a=Do(u,e.getValue()),s=$(null!=(t=e.operations)?t:void 0,null!=(n=e.operationName)?n:void 0,null==a?void 0:a.operations);return e.documentAST=null!=(r=null==a?void 0:a.documentAST)?r:null,e.operationName=null!=s?s:null,e.operations=null!=(i=null==a?void 0:a.operations)?i:null,b&&(b.state.lint.linterOptions.variableToType=null==a?void 0:a.variableToType,b.options.lint.variableToType=null==a?void 0:a.variableToType,b.options.hintOptions.variableToType=null==a?void 0:a.variableToType,null==(o=O.current)||o.signal(b,"change",b)),a?m(h({},a),{operationName:s}):null}g(e,"getAndUpdateOperationFacts"),CC(e,"getAndUpdateOperationFacts");const t=ww(100,(t=>{var n;const r=t.getValue();null==w||w.set(OC,r);const i=t.operationName,o=e(t);void 0!==(null==o?void 0:o.operationName)&&(null==w||w.set(IC,o.operationName)),null==a||a(r,null==o?void 0:o.documentAST),(null==o?void 0:o.operationName)&&i!==o.operationName&&p(o.operationName),E({query:r,operationName:null!=(n=null==o?void 0:o.operationName)?n:null})}));return e(f),f.on("change",t),()=>f.off("change",t)}),[a,f,u,p,w,b,E]),xC(f,null!=u?u:null,O),kC(f,null!=y?y:null,O),NC(f,c,O),sC(f,i||null,SC);const D=null==T?void 0:T.run,L=(0,t.useCallback)((()=>{var e;if(!(D&&f&&f.operations&&f.hasFocus()))return void(null==D||D());const t=f.indexFromPos(f.getCursor());let n;for(const r of f.operations)r.loc&&r.loc.start<=t&&r.loc.end>=t&&(n=null==(e=r.name)?void 0:e.value);n&&n!==f.operationName&&p(n),D()}),[f,D,p]);return lC(f,["Cmd-Enter","Ctrl-Enter"],L),lC(f,["Shift-Ctrl-C"],x),lC(f,["Shift-Ctrl-P","Shift-Ctrl-F"],N),lC(f,["Shift-Ctrl-M"],k),_}function xC(e,n,r){(0,t.useEffect)((()=>{if(!e)return;const t=e.options.lint.schema!==n;e.state.lint.linterOptions.schema=n,e.options.lint.schema=n,e.options.hintOptions.schema=n,e.options.info.schema=n,e.options.jump.schema=n,t&&r.current&&r.current.signal(e,"change",e)}),[e,n,r])}function kC(e,n,r){(0,t.useEffect)((()=>{if(!e)return;const t=e.options.lint.validationRules!==n;e.state.lint.linterOptions.validationRules=n,e.options.lint.validationRules=n,t&&r.current&&r.current.signal(e,"change",e)}),[e,n,r])}function NC(e,n,r){const i=(0,t.useMemo)((()=>[...n.values()]),[n]);(0,t.useEffect)((()=>{if(!e)return;const t=e.options.lint.externalFragments!==i;e.state.lint.linterOptions.externalFragments=i,e.options.lint.externalFragments=i,e.options.hintOptions.externalFragments=i,t&&r.current&&r.current.signal(e,"change",e)}),[e,i,r])}g(SC,"useQueryEditor"),CC(SC,"useQueryEditor"),g(xC,"useSynchronizeSchema"),CC(xC,"useSynchronizeSchema"),g(kC,"useSynchronizeValidationRules"),CC(kC,"useSynchronizeValidationRules"),g(NC,"useSynchronizeExternalFragments"),CC(NC,"useSynchronizeExternalFragments");const _C=/^[a-zA-Z0-9_@(]$/,OC="query",IC="operationName";var DC=Object.defineProperty,LC=g(((e,t)=>DC(e,"name",{value:t,configurable:!0})),"__name$c");function AC(e){let{defaultQuery:t,defaultHeaders:n,headers:r,defaultTabs:i,query:o,variables:a,storage:s}=e;const l=null==s?void 0:s.get(XC);try{if(!l)throw new Error("Storage for tabs is empty");const e=JSON.parse(l);if(MC(e)){const t=zC({query:o,variables:a,headers:r});let n=-1;for(let r=0;r=0)e.activeTabIndex=n;else{const n=o?WC(o):null;e.tabs.push({id:GC(),hash:t,title:n||QC,query:o,variables:a,headers:r,operationName:n,response:null}),e.activeTabIndex=e.tabs.length-1}return e}throw new Error("Storage for tabs is invalid")}catch{return{activeTabIndex:0,tabs:(i||[{query:null!=o?o:t,variables:a,headers:null!=r?r:n}]).map(qC)}}}function MC(e){return e&&"object"==typeof e&&!Array.isArray(e)&&FC(e,"activeTabIndex")&&"tabs"in e&&Array.isArray(e.tabs)&&e.tabs.every(RC)}function RC(e){return e&&"object"==typeof e&&!Array.isArray(e)&&PC(e,"id")&&PC(e,"title")&&jC(e,"query")&&jC(e,"variables")&&jC(e,"headers")&&jC(e,"operationName")&&jC(e,"response")}function FC(e,t){return t in e&&"number"==typeof e[t]}function PC(e,t){return t in e&&"string"==typeof e[t]}function jC(e,t){return t in e&&("string"==typeof e[t]||null===e[t])}function VC(e){let{queryEditor:n,variableEditor:r,headerEditor:i,responseEditor:o}=e;return(0,t.useCallback)((e=>{var t,a,s,l,u;const c=null!=(t=null==n?void 0:n.getValue())?t:null,d=null!=(a=null==r?void 0:r.getValue())?a:null,f=null!=(s=null==i?void 0:i.getValue())?s:null,p=null!=(l=null==n?void 0:n.operationName)?l:null;return HC(e,{query:c,variables:d,headers:f,response:null!=(u=null==o?void 0:o.getValue())?u:null,operationName:p})}),[n,r,i,o])}function UC(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return JSON.stringify(e,((e,n)=>"hash"===e||"response"===e||!t&&"headers"===e?null:n))}function BC(e){let{storage:n,shouldPersistHeaders:r}=e;const i=(0,t.useMemo)((()=>ww(500,(e=>{null==n||n.set(XC,e)}))),[n]);return(0,t.useCallback)((e=>{i(UC(e,r))}),[r,i])}function $C(e){let{queryEditor:n,variableEditor:r,headerEditor:i,responseEditor:o}=e;return(0,t.useCallback)((e=>{let{query:t,variables:a,headers:s,response:l}=e;null==n||n.setValue(null!=t?t:""),null==r||r.setValue(null!=a?a:""),null==i||i.setValue(null!=s?s:""),null==o||o.setValue(null!=l?l:"")}),[i,n,o,r])}function qC(){let{query:e=null,variables:t=null,headers:n=null}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{id:GC(),hash:zC({query:e,variables:t,headers:n}),title:e&&WC(e)||QC,query:e,variables:t,headers:n,operationName:null,response:null}}function HC(e,t){return m(h({},e),{tabs:e.tabs.map(((n,r)=>{if(r!==e.activeTabIndex)return n;const i=h(h({},n),t);return m(h({},i),{hash:zC(i),title:i.operationName||(i.query?WC(i.query):void 0)||QC})}))})}function GC(){const e=LC((()=>Math.floor(65536*(1+Math.random())).toString(16).slice(1)),"s4");return`${e()}${e()}-${e()}-${e()}-${e()}-${e()}${e()}${e()}`}function zC(e){var t,n,r;return[null!=(t=e.query)?t:"",null!=(n=e.variables)?n:"",null!=(r=e.headers)?r:""].join("|")}function WC(e){var t;const n=/^(?!#).*(query|subscription|mutation)\s+([a-zA-Z0-9_]+)/m.exec(e);return null!=(t=null==n?void 0:n[2])?t:null}function KC(e){const t=null==e?void 0:e.get(XC);if(t){const n=JSON.parse(t);null==e||e.set(XC,JSON.stringify(n,((e,t)=>"headers"===e?null:t)))}}g(AC,"getDefaultTabState"),LC(AC,"getDefaultTabState"),g(MC,"isTabsState"),LC(MC,"isTabsState"),g(RC,"isTabState"),LC(RC,"isTabState"),g(FC,"hasNumberKey"),LC(FC,"hasNumberKey"),g(PC,"hasStringKey"),LC(PC,"hasStringKey"),g(jC,"hasStringOrNullKey"),LC(jC,"hasStringOrNullKey"),g(VC,"useSynchronizeActiveTabValues"),LC(VC,"useSynchronizeActiveTabValues"),g(UC,"serializeTabState"),LC(UC,"serializeTabState"),g(BC,"useStoreTabs"),LC(BC,"useStoreTabs"),g($C,"useSetEditorValues"),LC($C,"useSetEditorValues"),g(qC,"createTab"),LC(qC,"createTab"),g(HC,"setPropertiesInActiveTab"),LC(HC,"setPropertiesInActiveTab"),g(GC,"guid"),LC(GC,"guid"),g(zC,"hashFromTabContents"),LC(zC,"hashFromTabContents"),g(WC,"fuzzyExtractOperationName"),LC(WC,"fuzzyExtractOperationName"),g(KC,"clearHeadersFromTabs"),LC(KC,"clearHeadersFromTabs");const QC="",XC="tabState";var YC=Object.defineProperty,JC=g(((e,t)=>YC(e,"name",{value:t,configurable:!0})),"__name$b");function ZC(){let{editorTheme:e=gE,keyMap:r=vE,onClickReference:i,onEdit:o,readOnly:a=!1}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},s=arguments.length>1?arguments[1]:void 0;const{initialVariables:l,variableEditor:u,setVariableEditor:c}=oS({nonNull:!0,caller:s||ZC}),d=fE(),f=cC({caller:s||ZC}),p=dC({caller:s||ZC}),h=(0,t.useRef)(null),m=(0,t.useRef)();return(0,t.useEffect)((()=>{let t=!0;return EE([Promise.resolve().then(n.t.bind(n,4712,23)),Promise.resolve().then(n.t.bind(n,8535,23)),Promise.resolve().then(n.t.bind(n,3340,23))]).then((n=>{if(!t)return;m.current=n;const r=h.current;if(!r)return;const i=n(r,{value:l,lineNumbers:!0,tabSize:2,mode:"graphql-variables",theme:e,autoCloseBrackets:!0,matchBrackets:!0,showCursorWhenSelecting:!0,readOnly:!!a&&"nocursor",foldGutter:!0,lint:{variableToType:void 0},hintOptions:{closeOnUnfocus:!1,completeSingle:!1,container:r,variableToType:void 0},gutters:["CodeMirror-linenumbers","CodeMirror-foldgutter"],extraKeys:bE});i.addKeyMap({"Cmd-Space"(){i.showHint({completeSingle:!1,container:r})},"Ctrl-Space"(){i.showHint({completeSingle:!1,container:r})},"Alt-Space"(){i.showHint({completeSingle:!1,container:r})},"Shift-Space"(){i.showHint({completeSingle:!1,container:r})}}),i.on("keyup",((e,t)=>{const{keyCode:n,key:r,shiftKey:i}=t;(n>=65&&n<=90||!i&&n>=48&&n<=57||"_"===r||'"'===r)&&e.execCommand("autocomplete")})),c(i)})),()=>{t=!1}}),[e,l,a,c]),oC(u,"keyMap",r),aC(u,o,eS,"variables",ZC),sC(u,i||null,ZC),lC(u,["Cmd-Enter","Ctrl-Enter"],null==d?void 0:d.run),lC(u,["Shift-Ctrl-P"],p),lC(u,["Shift-Ctrl-M"],f),h}g(ZC,"useVariableEditor"),JC(ZC,"useVariableEditor");const eS="variables";var tS=Object.defineProperty,nS=g(((e,t)=>tS(e,"name",{value:t,configurable:!0})),"__name$a");const rS=X("EditorContext");function iS(e){const n=ye(),[i,o]=(0,t.useState)(null),[a,s]=(0,t.useState)(null),[l,u]=(0,t.useState)(null),[c,d]=(0,t.useState)(null),[f,p]=(0,t.useState)((()=>{const t=null!==(null==n?void 0:n.get(aS));return!1!==e.shouldPersistHeaders&&t?"true"===(null==n?void 0:n.get(aS)):Boolean(e.shouldPersistHeaders)}));iC(i,e.headers),iC(a,e.query),iC(l,e.response),iC(c,e.variables);const g=BC({storage:n,shouldPersistHeaders:f}),[v]=(0,t.useState)((()=>{var t,r,i,o,a,s,l,u,c;const d=null!=(r=null!=(t=e.query)?t:null==n?void 0:n.get(OC))?r:null,f=null!=(o=null!=(i=e.variables)?i:null==n?void 0:n.get(eS))?o:null,p=null!=(s=null!=(a=e.headers)?a:null==n?void 0:n.get(gC))?s:null,h=null!=(l=e.response)?l:"",m=AC({query:d,variables:f,headers:p,defaultTabs:e.defaultTabs||e.initialTabs,defaultQuery:e.defaultQuery||sS,defaultHeaders:e.defaultHeaders,storage:n});return g(m),{query:null!=(u=null!=d?d:0===m.activeTabIndex?m.tabs[0].query:null)?u:"",variables:null!=f?f:"",headers:null!=(c=null!=p?p:e.defaultHeaders)?c:"",response:h,tabState:m}})),[y,b]=(0,t.useState)(v.tabState),E=(0,t.useCallback)((e=>{var t;if(e){null==n||n.set(gC,null!=(t=null==i?void 0:i.getValue())?t:"");const e=UC(y,!0);null==n||n.set(XC,e)}else null==n||n.set(gC,""),KC(n);p(e),null==n||n.set(aS,e.toString())}),[n,y,i]),T=(0,t.useRef)();(0,t.useEffect)((()=>{const t=Boolean(e.shouldPersistHeaders);T.current!==t&&(E(t),T.current=t)}),[e.shouldPersistHeaders,E]);const w=VC({queryEditor:a,variableEditor:c,headerEditor:i,responseEditor:l}),C=$C({queryEditor:a,variableEditor:c,headerEditor:i,responseEditor:l}),{onTabChange:S,defaultHeaders:x,children:k}=e,N=(0,t.useCallback)((()=>{b((e=>{const t=w(e),n={tabs:[...t.tabs,qC({headers:x})],activeTabIndex:t.tabs.length};return g(n),C(n.tabs[n.activeTabIndex]),null==S||S(n),n}))}),[x,S,C,g,w]),_=(0,t.useCallback)((e=>{b((t=>{const n=m(h({},w(t)),{activeTabIndex:e});return g(n),C(n.tabs[n.activeTabIndex]),null==S||S(n),n}))}),[S,C,g,w]),O=(0,t.useCallback)((e=>{b((t=>{const n={tabs:t.tabs.filter(((t,n)=>e!==n)),activeTabIndex:Math.max(t.activeTabIndex-1,0)};return g(n),C(n.tabs[n.activeTabIndex]),null==S||S(n),n}))}),[S,C,g]),I=(0,t.useCallback)((e=>{b((t=>{const n=HC(t,e);return g(n),null==S||S(n),n}))}),[S,g]),{onEditOperationName:D}=e,L=(0,t.useCallback)((e=>{a&&(a.operationName=e,I({operationName:e}),null==D||D(e))}),[D,a,I]),A=(0,t.useMemo)((()=>{const t=new Map;if(Array.isArray(e.externalFragments))for(const n of e.externalFragments)t.set(n.name.value,n);else if("string"==typeof e.externalFragments)(0,r.visit)((0,r.parse)(e.externalFragments,{}),{FragmentDefinition(e){t.set(e.name.value,e)}});else if(e.externalFragments)throw new Error("The `externalFragments` prop must either be a string that contains the fragment definitions in SDL or a list of FragmentDefinitionNode objects.");return t}),[e.externalFragments]),M=(0,t.useMemo)((()=>e.validationRules||[]),[e.validationRules]),R=(0,t.useMemo)((()=>m(h({},y),{addTab:N,changeTab:_,closeTab:O,updateActiveTabValues:I,headerEditor:i,queryEditor:a,responseEditor:l,variableEditor:c,setHeaderEditor:o,setQueryEditor:s,setResponseEditor:u,setVariableEditor:d,setOperationName:L,initialQuery:v.query,initialVariables:v.variables,initialHeaders:v.headers,initialResponse:v.response,externalFragments:A,validationRules:M,shouldPersistHeaders:f,setShouldPersistHeaders:E})),[y,N,_,O,I,i,a,l,c,L,v,A,M,f,E]);return de(rS.Provider,{value:R,children:k})}e.E=rS,g(iS,"EditorContextProvider"),nS(iS,"EditorContextProvider");const oS=Y(rS);e.f=oS;const aS="shouldPersistHeaders",sS='# Welcome to GraphiQL\n#\n# GraphiQL is an in-browser tool for writing, validating, and\n# testing GraphQL queries.\n#\n# Type queries into this side of the screen, and you will see intelligent\n# typeaheads aware of the current GraphQL type schema and live syntax and\n# validation errors highlighted within the text.\n#\n# GraphQL queries typically start with a "{" character. Lines that start\n# with a # are ignored.\n#\n# An example GraphQL query might look like:\n#\n# {\n# field(arg: "value") {\n# subField\n# }\n# }\n#\n# Keyboard shortcuts:\n#\n# Prettify query: Shift-Ctrl-P (or press the prettify button)\n#\n# Merge fragments: Shift-Ctrl-M (or press the merge button)\n#\n# Run Query: Ctrl-Enter (or press the play button)\n#\n# Auto Complete: Ctrl-Space (or just start typing)\n#\n\n';var lS=Object.defineProperty,uS=g(((e,t)=>lS(e,"name",{value:t,configurable:!0})),"__name$9");function cS(e){var n=e,{isHidden:r}=n,i=v(n,["isHidden"]);const{headerEditor:o}=oS({nonNull:!0,caller:cS}),a=mC(i,cS);return(0,t.useEffect)((()=>{o&&!r&&o.refresh()}),[o,r]),de("div",{className:b("graphiql-editor",r&&"hidden"),ref:a})}g(cS,"HeaderEditor"),uS(cS,"HeaderEditor");var dS=Object.defineProperty,fS=g(((e,t)=>dS(e,"name",{value:t,configurable:!0})),"__name$8");function pS(e){var n;const[r,i]=(0,t.useState)({width:null,height:null}),[o,a]=(0,t.useState)(null),s=(0,t.useRef)(null),l=null==(n=hS(e.token))?void 0:n.href;(0,t.useEffect)((()=>{if(s.current)return l?void fetch(l,{method:"HEAD"}).then((e=>{a(e.headers.get("Content-Type"))})).catch((()=>{a(null)})):(i({width:null,height:null}),void a(null))}),[l]);const u=null!==r.width&&null!==r.height?fe("div",{children:[r.width,"x",r.height,null===o?null:" "+o]}):null;return fe("div",{children:[de("img",{onLoad:()=>{var e,t,n,r;i({width:null!=(t=null==(e=s.current)?void 0:e.naturalWidth)?t:null,height:null!=(r=null==(n=s.current)?void 0:n.naturalHeight)?r:null})},ref:s,src:l}),u]})}function hS(e){if("string"!==e.type)return;const t=e.string.slice(1).slice(0,-1).trim();try{const{location:e}=window;return new URL(t,e.protocol+"//"+e.host)}catch{return}}function mS(e){return/(bmp|gif|jpeg|jpg|png|svg)$/.test(e.pathname)}g(pS,"ImagePreview"),fS(pS,"ImagePreview"),pS.shouldRender=fS(g((function(e){const t=hS(e);return!!t&&mS(t)}),"shouldRender"),"shouldRender"),g(hS,"tokenToURL"),fS(hS,"tokenToURL"),g(mS,"isImageURL"),fS(mS,"isImageURL");var gS=Object.defineProperty,vS=g(((e,t)=>gS(e,"name",{value:t,configurable:!0})),"__name$7");function yS(e){const t=SC(e,yS);return de("div",{className:"graphiql-editor",ref:t})}g(yS,"QueryEditor"),vS(yS,"QueryEditor");var bS=Object.defineProperty,ES=g(((e,t)=>bS(e,"name",{value:t,configurable:!0})),"__name$6");function TS(){let{responseTooltip:e,editorTheme:r=gE,keyMap:o=vE}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},a=arguments.length>1?arguments[1]:void 0;const{fetchError:s,validationErrors:l}=RE({nonNull:!0,caller:a||TS}),{initialResponse:u,responseEditor:c,setResponseEditor:d}=oS({nonNull:!0,caller:a||TS}),f=(0,t.useRef)(null),p=(0,t.useRef)(e);return(0,t.useEffect)((()=>{p.current=e}),[e]),(0,t.useEffect)((()=>{let e=!0;return EE([Promise.resolve().then(n.t.bind(n,8419,23)).then((function(e){return e.f})),Promise.resolve().then(n.t.bind(n,4468,23)).then((function(e){return e.b})),Promise.resolve().then(n.t.bind(n,8058,23)).then((function(e){return e.d})),Promise.resolve().then(n.t.bind(n,9509,23)).then((function(e){return e.s})),Promise.resolve().then(n.t.bind(n,9407,23)).then((function(e){return e.s})),Promise.resolve().then(n.t.bind(n,4471,23)).then((function(e){return e.j})),Promise.resolve().then(n.t.bind(n,2568,23)).then((function(e){return e.s})),Promise.resolve().then(n.t.bind(n,1430,23)),Promise.resolve().then(n.t.bind(n,7421,23))],{useCommonAddons:!1}).then((t=>{if(!e)return;const n=document.createElement("div");t.registerHelper("info","graphql-results",((e,t,r,o)=>{const a=[],s=p.current;return s&&a.push(de(s,{pos:o,token:e})),pS.shouldRender(e)&&a.push(de(pS,{token:e},"image-preview")),a.length?(i.default.render(a,n),n):(i.default.unmountComponentAtNode(n),null)}));const o=f.current;if(!o)return;const a=t(o,{value:u,lineWrapping:!0,readOnly:!0,theme:r,mode:"graphql-results",foldGutter:!0,gutters:["CodeMirror-foldgutter"],info:!0,extraKeys:bE});d(a)})),()=>{e=!1}}),[r,u,d]),oC(c,"keyMap",o),(0,t.useEffect)((()=>{s&&(null==c||c.setValue(s)),l.length>0&&(null==c||c.setValue(D(l)))}),[c,s,l]),f}g(TS,"useResponseEditor"),ES(TS,"useResponseEditor");var wS=Object.defineProperty,CS=g(((e,t)=>wS(e,"name",{value:t,configurable:!0})),"__name$5");function SS(e){const t=TS(e,SS);return de("section",{className:"result-window","aria-label":"Result Window","aria-live":"polite","aria-atomic":"true",ref:t})}g(SS,"ResponseEditor"),CS(SS,"ResponseEditor");var xS=Object.defineProperty,kS=g(((e,t)=>xS(e,"name",{value:t,configurable:!0})),"__name$4");function NS(e){var n=e,{isHidden:r}=n,i=v(n,["isHidden"]);const{variableEditor:o}=oS({nonNull:!0,caller:NS}),a=ZC(i,NS);return(0,t.useEffect)((()=>{o&&!r&&o.refresh()}),[o,r]),de("div",{className:b("graphiql-editor",r&&"hidden"),ref:a})}g(NS,"VariableEditor"),kS(NS,"VariableEditor");var _S=Object.defineProperty,OS=g(((e,t)=>_S(e,"name",{value:t,configurable:!0})),"__name$3");function IS(e){let{children:t,dangerouslyAssumeSchemaIsValid:n,defaultQuery:r,defaultHeaders:i,defaultTabs:o,externalFragments:a,fetcher:s,getDefaultFieldNames:l,headers:u,initialTabs:c,inputValueDeprecation:d,introspectionQueryName:f,maxHistoryLength:p,onEditOperationName:h,onSchemaChange:m,onTabChange:g,onTogglePluginVisibility:v,operationName:y,plugins:b,query:E,response:T,schema:w,schemaDescription:C,shouldPersistHeaders:S,storage:x,validationRules:k,variables:N,visiblePlugin:_}=e;return de(ve,{storage:x,children:de(eE,{maxHistoryLength:p,children:de(iS,{defaultQuery:r,defaultHeaders:i,defaultTabs:o,externalFragments:a,headers:u,initialTabs:c,onEditOperationName:h,onTabChange:g,query:E,response:T,shouldPersistHeaders:S,validationRules:k,variables:N,children:de(ME,{dangerouslyAssumeSchemaIsValid:n,fetcher:s,inputValueDeprecation:d,introspectionQueryName:f,onSchemaChange:m,schema:w,schemaDescription:C,children:de(dE,{getDefaultFieldNames:l,fetcher:s,operationName:y,children:de($E,{children:de(Xw,{onTogglePluginVisibility:v,plugins:b,visiblePlugin:_,children:t})})})})})})})}g(IS,"GraphiQLProvider"),OS(IS,"GraphiQLProvider");var DS=Object.defineProperty,LS=g(((e,t)=>DS(e,"name",{value:t,configurable:!0})),"__name$2");function AS(){const e=ye(),[n,r]=(0,t.useState)((()=>{if(!e)return null;const t=e.get(MS);switch(t){case"light":return"light";case"dark":return"dark";default:return"string"==typeof t&&e.set(MS,""),null}}));(0,t.useLayoutEffect)((()=>{"undefined"!=typeof window&&(document.body.classList.remove("graphiql-light","graphiql-dark"),n&&document.body.classList.add(`graphiql-${n}`))}),[n]);const i=(0,t.useCallback)((t=>{null==e||e.set(MS,t||""),r(t)}),[e]);return(0,t.useMemo)((()=>({theme:n,setTheme:i})),[n,i])}g(AS,"useTheme"),LS(AS,"useTheme");const MS="theme";var RS=Object.defineProperty,FS=g(((e,t)=>RS(e,"name",{value:t,configurable:!0})),"__name$1");function PS(e){let{defaultSizeRelation:n=jS,direction:r,initiallyHidden:i,onHiddenElementChange:o,sizeThresholdFirst:a=100,sizeThresholdSecond:s=100,storageKey:l}=e;const u=ye(),c=(0,t.useMemo)((()=>ww(500,(e=>{u&&l&&u.set(l,e)}))),[u,l]),[d,f]=(0,t.useState)((()=>{const e=u&&l?u.get(l):null;return e===VS||"first"===i?"first":e===US||"second"===i?"second":null})),p=(0,t.useCallback)((e=>{e!==d&&(f(e),null==o||o(e))}),[d,o]),h=(0,t.useRef)(null),m=(0,t.useRef)(null),v=(0,t.useRef)(null),y=(0,t.useRef)(`${n}`);(0,t.useLayoutEffect)((()=>{const e=u&&l&&u.get(l)||y.current,t="horizontal"===r?"row":"column";h.current&&(h.current.style.display="flex",h.current.style.flexDirection=t,h.current.style.flex=e===VS||e===US?y.current:e),v.current&&(v.current.style.display="flex",v.current.style.flexDirection=t,v.current.style.flex="1"),m.current&&(m.current.style.display="flex",m.current.style.flexDirection=t)}),[r,u,l]);const b=(0,t.useCallback)((e=>{const t="first"===e?h.current:v.current;if(t&&(t.style.left="-1000px",t.style.position="absolute",t.style.opacity="0",t.style.height="500px",t.style.width="500px",h.current)){const e=parseFloat(h.current.style.flex);(!Number.isFinite(e)||e<1)&&(h.current.style.flex="1")}}),[]),E=(0,t.useCallback)((e=>{const t="first"===e?h.current:v.current;if(t&&(t.style.width="",t.style.height="",t.style.opacity="",t.style.position="",t.style.left="",h.current&&u&&l)){const e=null==u?void 0:u.get(l);e!==VS&&e!==US&&(h.current.style.flex=e||y.current)}}),[u,l]);return(0,t.useLayoutEffect)((()=>{"first"===d?b("first"):E("first"),"second"===d?b("second"):E("second")}),[d,b,E]),(0,t.useEffect)((()=>{if(!m.current||!h.current||!v.current)return;const e=m.current,t=h.current,n=t.parentElement,i="horizontal"===r?"clientX":"clientY",o="horizontal"===r?"left":"top",l="horizontal"===r?"right":"bottom",u="horizontal"===r?"clientWidth":"clientHeight";function d(r){r.preventDefault();const d=r[i]-e.getBoundingClientRect()[o];function f(r){if(0===r.buttons)return h();const f=r[i]-n.getBoundingClientRect()[o]-d,m=n.getBoundingClientRect()[l]-r[i]+d-e[u];if(f{e.removeEventListener("mousedown",d),e.removeEventListener("dblclick",f)}}),[r,p,a,s,c]),(0,t.useMemo)((()=>({dragBarRef:m,hiddenElement:d,firstRef:h,setHiddenElement:f,secondRef:v})),[d,f])}g(PS,"useDragResize"),FS(PS,"useDragResize");const jS=1,VS="hide-first",US="hide-second",BS=(0,t.forwardRef)(((e,n)=>{var r=e,{label:i}=r,o=v(r,["label"]);const[a,s]=(0,t.useState)(null);return de(Pb,{label:i,children:de(os,m(h({},o),{ref:n,type:"button",className:b("graphiql-toolbar-button",a&&"error",o.className),onClick:e=>{var t;try{null==(t=o.onClick)||t.call(o,e),s(null)}catch(e){s(e instanceof Error?e:new Error(`Toolbar button click failed: ${e}`))}},"aria-label":a?a.message:i,"aria-invalid":a?"true":o["aria-invalid"]}))})}));e.aR=BS,BS.displayName="ToolbarButton";var $S=Object.defineProperty,qS=g(((e,t)=>$S(e,"name",{value:t,configurable:!0})),"__name");function HS(){const{queryEditor:e,setOperationName:t}=oS({nonNull:!0,caller:HS}),{isFetching:n,isSubscribed:r,operationName:i,run:o,stop:a}=fE({nonNull:!0,caller:HS}),s=(null==e?void 0:e.operations)||[],l=s.length>1&&"string"!=typeof i,u=n||r,c=(u?"Stop":"Execute")+" query (Ctrl-Enter)",d={type:"button",className:"graphiql-execute-button",children:de(u?ns:Ka,{}),"aria-label":c};return l&&!u?fe(Hh,{children:[de(Pb,{label:c,children:de(Hh.Button,h({},d))}),de(Hh.List,{children:s.map(((n,r)=>{const i=n.name?n.name.value:``;return de(Hh.Item,{onSelect:()=>{var r;const i=null==(r=n.name)?void 0:r.value;e&&i&&i!==e.operationName&&t(i),o()},children:i},`${i}-${r}`)}))})]}):de(Pb,{label:c,children:de("button",m(h({},d),{onClick:()=>{u?a():o()}}))})}g(HS,"ExecuteButton"),qS(HS,"ExecuteButton");const GS=(0,t.forwardRef)(((e,t)=>{var n=e,{button:r,children:i,label:o}=n,a=v(n,["button","children","label"]);const s=`${o}${a.value?`: ${a.value}`:""}`;return fe(zh.Input,m(h({},a),{ref:t,className:b("graphiql-toolbar-listbox",a.className),"aria-label":s,children:[de(Pb,{label:s,children:de(zh.Button,{children:r})}),de(zh.Popover,{children:i})]}))}));GS.displayName="ToolbarListbox";const zS=Xc(GS,{Option:zh.Option});e.aT=zS;const WS=(0,t.forwardRef)(((e,t)=>{var n=e,{button:r,children:i,label:o}=n,a=v(n,["button","children","label"]);return fe(Hh,m(h({},a),{ref:t,children:[de(Pb,{label:o,children:de(Hh.Button,{className:b("graphiql-un-styled graphiql-toolbar-menu",a.className),"aria-label":o,children:r})}),de(Hh.List,{children:i})]}))}));WS.displayName="ToolbarMenu";const KS=Xc(WS,{Item:Hh.Item});e.aU=KS},void 0===(o=r.apply(t,i))||(e.exports=o)},7421:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(6856),n(9196),n(3573),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i){"use strict";var o=Object.defineProperty,a=(e,t)=>o(e,"name",{value:t,configurable:!0});function s(e){return{options:e instanceof Function?{render:e}:!0===e?{}:e}}function l(e){const{options:t}=e.state.info;return(null==t?void 0:t.hoverTime)||500}function u(t,n){const r=t.state.info,i=n.target||n.srcElement;if(!(i instanceof HTMLElement))return;if("SPAN"!==i.nodeName||void 0!==r.hoverTimeout)return;const o=i.getBoundingClientRect(),s=a((function(){clearTimeout(r.hoverTimeout),r.hoverTimeout=setTimeout(d,f)}),"onMouseMove"),u=a((function(){e.C.off(document,"mousemove",s),e.C.off(t.getWrapperElement(),"mouseout",u),clearTimeout(r.hoverTimeout),r.hoverTimeout=void 0}),"onMouseOut"),d=a((function(){e.C.off(document,"mousemove",s),e.C.off(t.getWrapperElement(),"mouseout",u),r.hoverTimeout=void 0,c(t,o)}),"onHover"),f=l(t);r.hoverTimeout=setTimeout(d,f),e.C.on(document,"mousemove",s),e.C.on(t.getWrapperElement(),"mouseout",u)}function c(e,t){const n=e.coordsChar({left:(t.left+t.right)/2,top:(t.top+t.bottom)/2}),r=e.state.info,{options:i}=r,o=i.render||e.getHelper(n,"info");if(o){const r=e.getTokenAt(n,!0);if(r){const a=o(r,i,e,n);a&&d(e,t,a)}}}function d(t,n,r){const i=document.createElement("div");i.className="CodeMirror-info",i.append(r),document.body.append(i);const o=i.getBoundingClientRect(),s=window.getComputedStyle(i),l=o.right-o.left+parseFloat(s.marginLeft)+parseFloat(s.marginRight),u=o.bottom-o.top+parseFloat(s.marginTop)+parseFloat(s.marginBottom);let c=n.bottom;u>window.innerHeight-n.bottom-15&&n.top>window.innerHeight-n.bottom&&(c=n.top-u),c<0&&(c=n.bottom);let d,f=Math.max(0,window.innerWidth-l-15);f>n.left&&(f=n.left),i.style.opacity="1",i.style.top=c+"px",i.style.left=f+"px";const p=a((function(){clearTimeout(d)}),"onMouseOverPopup"),h=a((function(){clearTimeout(d),d=setTimeout(m,200)}),"onMouseOut"),m=a((function(){e.C.off(i,"mouseover",p),e.C.off(i,"mouseout",h),e.C.off(t.getWrapperElement(),"mouseout",h),i.style.opacity?(i.style.opacity="0",setTimeout((()=>{i.parentNode&&i.remove()}),600)):i.parentNode&&i.remove()}),"hidePopup");e.C.on(i,"mouseover",p),e.C.on(i,"mouseout",h),e.C.on(t.getWrapperElement(),"mouseout",h)}e.C.defineOption("info",!1,((t,n,r)=>{if(r&&r!==e.C.Init){const n=t.state.info.onMouseOver;e.C.off(t.getWrapperElement(),"mouseover",n),clearTimeout(t.state.info.hoverTimeout),delete t.state.info}if(n){const r=t.state.info=s(n);r.onMouseOver=u.bind(null,t),e.C.on(t.getWrapperElement(),"mouseover",r.onMouseOver)}})),a(s,"createState"),a(l,"getHoverTime"),a(u,"onMouseOver"),a(c,"onMouseHover"),a(d,"showPopup")})?r.apply(t,i):r)||(e.exports=o)},9890:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(3573),n(535),n(2645),n(7421),n(6856),n(9196),n(1850),n(2635)],r=function(e,t,n,r,i,o,a,s){"use strict";var l=Object.defineProperty,u=(e,t)=>l(e,"name",{value:t,configurable:!0});function c(e,t,n){d(e,t,n),m(e,t,n,t.type)}function d(e,t,r){var i;b(e,(null===(i=t.fieldDef)||void 0===i?void 0:i.name)||"","field-name",r,(0,n.a)(t))}function f(e,t,r){var i;b(e,"@"+((null===(i=t.directiveDef)||void 0===i?void 0:i.name)||""),"directive-name",r,(0,n.b)(t))}function p(e,t,r){var i;b(e,(null===(i=t.argDef)||void 0===i?void 0:i.name)||"","arg-name",r,(0,n.c)(t)),m(e,t,r,t.inputType)}function h(e,t,r){var i;const o=(null===(i=t.enumValue)||void 0===i?void 0:i.name)||"";g(e,t,r,t.inputType),b(e,"."),b(e,o,"enum-value",r,(0,n.d)(t))}function m(t,r,i,o){const a=document.createElement("span");a.className="type-name-pill",o instanceof e.GraphQLNonNull?(g(a,r,i,o.ofType),b(a,"!")):o instanceof e.GraphQLList?(b(a,"["),g(a,r,i,o.ofType),b(a,"]")):b(a,(null==o?void 0:o.name)||"","type-name",i,(0,n.e)(r,o)),t.append(a)}function g(t,r,i,o){o instanceof e.GraphQLNonNull?(g(t,r,i,o.ofType),b(t,"!")):o instanceof e.GraphQLList?(b(t,"["),g(t,r,i,o.ofType),b(t,"]")):b(t,(null==o?void 0:o.name)||"","type-name",i,(0,n.e)(r,o))}function v(e,t,n){const{description:r}=n;if(r){const n=document.createElement("div");n.className="info-description",t.renderDescription?n.innerHTML=t.renderDescription(r):n.append(document.createTextNode(r)),e.append(n)}y(e,t,n)}function y(e,t,n){const r=n.deprecationReason;if(r){const n=document.createElement("div");n.className="info-deprecation",e.append(n);const i=document.createElement("span");i.className="info-deprecation-label",i.append(document.createTextNode("Deprecated")),n.append(i);const o=document.createElement("div");o.className="info-deprecation-reason",t.renderDescription?o.innerHTML=t.renderDescription(r):o.append(document.createTextNode(r)),n.append(o)}}function b(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{onClick:null},i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:null;if(n){const{onClick:o}=r;let a;o?(a=document.createElement("a"),a.href="javascript:void 0",a.addEventListener("click",(e=>{o(i,e)}))):a=document.createElement("span"),a.className=n,a.append(document.createTextNode(t)),e.append(a)}else e.append(document.createTextNode(t))}t.C.registerHelper("info","graphql",((e,t)=>{if(!t.schema||!e.state)return;const{kind:r,step:i}=e.state,o=(0,n.g)(t.schema,e.state);if("Field"===r&&0===i&&o.fieldDef||"AliasedField"===r&&2===i&&o.fieldDef){const e=document.createElement("div");e.className="CodeMirror-info-header",c(e,o,t);const n=document.createElement("div");return n.append(e),v(n,t,o.fieldDef),n}if("Directive"===r&&1===i&&o.directiveDef){const e=document.createElement("div");e.className="CodeMirror-info-header",f(e,o,t);const n=document.createElement("div");return n.append(e),v(n,t,o.directiveDef),n}if("Argument"===r&&0===i&&o.argDef){const e=document.createElement("div");e.className="CodeMirror-info-header",p(e,o,t);const n=document.createElement("div");return n.append(e),v(n,t,o.argDef),n}if("EnumValue"===r&&o.enumValue&&o.enumValue.description){const e=document.createElement("div");e.className="CodeMirror-info-header",h(e,o,t);const n=document.createElement("div");return n.append(e),v(n,t,o.enumValue),n}if("NamedType"===r&&o.type&&o.type.description){const e=document.createElement("div");e.className="CodeMirror-info-header",g(e,o,t,o.type);const n=document.createElement("div");return n.append(e),v(n,t,o.type),n}})),u(c,"renderField"),u(d,"renderQualifiedField"),u(f,"renderDirective"),u(p,"renderArg"),u(h,"renderEnumValue"),u(m,"renderTypeAnnotation"),u(g,"renderType"),u(v,"renderDescription"),u(y,"renderDeprecation"),u(b,"text")},void 0===(o=r.apply(t,i))||(e.exports=o)},8888:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535)],r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.j=void 0;var n=Object.defineProperty,r=(e,t)=>n(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o,a={exports:{}};(o=t.a.exports).defineMode("javascript",(function(e,t){var n,i,a=e.indentUnit,s=t.statementIndent,l=t.jsonld,u=t.json||l,c=!1!==t.trackScope,d=t.typescript,f=t.wordCharacters||/[\w$\xa1-\uffff]/,p=function(){function e(e){return{type:e,style:"keyword"}}r(e,"kw");var t=e("keyword a"),n=e("keyword b"),i=e("keyword c"),o=e("keyword d"),a=e("operator"),s={type:"atom",style:"atom"};return{if:e("if"),while:t,with:t,else:n,do:n,try:n,finally:n,return:o,break:o,continue:o,new:e("new"),delete:i,void:i,throw:i,debugger:e("debugger"),var:e("var"),const:e("var"),let:e("var"),function:e("function"),catch:e("catch"),for:e("for"),switch:e("switch"),case:e("case"),default:e("default"),in:a,typeof:a,instanceof:a,true:s,false:s,null:s,undefined:s,NaN:s,Infinity:s,this:e("this"),class:e("class"),super:e("atom"),yield:i,export:e("export"),import:e("import"),extends:i,await:i}}(),h=/[+\-*&%=<>!?|~^@]/,m=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;function g(e){for(var t,n=!1,r=!1;null!=(t=e.next());){if(!n){if("/"==t&&!r)return;"["==t?r=!0:r&&"]"==t&&(r=!1)}n=!n&&"\\"==t}}function v(e,t,r){return n=e,i=r,t}function y(e,t){var n=e.next();if('"'==n||"'"==n)return t.tokenize=b(n),t.tokenize(e,t);if("."==n&&e.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/))return v("number","number");if("."==n&&e.match(".."))return v("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(n))return v(n);if("="==n&&e.eat(">"))return v("=>","operator");if("0"==n&&e.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/))return v("number","number");if(/\d/.test(n))return e.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/),v("number","number");if("/"==n)return e.eat("*")?(t.tokenize=E,E(e,t)):e.eat("/")?(e.skipToEnd(),v("comment","comment")):ot(e,t,1)?(g(e),e.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/),v("regexp","string-2")):(e.eat("="),v("operator","operator",e.current()));if("`"==n)return t.tokenize=T,T(e,t);if("#"==n&&"!"==e.peek())return e.skipToEnd(),v("meta","meta");if("#"==n&&e.eatWhile(f))return v("variable","property");if("<"==n&&e.match("!--")||"-"==n&&e.match("->")&&!/\S/.test(e.string.slice(0,e.start)))return e.skipToEnd(),v("comment","comment");if(h.test(n))return">"==n&&t.lexical&&">"==t.lexical.type||(e.eat("=")?"!"!=n&&"="!=n||e.eat("="):/[<>*+\-|&?]/.test(n)&&(e.eat(n),">"==n&&e.eat(n))),"?"==n&&e.eat(".")?v("."):v("operator","operator",e.current());if(f.test(n)){e.eatWhile(f);var r=e.current();if("."!=t.lastType){if(p.propertyIsEnumerable(r)){var i=p[r];return v(i.type,i.style,r)}if("async"==r&&e.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/,!1))return v("async","keyword",r)}return v("variable","variable",r)}}function b(e){return function(t,n){var r,i=!1;if(l&&"@"==t.peek()&&t.match(m))return n.tokenize=y,v("jsonld-keyword","meta");for(;null!=(r=t.next())&&(r!=e||i);)i=!i&&"\\"==r;return i||(n.tokenize=y),v("string","string")}}function E(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize=y;break}r="*"==n}return v("comment","comment")}function T(e,t){for(var n,r=!1;null!=(n=e.next());){if(!r&&("`"==n||"$"==n&&e.eat("{"))){t.tokenize=y;break}r=!r&&"\\"==n}return v("quasi","string-2",e.current())}r(g,"readRegexp"),r(v,"ret"),r(y,"tokenBase"),r(b,"tokenString"),r(E,"tokenComment"),r(T,"tokenQuasi");var w="([{}])";function C(e,t){t.fatArrowAt&&(t.fatArrowAt=null);var n=e.string.indexOf("=>",e.start);if(!(n<0)){if(d){var r=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(e.string.slice(e.start,n));r&&(n=r.index)}for(var i=0,o=!1,a=n-1;a>=0;--a){var s=e.string.charAt(a),l=w.indexOf(s);if(l>=0&&l<3){if(!i){++a;break}if(0==--i){"("==s&&(o=!0);break}}else if(l>=3&&l<6)++i;else if(f.test(s))o=!0;else if(/["'\/`]/.test(s))for(;;--a){if(0==a)return;if(e.string.charAt(a-1)==s&&"\\"!=e.string.charAt(a-2)){a--;break}}else if(o&&!i){++a;break}}o&&!i&&(t.fatArrowAt=a)}}r(C,"findFatArrow");var S={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,this:!0,import:!0,"jsonld-keyword":!0};function x(e,t,n,r,i,o){this.indented=e,this.column=t,this.type=n,this.prev=i,this.info=o,null!=r&&(this.align=r)}function k(e,t){if(!c)return!1;for(var n=e.localVars;n;n=n.next)if(n.name==t)return!0;for(var r=e.context;r;r=r.prev)for(n=r.vars;n;n=n.next)if(n.name==t)return!0}function N(e,t,n,r,i){var o=e.cc;for(_.state=e,_.stream=i,_.marked=null,_.cc=o,_.style=t,e.lexical.hasOwnProperty("align")||(e.lexical.align=!0);;)if((o.length?o.pop():u?z:H)(n,r)){for(;o.length&&o[o.length-1].lex;)o.pop()();return _.marked?_.marked:"variable"==n&&k(e,r)?"variable-2":t}}r(x,"JSLexical"),r(k,"inScope"),r(N,"parseJS");var _={state:null,column:null,marked:null,cc:null};function O(){for(var e=arguments.length-1;e>=0;e--)_.cc.push(arguments[e])}function I(){return O.apply(null,arguments),!0}function D(e,t){for(var n=t;n;n=n.next)if(n.name==e)return!0;return!1}function L(e){var n=_.state;if(_.marked="def",c){if(n.context)if("var"==n.lexical.info&&n.context&&n.context.block){var r=A(e,n.context);if(null!=r)return void(n.context=r)}else if(!D(e,n.localVars))return void(n.localVars=new F(e,n.localVars));t.globalVars&&!D(e,n.globalVars)&&(n.globalVars=new F(e,n.globalVars))}}function A(e,t){if(t){if(t.block){var n=A(e,t.prev);return n?n==t.prev?t:new R(n,t.vars,!0):null}return D(e,t.vars)?t:new R(t.prev,new F(e,t.vars),!1)}return null}function M(e){return"public"==e||"private"==e||"protected"==e||"abstract"==e||"readonly"==e}function R(e,t,n){this.prev=e,this.vars=t,this.block=n}function F(e,t){this.name=e,this.next=t}r(O,"pass"),r(I,"cont"),r(D,"inList"),r(L,"register"),r(A,"registerVarScoped"),r(M,"isModifier"),r(R,"Context"),r(F,"Var");var P=new F("this",new F("arguments",null));function j(){_.state.context=new R(_.state.context,_.state.localVars,!1),_.state.localVars=P}function V(){_.state.context=new R(_.state.context,_.state.localVars,!0),_.state.localVars=null}function U(){_.state.localVars=_.state.context.vars,_.state.context=_.state.context.prev}function B(e,t){var n=r((function(){var n=_.state,r=n.indented;if("stat"==n.lexical.type)r=n.lexical.indented;else for(var i=n.lexical;i&&")"==i.type&&i.align;i=i.prev)r=i.indented;n.lexical=new x(r,_.stream.column(),e,null,n.lexical,t)}),"result");return n.lex=!0,n}function $(){var e=_.state;e.lexical.prev&&(")"==e.lexical.type&&(e.indented=e.lexical.indented),e.lexical=e.lexical.prev)}function q(e){function t(n){return n==e?I():";"==e||"}"==n||")"==n||"]"==n?O():I(t)}return r(t,"exp"),t}function H(e,t){return"var"==e?I(B("vardef",t),Oe,q(";"),$):"keyword a"==e?I(B("form"),K,H,$):"keyword b"==e?I(B("form"),H,$):"keyword d"==e?_.stream.match(/^\s*$/,!1)?I():I(B("stat"),X,q(";"),$):"debugger"==e?I(q(";")):"{"==e?I(B("}"),V,pe,$,U):";"==e?I():"if"==e?("else"==_.state.lexical.info&&_.state.cc[_.state.cc.length-1]==$&&_.state.cc.pop()(),I(B("form"),K,H,$,Re)):"function"==e?I(Ve):"for"==e?I(B("form"),V,Fe,H,U,$):"class"==e||d&&"interface"==t?(_.marked="keyword",I(B("form","class"==e?e:t),He,$)):"variable"==e?d&&"declare"==t?(_.marked="keyword",I(H)):d&&("module"==t||"enum"==t||"type"==t)&&_.stream.match(/^\s*\w/,!1)?(_.marked="keyword","enum"==t?I(nt):"type"==t?I(Be,q("operator"),ye,q(";")):I(B("form"),Ie,q("{"),B("}"),pe,$,$)):d&&"namespace"==t?(_.marked="keyword",I(B("form"),z,H,$)):d&&"abstract"==t?(_.marked="keyword",I(H)):I(B("stat"),ae):"switch"==e?I(B("form"),K,q("{"),B("}","switch"),V,pe,$,$,U):"case"==e?I(z,q(":")):"default"==e?I(q(":")):"catch"==e?I(B("form"),j,G,H,$,U):"export"==e?I(B("stat"),Ke,$):"import"==e?I(B("stat"),Xe,$):"async"==e?I(H):"@"==t?I(z,H):O(B("stat"),z,q(";"),$)}function G(e){if("("==e)return I($e,q(")"))}function z(e,t){return Q(e,t,!1)}function W(e,t){return Q(e,t,!0)}function K(e){return"("!=e?O():I(B(")"),X,q(")"),$)}function Q(e,t,n){if(_.state.fatArrowAt==_.stream.start){var r=n?ne:te;if("("==e)return I(j,B(")"),de($e,")"),$,q("=>"),r,U);if("variable"==e)return O(j,Ie,q("=>"),r,U)}var i=n?J:Y;return S.hasOwnProperty(e)?I(i):"function"==e?I(Ve,i):"class"==e||d&&"interface"==t?(_.marked="keyword",I(B("form"),qe,$)):"keyword c"==e||"async"==e?I(n?W:z):"("==e?I(B(")"),X,q(")"),$,i):"operator"==e||"spread"==e?I(n?W:z):"["==e?I(B("]"),tt,$,i):"{"==e?fe(le,"}",null,i):"quasi"==e?O(Z,i):"new"==e?I(re(n)):I()}function X(e){return e.match(/[;\}\)\],]/)?O():O(z)}function Y(e,t){return","==e?I(X):J(e,t,!1)}function J(e,t,n){var r=0==n?Y:J,i=0==n?z:W;return"=>"==e?I(j,n?ne:te,U):"operator"==e?/\+\+|--/.test(t)||d&&"!"==t?I(r):d&&"<"==t&&_.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/,!1)?I(B(">"),de(ye,">"),$,r):"?"==t?I(z,q(":"),i):I(i):"quasi"==e?O(Z,r):";"!=e?"("==e?fe(W,")","call",r):"."==e?I(se,r):"["==e?I(B("]"),X,q("]"),$,r):d&&"as"==t?(_.marked="keyword",I(ye,r)):"regexp"==e?(_.state.lastType=_.marked="operator",_.stream.backUp(_.stream.pos-_.stream.start-1),I(i)):void 0:void 0}function Z(e,t){return"quasi"!=e?O():"${"!=t.slice(t.length-2)?I(Z):I(X,ee)}function ee(e){if("}"==e)return _.marked="string-2",_.state.tokenize=T,I(Z)}function te(e){return C(_.stream,_.state),O("{"==e?H:z)}function ne(e){return C(_.stream,_.state),O("{"==e?H:W)}function re(e){return function(t){return"."==t?I(e?oe:ie):"variable"==t&&d?I(ke,e?J:Y):O(e?W:z)}}function ie(e,t){if("target"==t)return _.marked="keyword",I(Y)}function oe(e,t){if("target"==t)return _.marked="keyword",I(J)}function ae(e){return":"==e?I($,H):O(Y,q(";"),$)}function se(e){if("variable"==e)return _.marked="property",I()}function le(e,t){return"async"==e?(_.marked="property",I(le)):"variable"==e||"keyword"==_.style?(_.marked="property","get"==t||"set"==t?I(ue):(d&&_.state.fatArrowAt==_.stream.start&&(n=_.stream.match(/^\s*:\s*/,!1))&&(_.state.fatArrowAt=_.stream.pos+n[0].length),I(ce))):"number"==e||"string"==e?(_.marked=l?"property":_.style+" property",I(ce)):"jsonld-keyword"==e?I(ce):d&&M(t)?(_.marked="keyword",I(le)):"["==e?I(z,he,q("]"),ce):"spread"==e?I(W,ce):"*"==t?(_.marked="keyword",I(le)):":"==e?O(ce):void 0;var n}function ue(e){return"variable"!=e?O(ce):(_.marked="property",I(Ve))}function ce(e){return":"==e?I(W):"("==e?O(Ve):void 0}function de(e,t,n){function i(r,o){if(n?n.indexOf(r)>-1:","==r){var a=_.state.lexical;return"call"==a.info&&(a.pos=(a.pos||0)+1),I((function(n,r){return n==t||r==t?O():O(e)}),i)}return r==t||o==t?I():n&&n.indexOf(";")>-1?O(e):I(q(t))}return r(i,"proceed"),function(n,r){return n==t||r==t?I():O(e,i)}}function fe(e,t,n){for(var r=3;r"),ye):"quasi"==e?O(we,xe):void 0}function be(e){if("=>"==e)return I(ye)}function Ee(e){return e.match(/[\}\)\]]/)?I():","==e||";"==e?I(Ee):O(Te,Ee)}function Te(e,t){return"variable"==e||"keyword"==_.style?(_.marked="property",I(Te)):"?"==t||"number"==e||"string"==e?I(Te):":"==e?I(ye):"["==e?I(q("variable"),me,q("]"),Te):"("==e?O(Ue,Te):e.match(/[;\}\)\],]/)?void 0:I()}function we(e,t){return"quasi"!=e?O():"${"!=t.slice(t.length-2)?I(we):I(ye,Ce)}function Ce(e){if("}"==e)return _.marked="string-2",_.state.tokenize=T,I(we)}function Se(e,t){return"variable"==e&&_.stream.match(/^\s*[?:]/,!1)||"?"==t?I(Se):":"==e?I(ye):"spread"==e?I(Se):O(ye)}function xe(e,t){return"<"==t?I(B(">"),de(ye,">"),$,xe):"|"==t||"."==e||"&"==t?I(ye):"["==e?I(ye,q("]"),xe):"extends"==t||"implements"==t?(_.marked="keyword",I(ye)):"?"==t?I(ye,q(":"),ye):void 0}function ke(e,t){if("<"==t)return I(B(">"),de(ye,">"),$,xe)}function Ne(){return O(ye,_e)}function _e(e,t){if("="==t)return I(ye)}function Oe(e,t){return"enum"==t?(_.marked="keyword",I(nt)):O(Ie,he,Ae,Me)}function Ie(e,t){return d&&M(t)?(_.marked="keyword",I(Ie)):"variable"==e?(L(t),I()):"spread"==e?I(Ie):"["==e?fe(Le,"]"):"{"==e?fe(De,"}"):void 0}function De(e,t){return"variable"!=e||_.stream.match(/^\s*:/,!1)?("variable"==e&&(_.marked="property"),"spread"==e?I(Ie):"}"==e?O():"["==e?I(z,q("]"),q(":"),De):I(q(":"),Ie,Ae)):(L(t),I(Ae))}function Le(){return O(Ie,Ae)}function Ae(e,t){if("="==t)return I(W)}function Me(e){if(","==e)return I(Oe)}function Re(e,t){if("keyword b"==e&&"else"==t)return I(B("form","else"),H,$)}function Fe(e,t){return"await"==t?I(Fe):"("==e?I(B(")"),Pe,$):void 0}function Pe(e){return"var"==e?I(Oe,je):"variable"==e?I(je):O(je)}function je(e,t){return")"==e?I():";"==e?I(je):"in"==t||"of"==t?(_.marked="keyword",I(z,je)):O(z,je)}function Ve(e,t){return"*"==t?(_.marked="keyword",I(Ve)):"variable"==e?(L(t),I(Ve)):"("==e?I(j,B(")"),de($e,")"),$,ge,H,U):d&&"<"==t?I(B(">"),de(Ne,">"),$,Ve):void 0}function Ue(e,t){return"*"==t?(_.marked="keyword",I(Ue)):"variable"==e?(L(t),I(Ue)):"("==e?I(j,B(")"),de($e,")"),$,ge,U):d&&"<"==t?I(B(">"),de(Ne,">"),$,Ue):void 0}function Be(e,t){return"keyword"==e||"variable"==e?(_.marked="type",I(Be)):"<"==t?I(B(">"),de(Ne,">"),$):void 0}function $e(e,t){return"@"==t&&I(z,$e),"spread"==e?I($e):d&&M(t)?(_.marked="keyword",I($e)):d&&"this"==e?I(he,Ae):O(Ie,he,Ae)}function qe(e,t){return"variable"==e?He(e,t):Ge(e,t)}function He(e,t){if("variable"==e)return L(t),I(Ge)}function Ge(e,t){return"<"==t?I(B(">"),de(Ne,">"),$,Ge):"extends"==t||"implements"==t||d&&","==e?("implements"==t&&(_.marked="keyword"),I(d?ye:z,Ge)):"{"==e?I(B("}"),ze,$):void 0}function ze(e,t){return"async"==e||"variable"==e&&("static"==t||"get"==t||"set"==t||d&&M(t))&&_.stream.match(/^\s+[\w$\xa1-\uffff]/,!1)?(_.marked="keyword",I(ze)):"variable"==e||"keyword"==_.style?(_.marked="property",I(We,ze)):"number"==e||"string"==e?I(We,ze):"["==e?I(z,he,q("]"),We,ze):"*"==t?(_.marked="keyword",I(ze)):d&&"("==e?O(Ue,ze):";"==e||","==e?I(ze):"}"==e?I():"@"==t?I(z,ze):void 0}function We(e,t){if("!"==t)return I(We);if("?"==t)return I(We);if(":"==e)return I(ye,Ae);if("="==t)return I(W);var n=_.state.lexical.prev;return O(n&&"interface"==n.info?Ue:Ve)}function Ke(e,t){return"*"==t?(_.marked="keyword",I(et,q(";"))):"default"==t?(_.marked="keyword",I(z,q(";"))):"{"==e?I(de(Qe,"}"),et,q(";")):O(H)}function Qe(e,t){return"as"==t?(_.marked="keyword",I(q("variable"))):"variable"==e?O(W,Qe):void 0}function Xe(e){return"string"==e?I():"("==e?O(z):"."==e?O(Y):O(Ye,Je,et)}function Ye(e,t){return"{"==e?fe(Ye,"}"):("variable"==e&&L(t),"*"==t&&(_.marked="keyword"),I(Ze))}function Je(e){if(","==e)return I(Ye,Je)}function Ze(e,t){if("as"==t)return _.marked="keyword",I(Ye)}function et(e,t){if("from"==t)return _.marked="keyword",I(z)}function tt(e){return"]"==e?I():O(de(W,"]"))}function nt(){return O(B("form"),Ie,q("{"),B("}"),de(rt,"}"),$,$)}function rt(){return O(Ie,Ae)}function it(e,t){return"operator"==e.lastType||","==e.lastType||h.test(t.charAt(0))||/[,.]/.test(t.charAt(0))}function ot(e,t,n){return t.tokenize==y&&/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(t.lastType)||"quasi"==t.lastType&&/\{\s*$/.test(e.string.slice(0,e.pos-(n||0)))}return r(j,"pushcontext"),r(V,"pushblockcontext"),j.lex=V.lex=!0,r(U,"popcontext"),U.lex=!0,r(B,"pushlex"),r($,"poplex"),$.lex=!0,r(q,"expect"),r(H,"statement"),r(G,"maybeCatchBinding"),r(z,"expression"),r(W,"expressionNoComma"),r(K,"parenExpr"),r(Q,"expressionInner"),r(X,"maybeexpression"),r(Y,"maybeoperatorComma"),r(J,"maybeoperatorNoComma"),r(Z,"quasi"),r(ee,"continueQuasi"),r(te,"arrowBody"),r(ne,"arrowBodyNoComma"),r(re,"maybeTarget"),r(ie,"target"),r(oe,"targetNoComma"),r(ae,"maybelabel"),r(se,"property"),r(le,"objprop"),r(ue,"getterSetter"),r(ce,"afterprop"),r(de,"commasep"),r(fe,"contCommasep"),r(pe,"block"),r(he,"maybetype"),r(me,"maybetypeOrIn"),r(ge,"mayberettype"),r(ve,"isKW"),r(ye,"typeexpr"),r(be,"maybeReturnType"),r(Ee,"typeprops"),r(Te,"typeprop"),r(we,"quasiType"),r(Ce,"continueQuasiType"),r(Se,"typearg"),r(xe,"afterType"),r(ke,"maybeTypeArgs"),r(Ne,"typeparam"),r(_e,"maybeTypeDefault"),r(Oe,"vardef"),r(Ie,"pattern"),r(De,"proppattern"),r(Le,"eltpattern"),r(Ae,"maybeAssign"),r(Me,"vardefCont"),r(Re,"maybeelse"),r(Fe,"forspec"),r(Pe,"forspec1"),r(je,"forspec2"),r(Ve,"functiondef"),r(Ue,"functiondecl"),r(Be,"typename"),r($e,"funarg"),r(qe,"classExpression"),r(He,"className"),r(Ge,"classNameAfter"),r(ze,"classBody"),r(We,"classfield"),r(Ke,"afterExport"),r(Qe,"exportField"),r(Xe,"afterImport"),r(Ye,"importSpec"),r(Je,"maybeMoreImports"),r(Ze,"maybeAs"),r(et,"maybeFrom"),r(tt,"arrayLiteral"),r(nt,"enumdef"),r(rt,"enummember"),r(it,"isContinuedStatement"),r(ot,"expressionAllowed"),{startState:function(e){var n={tokenize:y,lastType:"sof",cc:[],lexical:new x((e||0)-a,0,"block",!1),localVars:t.localVars,context:t.localVars&&new R(null,null,!1),indented:e||0};return t.globalVars&&"object"==typeof t.globalVars&&(n.globalVars=t.globalVars),n},token:function(e,t){if(e.sol()&&(t.lexical.hasOwnProperty("align")||(t.lexical.align=!1),t.indented=e.indentation(),C(e,t)),t.tokenize!=E&&e.eatSpace())return null;var r=t.tokenize(e,t);return"comment"==n?r:(t.lastType="operator"!=n||"++"!=i&&"--"!=i?n:"incdec",N(t,r,n,i,e))},indent:function(e,n){if(e.tokenize==E||e.tokenize==T)return o.Pass;if(e.tokenize!=y)return 0;var r,i=n&&n.charAt(0),l=e.lexical;if(!/^\s*else\b/.test(n))for(var u=e.cc.length-1;u>=0;--u){var c=e.cc[u];if(c==$)l=l.prev;else if(c!=Re&&c!=U)break}for(;("stat"==l.type||"form"==l.type)&&("}"==i||(r=e.cc[e.cc.length-1])&&(r==Y||r==J)&&!/^[,\.=+\-*:?[\(]/.test(n));)l=l.prev;s&&")"==l.type&&"stat"==l.prev.type&&(l=l.prev);var d=l.type,f=i==d;return"vardef"==d?l.indented+("operator"==e.lastType||","==e.lastType?l.info.length+1:0):"form"==d&&"{"==i?l.indented:"form"==d?l.indented+a:"stat"==d?l.indented+(it(e,n)?s||a:0):"switch"!=l.info||f||0==t.doubleIndentSwitch?l.align?l.column+(f?0:1):l.indented+(f?0:a):l.indented+(/^(?:case|default)\b/.test(n)?a:2*a)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:u?null:"/*",blockCommentEnd:u?null:"*/",blockCommentContinue:u?null:" * ",lineComment:u?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:u?"json":"javascript",jsonldMode:l,jsonMode:u,expressionAllowed:ot,skipExpression:function(e){N(e,"atom","atom","true",new o.StringStream("",2,null))}}})),o.registerHelper("wordChars","javascript",/[\w$]/),o.defineMIME("text/javascript","javascript"),o.defineMIME("text/ecmascript","javascript"),o.defineMIME("application/javascript","javascript"),o.defineMIME("application/x-javascript","javascript"),o.defineMIME("application/ecmascript","javascript"),o.defineMIME("application/json",{name:"javascript",json:!0}),o.defineMIME("application/x-json",{name:"javascript",json:!0}),o.defineMIME("application/manifest+json",{name:"javascript",json:!0}),o.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),o.defineMIME("text/typescript",{name:"javascript",typescript:!0}),o.defineMIME("application/typescript",{name:"javascript",typescript:!0});var s=i({__proto__:null,default:a.exports},[a.exports]);e.j=s},void 0===(o=r.apply(t,i))||(e.exports=o)},4471:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535),n(8058)],void 0===(o="function"==typeof(r=function(e,t,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.j=void 0;var r=Object.defineProperty,i=(e,t)=>r(e,"name",{value:t,configurable:!0});function o(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}i(o,"_mergeNamespaces");var a={exports:{}};!function(e){function t(e,t,n,r,i){e.openDialog?e.openDialog(t,i,{value:r,selectValueOnOpen:!0,bottom:e.options.search.bottom}):i(prompt(n,r))}function n(e){return e.phrase("Jump to line:")+' '+e.phrase("(Use line:column or scroll% syntax)")+""}function r(e,t){var n=Number(t);return/^[-+]/.test(t)?e.getCursor().line+n:n-1}e.defineOption("search",{bottom:!1}),i(t,"dialog"),i(n,"getJumpDialog"),i(r,"interpretLine"),e.commands.jumpToLine=function(e){var i=e.getCursor();t(e,n(e),e.phrase("Jump to line:"),i.line+1+":"+i.ch,(function(t){var n;if(t)if(n=/^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(t))e.setCursor(r(e,n[1]),Number(n[2]));else if(n=/^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(t)){var o=Math.round(e.lineCount()*Number(n[1])/100);/^[-+]/.test(n[1])&&(o=i.line+o+1),e.setCursor(o-1,i.ch)}else(n=/^\s*\:?\s*([\+\-]?\d+)\s*/.exec(t))&&e.setCursor(r(e,n[1]),i.ch)}))},e.keyMap.default["Alt-G"]="jumpToLine"}(t.a.exports,n.a.exports);var s=o({__proto__:null,default:a.exports},[a.exports]);e.j=s})?r.apply(t,i):r)||(e.exports=o)},5980:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(2645),n(6856),n(9196),n(3573),n(1850),n(2635)],void 0===(o="function"==typeof(r=function(e,t,n,r,i,o,a){"use strict";var s=Object.defineProperty,l=(e,t)=>s(e,"name",{value:t,configurable:!0});function u(e,t){const n=t.target||t.srcElement;if(!(n instanceof HTMLElement))return;if("SPAN"!==(null==n?void 0:n.nodeName))return;const r=n.getBoundingClientRect(),i={left:(r.left+r.right)/2,top:(r.top+r.bottom)/2};e.state.jump.cursor=i,e.state.jump.isHoldingModifier&&h(e)}function c(e){e.state.jump.isHoldingModifier||!e.state.jump.cursor?e.state.jump.isHoldingModifier&&e.state.jump.marker&&m(e):e.state.jump.cursor=null}function d(t,n){if(t.state.jump.isHoldingModifier||!p(n.key))return;t.state.jump.isHoldingModifier=!0,t.state.jump.cursor&&h(t);const r=l((a=>{a.code===n.code&&(t.state.jump.isHoldingModifier=!1,t.state.jump.marker&&m(t),e.C.off(document,"keyup",r),e.C.off(document,"click",i),t.off("mousedown",o))}),"onKeyUp"),i=l((e=>{const{destination:n,options:r}=t.state.jump;n&&r.onClick(n,e)}),"onClick"),o=l(((e,n)=>{t.state.jump.destination&&(n.codemirrorIgnore=!0)}),"onMouseDown");e.C.on(document,"keyup",r),e.C.on(document,"click",i),t.on("mousedown",o)}e.C.defineOption("jump",!1,((t,n,r)=>{if(r&&r!==e.C.Init){const n=t.state.jump.onMouseOver;e.C.off(t.getWrapperElement(),"mouseover",n);const r=t.state.jump.onMouseOut;e.C.off(t.getWrapperElement(),"mouseout",r),e.C.off(document,"keydown",t.state.jump.onKeyDown),delete t.state.jump}if(n){const r=t.state.jump={options:n,onMouseOver:u.bind(null,t),onMouseOut:c.bind(null,t),onKeyDown:d.bind(null,t)};e.C.on(t.getWrapperElement(),"mouseover",r.onMouseOver),e.C.on(t.getWrapperElement(),"mouseout",r.onMouseOut),e.C.on(document,"keydown",r.onKeyDown)}})),l(u,"onMouseOver"),l(c,"onMouseOut"),l(d,"onKeyDown");const f="undefined"!=typeof navigator&&navigator&&navigator.appVersion.includes("Mac");function p(e){return e===(f?"Meta":"Control")}function h(e){if(e.state.jump.marker)return;const{cursor:t,options:n}=e.state.jump,r=e.coordsChar(t),i=e.getTokenAt(r,!0),o=n.getDestination||e.getHelper(r,"jump");if(o){const t=o(i,n,e);if(t){const n=e.markText({line:r.line,ch:i.start},{line:r.line,ch:i.end},{className:"CodeMirror-jump-token"});e.state.jump.marker=n,e.state.jump.destination=t}}}function m(e){const{marker:t}=e.state.jump;e.state.jump.marker=null,e.state.jump.destination=null,t.clear()}l(p,"isJumpModifier"),l(h,"enableJumpMode"),l(m,"disableJumpMode"),e.C.registerHelper("jump","graphql",((e,n)=>{if(!n.schema||!n.onClick||!e.state)return;const{state:r}=e,{kind:i,step:o}=r,a=(0,t.g)(n.schema,r);return"Field"===i&&0===o&&a.fieldDef||"AliasedField"===i&&2===o&&a.fieldDef?(0,t.a)(a):"Directive"===i&&1===o&&a.directiveDef?(0,t.b)(a):"Argument"===i&&0===o&&a.argDef?(0,t.c)(a):"EnumValue"===i&&a.enumValue?(0,t.d)(a):"NamedType"===i&&a.type?(0,t.e)(a):void 0}))})?r.apply(t,i):r)||(e.exports=o)},9444:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(3573),n(6856),n(5609),n(9196),n(1850)],r=function(e,t,n,r,i,o){"use strict";var a=Object.defineProperty,s=(e,t)=>a(e,"name",{value:t,configurable:!0});const l=[t.LoneSchemaDefinitionRule,t.UniqueOperationTypesRule,t.UniqueTypeNamesRule,t.UniqueEnumValueNamesRule,t.UniqueFieldDefinitionNamesRule,t.UniqueDirectiveNamesRule,t.KnownTypeNamesRule,t.KnownDirectivesRule,t.UniqueDirectivesPerLocationRule,t.PossibleTypeExtensionsRule,t.UniqueArgumentNamesRule,t.UniqueInputFieldNamesRule];function u(e,n,r,i,o){const a=t.specifiedRules.filter((e=>e!==t.NoUnusedFragmentsRule&&e!==t.ExecutableDefinitionsRule&&(!i||e!==t.KnownFragmentNamesRule)));return r&&Array.prototype.push.apply(a,r),o&&Array.prototype.push.apply(a,l),(0,t.validate)(e,n,a).filter((e=>{if(e.message.includes("Unknown directive")&&e.nodes){const n=e.nodes[0];if(n&&n.kind===t.Kind.DIRECTIVE){const e=n.name.value;if("arguments"===e||"argumentDefinitions"===e)return!1}}return!0}))}s(u,"validateWithCustomRules");const c={["Error"]:1,["Warning"]:2,["Information"]:3,["Hint"]:4},d=s(((e,t)=>{if(!e)throw new Error(t)}),"invariant");function f(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=arguments.length>2?arguments[2]:void 0,i=arguments.length>3?arguments[3]:void 0,o=arguments.length>4?arguments[4]:void 0;var a,s;let l=null,u="";o&&(u="string"==typeof o?o:o.reduce(((e,n)=>e+(0,t.print)(n)+"\n\n"),""));const d=u?`${e}\n\n${u}`:e;try{l=(0,t.parse)(d)}catch(e){if(e instanceof t.GraphQLError){const t=m(null!==(s=null===(a=e.locations)||void 0===a?void 0:a[0])&&void 0!==s?s:{line:0,column:0},d);return[{severity:c.Error,message:e.message,source:"GraphQL: Syntax",range:t}]}throw e}return p(l,n,r,i)}function p(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(!n)return[];const r=u(n,e,arguments.length>2?arguments[2]:void 0,arguments.length>3?arguments[3]:void 0).flatMap((e=>h(e,c.Error,"Validation"))),i=(0,t.validate)(n,e,[t.NoDeprecatedCustomRule]).flatMap((e=>h(e,c.Warning,"Deprecation")));return r.concat(i)}function h(e,t,n){if(!e.nodes)return[];const i=[];for(const[o,a]of e.nodes.entries()){const s="Variable"!==a.kind&&"name"in a&&void 0!==a.name?a.name:"variable"in a&&void 0!==a.variable?a.variable:a;if(s){d(e.locations,"GraphQL validation error requires locations.");const a=e.locations[o],l=g(s),u=a.column+(l.end-l.start);i.push({source:`GraphQL: ${n}`,message:e.message,severity:t,range:new r.R(new r.P(a.line-1,a.column-1),new r.P(a.line-1,u))})}}return i}function m(e,t){const i=(0,n.o)(),o=i.startState(),a=t.split("\n");d(a.length>=e.line,"Query text must have more lines than where the error happened");let s=null;for(let t=0;t{const{schema:r,validationRules:i,externalFragments:o}=n;return f(t,r,i,void 0,o).map((t=>({message:t.message,severity:t.severity?v[t.severity-1]:v[0],type:t.source?y[t.source]:void 0,from:e.C.Pos(t.range.start.line,t.range.start.character),to:e.C.Pos(t.range.end.line,t.range.end.character)})))}))},void 0===(o=r.apply(t,i))||(e.exports=o)},8535:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(3573),n(6856),n(9196),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i){"use strict";var o=Object.defineProperty,a=(e,t)=>o(e,"name",{value:t,configurable:!0});function s(e){l=e,u=e.length,c=d=f=-1,S(),x();const t=m();return E("EOF"),t}let l,u,c,d,f,p,h;function m(){const e=c,t=[];if(E("{"),!C("}")){do{t.push(g())}while(C(","));E("}")}return{kind:"Object",start:e,end:f,members:t}}function g(){const e=c,t="String"===h?b():null;E("String"),E(":");const n=y();return{kind:"Member",start:e,end:f,key:t,value:n}}function v(){const e=c,t=[];if(E("["),!C("]")){do{t.push(y())}while(C(","));E("]")}return{kind:"Array",start:e,end:f,values:t}}function y(){switch(h){case"[":return v();case"{":return m();case"String":case"Number":case"Boolean":case"Null":const e=b();return x(),e}E("Value")}function b(){return{kind:h,start:c,end:d,value:JSON.parse(l.slice(c,d))}}function E(e){if(h===e)return void x();let t;if("EOF"===h)t="[end of file]";else if(d-c>1)t="`"+l.slice(c,d)+"`";else{const e=l.slice(c).match(/^.+?\b/);t="`"+(e?e[0]:l[c])+"`"}throw w(`Expected ${e} but found ${t}.`)}a(s,"jsonParse"),a(m,"parseObj"),a(g,"parseMember"),a(v,"parseArr"),a(y,"parseVal"),a(b,"curToken"),a(E,"expect");class T extends Error{constructor(e,t){super(e),this.position=t}}function w(e){return new T(e,{start:c,end:d})}function C(e){if(h===e)return x(),!0}function S(){return d31;)if(92===p)switch(p=S(),p){case 34:case 47:case 92:case 98:case 102:case 110:case 114:case 116:S();break;case 117:S(),N(),N(),N(),N();break;default:throw w("Bad character escape sequence.")}else{if(d===u)throw w("Unterminated string.");S()}if(34!==p)throw w("Unterminated string.");S()}function N(){if(p>=48&&p<=57||p>=65&&p<=70||p>=97&&p<=102)return S();throw w("Expected hexadecimal digit.")}function _(){45===p&&S(),48===p?S():O(),46===p&&(S(),O()),69!==p&&101!==p||(p=S(),43!==p&&45!==p||S(),O())}function O(){if(p<48||p>57)throw w("Expected decimal digit.");do{S()}while(p>=48&&p<=57)}function I(e,t,n){var r;const i=[];for(const o of n.members)if(o){const n=null===(r=o.key)||void 0===r?void 0:r.value,a=t[n];if(a)for(const[t,n]of D(a,o.value))i.push(L(e,t,n));else i.push(L(e,o.key,`Variable "$${n}" does not appear in any GraphQL query.`))}return i}function D(e,n){if(!e||!n)return[];if(e instanceof t.GraphQLNonNull)return"Null"===n.kind?[[n,`Type "${e}" is non-nullable and cannot be null.`]]:D(e.ofType,n);if("Null"===n.kind)return[];if(e instanceof t.GraphQLList){const t=e.ofType;return"Array"===n.kind?M(n.values||[],(e=>D(t,e))):D(t,n)}if(e instanceof t.GraphQLInputObjectType){if("Object"!==n.kind)return[[n,`Type "${e}" must be an Object.`]];const r=Object.create(null),i=M(n.members,(t=>{var n;const i=null===(n=null==t?void 0:t.key)||void 0===n?void 0:n.value;r[i]=!0;const o=e.getFields()[i];return o?D(o?o.type:void 0,t.value):[[t.key,`Type "${e}" does not have a field "${i}".`]]}));for(const o of Object.keys(e.getFields())){const a=e.getFields()[o];!r[o]&&a.type instanceof t.GraphQLNonNull&&!a.defaultValue&&i.push([n,`Object of type "${e}" is missing required field "${o}".`])}return i}return"Boolean"===e.name&&"Boolean"!==n.kind||"String"===e.name&&"String"!==n.kind||"ID"===e.name&&"Number"!==n.kind&&"String"!==n.kind||"Float"===e.name&&"Number"!==n.kind||"Int"===e.name&&("Number"!==n.kind||(0|n.value)!==n.value)||(e instanceof t.GraphQLEnumType||e instanceof t.GraphQLScalarType)&&("String"!==n.kind&&"Number"!==n.kind&&"Boolean"!==n.kind&&"Null"!==n.kind||A(e.parseValue(n.value)))?[[n,`Expected value of type "${e}".`]]:[]}function L(e,t,n){return{message:n,severity:"error",type:"validation",from:e.posFromIndex(t.start),to:e.posFromIndex(t.end)}}function A(e){return null==e||e!=e}function M(e,t){return Array.prototype.concat.apply([],e.map(t))}a(T,"JSONSyntaxError"),a(w,"syntaxError"),a(C,"skip"),a(S,"ch"),a(x,"lex"),a(k,"readString"),a(N,"readHex"),a(_,"readNumber"),a(O,"readDigits"),e.C.registerHelper("lint","graphql-variables",((e,t,n)=>{if(!e)return[];let r;try{r=s(e)}catch(e){if(e instanceof T)return[L(n,e.position,e.message)];throw e}const{variableToType:i}=t;return i?I(n,i,r):[]})),a(I,"validateVariables"),a(D,"validateValue"),a(L,"lintError"),a(A,"isNullish"),a(M,"mapCat")})?r.apply(t,i):r)||(e.exports=o)},4054:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535)],void 0===(o="function"==typeof(r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.l=void 0;var n=Object.defineProperty,r=(e,t)=>n(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};!function(e){var t="CodeMirror-lint-markers",n="CodeMirror-lint-line-";function i(t,n,i){var o=document.createElement("div");function a(t){if(!o.parentNode)return e.off(document,"mousemove",a);o.style.top=Math.max(0,t.clientY-o.offsetHeight-5)+"px",o.style.left=t.clientX+5+"px"}return o.className="CodeMirror-lint-tooltip cm-s-"+t.options.theme,o.appendChild(i.cloneNode(!0)),t.state.lint.options.selfContain?t.getWrapperElement().appendChild(o):document.body.appendChild(o),r(a,"position"),e.on(document,"mousemove",a),a(n),null!=o.style.opacity&&(o.style.opacity=1),o}function o(e){e.parentNode&&e.parentNode.removeChild(e)}function a(e){e.parentNode&&(null==e.style.opacity&&o(e),e.style.opacity=0,setTimeout((function(){o(e)}),600))}function s(t,n,o,s){var l=i(t,n,o);function u(){e.off(s,"mouseout",u),l&&(a(l),l=null)}r(u,"hide");var c=setInterval((function(){if(l)for(var e=s;;e=e.parentNode){if(e&&11==e.nodeType&&(e=e.host),e==document.body)return;if(!e){u();break}}if(!l)return clearInterval(c)}),400);e.on(s,"mouseout",u)}function l(e,t,n){for(var r in this.marked=[],t instanceof Function&&(t={getAnnotations:t}),t&&!0!==t||(t={}),this.options={},this.linterOptions=t.options||{},u)this.options[r]=u[r];for(var r in t)u.hasOwnProperty(r)?null!=t[r]&&(this.options[r]=t[r]):t.options||(this.linterOptions[r]=t[r]);this.timeout=null,this.hasGutter=n,this.onMouseOver=function(t){T(e,t)},this.waitingFor=0}r(i,"showTooltip"),r(o,"rm"),r(a,"hideTooltip"),r(s,"showTooltipFor"),r(l,"LintState");var u={highlightLines:!1,tooltips:!0,delay:500,lintOnChange:!0,getAnnotations:null,async:!1,selfContain:null,formatAnnotation:null,onUpdateLinting:null};function c(e){var n=e.state.lint;n.hasGutter&&e.clearGutter(t),n.options.highlightLines&&d(e);for(var r=0;r-1)&&u.push(e.message)}));for(var d=null,g=i.hasGutter&&document.createDocumentFragment(),v=0;v1,o.tooltips)),o.highlightLines&&e.addLineClass(s,"wrap",n+d)}}o.onUpdateLinting&&o.onUpdateLinting(r,a,e)}}function b(e){var t=e.state.lint;t&&(clearTimeout(t.timeout),t.timeout=setTimeout((function(){v(e)}),t.options.delay))}function E(e,t,n){for(var r=n.target||n.srcElement,i=document.createDocumentFragment(),o=0;on(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};e.a=o,function(e){var t=/MSIE \d/.test(navigator.userAgent)&&(null==document.documentMode||document.documentMode<8),n=e.Pos,i={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<","<":">>",">":"<<"};function o(e){return e&&e.bracketRegex||/[(){}[\]]/}function a(e,t,r){var a=e.getLineHandle(t.line),l=t.ch-1,u=r&&r.afterCursor;null==u&&(u=/(^| )cm-fat-cursor($| )/.test(e.getWrapperElement().className));var c=o(r),d=!u&&l>=0&&c.test(a.text.charAt(l))&&i[a.text.charAt(l)]||c.test(a.text.charAt(l+1))&&i[a.text.charAt(++l)];if(!d)return null;var f=">"==d.charAt(1)?1:-1;if(r&&r.strict&&f>0!=(l==t.ch))return null;var p=e.getTokenTypeAt(n(t.line,l+1)),h=s(e,n(t.line,l+(f>0?1:0)),f,p,r);return null==h?null:{from:n(t.line,l),to:h&&h.pos,match:h&&h.ch==d.charAt(0),forward:f>0}}function s(e,t,r,a,s){for(var l=s&&s.maxScanLineLength||1e4,u=s&&s.maxScanLines||1e3,c=[],d=o(s),f=r>0?Math.min(t.line+u,e.lastLine()+1):Math.max(e.firstLine()-1,t.line-u),p=t.line;p!=f;p+=r){var h=e.getLine(p);if(h){var m=r>0?0:h.length-1,g=r>0?h.length:-1;if(!(h.length>l))for(p==t.line&&(m=t.ch-(r<0?1:0));m!=g;m+=r){var v=h.charAt(m);if(d.test(v)&&(void 0===a||(e.getTokenTypeAt(n(p,m+1))||"")==(a||""))){var y=i[v];if(y&&">"==y.charAt(1)==r>0)c.push(v);else{if(!c.length)return{pos:n(p,m),ch:v};c.pop()}}}}}return p-r!=(r>0?e.lastLine():e.firstLine())&&null}function l(e,i,o){for(var s=e.state.matchBrackets.maxHighlightLineLength||1e3,l=o&&o.highlightNonMatching,u=[],c=e.listSelections(),d=0;da((e=>{const t=(0,n.o)({eatWhitespace:e=>e.eatWhile(n.i),lexRules:n.L,parseRules:n.P,editorConfig:{tabSize:e.tabSize}});return{config:e,startState:t.startState,token:t.token,indent:r.i,electricInput:/^\s*[})\]]/,fold:"brace",lineComment:"#",closeBrackets:{pairs:'()[]{}""',explode:"()[]{}"}}}),"name",{value:"graphqlModeFactory",configurable:!0}))();e.C.defineMode("graphql",s)})?r.apply(t,i):r)||(e.exports=o)},1430:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(3573),n(6856),n(6592),n(9196),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i,o){"use strict";e.C.defineMode("graphql-results",(e=>{const t=(0,n.o)({eatWhitespace:e=>e.eatSpace(),lexRules:a,parseRules:s,editorConfig:{tabSize:e.tabSize}});return{config:e,startState:t.startState,token:t.token,indent:r.i,electricInput:/^\s*[}\]]/,fold:"brace",closeBrackets:{pairs:'[]{}""',explode:"[]{}"}}}));const a={Punctuation:/^\[|]|\{|\}|:|,/,Number:/^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/,String:/^"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?/,Keyword:/^true|false|null/},s={Document:[(0,n.p)("{"),(0,n.l)("Entry",(0,n.p)(",")),(0,n.p)("}")],Entry:[(0,n.t)("String","def"),(0,n.p)(":"),"Value"],Value(e){switch(e.kind){case"Number":return"NumberValue";case"String":return"StringValue";case"Punctuation":switch(e.value){case"[":return"ListValue";case"{":return"ObjectValue"}return null;case"Keyword":switch(e.value){case"true":case"false":return"BooleanValue";case"null":return"NullValue"}return null}},NumberValue:[(0,n.t)("Number","number")],StringValue:[(0,n.t)("String","string")],BooleanValue:[(0,n.t)("Keyword","builtin")],NullValue:[(0,n.t)("Keyword","keyword")],ListValue:[(0,n.p)("["),(0,n.l)("Value",(0,n.p)(",")),(0,n.p)("]")],ObjectValue:[(0,n.p)("{"),(0,n.l)("ObjectField",(0,n.p)(",")),(0,n.p)("}")],ObjectField:[(0,n.t)("String","property"),(0,n.p)(":"),"Value"]}})?r.apply(t,i):r)||(e.exports=o)},3340:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[n(535),n(3573),n(6856),n(6592),n(9196),n(1850)],void 0===(o="function"==typeof(r=function(e,t,n,r,i,o){"use strict";var a=Object.defineProperty;e.C.defineMode("graphql-variables",(e=>{const t=(0,n.o)({eatWhitespace:e=>e.eatSpace(),lexRules:s,parseRules:l,editorConfig:{tabSize:e.tabSize}});return{config:e,startState:t.startState,token:t.token,indent:r.i,electricInput:/^\s*[}\]]/,fold:"brace",closeBrackets:{pairs:'[]{}""',explode:"[]{}"}}}));const s={Punctuation:/^\[|]|\{|\}|:|,/,Number:/^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/,String:/^"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?/,Keyword:/^true|false|null/},l={Document:[(0,n.p)("{"),(0,n.l)("Variable",(0,n.b)((0,n.p)(","))),(0,n.p)("}")],Variable:[u("variable"),(0,n.p)(":"),"Value"],Value(e){switch(e.kind){case"Number":return"NumberValue";case"String":return"StringValue";case"Punctuation":switch(e.value){case"[":return"ListValue";case"{":return"ObjectValue"}return null;case"Keyword":switch(e.value){case"true":case"false":return"BooleanValue";case"null":return"NullValue"}return null}},NumberValue:[(0,n.t)("Number","number")],StringValue:[(0,n.t)("String","string")],BooleanValue:[(0,n.t)("Keyword","builtin")],NullValue:[(0,n.t)("Keyword","keyword")],ListValue:[(0,n.p)("["),(0,n.l)("Value",(0,n.b)((0,n.p)(","))),(0,n.p)("]")],ObjectValue:[(0,n.p)("{"),(0,n.l)("ObjectField",(0,n.b)((0,n.p)(","))),(0,n.p)("}")],ObjectField:[u("attribute"),(0,n.p)(":"),"Value"]};function u(e){return{style:e,match:e=>"String"===e.kind,update(e,t){e.name=t.value.slice(1,-1)}}}a(u,"name",{value:"namedKey",configurable:!0})})?r.apply(t,i):r)||(e.exports=o)},9509:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535),n(9407),n(8058)],r=function(e,t,n,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.s=void 0;var i=Object.defineProperty,o=(e,t)=>i(e,"name",{value:t,configurable:!0});function a(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}o(a,"_mergeNamespaces");var s={exports:{}};!function(e){function t(e,t){return"string"==typeof e?e=new RegExp(e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),t?"gi":"g"):e.global||(e=new RegExp(e.source,e.ignoreCase?"gi":"g")),{token:function(t){e.lastIndex=t.pos;var n=e.exec(t.string);if(n&&n.index==t.pos)return t.pos+=n[0].length||1,"searching";n?t.pos=n.index:t.skipToEnd()}}}function n(){this.posFrom=this.posTo=this.lastQuery=this.query=null,this.overlay=null}function r(e){return e.state.search||(e.state.search=new n)}function i(e){return"string"==typeof e&&e==e.toLowerCase()}function a(e,t,n){return e.getSearchCursor(t,n,{caseFold:i(t),multiline:!0})}function s(e,t,n,r,i){e.openDialog(t,r,{value:n,selectValueOnOpen:!0,closeOnEnter:!1,onClose:function(){m(e)},onKeyDown:i,bottom:e.options.search.bottom})}function l(e,t,n,r,i){e.openDialog?e.openDialog(t,i,{value:r,selectValueOnOpen:!0,bottom:e.options.search.bottom}):i(prompt(n,r))}function u(e,t,n,r){e.openConfirm?e.openConfirm(t,r):confirm(n)&&r[0]()}function c(e){return e.replace(/\\([nrt\\])/g,(function(e,t){return"n"==t?"\n":"r"==t?"\r":"t"==t?"\t":"\\"==t?"\\":e}))}function d(e){var t=e.match(/^\/(.*)\/([a-z]*)$/);if(t)try{e=new RegExp(t[1],-1==t[2].indexOf("i")?"":"i")}catch(e){}else e=c(e);return("string"==typeof e?""==e:e.test(""))&&(e=/x^/),e}function f(e,n,r){n.queryText=r,n.query=d(r),e.removeOverlay(n.overlay,i(n.query)),n.overlay=t(n.query,i(n.query)),e.addOverlay(n.overlay),e.showMatchesOnScrollbar&&(n.annotate&&(n.annotate.clear(),n.annotate=null),n.annotate=e.showMatchesOnScrollbar(n.query,i(n.query)))}function p(t,n,i,a){var u=r(t);if(u.query)return h(t,n);var c=t.getSelection()||u.lastQuery;if(c instanceof RegExp&&"x^"==c.source&&(c=null),i&&t.openDialog){var d=null,p=o((function(n,r){e.e_stop(r),n&&(n!=u.queryText&&(f(t,u,n),u.posFrom=u.posTo=t.getCursor()),d&&(d.style.opacity=1),h(t,r.shiftKey,(function(e,n){var r;n.line<3&&document.querySelector&&(r=t.display.wrapper.querySelector(".CodeMirror-dialog"))&&r.getBoundingClientRect().bottom-4>t.cursorCoords(n,"window").top&&((d=r).style.opacity=.4)})))}),"searchNext");s(t,v(t),c,p,(function(n,i){var o=e.keyName(n),a=t.getOption("extraKeys"),s=a&&a[o]||e.keyMap[t.getOption("keyMap")][o];"findNext"==s||"findPrev"==s||"findPersistentNext"==s||"findPersistentPrev"==s?(e.e_stop(n),f(t,r(t),i),t.execCommand(s)):"find"!=s&&"findPersistent"!=s||(e.e_stop(n),p(i,n))})),a&&c&&(f(t,u,c),h(t,n))}else l(t,v(t),"Search for:",c,(function(e){e&&!u.query&&t.operation((function(){f(t,u,e),u.posFrom=u.posTo=t.getCursor(),h(t,n)}))}))}function h(t,n,i){t.operation((function(){var o=r(t),s=a(t,o.query,n?o.posFrom:o.posTo);(s.find(n)||(s=a(t,o.query,n?e.Pos(t.lastLine()):e.Pos(t.firstLine(),0))).find(n))&&(t.setSelection(s.from(),s.to()),t.scrollIntoView({from:s.from(),to:s.to()},20),o.posFrom=s.from(),o.posTo=s.to(),i&&i(s.from(),s.to()))}))}function m(e){e.operation((function(){var t=r(e);t.lastQuery=t.query,t.query&&(t.query=t.queryText=null,e.removeOverlay(t.overlay),t.annotate&&(t.annotate.clear(),t.annotate=null))}))}function g(e,t){var n=e?document.createElement(e):document.createDocumentFragment();for(var r in t)n[r]=t[r];for(var i=2;in(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};e.a=o,function(e){var t,n,i=e.Pos;function o(e){var t=e.flags;return null!=t?t:(e.ignoreCase?"i":"")+(e.global?"g":"")+(e.multiline?"m":"")}function a(e,t){for(var n=o(e),r=n,i=0;ic);d++){var f=e.getLine(u++);r=null==r?f:r+"\n"+f}o*=2,t.lastIndex=n.ch;var p=t.exec(r);if(p){var h=r.slice(0,p.index).split("\n"),m=p[0].split("\n"),g=n.line+h.length-1,v=h[h.length-1].length;return{from:i(g,v),to:i(g+m.length-1,1==m.length?v+m[0].length:m[m.length-1].length),match:p}}}}function c(e,t,n){for(var r,i=0;i<=e.length;){t.lastIndex=i;var o=t.exec(e);if(!o)break;var a=o.index+o[0].length;if(a>e.length-n)break;(!r||a>r.index+r[0].length)&&(r=o),i=o.index+1}return r}function d(e,t,n){t=a(t,"g");for(var r=n.line,o=n.ch,s=e.firstLine();r>=s;r--,o=-1){var l=e.getLine(r),u=c(l,t,o<0?0:l.length-o);if(u)return{from:i(r,u.index),to:i(r,u.index+u[0].length),match:u}}}function f(e,t,n){if(!s(t))return d(e,t,n);t=a(t,"gm");for(var r,o=1,l=e.getLine(n.line).length-n.ch,u=n.line,f=e.firstLine();u>=f;){for(var p=0;p=f;p++){var h=e.getLine(u--);r=null==r?h:h+"\n"+r}o*=2;var m=c(r,t,l);if(m){var g=r.slice(0,m.index).split("\n"),v=m[0].split("\n"),y=u+g.length,b=g[g.length-1].length;return{from:i(y,b),to:i(y+v.length-1,1==v.length?b+v[0].length:v[v.length-1].length),match:m}}}}function p(e,t,n,r){if(e.length==t.length)return n;for(var i=0,o=n+Math.max(0,e.length-t.length);;){if(i==o)return i;var a=i+o>>1,s=r(e.slice(0,a)).length;if(s==n)return a;s>n?o=a:i=a+1}}function h(e,r,o,a){if(!r.length)return null;var s=a?t:n,l=s(r).split(/\r|\n\r?/);e:for(var u=o.line,c=o.ch,d=e.lastLine()+1-l.length;u<=d;u++,c=0){var f=e.getLine(u).slice(c),h=s(f);if(1==l.length){var m=h.indexOf(l[0]);if(-1==m)continue e;return o=p(f,h,m,s)+c,{from:i(u,p(f,h,m,s)+c),to:i(u,p(f,h,m+l[0].length,s)+c)}}var g=h.length-l[0].length;if(h.slice(g)==l[0]){for(var v=1;v=d;u--,c=-1){var f=e.getLine(u);c>-1&&(f=f.slice(0,c));var h=s(f);if(1==l.length){var m=h.lastIndexOf(l[0]);if(-1==m)continue e;return{from:i(u,p(f,h,m,s)),to:i(u,p(f,h,m+l[0].length,s))}}var g=l[l.length-1];if(h.slice(0,g.length)==g){var v=1;for(o=u-l.length+1;v(this.doc.getLine(n.line)||"").length&&(n.ch=0,n.line++)),0!=e.cmpPos(n,this.doc.clipPos(n))))return this.atOccurrence=!1;var r=this.matches(t,n);if(this.afterEmptyMatch=r&&0==e.cmpPos(r.from,r.to),r)return this.pos=r,this.atOccurrence=!0,this.pos.match||!0;var o=i(t?this.doc.firstLine():this.doc.lastLine()+1,0);return this.pos={from:o,to:o},this.atOccurrence=!1},from:function(){if(this.atOccurrence)return this.pos.from},to:function(){if(this.atOccurrence)return this.pos.to},replace:function(t,n){if(this.atOccurrence){var r=e.splitLines(t);this.doc.replaceRange(r,this.pos.from,this.pos.to,n),this.pos.to=i(this.pos.from.line+r.length-1,r[r.length-1].length+(1==r.length?this.pos.from.ch:0))}}},e.defineExtension("getSearchCursor",(function(e,t,n){return new g(this.doc,e,t,n)})),e.defineDocExtension("getSearchCursor",(function(e,t,n){return new g(this,e,t,n)})),e.defineExtension("selectMatches",(function(t,n){for(var r=[],i=this.getSearchCursor(t,this.getCursor("from"),n);i.findNext()&&!(e.cmpPos(i.to(),this.getCursor("to"))>0);)r.push({anchor:i.from(),head:i.to()});r.length&&this.setSelections(r,0)}))}(t.a.exports);var a=i({__proto__:null,default:o.exports},[o.exports]);e.s=a})?r.apply(t,i):r)||(e.exports=o)},6980:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535)],void 0===(o="function"==typeof(r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.s=void 0;var n=Object.defineProperty,r=(e,t)=>n(e,"name",{value:t,configurable:!0});function i(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(i,"_mergeNamespaces");var o={exports:{}};!function(e){var t="CodeMirror-hint",n="CodeMirror-hint-active";function i(e,t){if(this.cm=e,this.options=t,this.widget=null,this.debounce=0,this.tick=0,this.startPos=this.cm.getCursor("start"),this.startLen=this.cm.getLine(this.startPos.line).length-this.cm.getSelection().length,this.options.updateOnCursorActivity){var n=this;e.on("cursorActivity",this.activityFunc=function(){n.cursorActivity()})}}e.showHint=function(e,t,n){if(!t)return e.showHint(n);n&&n.async&&(t.async=!0);var r={hint:t};if(n)for(var i in n)r[i]=n[i];return e.showHint(r)},e.defineExtension("showHint",(function(t){t=s(this,this.getCursor("start"),t);var n=this.listSelections();if(!(n.length>1)){if(this.somethingSelected()){if(!t.hint.supportsSelection)return;for(var r=0;rf.clientHeight+1;if(setTimeout((function(){D=a.getScrollInfo()})),L.bottom-I>0){var M=L.bottom-L.top;if(E.top-(E.bottom-L.top)-M>0)f.style.top=(w=E.top-M-x)+"px",C=!1;else if(M>I){f.style.height=I-5+"px",f.style.top=(w=E.bottom-L.top-x)+"px";var R=a.getCursor();i.from.ch!=R.ch&&(E=a.cursorCoords(R),f.style.left=(T=E.left-S)+"px",L=f.getBoundingClientRect())}}var F,P=L.right-O;if(A&&(P+=a.display.nativeBarWidth),P>0&&(L.right-L.left>O&&(f.style.width=O-5+"px",P-=L.right-L.left-O),f.style.left=(T=E.left-P-S)+"px"),A)for(var j=f.firstChild;j;j=j.nextSibling)j.style.paddingRight=a.display.nativeBarWidth+"px";a.addKeyMap(this.keyMap=u(r,{moveFocus:function(e,t){o.changeActive(o.selectedHint+e,t)},setFocus:function(e){o.changeActive(e)},menuSize:function(){return o.screenAmount()},length:h.length,close:function(){r.close()},pick:function(){o.pick()},data:i})),r.options.closeOnUnfocus&&(a.on("blur",this.onBlur=function(){F=setTimeout((function(){r.close()}),100)}),a.on("focus",this.onFocus=function(){clearTimeout(F)})),a.on("scroll",this.onScroll=function(){var e=a.getScrollInfo(),t=a.getWrapperElement().getBoundingClientRect();D||(D=a.getScrollInfo());var n=w+D.top-e.top,i=n-(d.pageYOffset||(s.documentElement||s.body).scrollTop);if(C||(i+=f.offsetHeight),i<=t.top||i>=t.bottom)return r.close();f.style.top=n+"px",f.style.left=T+D.left-e.left+"px"}),e.on(f,"dblclick",(function(e){var t=c(f,e.target||e.srcElement);t&&null!=t.hintId&&(o.changeActive(t.hintId),o.pick())})),e.on(f,"click",(function(e){var t=c(f,e.target||e.srcElement);t&&null!=t.hintId&&(o.changeActive(t.hintId),r.options.completeOnSingleClick&&o.pick())})),e.on(f,"mousedown",(function(){setTimeout((function(){a.focus()}),20)}));var V=this.getSelectedHintRange();return 0===V.from&&0===V.to||this.scrollToActive(),e.signal(i,"select",h[this.selectedHint],f.childNodes[this.selectedHint]),!0}function f(e,t){if(!e.somethingSelected())return t;for(var n=[],r=0;r0?t(e):a(r+1)}))}r(a,"run"),a(0)}),"resolved");return a.async=!0,a.supportsSelection=!0,a}return(i=t.getHelper(t.getCursor(),"hintWords"))?function(t){return e.hint.fromList(t,{words:i})}:e.hint.anyword?function(t,n){return e.hint.anyword(t,n)}:function(){}}i.prototype={close:function(){this.active()&&(this.cm.state.completionActive=null,this.tick=null,this.options.updateOnCursorActivity&&this.cm.off("cursorActivity",this.activityFunc),this.widget&&this.data&&e.signal(this.data,"close"),this.widget&&this.widget.close(),e.signal(this.cm,"endCompletion",this.cm))},active:function(){return this.cm.state.completionActive==this},pick:function(t,n){var r=t.list[n],i=this;this.cm.operation((function(){r.hint?r.hint(i.cm,t,r):i.cm.replaceRange(l(r),r.from||t.from,r.to||t.to,"complete"),e.signal(t,"pick",r),i.cm.scrollIntoView()})),this.options.closeOnPick&&this.close()},cursorActivity:function(){this.debounce&&(a(this.debounce),this.debounce=0);var e=this.startPos;this.data&&(e=this.data.from);var t=this.cm.getCursor(),n=this.cm.getLine(t.line);if(t.line!=this.startPos.line||n.length-t.ch!=this.startLen-this.startPos.ch||t.ch=this.data.list.length?t=r?this.data.list.length-1:0:t<0&&(t=r?0:this.data.list.length-1),this.selectedHint!=t){var i=this.hints.childNodes[this.selectedHint];i&&(i.className=i.className.replace(" "+n,""),i.removeAttribute("aria-selected")),(i=this.hints.childNodes[this.selectedHint=t]).className+=" "+n,i.setAttribute("aria-selected","true"),this.completion.cm.getInputField().setAttribute("aria-activedescendant",i.id),this.scrollToActive(),e.signal(this.data,"select",this.data.list[this.selectedHint],i)}},scrollToActive:function(){var e=this.getSelectedHintRange(),t=this.hints.childNodes[e.from],n=this.hints.childNodes[e.to],r=this.hints.firstChild;t.offsetTopthis.hints.scrollTop+this.hints.clientHeight&&(this.hints.scrollTop=n.offsetTop+n.offsetHeight-this.hints.clientHeight+r.offsetTop)},screenAmount:function(){return Math.floor(this.hints.clientHeight/this.hints.firstChild.offsetHeight)||1},getSelectedHintRange:function(){var e=this.completion.options.scrollMargin||0;return{from:Math.max(0,this.selectedHint-e),to:Math.min(this.data.list.length-1,this.selectedHint+e)}}},r(f,"applicableHelpers"),r(p,"fetchHints"),r(h,"resolveAutoHints"),e.registerHelper("hint","auto",{resolve:h}),e.registerHelper("hint","fromList",(function(t,n){var r,i=t.getCursor(),o=t.getTokenAt(i),a=e.Pos(i.line,o.start),s=i;o.start,]/,closeOnPick:!0,closeOnUnfocus:!0,updateOnCursorActivity:!0,completeOnSingleClick:!0,container:null,customKeys:null,extraKeys:null,paddingForScrollbar:!0,moveOnOverlap:!0};e.defineOption("hintOptions",null)}(t.a.exports);var a=i({__proto__:null,default:o.exports},[o.exports]);e.s=a})?r.apply(t,i):r)||(e.exports=o)},2568:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(535),n(9407),n(9171)],void 0===(o="function"==typeof(r=function(e,t,n,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.s=void 0;var i=Object.defineProperty,o=(e,t)=>i(e,"name",{value:t,configurable:!0});function a(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}o(a,"_mergeNamespaces");var s={exports:{}};!function(e){var t=e.commands,n=e.Pos;function r(t,r,i){if(i<0&&0==r.ch)return t.clipPos(n(r.line-1));var o=t.getLine(r.line);if(i>0&&r.ch>=o.length)return t.clipPos(n(r.line+1,0));for(var a,s="start",l=r.ch,u=l,c=i<0?0:o.length,d=0;u!=c;u+=i,d++){var f=o.charAt(i<0?u-1:u),p="_"!=f&&e.isWordChar(f)?"w":"o";if("w"==p&&f.toUpperCase()==f&&(p="W"),"start"==s)"o"!=p?(s="in",a=p):l=u+i;else if("in"==s&&a!=p){if("w"==a&&"W"==p&&i<0&&u--,"W"==a&&"w"==p&&i>0){if(u==l+1){a="w";continue}u--}break}}return n(r.line,u)}function i(e,t){e.extendSelectionsBy((function(n){return e.display.shift||e.doc.extend||n.empty()?r(e.doc,n.head,t):t<0?n.from():n.to()}))}function a(t,r){if(t.isReadOnly())return e.Pass;t.operation((function(){for(var e=t.listSelections().length,i=[],o=-1,a=0;a=n&&e.execCommand("goLineUp")}e.scrollTo(null,t.top-e.defaultTextHeight())},t.scrollLineDown=function(e){var t=e.getScrollInfo();if(!e.somethingSelected()){var n=e.lineAtHeight(t.top,"local")+1;e.getCursor().line<=n&&e.execCommand("goLineDown")}e.scrollTo(null,t.top+e.defaultTextHeight())},t.splitSelectionByLine=function(e){for(var t=e.listSelections(),r=[],i=0;io.line&&s==a.line&&0==a.ch||r.push({anchor:s==o.line?o:n(s,0),head:s==a.line?a:n(s)});e.setSelections(r,0)},t.singleSelectionTop=function(e){var t=e.listSelections()[0];e.setSelection(t.anchor,t.head,{scroll:!1})},t.selectLine=function(e){for(var t=e.listSelections(),r=[],i=0;i=0;a--){var u=r[i[a]];if(!(l&&e.cmpPos(u.head,l)>0)){var c=s(t,u.head);l=c.from,t.replaceRange(n(c.word),c.from,c.to)}}}))}function m(t){var n=t.getCursor("from"),r=t.getCursor("to");if(0==e.cmpPos(n,r)){var i=s(t,n);if(!i.word)return;n=i.from,r=i.to}return{from:n,to:r,query:t.getRange(n,r),word:i}}function g(e,t){var r=m(e);if(r){var i=r.query,o=e.getSearchCursor(i,t?r.to:r.from);(t?o.findNext():o.findPrevious())?e.setSelection(o.from(),o.to()):(o=e.getSearchCursor(i,t?n(e.firstLine(),0):e.clipPos(n(e.lastLine()))),(t?o.findNext():o.findPrevious())?e.setSelection(o.from(),o.to()):r.word&&e.setSelection(r.from,r.to))}}o(d,"selectBetweenBrackets"),t.selectScope=function(e){d(e)||e.execCommand("selectAll")},t.selectBetweenBrackets=function(t){if(!d(t))return e.Pass},o(f,"puncType"),t.goToBracket=function(t){t.extendSelectionsBy((function(r){var i=t.scanForBracket(r.head,1,f(t.getTokenTypeAt(r.head)));if(i&&0!=e.cmpPos(i.pos,r.head))return i.pos;var o=t.scanForBracket(r.head,-1,f(t.getTokenTypeAt(n(r.head.line,r.head.ch+1))));return o&&n(o.pos.line,o.pos.ch+1)||r.head}))},t.swapLineUp=function(t){if(t.isReadOnly())return e.Pass;for(var r=t.listSelections(),i=[],o=t.firstLine()-1,a=[],s=0;so?i.push(u,c):i.length&&(i[i.length-1]=c),o=c}t.operation((function(){for(var e=0;et.lastLine()?t.replaceRange("\n"+s,n(t.lastLine()),null,"+swapLine"):t.replaceRange(s+"\n",n(o,0),null,"+swapLine")}t.setSelections(a),t.scrollIntoView()}))},t.swapLineDown=function(t){if(t.isReadOnly())return e.Pass;for(var r=t.listSelections(),i=[],o=t.lastLine()+1,a=r.length-1;a>=0;a--){var s=r[a],l=s.to().line+1,u=s.from().line;0!=s.to().ch||s.empty()||l--,l=0;e-=2){var r=i[e],o=i[e+1],a=t.getLine(r);r==t.lastLine()?t.replaceRange("",n(r-1),n(r),"+swapLine"):t.replaceRange("",n(r,0),n(r+1,0),"+swapLine"),t.replaceRange(a+"\n",n(o,0),null,"+swapLine")}t.scrollIntoView()}))},t.toggleCommentIndented=function(e){e.toggleComment({indent:!0})},t.joinLines=function(e){for(var t=e.listSelections(),r=[],i=0;i=0;o--){var a=r[o].head,s=t.getRange({line:a.line,ch:0},a),l=e.countColumn(s,null,t.getOption("tabSize")),u=t.findPosH(a,-1,"char",!1);if(s&&!/\S/.test(s)&&l%i==0){var c=new n(a.line,e.findColumn(s,l-i,i));c.ch!=a.ch&&(u=c)}t.replaceRange("",u,a,"+delete")}}))},t.delLineRight=function(e){e.operation((function(){for(var t=e.listSelections(),r=t.length-1;r>=0;r--)e.replaceRange("",t[r].anchor,n(t[r].to().line),"+delete");e.scrollIntoView()}))},t.upcaseAtCursor=function(e){h(e,(function(e){return e.toUpperCase()}))},t.downcaseAtCursor=function(e){h(e,(function(e){return e.toLowerCase()}))},t.setSublimeMark=function(e){e.state.sublimeMark&&e.state.sublimeMark.clear(),e.state.sublimeMark=e.setBookmark(e.getCursor())},t.selectToSublimeMark=function(e){var t=e.state.sublimeMark&&e.state.sublimeMark.find();t&&e.setSelection(e.getCursor(),t)},t.deleteToSublimeMark=function(t){var n=t.state.sublimeMark&&t.state.sublimeMark.find();if(n){var r=t.getCursor(),i=n;if(e.cmpPos(r,i)>0){var o=i;i=r,r=o}t.state.sublimeKilled=t.getRange(r,i),t.replaceRange("",r,i)}},t.swapWithSublimeMark=function(e){var t=e.state.sublimeMark&&e.state.sublimeMark.find();t&&(e.state.sublimeMark.clear(),e.state.sublimeMark=e.setBookmark(e.getCursor()),e.setCursor(t))},t.sublimeYank=function(e){null!=e.state.sublimeKilled&&e.replaceSelection(e.state.sublimeKilled,null,"paste")},t.showInCenter=function(e){var t=e.cursorCoords(null,"local");e.scrollTo(null,(t.top+t.bottom)/2-e.getScrollInfo().clientHeight/2)},o(m,"getTarget"),o(g,"findAndGoTo"),t.findUnder=function(e){g(e,!0)},t.findUnderPrevious=function(e){g(e,!1)},t.findAllUnder=function(e){var t=m(e);if(t){for(var n=e.getSearchCursor(t.query),r=[],i=-1;n.findNext();)r.push({anchor:n.from(),head:n.to()}),n.from().line<=t.from.line&&n.from().ch<=t.from.ch&&i++;e.setSelections(r,i)}};var v=e.keyMap;v.macSublime={"Cmd-Left":"goLineStartSmart","Shift-Tab":"indentLess","Shift-Ctrl-K":"deleteLine","Alt-Q":"wrapLines","Ctrl-Left":"goSubwordLeft","Ctrl-Right":"goSubwordRight","Ctrl-Alt-Up":"scrollLineUp","Ctrl-Alt-Down":"scrollLineDown","Cmd-L":"selectLine","Shift-Cmd-L":"splitSelectionByLine",Esc:"singleSelectionTop","Cmd-Enter":"insertLineAfter","Shift-Cmd-Enter":"insertLineBefore","Cmd-D":"selectNextOccurrence","Shift-Cmd-Space":"selectScope","Shift-Cmd-M":"selectBetweenBrackets","Cmd-M":"goToBracket","Cmd-Ctrl-Up":"swapLineUp","Cmd-Ctrl-Down":"swapLineDown","Cmd-/":"toggleCommentIndented","Cmd-J":"joinLines","Shift-Cmd-D":"duplicateLine",F5:"sortLines","Shift-F5":"reverseSortLines","Cmd-F5":"sortLinesInsensitive","Shift-Cmd-F5":"reverseSortLinesInsensitive",F2:"nextBookmark","Shift-F2":"prevBookmark","Cmd-F2":"toggleBookmark","Shift-Cmd-F2":"clearBookmarks","Alt-F2":"selectBookmarks",Backspace:"smartBackspace","Cmd-K Cmd-D":"skipAndSelectNextOccurrence","Cmd-K Cmd-K":"delLineRight","Cmd-K Cmd-U":"upcaseAtCursor","Cmd-K Cmd-L":"downcaseAtCursor","Cmd-K Cmd-Space":"setSublimeMark","Cmd-K Cmd-A":"selectToSublimeMark","Cmd-K Cmd-W":"deleteToSublimeMark","Cmd-K Cmd-X":"swapWithSublimeMark","Cmd-K Cmd-Y":"sublimeYank","Cmd-K Cmd-C":"showInCenter","Cmd-K Cmd-G":"clearBookmarks","Cmd-K Cmd-Backspace":"delLineLeft","Cmd-K Cmd-1":"foldAll","Cmd-K Cmd-0":"unfoldAll","Cmd-K Cmd-J":"unfoldAll","Ctrl-Shift-Up":"addCursorToPrevLine","Ctrl-Shift-Down":"addCursorToNextLine","Cmd-F3":"findUnder","Shift-Cmd-F3":"findUnderPrevious","Alt-F3":"findAllUnder","Shift-Cmd-[":"fold","Shift-Cmd-]":"unfold","Cmd-I":"findIncremental","Shift-Cmd-I":"findIncrementalReverse","Cmd-H":"replace",F3:"findNext","Shift-F3":"findPrev",fallthrough:"macDefault"},e.normalizeKeyMap(v.macSublime),v.pcSublime={"Shift-Tab":"indentLess","Shift-Ctrl-K":"deleteLine","Alt-Q":"wrapLines","Ctrl-T":"transposeChars","Alt-Left":"goSubwordLeft","Alt-Right":"goSubwordRight","Ctrl-Up":"scrollLineUp","Ctrl-Down":"scrollLineDown","Ctrl-L":"selectLine","Shift-Ctrl-L":"splitSelectionByLine",Esc:"singleSelectionTop","Ctrl-Enter":"insertLineAfter","Shift-Ctrl-Enter":"insertLineBefore","Ctrl-D":"selectNextOccurrence","Shift-Ctrl-Space":"selectScope","Shift-Ctrl-M":"selectBetweenBrackets","Ctrl-M":"goToBracket","Shift-Ctrl-Up":"swapLineUp","Shift-Ctrl-Down":"swapLineDown","Ctrl-/":"toggleCommentIndented","Ctrl-J":"joinLines","Shift-Ctrl-D":"duplicateLine",F9:"sortLines","Shift-F9":"reverseSortLines","Ctrl-F9":"sortLinesInsensitive","Shift-Ctrl-F9":"reverseSortLinesInsensitive",F2:"nextBookmark","Shift-F2":"prevBookmark","Ctrl-F2":"toggleBookmark","Shift-Ctrl-F2":"clearBookmarks","Alt-F2":"selectBookmarks",Backspace:"smartBackspace","Ctrl-K Ctrl-D":"skipAndSelectNextOccurrence","Ctrl-K Ctrl-K":"delLineRight","Ctrl-K Ctrl-U":"upcaseAtCursor","Ctrl-K Ctrl-L":"downcaseAtCursor","Ctrl-K Ctrl-Space":"setSublimeMark","Ctrl-K Ctrl-A":"selectToSublimeMark","Ctrl-K Ctrl-W":"deleteToSublimeMark","Ctrl-K Ctrl-X":"swapWithSublimeMark","Ctrl-K Ctrl-Y":"sublimeYank","Ctrl-K Ctrl-C":"showInCenter","Ctrl-K Ctrl-G":"clearBookmarks","Ctrl-K Ctrl-Backspace":"delLineLeft","Ctrl-K Ctrl-1":"foldAll","Ctrl-K Ctrl-0":"unfoldAll","Ctrl-K Ctrl-J":"unfoldAll","Ctrl-Alt-Up":"addCursorToPrevLine","Ctrl-Alt-Down":"addCursorToNextLine","Ctrl-F3":"findUnder","Shift-Ctrl-F3":"findUnderPrevious","Alt-F3":"findAllUnder","Shift-Ctrl-[":"fold","Shift-Ctrl-]":"unfold","Ctrl-I":"findIncremental","Shift-Ctrl-I":"findIncrementalReverse","Ctrl-H":"replace",F3:"findNext","Shift-F3":"findPrev",fallthrough:"pcDefault"},e.normalizeKeyMap(v.pcSublime);var y=v.default==v.macDefault;v.sublime=y?v.macSublime:v.pcSublime}(t.a.exports,n.a.exports,r.a.exports);var l=a({__proto__:null,default:s.exports},[s.exports]);e.s=l})?r.apply(t,i):r)||(e.exports=o)},3691:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(r="function"==typeof(n=function(e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.fetcherReturnToPromise=function(e){return t(this,void 0,void 0,(function*(){const i=yield e;return r(i)?function(e){var n;return t(this,void 0,void 0,(function*(){const t=null===(n=("return"in e?e:e[Symbol.asyncIterator]()).return)||void 0===n?void 0:n.bind(e),r=("next"in e?e:e[Symbol.asyncIterator]()).next.bind(e),i=yield r();return null==t||t(),i.value}))}(i):n(i)?(o=i,new Promise(((e,t)=>{const n=o.subscribe({next:t=>{e(t),n.unsubscribe()},error:t,complete:()=>{t(new Error("no value resolved"))}})}))):i;var o}))},e.isAsyncIterable=r,e.isObservable=n,e.isPromise=function(e){return"object"==typeof e&&null!==e&&"function"==typeof e.then};var t=function(e,t,n,r){return new(n||(n=Promise))((function(i,o){function a(e){try{l(r.next(e))}catch(e){o(e)}}function s(e){try{l(r.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}l((r=r.apply(e,t||[])).next())}))};function n(e){return"object"==typeof e&&null!==e&&"subscribe"in e&&"function"==typeof e.subscribe}function r(e){return"object"==typeof e&&null!==e&&("AsyncGenerator"===e[Symbol.toStringTag]||Symbol.asyncIterator in e)}})?n.apply(t,[t]):n)||(e.exports=r)},5454:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(2501)],void 0===(o="function"==typeof(r=function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.createGraphiQLFetcher=function(e){let n;if("undefined"!=typeof window&&window.fetch&&(n=window.fetch),null!==(null==e?void 0:e.enableIncrementalDelivery)&&!1===e.enableIncrementalDelivery||(e.enableIncrementalDelivery=!0),e.fetch&&(n=e.fetch),!n)throw new Error("No valid fetcher implementation available");const r=(0,t.createSimpleFetcher)(e,n),i=e.enableIncrementalDelivery?(0,t.createMultipartFetcher)(e,n):r;return(n,o)=>{if("IntrospectionQuery"===n.operationName)return(e.schemaFetcher||r)(n,o);if((null==o?void 0:o.documentAST)&&(0,t.isSubscriptionWithName)(o.documentAST,n.operationName||void 0)){const r=(0,t.getWsFetcher)(e,o);if(!r)throw new Error("Your GraphiQL createFetcher is not properly configured for websocket subscriptions yet. "+(e.subscriptionUrl?`Provided URL ${e.subscriptionUrl} failed`:"Please provide subscriptionUrl, wsClient or legacyClient option first."));return r(n)}return i(n,o)}}})?r.apply(t,i):r)||(e.exports=o)},1799:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(3080),n(5454)],void 0===(o="function"==typeof(r=function(e,t,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r={createGraphiQLFetcher:!0};Object.defineProperty(e,"createGraphiQLFetcher",{enumerable:!0,get:function(){return n.createGraphiQLFetcher}}),Object.keys(t).forEach((function(n){"default"!==n&&"__esModule"!==n&&(Object.prototype.hasOwnProperty.call(r,n)||n in e&&e[n]===t[n]||Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[n]}}))}))})?r.apply(t,i):r)||(e.exports=o)},2501:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(3573),n(8488),n(8042)],r=function(e,t,r,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.isSubscriptionWithName=e.getWsFetcher=e.createWebsocketsFetcherFromUrl=e.createWebsocketsFetcherFromClient=e.createSimpleFetcher=e.createMultipartFetcher=e.createLegacyWebsocketsFetcher=void 0;var o=function(e,t,n,r){return new(n||(n=Promise))((function(i,o){function a(e){try{l(r.next(e))}catch(e){o(e)}}function s(e){try{l(r.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}l((r=r.apply(e,t||[])).next())}))},a=function(e){return this instanceof a?(this.v=e,this):new a(e)},s=function(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e="function"==typeof __values?__values(e):e[Symbol.iterator](),t={},r("next"),r("throw"),r("return"),t[Symbol.asyncIterator]=function(){return this},t);function r(n){t[n]=e[n]&&function(t){return new Promise((function(r,i){!function(e,t,n,r){Promise.resolve(r).then((function(t){e({value:t,done:n})}),t)}(r,i,(t=e[n](t)).done,t.value)}))}}},l=function(e,t,n){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var r,i=n.apply(e,t||[]),o=[];return r={},s("next"),s("throw"),s("return"),r[Symbol.asyncIterator]=function(){return this},r;function s(e){i[e]&&(r[e]=function(t){return new Promise((function(n,r){o.push([e,t,n,r])>1||l(e,t)}))})}function l(e,t){try{(n=i[e](t)).value instanceof a?Promise.resolve(n.value.v).then(u,c):d(o[0][2],n)}catch(e){d(o[0][3],e)}var n}function u(e){l("next",e)}function c(e){l("throw",e)}function d(e,t){e(t),o.shift(),o.length&&l(o[0][0],o[0][1])}};e.isSubscriptionWithName=(e,n)=>{let r=!1;return(0,t.visit)(e,{OperationDefinition(e){var t;n===(null===(t=e.name)||void 0===t?void 0:t.value)&&"subscription"===e.operation&&(r=!0)}}),r};e.createSimpleFetcher=(e,t)=>(n,r)=>o(void 0,void 0,void 0,(function*(){return(yield t(e.url,{method:"POST",body:JSON.stringify(n),headers:Object.assign(Object.assign({"content-type":"application/json"},e.headers),null==r?void 0:r.headers)})).json()}));const u=(e,t)=>{let r;try{const{createClient:i}=n(7674);return r=i({url:e,connectionParams:t}),c(r)}catch(t){if((e=>"object"==typeof e&&null!==e&&"code"in e)(t)&&"MODULE_NOT_FOUND"===t.code)throw new Error("You need to install the 'graphql-ws' package to use websockets when passing a 'subscriptionUrl'");console.error(`Error creating websocket client for ${e}`,t)}};e.createWebsocketsFetcherFromUrl=u;const c=e=>t=>(0,i.makeAsyncIterableIteratorFromSink)((n=>e.subscribe(t,Object.assign(Object.assign({},n),{error:e=>{e instanceof CloseEvent?n.error(new Error(`Socket closed with event ${e.code} ${e.reason||""}`.trim())):n.error(e)}}))));e.createWebsocketsFetcherFromClient=c;const d=e=>t=>{const n=e.request(t);return(0,i.makeAsyncIterableIteratorFromSink)((e=>n.subscribe(e).unsubscribe))};e.createLegacyWebsocketsFetcher=d;e.createMultipartFetcher=(e,t)=>function(n,o){return l(this,arguments,(function*(){var l,u;const c=yield a(t(e.url,{method:"POST",body:JSON.stringify(n),headers:Object.assign(Object.assign({"content-type":"application/json",accept:"application/json, multipart/mixed"},e.headers),null==o?void 0:o.headers)}).then((e=>(0,r.meros)(e,{multiple:!0}))));if(!(0,i.isAsyncIterable)(c))return yield a(yield yield a(c.json()));try{for(var d,f=s(c);!(d=yield a(f.next())).done;){const e=d.value;if(e.some((e=>!e.json))){const t=e.map((e=>`Headers::\n${e.headers}\n\nBody::\n${e.body}`));throw new Error(`Expected multipart chunks to be of json type. got:\n${t}`)}yield yield a(e.map((e=>e.body)))}}catch(e){l={error:e}}finally{try{d&&!d.done&&(u=f.return)&&(yield a(u.call(f)))}finally{if(l)throw l.error}}}))};e.getWsFetcher=(e,t)=>{if(e.wsClient)return c(e.wsClient);if(e.subscriptionUrl)return u(e.subscriptionUrl,Object.assign(Object.assign({},e.wsConnectionParams),null==t?void 0:t.headers));const n=e.legacyClient||e.legacyWsClient;return n?d(n):void 0}},void 0===(o=r.apply(t,i))||(e.exports=o)},3080:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(r="function"==typeof(n=function(e){"use strict";Object.defineProperty(e,"__esModule",{value:!0})})?n.apply(t,[t]):n)||(e.exports=r)},4574:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(r="function"==typeof(n=function(e){"use strict";function t(e){return JSON.stringify(e,null,2)}function n(e){return e instanceof Error?function(e){return Object.assign(Object.assign({},e),{message:e.message,stack:e.stack})}(e):e}Object.defineProperty(e,"__esModule",{value:!0}),e.formatError=function(e){return Array.isArray(e)?t({errors:e.map((e=>n(e)))}):t({errors:[n(e)]})},e.formatResult=function(e){return t(e)}})?n.apply(t,[t]):n)||(e.exports=r)},3738:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(3573)],void 0===(o="function"==typeof(r=function(e,t){"use strict";function n(e){if(!("getFields"in e))return[];const n=e.getFields();if(n.id)return["id"];if(n.edges)return["edges"];if(n.node)return["node"];const r=[];for(const e of Object.keys(n))(0,t.isLeafType)(n[e].type)&&r.push(e);return r}function r(e,n){const i=(0,t.getNamedType)(e);if(!e||(0,t.isLeafType)(e))return;const o=n(i);return Array.isArray(o)&&0!==o.length&&"getFields"in i?{kind:t.Kind.SELECTION_SET,selections:o.map((e=>{const o=i.getFields()[e],a=o?o.type:null;return{kind:t.Kind.FIELD,name:{kind:t.Kind.NAME,value:e},selectionSet:r(a,n)}}))}:void 0}function i(e,t){if(0===t.length)return e;let n="",r=0;for(const{index:i,string:o}of t)n+=e.slice(r,i)+o,r=i;return n+=e.slice(r),n}Object.defineProperty(e,"__esModule",{value:!0}),e.fillLeafs=function(e,o,a){const s=[];if(!e||!o)return{insertions:s,result:o};let l;try{l=(0,t.parse)(o)}catch(e){return{insertions:s,result:o}}const u=a||n,c=new t.TypeInfo(e);return(0,t.visit)(l,{leave(e){c.leave(e)},enter(e){if(c.enter(e),"Field"===e.kind&&!e.selectionSet){const n=r(function(e){if(e)return e}(c.getType()),u);if(n&&e.loc){const r=function(e,t){let n=t,r=t;for(;n;){const t=e.charCodeAt(n-1);if(10===t||13===t||8232===t||8233===t)break;n--,9!==t&&11!==t&&12!==t&&32!==t&&160!==t&&(r=n)}return e.slice(n,r)}(o,e.loc.start);s.push({index:e.loc.end,string:" "+(0,t.print)(n).replaceAll("\n","\n"+r)})}}}}),{insertions:s,result:i(o,s)}}})?r.apply(t,i):r)||(e.exports=o)},7293:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(3738),n(5682),n(1312)],void 0===(o="function"==typeof(r=function(e,t,n,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),Object.keys(t).forEach((function(n){"default"!==n&&"__esModule"!==n&&(n in e&&e[n]===t[n]||Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[n]}}))})),Object.keys(n).forEach((function(t){"default"!==t&&"__esModule"!==t&&(t in e&&e[t]===n[t]||Object.defineProperty(e,t,{enumerable:!0,get:function(){return n[t]}}))})),Object.keys(r).forEach((function(t){"default"!==t&&"__esModule"!==t&&(t in e&&e[t]===r[t]||Object.defineProperty(e,t,{enumerable:!0,get:function(){return r[t]}}))}))})?r.apply(t,i):r)||(e.exports=o)},5682:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(3573)],void 0===(o="function"==typeof(r=function(e,t){"use strict";function n(e,r,i){var o;const a=i?(0,t.getNamedType)(i).name:null,s=[],l=[];for(let u of r){if("FragmentSpread"===u.kind){const n=u.name.value;if(!u.directives||0===u.directives.length){if(l.includes(n))continue;l.push(n)}const r=e[u.name.value];if(r){const{typeCondition:e,directives:n,selectionSet:i}=r;u={kind:t.Kind.INLINE_FRAGMENT,typeCondition:e,directives:n,selectionSet:i}}}if(u.kind===t.Kind.INLINE_FRAGMENT&&(!u.directives||0===(null===(o=u.directives)||void 0===o?void 0:o.length))){const t=u.typeCondition?u.typeCondition.name.value:null;if(!t||t===a){s.push(...n(e,u.selectionSet.selections,i));continue}}s.push(u)}return s}Object.defineProperty(e,"__esModule",{value:!0}),e.mergeAst=function(e,r){const i=r?new t.TypeInfo(r):null,o=Object.create(null);for(const n of e.definitions)n.kind===t.Kind.FRAGMENT_DEFINITION&&(o[n.name.value]=n);const a={SelectionSet(e){const t=i?i.getParentType():null;let{selections:r}=e;return r=n(o,r,t),r=function(e,t){var n;const r=new Map,i=[];for(const o of e)if("Field"===o.kind){const e=t(o),a=r.get(e);if(null===(n=o.directives)||void 0===n?void 0:n.length){const e=Object.assign({},o);i.push(e)}else if((null==a?void 0:a.selectionSet)&&o.selectionSet)a.selectionSet.selections=[...a.selectionSet.selections,...o.selectionSet.selections];else if(!a){const t=Object.assign({},o);r.set(e,t),i.push(t)}}else i.push(o);return i}(r,(e=>e.alias?e.alias.value:e.name.value)),Object.assign(Object.assign({},e),{selections:r})},FragmentDefinition(){return null}};return(0,t.visit)(e,i?(0,t.visitWithTypeInfo)(i,a):a)}})?r.apply(t,i):r)||(e.exports=o)},1312:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(r="function"==typeof(n=function(e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.getSelectedOperationName=function(e,t,n){if(!n||n.length<1)return;const r=n.map((e=>{var t;return null===(t=e.name)||void 0===t?void 0:t.value}));if(t&&r.includes(t))return t;if(t&&e){const n=e.map((e=>{var t;return null===(t=e.name)||void 0===t?void 0:t.value})).indexOf(t);if(-1!==n&&n{for(const e in window.localStorage)0===e.indexOf(`${t}:`)&&window.localStorage.removeItem(e)}}}get(e){if(!this.storage)return null;const n=`${t}:${e}`,r=this.storage.getItem(n);return"null"===r||"undefined"===r?(this.storage.removeItem(n),null):r||null}set(e,n){let r=!1,i=null;if(this.storage){const o=`${t}:${e}`;if(n)try{this.storage.setItem(o,n)}catch(e){i=e instanceof Error?e:new Error(`${e}`),r=function(e,t){return t instanceof DOMException&&(22===t.code||1014===t.code||"QuotaExceededError"===t.name||"NS_ERROR_DOM_QUOTA_REACHED"===t.name)&&0!==e.length}(this.storage,e)}else this.storage.removeItem(o)}return{isQuotaError:r,error:i}}clear(){this.storage&&this.storage.clear()}};const t="graphiql"})?n.apply(t,[t]):n)||(e.exports=r)},1925:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(3573),n(6837)],void 0===(o="function"==typeof(r=function(e,t,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.HistoryStore=void 0;e.HistoryStore=class{constructor(e,t){this.storage=e,this.maxHistoryLength=t,this.updateHistory=(e,t,n,r)=>{if(this.shouldSaveQuery(e,t,n,this.history.fetchRecent())){this.history.push({query:e,variables:t,headers:n,operationName:r});const i=this.history.items,o=this.favorite.items;this.queries=i.concat(o)}},this.history=new n.QueryStore("queries",this.storage,this.maxHistoryLength),this.favorite=new n.QueryStore("favorites",this.storage,null),this.queries=[...this.history.fetchAll(),...this.favorite.fetchAll()]}shouldSaveQuery(e,n,r,i){if(!e)return!1;try{(0,t.parse)(e)}catch(e){return!1}if(e.length>1e5)return!1;if(!i)return!0;if(JSON.stringify(e)===JSON.stringify(i.query)){if(JSON.stringify(n)===JSON.stringify(i.variables)){if(JSON.stringify(r)===JSON.stringify(i.headers))return!1;if(r&&!i.headers)return!1}if(n&&!i.variables)return!1}return!0}toggleFavorite(e,t,n,r,i,o){const a={query:e,variables:t,headers:n,operationName:r,label:i};this.favorite.contains(a)?o&&(a.favorite=!1,this.favorite.delete(a)):(a.favorite=!0,this.favorite.push(a)),this.queries=[...this.history.items,...this.favorite.items]}editLabel(e,t,n,r,i,o){const a={query:e,variables:t,headers:n,operationName:r,label:i};o?this.favorite.edit(Object.assign(Object.assign({},a),{favorite:o})):this.history.edit(a),this.queries=[...this.history.items,...this.favorite.items]}}})?r.apply(t,i):r)||(e.exports=o)},920:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(1180),n(1925),n(6837)],void 0===(o="function"==typeof(r=function(e,t,n,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),Object.keys(t).forEach((function(n){"default"!==n&&"__esModule"!==n&&(n in e&&e[n]===t[n]||Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[n]}}))})),Object.keys(n).forEach((function(t){"default"!==t&&"__esModule"!==t&&(t in e&&e[t]===n[t]||Object.defineProperty(e,t,{enumerable:!0,get:function(){return n[t]}}))})),Object.keys(r).forEach((function(t){"default"!==t&&"__esModule"!==t&&(t in e&&e[t]===r[t]||Object.defineProperty(e,t,{enumerable:!0,get:function(){return r[t]}}))}))})?r.apply(t,i):r)||(e.exports=o)},6837:function(e,t){var n,r;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,n=function(e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.QueryStore=void 0;e.QueryStore=class{constructor(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;this.key=e,this.storage=t,this.maxSize=n,this.items=this.fetchAll()}get length(){return this.items.length}contains(e){return this.items.some((t=>t.query===e.query&&t.variables===e.variables&&t.headers===e.headers&&t.operationName===e.operationName))}edit(e){const t=this.items.findIndex((t=>t.query===e.query&&t.variables===e.variables&&t.headers===e.headers&&t.operationName===e.operationName));-1!==t&&(this.items.splice(t,1,e),this.save())}delete(e){const t=this.items.findIndex((t=>t.query===e.query&&t.variables===e.variables&&t.headers===e.headers&&t.operationName===e.operationName));-1!==t&&(this.items.splice(t,1),this.save())}fetchRecent(){return this.items.at(-1)}fetchAll(){const e=this.storage.get(this.key);return e?JSON.parse(e)[this.key]:[]}push(e){const t=[...this.items,e];this.maxSize&&t.length>this.maxSize&&t.shift();for(let e=0;e<5;e++){const e=this.storage.set(this.key,JSON.stringify({[this.key]:t}));if(null==e?void 0:e.error){if(!e.isQuotaError||!this.maxSize)return;t.shift()}else this.items=t}}save(){this.storage.set(this.key,JSON.stringify({[this.key]:this.items}))}}},void 0===(r=n.apply(t,[t]))||(e.exports=r)},6676:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(7139),n(7644),n(3573),n(8506),n(5251),n(2162),n(5605),n(6785)],void 0===(o="function"==typeof(r=function(e,t,n,r,i,o,a,s,l){"use strict";function u(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(u=function(e){return e?n:t})(e)}function c(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=u(t);if(n&&n.has(e))return n.get(e);var r={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if("default"!==o&&Object.prototype.hasOwnProperty.call(e,o)){var a=i?Object.getOwnPropertyDescriptor(e,o):null;a&&(a.get||a.set)?Object.defineProperty(r,o,a):r[o]=e[o]}return r.default=e,n&&n.set(e,r),r}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0,t=c(t),r=c(r),i.GraphiQL.createFetcher=n.createGraphiQLFetcher,i.GraphiQL.GraphQL=r,i.GraphiQL.React=t;var d=i.GraphiQL;e.default=d})?r.apply(t,i):r)||(e.exports=o)},8506:function(e,t,n){var r,i,o;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,i=[t,n(9196),n(7139)],r=function(e,t,n){"use strict";function r(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(r=function(e){return e?n:t})(e)}function i(){return i=Object.assign?Object.assign.bind():function(e){for(var t=1;t{"first"===e&&(null==p||p.setVisiblePlugin(null))},sizeThresholdSecond:200,storageKey:"docExplorerFlex"}),T=(0,n.useDragResize)({direction:"horizontal",storageKey:"editorFlex"}),w=(0,n.useDragResize)({defaultSizeRelation:3,direction:"vertical",initiallyHidden:(()=>{if("variables"!==e.defaultEditorToolsVisibility&&"headers"!==e.defaultEditorToolsVisibility)return"boolean"==typeof e.defaultEditorToolsVisibility?e.defaultEditorToolsVisibility?void 0:"second":l.initialVariables||l.initialHeaders?void 0:"second"})(),sizeThresholdSecond:60,storageKey:"secondaryEditorFlex"}),[C,S]=(0,t.useState)((()=>"variables"===e.defaultEditorToolsVisibility||"headers"===e.defaultEditorToolsVisibility?e.defaultEditorToolsVisibility:!l.initialVariables&&l.initialHeaders&&s?"headers":"variables")),[x,k]=(0,t.useState)(null),[N,_]=(0,t.useState)(null),O=t.default.Children.toArray(e.children),I=O.find((e=>c(e,o.Logo)))||t.default.createElement(o.Logo,null),D=O.find((e=>c(e,o.Toolbar)))||t.default.createElement(t.default.Fragment,null,t.default.createElement(n.ToolbarButton,{onClick:()=>g(),label:"Prettify query (Shift-Ctrl-P)"},t.default.createElement(n.PrettifyIcon,{className:"graphiql-toolbar-icon","aria-hidden":"true"})),t.default.createElement(n.ToolbarButton,{onClick:()=>m(),label:"Merge fragments into query (Shift-Ctrl-M)"},t.default.createElement(n.MergeIcon,{className:"graphiql-toolbar-icon","aria-hidden":"true"})),t.default.createElement(n.ToolbarButton,{onClick:()=>h(),label:"Copy query (Shift-Ctrl-C)"},t.default.createElement(n.CopyIcon,{className:"graphiql-toolbar-icon","aria-hidden":"true"})),(null===(a=e.toolbar)||void 0===a?void 0:a.additionalContent)||null),L=O.find((e=>c(e,o.Footer))),A=()=>{"first"===E.hiddenElement&&E.setHiddenElement(null)},M=0===window.navigator.platform.toLowerCase().indexOf("mac")?t.default.createElement("code",{className:"graphiql-key"},"Cmd"):t.default.createElement("code",{className:"graphiql-key"},"Ctrl");return t.default.createElement("div",{"data-testid":"graphiql-container",className:"graphiql-container"},t.default.createElement("div",{className:"graphiql-sidebar"},t.default.createElement("div",{className:"graphiql-sidebar-section"},null==p?void 0:p.plugins.map((e=>{const r=e===p.visiblePlugin,i=`${r?"Hide":"Show"} ${e.title}`,o=e.icon;return t.default.createElement(n.Tooltip,{key:e.title,label:i},t.default.createElement(n.UnStyledButton,{type:"button",className:r?"active":"",onClick:()=>{r?(p.setVisiblePlugin(null),E.setHiddenElement("first")):(p.setVisiblePlugin(e),E.setHiddenElement(null))},"aria-label":i},t.default.createElement(o,{"aria-hidden":"true"})))}))),t.default.createElement("div",{className:"graphiql-sidebar-section"},t.default.createElement(n.Tooltip,{label:"Re-fetch GraphQL schema"},t.default.createElement(n.UnStyledButton,{type:"button",disabled:d.isFetching,onClick:()=>d.introspect(),"aria-label":"Re-fetch GraphQL schema"},t.default.createElement(n.ReloadIcon,{className:d.isFetching?"graphiql-spin":"","aria-hidden":"true"}))),t.default.createElement(n.Tooltip,{label:"Open short keys dialog"},t.default.createElement(n.UnStyledButton,{type:"button",onClick:()=>k("short-keys"),"aria-label":"Open short keys dialog"},t.default.createElement(n.KeyboardShortcutIcon,{"aria-hidden":"true"}))),t.default.createElement(n.Tooltip,{label:"Open settings dialog"},t.default.createElement(n.UnStyledButton,{type:"button",onClick:()=>k("settings"),"aria-label":"Open settings dialog"},t.default.createElement(n.SettingsIcon,{"aria-hidden":"true"}))))),t.default.createElement("div",{className:"graphiql-main"},t.default.createElement("div",{ref:E.firstRef,style:{minWidth:"200px"}},t.default.createElement("div",{className:"graphiql-plugin"},b?t.default.createElement(b,null):null)),t.default.createElement("div",{ref:E.dragBarRef},null!=p&&p.visiblePlugin?t.default.createElement("div",{className:"graphiql-horizontal-drag-bar"}):null),t.default.createElement("div",{ref:E.secondRef,style:{minWidth:0}},t.default.createElement("div",{className:"graphiql-sessions"},t.default.createElement("div",{className:"graphiql-session-header"},t.default.createElement(n.Tabs,{"aria-label":"Select active operation"},l.tabs.length>1?t.default.createElement(t.default.Fragment,null,l.tabs.map(((e,r)=>t.default.createElement(n.Tab,{key:e.id,isActive:r===l.activeTabIndex},t.default.createElement(n.Tab.Button,{"aria-controls":"graphiql-session",id:`graphiql-session-tab-${r}`,onClick:()=>{u.stop(),l.changeTab(r)}},e.title),t.default.createElement(n.Tab.Close,{onClick:()=>{l.activeTabIndex===r&&u.stop(),l.closeTab(r)}})))),t.default.createElement("div",null,t.default.createElement(n.Tooltip,{label:"Add tab"},t.default.createElement(n.UnStyledButton,{type:"button",className:"graphiql-tab-add",onClick:()=>l.addTab(),"aria-label":"Add tab"},t.default.createElement(n.PlusIcon,{"aria-hidden":"true"}))))):null),t.default.createElement("div",{className:"graphiql-session-header-right"},1===l.tabs.length?t.default.createElement("div",{className:"graphiql-add-tab-wrapper"},t.default.createElement(n.Tooltip,{label:"Add tab"},t.default.createElement(n.UnStyledButton,{type:"button",className:"graphiql-tab-add",onClick:()=>l.addTab(),"aria-label":"Add tab"},t.default.createElement(n.PlusIcon,{"aria-hidden":"true"})))):null,I)),t.default.createElement("div",{role:"tabpanel",id:"graphiql-session",className:"graphiql-session","aria-labelledby":`graphiql-session-tab-${l.activeTabIndex}`},t.default.createElement("div",{ref:T.firstRef},t.default.createElement("div",{className:"graphiql-editors"+(1===l.tabs.length?" full-height":"")},t.default.createElement("div",{ref:w.firstRef},t.default.createElement("section",{className:"graphiql-query-editor","aria-label":"Query Editor"},t.default.createElement("div",{className:"graphiql-query-editor-wrapper"},t.default.createElement(n.QueryEditor,{editorTheme:e.editorTheme,keyMap:e.keyMap,onClickReference:A,onCopyQuery:e.onCopyQuery,onEdit:e.onEditQuery,readOnly:e.readOnly})),t.default.createElement("div",{className:"graphiql-toolbar",role:"toolbar","aria-label":"Editor Commands"},t.default.createElement(n.ExecuteButton,null),D))),t.default.createElement("div",{ref:w.dragBarRef},t.default.createElement("div",{className:"graphiql-editor-tools"},t.default.createElement("div",{className:"graphiql-editor-tools-tabs"},t.default.createElement(n.UnStyledButton,{type:"button",className:"variables"===C&&"second"!==w.hiddenElement?"active":"",onClick:()=>{"second"===w.hiddenElement&&w.setHiddenElement(null),S("variables")}},"Variables"),s?t.default.createElement(n.UnStyledButton,{type:"button",className:"headers"===C&&"second"!==w.hiddenElement?"active":"",onClick:()=>{"second"===w.hiddenElement&&w.setHiddenElement(null),S("headers")}},"Headers"):null),t.default.createElement(n.Tooltip,{label:"second"===w.hiddenElement?"Show editor tools":"Hide editor tools"},t.default.createElement(n.UnStyledButton,{type:"button",onClick:()=>{w.setHiddenElement("second"===w.hiddenElement?null:"second")},"aria-label":"second"===w.hiddenElement?"Show editor tools":"Hide editor tools"},"second"===w.hiddenElement?t.default.createElement(n.ChevronUpIcon,{className:"graphiql-chevron-icon","aria-hidden":"true"}):t.default.createElement(n.ChevronDownIcon,{className:"graphiql-chevron-icon","aria-hidden":"true"}))))),t.default.createElement("div",{ref:w.secondRef},t.default.createElement("section",{className:"graphiql-editor-tool","aria-label":"variables"===C?"Variables":"Headers"},t.default.createElement(n.VariableEditor,{editorTheme:e.editorTheme,isHidden:"variables"!==C,keyMap:e.keyMap,onEdit:e.onEditVariables,onClickReference:A,readOnly:e.readOnly}),s&&t.default.createElement(n.HeaderEditor,{editorTheme:e.editorTheme,isHidden:"headers"!==C,keyMap:e.keyMap,onEdit:e.onEditHeaders,readOnly:e.readOnly}))))),t.default.createElement("div",{ref:T.dragBarRef},t.default.createElement("div",{className:"graphiql-horizontal-drag-bar"})),t.default.createElement("div",{ref:T.secondRef},t.default.createElement("div",{className:"graphiql-response"},u.isFetching?t.default.createElement(n.Spinner,null):null,t.default.createElement(n.ResponseEditor,{editorTheme:e.editorTheme,responseTooltip:e.responseTooltip,keyMap:e.keyMap}),L)))))),t.default.createElement(n.Dialog,{isOpen:"short-keys"===x,onDismiss:()=>k(null)},t.default.createElement("div",{className:"graphiql-dialog-header"},t.default.createElement("div",{className:"graphiql-dialog-title"},"Short Keys"),t.default.createElement(n.Dialog.Close,{onClick:()=>k(null)})),t.default.createElement("div",{className:"graphiql-dialog-section"},t.default.createElement("div",null,t.default.createElement("table",{className:"graphiql-table"},t.default.createElement("thead",null,t.default.createElement("tr",null,t.default.createElement("th",null,"Short key"),t.default.createElement("th",null,"Function"))),t.default.createElement("tbody",null,t.default.createElement("tr",null,t.default.createElement("td",null,M," + ",t.default.createElement("code",{className:"graphiql-key"},"F")),t.default.createElement("td",null,"Search in editor")),t.default.createElement("tr",null,t.default.createElement("td",null,M," + ",t.default.createElement("code",{className:"graphiql-key"},"K")),t.default.createElement("td",null,"Search in documentation")),t.default.createElement("tr",null,t.default.createElement("td",null,M," + ",t.default.createElement("code",{className:"graphiql-key"},"Enter")),t.default.createElement("td",null,"Execute query")),t.default.createElement("tr",null,t.default.createElement("td",null,t.default.createElement("code",{className:"graphiql-key"},"Ctrl")," + ",t.default.createElement("code",{className:"graphiql-key"},"Shift")," + ",t.default.createElement("code",{className:"graphiql-key"},"P")),t.default.createElement("td",null,"Prettify editors")),t.default.createElement("tr",null,t.default.createElement("td",null,t.default.createElement("code",{className:"graphiql-key"},"Ctrl")," + ",t.default.createElement("code",{className:"graphiql-key"},"Shift")," + ",t.default.createElement("code",{className:"graphiql-key"},"M")),t.default.createElement("td",null,"Merge fragments definitions into operation definition")),t.default.createElement("tr",null,t.default.createElement("td",null,t.default.createElement("code",{className:"graphiql-key"},"Ctrl")," + ",t.default.createElement("code",{className:"graphiql-key"},"Shift")," + ",t.default.createElement("code",{className:"graphiql-key"},"C")),t.default.createElement("td",null,"Copy query")),t.default.createElement("tr",null,t.default.createElement("td",null,t.default.createElement("code",{className:"graphiql-key"},"Ctrl")," + ",t.default.createElement("code",{className:"graphiql-key"},"Shift")," + ",t.default.createElement("code",{className:"graphiql-key"},"R")),t.default.createElement("td",null,"Re-fetch schema using introspection")))),t.default.createElement("p",null,"The editors use"," ",t.default.createElement("a",{href:"https://codemirror.net/5/doc/manual.html#keymaps",target:"_blank",rel:"noopener noreferrer"},"CodeMirror Key Maps")," ","that add more short keys. This instance of Graph",t.default.createElement("em",null,"i"),"QL uses"," ",t.default.createElement("code",null,e.keyMap||"sublime"),".")))),t.default.createElement(n.Dialog,{isOpen:"settings"===x,onDismiss:()=>{k(null),_(null)}},t.default.createElement("div",{className:"graphiql-dialog-header"},t.default.createElement("div",{className:"graphiql-dialog-title"},"Settings"),t.default.createElement(n.Dialog.Close,{onClick:()=>{k(null),_(null)}})),e.showPersistHeadersSettings?t.default.createElement("div",{className:"graphiql-dialog-section"},t.default.createElement("div",null,t.default.createElement("div",{className:"graphiql-dialog-section-title"},"Persist headers"),t.default.createElement("div",{className:"graphiql-dialog-section-caption"},"Save headers upon reloading."," ",t.default.createElement("span",{className:"graphiql-warning-text"},"Only enable if you trust this device."))),t.default.createElement(n.ButtonGroup,null,t.default.createElement(n.Button,{type:"button",id:"enable-persist-headers",className:l.shouldPersistHeaders?"active":void 0,onClick:()=>{l.setShouldPersistHeaders(!0)}},"On"),t.default.createElement(n.Button,{type:"button",id:"disable-persist-headers",className:l.shouldPersistHeaders?void 0:"active",onClick:()=>{l.setShouldPersistHeaders(!1)}},"Off"))):null,t.default.createElement("div",{className:"graphiql-dialog-section"},t.default.createElement("div",null,t.default.createElement("div",{className:"graphiql-dialog-section-title"},"Theme"),t.default.createElement("div",{className:"graphiql-dialog-section-caption"},"Adjust how the interface looks like.")),t.default.createElement("div",null,t.default.createElement(n.ButtonGroup,null,t.default.createElement(n.Button,{type:"button",className:null===v?"active":"",onClick:()=>y(null)},"System"),t.default.createElement(n.Button,{type:"button",className:"light"===v?"active":"",onClick:()=>y("light")},"Light"),t.default.createElement(n.Button,{type:"button",className:"dark"===v?"active":"",onClick:()=>y("dark")},"Dark")))),f?t.default.createElement("div",{className:"graphiql-dialog-section"},t.default.createElement("div",null,t.default.createElement("div",{className:"graphiql-dialog-section-title"},"Clear storage"),t.default.createElement("div",{className:"graphiql-dialog-section-caption"},"Remove all locally stored data and start fresh.")),t.default.createElement("div",null,t.default.createElement(n.Button,{type:"button",state:N||void 0,disabled:"success"===N,onClick:()=>{try{null==f||f.clear(),_("success")}catch{_("error")}}},"success"===N?"Cleared data":"error"===N?"Failed":"Clear data"))):null))}function s(e){return t.default.createElement("div",{className:"graphiql-logo"},e.children||t.default.createElement("a",{className:"graphiql-logo-link",href:"https://github.com/graphql/graphiql",target:"_blank",rel:"noreferrer"},"Graph",t.default.createElement("em",null,"i"),"QL"))}function l(e){return t.default.createElement(t.default.Fragment,null,e.children)}function u(e){return t.default.createElement("div",{className:"graphiql-footer"},e.children)}function c(e,t){var n;return!(null==e||null===(n=e.type)||void 0===n||!n.displayName||e.type.displayName!==t.displayName)||e.type===t}o.Logo=s,o.Toolbar=l,o.Footer=u,s.displayName="GraphiQLLogo",l.displayName="GraphiQLToolbar",u.displayName="GraphiQLFooter"},void 0===(o=r.apply(t,i))||(e.exports=o)},5313:function(e,t,n){"use strict";n.r(t),n.d(t,{CloseCode:function(){return r.CloseCode},GRAPHQL_TRANSPORT_WS_PROTOCOL:function(){return r.GRAPHQL_TRANSPORT_WS_PROTOCOL},MessageType:function(){return r.MessageType},createClient:function(){return o},isMessage:function(){return r.isMessage},parseMessage:function(){return r.parseMessage},stringifyMessage:function(){return r.stringifyMessage}});var r=n(863),i=n(6764);function o(e){const{url:t,connectionParams:o,lazy:s=!0,onNonLazyError:l=console.error,lazyCloseTimeout:u=0,keepAlive:c=0,disablePong:d,connectionAckWaitTimeout:f=0,retryAttempts:p=5,retryWait:h=async function(e){let t=1e3;for(let n=0;nsetTimeout(e,t+Math.floor(2700*Math.random()+300))))},isFatalConnectionProblem:m=(e=>!a(e)),on:g,webSocketImpl:v,generateID:y=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(e=>{const t=16*Math.random()|0;return("x"==e?t:3&t|8).toString(16)}))},jsonMessageReplacer:b,jsonMessageReviver:E}=e;let T;if(v){if(!("function"==typeof(w=v)&&"constructor"in w&&"CLOSED"in w&&"CLOSING"in w&&"CONNECTING"in w&&"OPEN"in w))throw new Error("Invalid WebSocket implementation provided");T=v}else"undefined"!=typeof WebSocket?T=WebSocket:void 0!==n.g?T=n.g.WebSocket||n.g.MozWebSocket:"undefined"!=typeof window&&(T=window.WebSocket||window.MozWebSocket);var w;if(!T)throw new Error("WebSocket implementation missing");const C=T,S=(()=>{const e=(()=>{const e={};return{on(t,n){return e[t]=n,()=>{delete e[t]}},emit(t){var n;"id"in t&&(null===(n=e[t.id])||void 0===n||n.call(e,t))}}})(),t={connecting:(null==g?void 0:g.connecting)?[g.connecting]:[],opened:(null==g?void 0:g.opened)?[g.opened]:[],connected:(null==g?void 0:g.connected)?[g.connected]:[],ping:(null==g?void 0:g.ping)?[g.ping]:[],pong:(null==g?void 0:g.pong)?[g.pong]:[],message:(null==g?void 0:g.message)?[e.emit,g.message]:[e.emit],closed:(null==g?void 0:g.closed)?[g.closed]:[],error:(null==g?void 0:g.error)?[g.error]:[]};return{onMessage:e.on,on(e,n){const r=t[e];return r.push(n),()=>{r.splice(r.indexOf(n),1)}},emit(e,...n){for(const r of[...t[e]])r(...n)}}})();function x(e){const t=[S.on("error",(n=>{t.forEach((e=>e())),e(n)})),S.on("closed",(n=>{t.forEach((e=>e())),e(n)}))]}let k,N=0,_=!1,O=0,I=!1;async function D(){const[e,n]=await(null!=k?k:k=new Promise(((e,n)=>(async()=>{if(_){if(await h(O),!N)return k=void 0,n({code:1e3,reason:"All Subscriptions Gone"});O++}S.emit("connecting");const a=new C("function"==typeof t?await t():t,r.GRAPHQL_TRANSPORT_WS_PROTOCOL);let s,l;function u(){isFinite(c)&&c>0&&(clearTimeout(l),l=setTimeout((()=>{a.readyState===C.OPEN&&(a.send((0,r.stringifyMessage)({type:r.MessageType.Ping})),S.emit("ping",!1,void 0))}),c))}x((e=>{k=void 0,clearTimeout(s),clearTimeout(l),n(e)})),a.onerror=e=>S.emit("error",e),a.onclose=e=>S.emit("closed",e),a.onopen=async()=>{try{S.emit("opened",a);const e="function"==typeof o?await o():o;a.send((0,r.stringifyMessage)(e?{type:r.MessageType.ConnectionInit,payload:e}:{type:r.MessageType.ConnectionInit},b)),isFinite(f)&&f>0&&(s=setTimeout((()=>{a.close(r.CloseCode.ConnectionAcknowledgementTimeout,"Connection acknowledgement timeout")}),f)),u()}catch(e){S.emit("error",e),a.close(r.CloseCode.InternalClientError,(0,i.qj)(e instanceof Error?e.message:new Error(e).message,"Internal client error"))}};let p=!1;a.onmessage=({data:t})=>{try{const n=(0,r.parseMessage)(t,E);if(S.emit("message",n),"ping"===n.type||"pong"===n.type)return S.emit(n.type,!0,n.payload),void("pong"===n.type?u():d||(a.send((0,r.stringifyMessage)(n.payload?{type:r.MessageType.Pong,payload:n.payload}:{type:r.MessageType.Pong})),S.emit("pong",!1,n.payload)));if(p)return;if(n.type!==r.MessageType.ConnectionAck)throw new Error(`First message cannot be of type ${n.type}`);clearTimeout(s),p=!0,S.emit("connected",a,n.payload),_=!1,O=0,e([a,new Promise(((e,t)=>x(t)))])}catch(e){a.onmessage=null,S.emit("error",e),a.close(r.CloseCode.BadResponse,(0,i.qj)(e instanceof Error?e.message:new Error(e).message,"Bad response"))}}})())));e.readyState===C.CLOSING&&await n;let a=()=>{};const s=new Promise((e=>a=e));return[e,a,Promise.race([s.then((()=>{if(!N){const t=()=>e.close(1e3,"Normal Closure");isFinite(u)&&u>0?setTimeout((()=>{N||e.readyState!==C.OPEN||t()}),u):t()}})),n])]}function L(e){if(a(e)&&(t=e.code,![1e3,1001,1006,1005,1012,1013,1013].includes(t)&&t>=1e3&&t<=1999||[r.CloseCode.InternalServerError,r.CloseCode.InternalClientError,r.CloseCode.BadRequest,r.CloseCode.BadResponse,r.CloseCode.Unauthorized,r.CloseCode.SubprotocolNotAcceptable,r.CloseCode.SubscriberAlreadyExists,r.CloseCode.TooManyInitialisationRequests].includes(e.code)))throw e;var t;if(I)return!1;if(a(e)&&1e3===e.code)return N>0;if(!p||O>=p)throw e;if(m(e))throw e;return _=!0}return s||(async()=>{for(N++;;)try{const[,,e]=await D();await e}catch(e){try{if(!L(e))return}catch(e){return null==l?void 0:l(e)}}})(),{on:S.on,subscribe(e,t){const n=y();let i=!1,o=!1,a=()=>{N--,i=!0};return(async()=>{for(N++;;)try{const[s,l,u]=await D();if(i)return l();const c=S.onMessage(n,(e=>{switch(e.type){case r.MessageType.Next:return void t.next(e.payload);case r.MessageType.Error:return o=!0,i=!0,t.error(e.payload),void a();case r.MessageType.Complete:return i=!0,void a()}}));return s.send((0,r.stringifyMessage)({id:n,type:r.MessageType.Subscribe,payload:e},b)),a=()=>{i||s.readyState!==C.OPEN||s.send((0,r.stringifyMessage)({id:n,type:r.MessageType.Complete},b)),N--,i=!0,l()},void await u.finally(c)}catch(e){if(!L(e))return}})().then((()=>{o||t.complete()})).catch((e=>{t.error(e)})),()=>{i||a()}},async dispose(){if(I=!0,k){const[e]=await k;e.close(1e3,"Normal Closure")}}}}function a(e){return(0,i.Kn)(e)&&"code"in e&&"reason"in e}},863:function(e,t,n){"use strict";n.r(t),n.d(t,{CloseCode:function(){return o},GRAPHQL_TRANSPORT_WS_PROTOCOL:function(){return i},MessageType:function(){return a},isMessage:function(){return s},parseMessage:function(){return l},stringifyMessage:function(){return u}});var r=n(6764);const i="graphql-transport-ws";var o,a;function s(e){if((0,r.Kn)(e)){if(!(0,r.ND)(e,"type"))return!1;switch(e.type){case a.ConnectionInit:case a.ConnectionAck:case a.Ping:case a.Pong:return!(0,r.nr)(e,"payload")||void 0===e.payload||(0,r.Kn)(e.payload);case a.Subscribe:return(0,r.ND)(e,"id")&&(0,r.O2)(e,"payload")&&(!(0,r.nr)(e.payload,"operationName")||void 0===e.payload.operationName||null===e.payload.operationName||"string"==typeof e.payload.operationName)&&(0,r.ND)(e.payload,"query")&&(!(0,r.nr)(e.payload,"variables")||void 0===e.payload.variables||null===e.payload.variables||(0,r.O2)(e.payload,"variables"))&&(!(0,r.nr)(e.payload,"extensions")||void 0===e.payload.extensions||null===e.payload.extensions||(0,r.O2)(e.payload,"extensions"));case a.Next:return(0,r.ND)(e,"id")&&(0,r.O2)(e,"payload");case a.Error:return(0,r.ND)(e,"id")&&(0,r.Ox)(e.payload);case a.Complete:return(0,r.ND)(e,"id");default:return!1}}return!1}function l(e,t){if(s(e))return e;if("string"!=typeof e)throw new Error("Message not parsable");const n=JSON.parse(e,t);if(!s(n))throw new Error("Invalid message");return n}function u(e,t){if(!s(e))throw new Error("Cannot stringify invalid message");return JSON.stringify(e,t)}!function(e){e[e.InternalServerError=4500]="InternalServerError",e[e.InternalClientError=4005]="InternalClientError",e[e.BadRequest=4400]="BadRequest",e[e.BadResponse=4004]="BadResponse",e[e.Unauthorized=4401]="Unauthorized",e[e.Forbidden=4403]="Forbidden",e[e.SubprotocolNotAcceptable=4406]="SubprotocolNotAcceptable",e[e.ConnectionInitialisationTimeout=4408]="ConnectionInitialisationTimeout",e[e.ConnectionAcknowledgementTimeout=4504]="ConnectionAcknowledgementTimeout",e[e.SubscriberAlreadyExists=4409]="SubscriberAlreadyExists",e[e.TooManyInitialisationRequests=4429]="TooManyInitialisationRequests"}(o||(o={})),function(e){e.ConnectionInit="connection_init",e.ConnectionAck="connection_ack",e.Ping="ping",e.Pong="pong",e.Subscribe="subscribe",e.Next="next",e.Error="error",e.Complete="complete"}(a||(a={}))},6718:function(e,t,n){"use strict";n.r(t),n.d(t,{makeServer:function(){return f}});var r=n(953),i=n(2780),o=n(9458),a=n(4117),s=n(2941),l=n(7180),u=n(863),c=n(6764),d=function(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e="function"==typeof __values?__values(e):e[Symbol.iterator](),t={},r("next"),r("throw"),r("return"),t[Symbol.asyncIterator]=function(){return this},t);function r(n){t[n]=e[n]&&function(t){return new Promise((function(r,i){!function(e,t,n,r){Promise.resolve(r).then((function(t){e({value:t,done:n})}),t)}(r,i,(t=e[n](t)).done,t.value)}))}}};function f(e){const{schema:t,context:n,roots:f,validate:p,execute:h,subscribe:m,connectionInitWaitTimeout:g=3e3,onConnect:v,onDisconnect:y,onClose:b,onSubscribe:E,onOperation:T,onNext:w,onError:C,onComplete:S,jsonMessageReviver:x,jsonMessageReplacer:k}=e;return{opened(e,N){const _={connectionInitReceived:!1,acknowledged:!1,subscriptions:{},extra:N};if(e.protocol!==u.GRAPHQL_TRANSPORT_WS_PROTOCOL)return e.close(u.CloseCode.SubprotocolNotAcceptable,"Subprotocol not acceptable"),async(e,t)=>{await(null==b?void 0:b(_,e,t))};const O=g>0&&isFinite(g)?setTimeout((()=>{_.connectionInitReceived||e.close(u.CloseCode.ConnectionInitialisationTimeout,"Connection initialisation timeout")}),g):null;return e.onMessage((async function(g){var y,b,N;let O;try{O=(0,u.parseMessage)(g,x)}catch(t){return e.close(u.CloseCode.BadRequest,"Invalid message received")}switch(O.type){case u.MessageType.ConnectionInit:{if(_.connectionInitReceived)return e.close(u.CloseCode.TooManyInitialisationRequests,"Too many initialisation requests");_.connectionInitReceived=!0,(0,c.Kn)(O.payload)&&(_.connectionParams=O.payload);const t=await(null==v?void 0:v(_));return!1===t?e.close(u.CloseCode.Forbidden,"Forbidden"):(await e.send((0,u.stringifyMessage)((0,c.Kn)(t)?{type:u.MessageType.ConnectionAck,payload:t}:{type:u.MessageType.ConnectionAck},k)),void(_.acknowledged=!0))}case u.MessageType.Ping:return e.onPing?await e.onPing(O.payload):void await e.send((0,u.stringifyMessage)(O.payload?{type:u.MessageType.Pong,payload:O.payload}:{type:u.MessageType.Pong}));case u.MessageType.Pong:return await(null===(N=e.onPong)||void 0===N?void 0:N.call(e,O.payload));case u.MessageType.Subscribe:{if(!_.acknowledged)return e.close(u.CloseCode.Unauthorized,"Unauthorized");const{id:g,payload:v}=O;if(g in _.subscriptions)return e.close(u.CloseCode.SubscriberAlreadyExists,`Subscriber for ${g} already exists`);_.subscriptions[g]=null;const x={next:async(t,n)=>{let r={id:g,type:u.MessageType.Next,payload:t};const i=await(null==w?void 0:w(_,r,n,t));i&&(r=Object.assign(Object.assign({},r),{payload:i})),await e.send((0,u.stringifyMessage)(r,k))},error:async t=>{let n={id:g,type:u.MessageType.Error,payload:t};const r=await(null==C?void 0:C(_,n,t));r&&(n=Object.assign(Object.assign({},n),{payload:r})),await e.send((0,u.stringifyMessage)(n,k))},complete:async t=>{const n={id:g,type:u.MessageType.Complete};await(null==S?void 0:S(_,n)),t&&await e.send((0,u.stringifyMessage)(n,k))}};let N;const L=await(null==E?void 0:E(_,O));if(L){if((0,c.Ox)(L))return await x.error(L);if(Array.isArray(L))throw new Error("Invalid return value from onSubscribe hook, expected an array of GraphQLError objects");N=L}else{if(!t)throw new Error("The GraphQL schema is not provided");const e={operationName:v.operationName,document:(0,r.Qc)(v.query),variableValues:v.variables};N=Object.assign(Object.assign({},e),{schema:"function"==typeof t?await t(_,O,e):t});const n=(null!=p?p:i.Gu)(N.schema,N.document);if(n.length>0)return await x.error(n)}const A=(0,o.S)(N.document,N.operationName);if(!A)return await x.error([new a.__("Unable to identify operation")]);let M;"rootValue"in N||(N.rootValue=null==f?void 0:f[A.operation]),"contextValue"in N||(N.contextValue="function"==typeof n?await n(_,O,N):n),M="subscription"===A.operation?await(null!=m?m:s.L)(N):await(null!=h?h:l.ht)(N);const R=await(null==T?void 0:T(_,O,N,M));if(R&&(M=R),(0,c.D0)(M))if(g in _.subscriptions){_.subscriptions[g]=M;try{for(var I,D=d(M);!(I=await D.next()).done;){const e=I.value;await x.next(e,N)}}catch(e){y={error:e}}finally{try{I&&!I.done&&(b=D.return)&&await b.call(D)}finally{if(y)throw y.error}}}else(0,c.Jy)(M)&&M.return(void 0);else g in _.subscriptions&&await x.next(M,N);return await x.complete(g in _.subscriptions),void delete _.subscriptions[g]}case u.MessageType.Complete:{const e=_.subscriptions[O.id];return(0,c.Jy)(e)&&await e.return(void 0),void delete _.subscriptions[O.id]}default:throw new Error(`Unexpected message of type ${O.type} received`)}})),async(e,t)=>{O&&clearTimeout(O);for(const e of Object.values(_.subscriptions))(0,c.Jy)(e)&&await e.return(void 0);_.acknowledged&&await(null==y?void 0:y(_,e,t)),await(null==b?void 0:b(_,e,t))}}}}},6764:function(e,t,n){"use strict";n.d(t,{D0:function(){return o},Jy:function(){return a},Kn:function(){return i},ND:function(){return c},O2:function(){return u},Ox:function(){return s},nr:function(){return l},qj:function(){return d}});const r=Object.prototype.hasOwnProperty;function i(e){return"object"==typeof e&&null!==e}function o(e){return"function"==typeof Object(e)[Symbol.asyncIterator]}function a(e){return i(e)&&"function"==typeof Object(e)[Symbol.asyncIterator]&&"function"==typeof e.return}function s(e){return Array.isArray(e)&&e.length>0&&e.every((e=>"message"in e))}function l(e,t){return r.call(e,t)}function u(e,t){return r.call(e,t)&&i(e[t])}function c(e,t){return r.call(e,t)&&"string"==typeof e[t]}function d(e,t){return e.length<124?e:t}},4117:function(e,t,n){"use strict";n.d(t,{OS:function(){return l},Z:function(){return u},__:function(){return a}});var r=n(1315),i=n(3302),o=n(7026);class a extends Error{constructor(e,...t){var n,o,l;const{nodes:u,source:c,positions:d,path:f,originalError:p,extensions:h}=function(e){const t=e[0];return null==t||"kind"in t||"length"in t?{nodes:t,source:e[1],positions:e[2],path:e[3],originalError:e[4],extensions:e[5]}:t}(t);super(e),this.name="GraphQLError",this.path=null!=f?f:void 0,this.originalError=null!=p?p:void 0,this.nodes=s(Array.isArray(u)?u:u?[u]:void 0);const m=s(null===(n=this.nodes)||void 0===n?void 0:n.map((e=>e.loc)).filter((e=>null!=e)));this.source=null!=c?c:null==m||null===(o=m[0])||void 0===o?void 0:o.source,this.positions=null!=d?d:null==m?void 0:m.map((e=>e.start)),this.locations=d&&c?d.map((e=>(0,i.k)(c,e))):null==m?void 0:m.map((e=>(0,i.k)(e.source,e.start)));const g=(0,r.y)(null==p?void 0:p.extensions)?null==p?void 0:p.extensions:void 0;this.extensions=null!==(l=null!=h?h:g)&&void 0!==l?l:Object.create(null),Object.defineProperties(this,{message:{writable:!0,enumerable:!0},name:{enumerable:!1},nodes:{enumerable:!1},source:{enumerable:!1},positions:{enumerable:!1},originalError:{enumerable:!1}}),null!=p&&p.stack?Object.defineProperty(this,"stack",{value:p.stack,writable:!0,configurable:!0}):Error.captureStackTrace?Error.captureStackTrace(this,a):Object.defineProperty(this,"stack",{value:Error().stack,writable:!0,configurable:!0})}get[Symbol.toStringTag](){return"GraphQLError"}toString(){let e=this.message;if(this.nodes)for(const t of this.nodes)t.loc&&(e+="\n\n"+(0,o.Q)(t.loc));else if(this.source&&this.locations)for(const t of this.locations)e+="\n\n"+(0,o.z)(this.source,t);return e}toJSON(){const e={message:this.message};return null!=this.locations&&(e.locations=this.locations),null!=this.path&&(e.path=this.path),null!=this.extensions&&Object.keys(this.extensions).length>0&&(e.extensions=this.extensions),e}}function s(e){return void 0===e||0===e.length?void 0:e}function l(e){return e.toString()}function u(e){return e.toJSON()}},4647:function(e,t,n){"use strict";n.d(t,{y:function(){return a}});var r=n(5648);class i extends Error{constructor(e){super("Unexpected error value: "+(0,r.X)(e)),this.name="NonErrorThrown",this.thrownValue=e}}var o=n(4117);function a(e,t,n){var r;const a=(s=e)instanceof Error?s:new i(s);var s,l;return l=a,Array.isArray(l.path)?a:new o.__(a.message,{nodes:null!==(r=a.nodes)&&void 0!==r?r:t,source:a.source,positions:a.positions,path:n,originalError:a})}},2024:function(e,t,n){"use strict";n.d(t,{h:function(){return i}});var r=n(4117);function i(e,t,n){return new r.__(`Syntax Error: ${n}`,{source:e,positions:[t]})}},5267:function(e,t,n){"use strict";n.d(t,{g:function(){return l},w:function(){return u}});var r=n(3830),i=n(755),o=n(5946),a=n(5998),s=n(2806);function l(e,t,n,r,i){const o=new Map;return c(e,t,n,r,i,o,new Set),o}function u(e,t,n,r,i){const o=new Map,a=new Set;for(const s of i)s.selectionSet&&c(e,t,n,r,s.selectionSet,o,a);return o}function c(e,t,n,i,o,a,s){for(const u of o.selections)switch(u.kind){case r.h.FIELD:{if(!d(n,u))continue;const e=(l=u).alias?l.alias.value:l.name.value,t=a.get(e);void 0!==t?t.push(u):a.set(e,[u]);break}case r.h.INLINE_FRAGMENT:if(!d(n,u)||!f(e,u,i))continue;c(e,t,n,i,u.selectionSet,a,s);break;case r.h.FRAGMENT_SPREAD:{const r=u.name.value;if(s.has(r)||!d(n,u))continue;s.add(r);const o=t[r];if(!o||!f(e,o,i))continue;c(e,t,n,i,o.selectionSet,a,s);break}}var l}function d(e,t){const n=(0,s.zu)(o.QE,t,e);if(!0===(null==n?void 0:n.if))return!1;const r=(0,s.zu)(o.Yf,t,e);return!1!==(null==r?void 0:r.if)}function f(e,t,n){const r=t.typeCondition;if(!r)return!0;const o=(0,a._)(e,r);return o===n||!!(0,i.m0)(o)&&e.isSubType(o,n)}},7180:function(e,t,n){"use strict";n.d(t,{td:function(){return C},VZ:function(){return S},p$:function(){return N},El:function(){return M},mn:function(){return A},ht:function(){return E},p0:function(){return T},Vm:function(){return R}});var r=n(1172),i=n(5648),o=n(5052),a=n(2910),s=n(1315),l=n(1864),u=n(9878),c=n(4117),d=n(4647),f=n(3526),p=n(3830),h=n(755),m=n(8078),g=n(8555),v=n(5267),y=n(2806);const b=function(e){let t;return function(e,n,r){void 0===t&&(t=new WeakMap);let i=t.get(e);void 0===i&&(i=new WeakMap,t.set(e,i));let o=i.get(n);void 0===o&&(o=new WeakMap,i.set(n,o));let a=o.get(r);return void 0===a&&(s=e,l=n,u=r,a=(0,v.w)(s.schema,s.fragments,s.variableValues,l,u),o.set(r,a)),a;var s,l,u}}();function E(e){arguments.length<2||(0,r.a)(!1,"graphql@16 dropped long-deprecated support for positional arguments, please pass an object instead.");const{schema:t,document:n,variableValues:i,rootValue:o}=e;C(t,n,i);const a=S(e);if(!("schema"in a))return{errors:a};try{const{operation:e}=a,t=function(e,t,n){const r=e.schema.getRootType(t.operation);if(null==r)throw new c.__(`Schema is not configured to execute ${t.operation} operation.`,{nodes:t});const i=(0,v.g)(e.schema,e.fragments,e.variableValues,r,t.selectionSet),o=void 0;switch(t.operation){case f.ku.QUERY:return x(e,r,n,o,i);case f.ku.MUTATION:return function(e,t,n,r,i){return function(e,t,n){let r=Object.create(null);for(const n of e)r=(0,l.t)(r)?r.then((e=>t(e,n))):t(r,n);return r}(i.entries(),((r,[i,o])=>{const a=(0,u.Q)(undefined,i,t.name),s=k(e,t,n,o,a);return void 0===s?r:(0,l.t)(s)?s.then((e=>(r[i]=e,r))):(r[i]=s,r)}))}(e,r,n,0,i);case f.ku.SUBSCRIPTION:return x(e,r,n,o,i)}}(a,e,o);return(0,l.t)(t)?t.then((e=>w(e,a.errors)),(e=>(a.errors.push(e),w(null,a.errors)))):w(t,a.errors)}catch(e){return a.errors.push(e),w(null,a.errors)}}function T(e){const t=E(e);if((0,l.t)(t))throw new Error("GraphQL execution failed to complete synchronously.");return t}function w(e,t){return 0===t.length?{data:e}:{errors:t,data:e}}function C(e,t,n){t||(0,r.a)(!1,"Must provide document."),(0,g.J)(e),null==n||(0,s.y)(n)||(0,r.a)(!1,"Variables must be provided as an Object where each property is a variable value. Perhaps look to see if an unparsed JSON string was provided.")}function S(e){var t,n;const{schema:r,document:i,rootValue:o,contextValue:a,variableValues:s,operationName:l,fieldResolver:u,typeResolver:d,subscribeFieldResolver:f}=e;let h;const m=Object.create(null);for(const e of i.definitions)switch(e.kind){case p.h.OPERATION_DEFINITION:if(null==l){if(void 0!==h)return[new c.__("Must provide operation name if query contains multiple operations.")];h=e}else(null===(t=e.name)||void 0===t?void 0:t.value)===l&&(h=e);break;case p.h.FRAGMENT_DEFINITION:m[e.name.value]=e}if(!h)return null!=l?[new c.__(`Unknown operation named "${l}".`)]:[new c.__("Must provide an operation.")];const g=null!==(n=h.variableDefinitions)&&void 0!==n?n:[],v=(0,y.QF)(r,g,null!=s?s:{},{maxErrors:50});return v.errors?v.errors:{schema:r,fragments:m,rootValue:o,contextValue:a,operation:h,variableValues:v.coerced,fieldResolver:null!=u?u:M,typeResolver:null!=d?d:A,subscribeFieldResolver:null!=f?f:M,errors:[]}}function x(e,t,n,r,i){const o=Object.create(null);let a=!1;for(const[s,c]of i.entries()){const i=k(e,t,n,c,(0,u.Q)(r,s,t.name));void 0!==i&&(o[s]=i,(0,l.t)(i)&&(a=!0))}return a?(s=o,Promise.all(Object.values(s)).then((e=>{const t=Object.create(null);for(const[n,r]of Object.keys(s).entries())t[r]=e[n];return t}))):o;var s}function k(e,t,n,r,i){var o;const a=R(e.schema,t,r[0]);if(!a)return;const s=a.type,c=null!==(o=a.resolve)&&void 0!==o?o:e.fieldResolver,f=N(e,a,r,t,i);try{const t=c(n,(0,y.LX)(a,r[0],e.variableValues),e.contextValue,f);let o;return o=(0,l.t)(t)?t.then((t=>O(e,s,r,f,i,t))):O(e,s,r,f,i,t),(0,l.t)(o)?o.then(void 0,(t=>_((0,d.y)(t,r,(0,u.N)(i)),s,e))):o}catch(t){return _((0,d.y)(t,r,(0,u.N)(i)),s,e)}}function N(e,t,n,r,i){return{fieldName:t.name,fieldNodes:n,returnType:t.type,parentType:r,path:i,schema:e.schema,fragments:e.fragments,rootValue:e.rootValue,operation:e.operation,variableValues:e.variableValues}}function _(e,t,n){if((0,h.zM)(t))throw e;return n.errors.push(e),null}function O(e,t,n,r,s,f){if(f instanceof Error)throw f;if((0,h.zM)(t)){const i=O(e,t.ofType,n,r,s,f);if(null===i)throw new Error(`Cannot return null for non-nullable field ${r.parentType.name}.${r.fieldName}.`);return i}return null==f?null:(0,h.HG)(t)?function(e,t,n,r,i,o){if(!(0,a.i)(o))throw new c.__(`Expected Iterable, but did not find one for field "${r.parentType.name}.${r.fieldName}".`);const s=t.ofType;let f=!1;const p=Array.from(o,((t,o)=>{const a=(0,u.Q)(i,o,void 0);try{let i;return i=(0,l.t)(t)?t.then((t=>O(e,s,n,r,a,t))):O(e,s,n,r,a,t),(0,l.t)(i)?(f=!0,i.then(void 0,(t=>_((0,d.y)(t,n,(0,u.N)(a)),s,e)))):i}catch(t){return _((0,d.y)(t,n,(0,u.N)(a)),s,e)}}));return f?Promise.all(p):p}(e,t,n,r,s,f):(0,h.UT)(t)?function(e,t){const n=e.serialize(t);if(null==n)throw new Error(`Expected \`${(0,i.X)(e)}.serialize(${(0,i.X)(t)})\` to return non-nullable value, returned: ${(0,i.X)(n)}`);return n}(t,f):(0,h.m0)(t)?function(e,t,n,r,i,o){var a;const s=null!==(a=t.resolveType)&&void 0!==a?a:e.typeResolver,u=e.contextValue,c=s(o,u,r,t);return(0,l.t)(c)?c.then((a=>D(e,I(a,e,t,n,r,o),n,r,i,o))):D(e,I(c,e,t,n,r,o),n,r,i,o)}(e,t,n,r,s,f):(0,h.lp)(t)?D(e,t,n,r,s,f):void(0,o.k)(!1,"Cannot complete value of unexpected output type: "+(0,i.X)(t))}function I(e,t,n,r,o,a){if(null==e)throw new c.__(`Abstract type "${n.name}" must resolve to an Object type at runtime for field "${o.parentType.name}.${o.fieldName}". Either the "${n.name}" type should provide a "resolveType" function or each possible type should provide an "isTypeOf" function.`,r);if((0,h.lp)(e))throw new c.__("Support for returning GraphQLObjectType from resolveType was removed in graphql-js@16.0.0 please return type name instead.");if("string"!=typeof e)throw new c.__(`Abstract type "${n.name}" must resolve to an Object type at runtime for field "${o.parentType.name}.${o.fieldName}" with value ${(0,i.X)(a)}, received "${(0,i.X)(e)}".`);const s=t.schema.getType(e);if(null==s)throw new c.__(`Abstract type "${n.name}" was resolved to a type "${e}" that does not exist inside the schema.`,{nodes:r});if(!(0,h.lp)(s))throw new c.__(`Abstract type "${n.name}" was resolved to a non-object type "${e}".`,{nodes:r});if(!t.schema.isSubType(n,s))throw new c.__(`Runtime Object type "${s.name}" is not a possible type for "${n.name}".`,{nodes:r});return s}function D(e,t,n,r,i,o){const a=b(e,t,n);if(t.isTypeOf){const s=t.isTypeOf(o,e.contextValue,r);if((0,l.t)(s))return s.then((r=>{if(!r)throw L(t,o,n);return x(e,t,o,i,a)}));if(!s)throw L(t,o,n)}return x(e,t,o,i,a)}function L(e,t,n){return new c.__(`Expected value of type "${e.name}" but got: ${(0,i.X)(t)}.`,{nodes:n})}const A=function(e,t,n,r){if((0,s.y)(e)&&"string"==typeof e.__typename)return e.__typename;const i=n.schema.getPossibleTypes(r),o=[];for(let r=0;r{for(let t=0;t(0,c.ht)({schema:t,document:n,rootValue:e,contextValue:a,variableValues:s,operationName:l,fieldResolver:u}))):f}async function p(e,t,n,r,f,p,h){(0,c.td)(e,t,f);const m=(0,c.VZ)({schema:e,document:t,rootValue:n,contextValue:r,variableValues:f,operationName:p,subscribeFieldResolver:h});if(!("schema"in m))return{errors:m};try{const e=await async function(e){const{schema:t,fragments:n,operation:r,variableValues:i,rootValue:o}=e,f=t.getSubscriptionType();if(null==f)throw new s.__("Schema is not configured to execute subscription operation.",{nodes:r});const p=(0,u.g)(t,n,i,f,r.selectionSet),[h,m]=[...p.entries()][0],g=(0,c.Vm)(t,f,m[0]);if(!g){const e=m[0].name.value;throw new s.__(`The subscription field "${e}" is not defined.`,{nodes:m})}const v=(0,a.Q)(void 0,h,f.name),y=(0,c.p$)(e,g,m,f,v);try{var b;const t=(0,d.LX)(g,m[0],i),n=e.contextValue,r=null!==(b=g.subscribe)&&void 0!==b?b:e.subscribeFieldResolver,a=await r(o,t,n,y);if(a instanceof Error)throw a;return a}catch(e){throw(0,l.y)(e,m,(0,a.N)(v))}}(m);if(!o(e))throw new Error(`Subscription field must return Async Iterable. Received: ${(0,i.X)(e)}.`);return e}catch(e){if(e instanceof s.__)return{errors:[e]};throw e}}},2806:function(e,t,n){"use strict";n.d(t,{LX:function(){return h},QF:function(){return p},zu:function(){return m}});var r=n(5648),i=n(9815),o=n(4987),a=n(4117),s=n(3830),l=n(5895),u=n(755),c=n(5925),d=n(5998),f=n(5284);function p(e,t,n,i){const s=[],p=null==i?void 0:i.maxErrors;try{const i=function(e,t,n,i){const s={};for(const p of t){const t=p.variable.name.value,h=(0,d._)(e,p.type);if(!(0,u.j$)(h)){const e=(0,l.S)(p.type);i(new a.__(`Variable "$${t}" expected value of type "${e}" which cannot be used as an input type.`,{nodes:p.type}));continue}if(!g(n,t)){if(p.defaultValue)s[t]=(0,f.u)(p.defaultValue,h);else if((0,u.zM)(h)){const e=(0,r.X)(h);i(new a.__(`Variable "$${t}" of required type "${e}" was not provided.`,{nodes:p}))}continue}const m=n[t];if(null===m&&(0,u.zM)(h)){const e=(0,r.X)(h);i(new a.__(`Variable "$${t}" of non-null type "${e}" must not be null.`,{nodes:p}))}else s[t]=(0,c.K)(m,h,((e,n,s)=>{let l=`Variable "$${t}" got invalid value `+(0,r.X)(n);e.length>0&&(l+=` at "${t}${(0,o.F)(e)}"`),i(new a.__(l+"; "+s.message,{nodes:p,originalError:s.originalError}))}))}return s}(e,t,n,(e=>{if(null!=p&&s.length>=p)throw new a.__("Too many errors processing variables, error limit reached. Execution aborted.");s.push(e)}));if(0===s.length)return{coerced:i}}catch(e){s.push(e)}return{errors:s}}function h(e,t,n){var o;const c={},d=null!==(o=t.arguments)&&void 0!==o?o:[],p=(0,i.P)(d,(e=>e.name.value));for(const i of e.args){const e=i.name,o=i.type,d=p[e];if(!d){if(void 0!==i.defaultValue)c[e]=i.defaultValue;else if((0,u.zM)(o))throw new a.__(`Argument "${e}" of required type "${(0,r.X)(o)}" was not provided.`,{nodes:t});continue}const h=d.value;let m=h.kind===s.h.NULL;if(h.kind===s.h.VARIABLE){const t=h.name.value;if(null==n||!g(n,t)){if(void 0!==i.defaultValue)c[e]=i.defaultValue;else if((0,u.zM)(o))throw new a.__(`Argument "${e}" of required type "${(0,r.X)(o)}" was provided the variable "$${t}" which was not provided a runtime value.`,{nodes:h});continue}m=null==n[t]}if(m&&(0,u.zM)(o))throw new a.__(`Argument "${e}" of non-null type "${(0,r.X)(o)}" must not be null.`,{nodes:h});const v=(0,f.u)(h,o,n);if(void 0===v)throw new a.__(`Argument "${e}" has invalid value ${(0,l.S)(h)}.`,{nodes:h});c[e]=v}return c}function m(e,t,n){var r;const i=null===(r=t.directives)||void 0===r?void 0:r.find((t=>t.name.value===e.name));if(i)return h(e,i,n)}function g(e,t){return Object.prototype.hasOwnProperty.call(e,t)}},3573:function(e,t,n){"use strict";n.r(t),n.d(t,{BREAK:function(){return N.$_},BreakingChangeType:function(){return pt},DEFAULT_DEPRECATION_REASON:function(){return g.SY},DangerousChangeType:function(){return ht},DirectiveLocation:function(){return O.B},ExecutableDefinitionsRule:function(){return U.i},FieldsOnCorrectTypeRule:function(){return B.A},FragmentsOnCompositeTypesRule:function(){return $.T},GRAPHQL_MAX_INT:function(){return v.HI},GRAPHQL_MIN_INT:function(){return v.st},GraphQLBoolean:function(){return v.EZ},GraphQLDeprecatedDirective:function(){return g.fg},GraphQLDirective:function(){return g.NZ},GraphQLEnumType:function(){return h.mR},GraphQLError:function(){return R.__},GraphQLFloat:function(){return v.av},GraphQLID:function(){return v.km},GraphQLIncludeDirective:function(){return g.Yf},GraphQLInputObjectType:function(){return h.sR},GraphQLInt:function(){return v._o},GraphQLInterfaceType:function(){return h.oW},GraphQLList:function(){return h.p2},GraphQLNonNull:function(){return h.bM},GraphQLObjectType:function(){return h.h6},GraphQLScalarType:function(){return h.n2},GraphQLSchema:function(){return m.XO},GraphQLSkipDirective:function(){return g.QE},GraphQLSpecifiedByDirective:function(){return g.df},GraphQLString:function(){return v.kH},GraphQLUnionType:function(){return h.Gp},Kind:function(){return _.h},KnownArgumentNamesRule:function(){return q.e},KnownDirectivesRule:function(){return H.J},KnownFragmentNamesRule:function(){return G.a},KnownTypeNamesRule:function(){return z.I},Lexer:function(){return S.h},Location:function(){return E.Ye},LoneAnonymousOperationRule:function(){return W.F},LoneSchemaDefinitionRule:function(){return fe.t},NoDeprecatedCustomRule:function(){return F},NoFragmentCyclesRule:function(){return K.H},NoSchemaIntrospectionCustomRule:function(){return P},NoUndefinedVariablesRule:function(){return Q.$},NoUnusedFragmentsRule:function(){return X.J},NoUnusedVariablesRule:function(){return Y.p},OperationTypeNode:function(){return E.ku},OverlappingFieldsCanBeMergedRule:function(){return J.y},PossibleFragmentSpreadsRule:function(){return Z.a},PossibleTypeExtensionsRule:function(){return be.g},ProvidedRequiredArgumentsRule:function(){return ee.s},ScalarLeafsRule:function(){return te.O},SchemaMetaFieldDef:function(){return y.Az},SingleFieldSubscriptionsRule:function(){return ne.Z},Source:function(){return T.H},Token:function(){return E.WU},TokenKind:function(){return x.T},TypeInfo:function(){return Mt.a},TypeKind:function(){return y.zU},TypeMetaFieldDef:function(){return y.tF},TypeNameMetaFieldDef:function(){return y.hU},UniqueArgumentDefinitionNamesRule:function(){return ve.L},UniqueArgumentNamesRule:function(){return re.L},UniqueDirectiveNamesRule:function(){return ye.o},UniqueDirectivesPerLocationRule:function(){return ie.k},UniqueEnumValueNamesRule:function(){return me.L},UniqueFieldDefinitionNamesRule:function(){return ge.y},UniqueFragmentNamesRule:function(){return oe.N},UniqueInputFieldNamesRule:function(){return ae.P},UniqueOperationNamesRule:function(){return se.H},UniqueOperationTypesRule:function(){return pe.q},UniqueTypeNamesRule:function(){return he.P},UniqueVariableNamesRule:function(){return le.H},ValidationContext:function(){return j._t},ValuesOfCorrectTypeRule:function(){return ue.j},VariablesAreInputTypesRule:function(){return ce.I},VariablesInAllowedPositionRule:function(){return de.w},__Directive:function(){return y.l3},__DirectiveLocation:function(){return y.x2},__EnumValue:function(){return y.jT},__Field:function(){return y.e_},__InputValue:function(){return y.XQ},__Schema:function(){return y.TK},__Type:function(){return y.qz},__TypeKind:function(){return y.PX},assertAbstractType:function(){return h.fU},assertCompositeType:function(){return h.M_},assertDirective:function(){return g.CO},assertEnumType:function(){return h.Zu},assertEnumValueName:function(){return b.g},assertInputObjectType:function(){return h.U8},assertInputType:function(){return h.qT},assertInterfaceType:function(){return h.k2},assertLeafType:function(){return h.H5},assertListType:function(){return h.kS},assertName:function(){return b.i},assertNamedType:function(){return h.rM},assertNonNullType:function(){return h.E$},assertNullableType:function(){return h.i_},assertObjectType:function(){return h.Z6},assertOutputType:function(){return h.Gt},assertScalarType:function(){return h.Pt},assertSchema:function(){return m.EO},assertType:function(){return h.p_},assertUnionType:function(){return h.rc},assertValidName:function(){return ct},assertValidSchema:function(){return l.J},assertWrappingType:function(){return h.vX},astFromValue:function(){return Ge.J},buildASTSchema:function(){return Pe},buildClientSchema:function(){return Oe},buildSchema:function(){return je},coerceInputValue:function(){return Rt.K},concatAST:function(){return ot},createSourceEventStream:function(){return A.z},defaultFieldResolver:function(){return c.El},defaultTypeResolver:function(){return c.mn},doTypesOverlap:function(){return Ft.zR},execute:function(){return c.ht},executeSync:function(){return c.p0},extendSchema:function(){return Le},findBreakingChanges:function(){return mt},findDangerousChanges:function(){return gt},formatError:function(){return R.Z},getArgumentValues:function(){return L.LX},getDirectiveValues:function(){return L.zu},getEnterLeaveForKind:function(){return N.Eu},getIntrospectionQuery:function(){return we},getLocation:function(){return w.k},getNamedType:function(){return h.xC},getNullableType:function(){return h.tf},getOperationAST:function(){return Dt.S},getOperationRootType:function(){return Ce},getVariableValues:function(){return L.QF},getVisitFn:function(){return N.CK},graphql:function(){return d},graphqlSync:function(){return f},introspectionFromSchema:function(){return Se},introspectionTypes:function(){return y.nL},isAbstractType:function(){return h.m0},isCompositeType:function(){return h.Gv},isConstValueNode:function(){return I.Of},isDefinitionNode:function(){return I.Ir},isDirective:function(){return g.wX},isEnumType:function(){return h.EM},isEqualType:function(){return Ft._7},isExecutableDefinitionNode:function(){return I.Wk},isInputObjectType:function(){return h.hL},isInputType:function(){return h.j$},isInterfaceType:function(){return h.oT},isIntrospectionType:function(){return y.s9},isLeafType:function(){return h.UT},isListType:function(){return h.HG},isNamedType:function(){return h.Zs},isNonNullType:function(){return h.zM},isNullableType:function(){return h.zP},isObjectType:function(){return h.lp},isOutputType:function(){return h.SZ},isRequiredArgument:function(){return h.dK},isRequiredInputField:function(){return h.Wd},isScalarType:function(){return h.KA},isSchema:function(){return m.nN},isSelectionNode:function(){return I.pO},isSpecifiedDirective:function(){return g.xg},isSpecifiedScalarType:function(){return v.u1},isType:function(){return h.P9},isTypeDefinitionNode:function(){return I.zT},isTypeExtensionNode:function(){return I.D$},isTypeNode:function(){return I.VB},isTypeSubTypeOf:function(){return Ft.uJ},isTypeSystemDefinitionNode:function(){return I.G4},isTypeSystemExtensionNode:function(){return I.aU},isUnionType:function(){return h.EN},isValidNameError:function(){return dt},isValueNode:function(){return I.nr},isWrappingType:function(){return h.fw},lexicographicSortSchema:function(){return Ue},locatedError:function(){return Te.y},parse:function(){return s.Qc},parseConstValue:function(){return s.tl},parseType:function(){return s.gZ},parseValue:function(){return s.H2},print:function(){return k.S},printError:function(){return R.OS},printIntrospectionSchema:function(){return We},printLocation:function(){return C.Q},printSchema:function(){return ze},printSourceLocation:function(){return C.z},printType:function(){return Ye},resolveObjMapThunk:function(){return h.WB},resolveReadonlyArrayThunk:function(){return h._9},responsePathAsArray:function(){return D.N},separateOperations:function(){return at},specifiedDirectives:function(){return g.V4},specifiedRules:function(){return V.i},specifiedScalarTypes:function(){return v.HS},stripIgnoredCharacters:function(){return ut},subscribe:function(){return A.L},syntaxError:function(){return Ee.h},typeFromAST:function(){return Lt._},validate:function(){return u.Gu},validateSchema:function(){return l.F},valueFromAST:function(){return _e.u},valueFromASTUntyped:function(){return At.M},version:function(){return r},versionInfo:function(){return i},visit:function(){return N.Vn},visitInParallel:function(){return N.j1},visitWithTypeInfo:function(){return Mt.y}});const r="16.5.0",i=Object.freeze({major:16,minor:5,patch:0,preReleaseTag:null});var o=n(1172),a=n(1864),s=n(953),l=n(8555),u=n(2780),c=n(7180);function d(e){return new Promise((t=>t(p(e))))}function f(e){const t=p(e);if((0,a.t)(t))throw new Error("GraphQL execution failed to complete synchronously.");return t}function p(e){arguments.length<2||(0,o.a)(!1,"graphql@16 dropped long-deprecated support for positional arguments, please pass an object instead.");const{schema:t,source:n,rootValue:r,contextValue:i,variableValues:a,operationName:d,fieldResolver:f,typeResolver:p}=e,h=(0,l.F)(t);if(h.length>0)return{errors:h};let m;try{m=(0,s.Qc)(n)}catch(e){return{errors:[e]}}const g=(0,u.Gu)(t,m);return g.length>0?{errors:g}:(0,c.ht)({schema:t,document:m,rootValue:r,contextValue:i,variableValues:a,operationName:d,fieldResolver:f,typeResolver:p})}var h=n(755),m=n(773),g=n(5946),v=n(1774),y=n(8078),b=n(3228),E=n(3526),T=n(4680),w=n(3302),C=n(7026),S=n(9230),x=n(5685),k=n(5895),N=n(9685),_=n(3830),O=n(3140),I=n(9615),D=n(9878),L=n(2806),A=n(2941),M=n(5052),R=n(4117);function F(e){return{Field(t){const n=e.getFieldDef(),r=null==n?void 0:n.deprecationReason;if(n&&null!=r){const i=e.getParentType();null!=i||(0,M.k)(!1),e.reportError(new R.__(`The field ${i.name}.${n.name} is deprecated. ${r}`,{nodes:t}))}},Argument(t){const n=e.getArgument(),r=null==n?void 0:n.deprecationReason;if(n&&null!=r){const i=e.getDirective();if(null!=i)e.reportError(new R.__(`Directive "@${i.name}" argument "${n.name}" is deprecated. ${r}`,{nodes:t}));else{const i=e.getParentType(),o=e.getFieldDef();null!=i&&null!=o||(0,M.k)(!1),e.reportError(new R.__(`Field "${i.name}.${o.name}" argument "${n.name}" is deprecated. ${r}`,{nodes:t}))}}},ObjectField(t){const n=(0,h.xC)(e.getParentInputType());if((0,h.hL)(n)){const r=n.getFields()[t.name.value],i=null==r?void 0:r.deprecationReason;null!=i&&e.reportError(new R.__(`The input field ${n.name}.${r.name} is deprecated. ${i}`,{nodes:t}))}},EnumValue(t){const n=e.getEnumValue(),r=null==n?void 0:n.deprecationReason;if(n&&null!=r){const i=(0,h.xC)(e.getInputType());null!=i||(0,M.k)(!1),e.reportError(new R.__(`The enum value "${i.name}.${n.name}" is deprecated. ${r}`,{nodes:t}))}}}}function P(e){return{Field(t){const n=(0,h.xC)(e.getType());n&&(0,y.s9)(n)&&e.reportError(new R.__(`GraphQL introspection has been disabled, but the requested query contained the field "${t.name.value}".`,{nodes:t}))}}}var j=n(2716),V=n(9299),U=n(3857),B=n(1870),$=n(5167),q=n(4875),H=n(7513),G=n(1435),z=n(591),W=n(831),K=n(9316),Q=n(9518),X=n(3447),Y=n(7114),J=n(7163),Z=n(5961),ee=n(16),te=n(3989),ne=n(9309),re=n(9168),ie=n(5673),oe=n(614),ae=n(5707),se=n(2355),le=n(7417),ue=n(4697),ce=n(6192),de=n(377),fe=n(3402),pe=n(5427),he=n(4519),me=n(4560),ge=n(5240),ve=n(5947),ye=n(5681),be=n(3721),Ee=n(2024),Te=n(4647);function we(e){const t={descriptions:!0,specifiedByUrl:!1,directiveIsRepeatable:!1,schemaDescription:!1,inputValueDeprecation:!1,...e},n=t.descriptions?"description":"",r=t.specifiedByUrl?"specifiedByURL":"",i=t.directiveIsRepeatable?"isRepeatable":"";function o(e){return t.inputValueDeprecation?e:""}return`\n query IntrospectionQuery {\n __schema {\n ${t.schemaDescription?n:""}\n queryType { name }\n mutationType { name }\n subscriptionType { name }\n types {\n ...FullType\n }\n directives {\n name\n ${n}\n ${i}\n locations\n args${o("(includeDeprecated: true)")} {\n ...InputValue\n }\n }\n }\n }\n\n fragment FullType on __Type {\n kind\n name\n ${n}\n ${r}\n fields(includeDeprecated: true) {\n name\n ${n}\n args${o("(includeDeprecated: true)")} {\n ...InputValue\n }\n type {\n ...TypeRef\n }\n isDeprecated\n deprecationReason\n }\n inputFields${o("(includeDeprecated: true)")} {\n ...InputValue\n }\n interfaces {\n ...TypeRef\n }\n enumValues(includeDeprecated: true) {\n name\n ${n}\n isDeprecated\n deprecationReason\n }\n possibleTypes {\n ...TypeRef\n }\n }\n\n fragment InputValue on __InputValue {\n name\n ${n}\n type { ...TypeRef }\n defaultValue\n ${o("isDeprecated")}\n ${o("deprecationReason")}\n }\n\n fragment TypeRef on __Type {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n }\n `}function Ce(e,t){if("query"===t.operation){const n=e.getQueryType();if(!n)throw new R.__("Schema does not define the required query root type.",{nodes:t});return n}if("mutation"===t.operation){const n=e.getMutationType();if(!n)throw new R.__("Schema is not configured for mutations.",{nodes:t});return n}if("subscription"===t.operation){const n=e.getSubscriptionType();if(!n)throw new R.__("Schema is not configured for subscriptions.",{nodes:t});return n}throw new R.__("Can only have query, mutation and subscription operations.",{nodes:t})}function Se(e,t){const n={specifiedByUrl:!0,directiveIsRepeatable:!0,schemaDescription:!0,inputValueDeprecation:!0,...t},r=(0,s.Qc)(we(n)),i=(0,c.p0)({schema:e,document:r});return!i.errors&&i.data||(0,M.k)(!1),i.data}var xe=n(5648),ke=n(1315),Ne=n(8240),_e=n(5284);function Oe(e,t){(0,ke.y)(e)&&(0,ke.y)(e.__schema)||(0,o.a)(!1,`Invalid or incomplete introspection result. Ensure that you are passing "data" property of introspection response and no "errors" was returned alongside: ${(0,xe.X)(e)}.`);const n=e.__schema,r=(0,Ne.w)(n.types,(e=>e.name),(e=>function(e){if(null!=e&&null!=e.name&&null!=e.kind)switch(e.kind){case y.zU.SCALAR:return r=e,new h.n2({name:r.name,description:r.description,specifiedByURL:r.specifiedByURL});case y.zU.OBJECT:return n=e,new h.h6({name:n.name,description:n.description,interfaces:()=>b(n),fields:()=>E(n)});case y.zU.INTERFACE:return t=e,new h.oW({name:t.name,description:t.description,interfaces:()=>b(t),fields:()=>E(t)});case y.zU.UNION:return function(e){if(!e.possibleTypes){const t=(0,xe.X)(e);throw new Error(`Introspection result missing possibleTypes: ${t}.`)}return new h.Gp({name:e.name,description:e.description,types:()=>e.possibleTypes.map(f)})}(e);case y.zU.ENUM:return function(e){if(!e.enumValues){const t=(0,xe.X)(e);throw new Error(`Introspection result missing enumValues: ${t}.`)}return new h.mR({name:e.name,description:e.description,values:(0,Ne.w)(e.enumValues,(e=>e.name),(e=>({description:e.description,deprecationReason:e.deprecationReason})))})}(e);case y.zU.INPUT_OBJECT:return function(e){if(!e.inputFields){const t=(0,xe.X)(e);throw new Error(`Introspection result missing inputFields: ${t}.`)}return new h.sR({name:e.name,description:e.description,fields:()=>w(e.inputFields)})}(e)}var t,n,r;const i=(0,xe.X)(e);throw new Error(`Invalid or incomplete introspection result. Ensure that a full introspection query is used in order to build a client schema: ${i}.`)}(e)));for(const e of[...v.HS,...y.nL])r[e.name]&&(r[e.name]=e);const i=n.queryType?f(n.queryType):null,a=n.mutationType?f(n.mutationType):null,l=n.subscriptionType?f(n.subscriptionType):null,u=n.directives?n.directives.map((function(e){if(!e.args){const t=(0,xe.X)(e);throw new Error(`Introspection result missing directive args: ${t}.`)}if(!e.locations){const t=(0,xe.X)(e);throw new Error(`Introspection result missing directive locations: ${t}.`)}return new g.NZ({name:e.name,description:e.description,isRepeatable:e.isRepeatable,locations:e.locations.slice(),args:w(e.args)})})):[];return new m.XO({description:n.description,query:i,mutation:a,subscription:l,types:Object.values(r),directives:u,assumeValid:null==t?void 0:t.assumeValid});function c(e){if(e.kind===y.zU.LIST){const t=e.ofType;if(!t)throw new Error("Decorated type deeper than introspection query.");return new h.p2(c(t))}if(e.kind===y.zU.NON_NULL){const t=e.ofType;if(!t)throw new Error("Decorated type deeper than introspection query.");const n=c(t);return new h.bM((0,h.i_)(n))}return d(e)}function d(e){const t=e.name;if(!t)throw new Error(`Unknown type reference: ${(0,xe.X)(e)}.`);const n=r[t];if(!n)throw new Error(`Invalid or incomplete schema, unknown type: ${t}. Ensure that a full introspection query is used in order to build a client schema.`);return n}function f(e){return(0,h.Z6)(d(e))}function p(e){return(0,h.k2)(d(e))}function b(e){if(null===e.interfaces&&e.kind===y.zU.INTERFACE)return[];if(!e.interfaces){const t=(0,xe.X)(e);throw new Error(`Introspection result missing interfaces: ${t}.`)}return e.interfaces.map(p)}function E(e){if(!e.fields)throw new Error(`Introspection result missing fields: ${(0,xe.X)(e)}.`);return(0,Ne.w)(e.fields,(e=>e.name),T)}function T(e){const t=c(e.type);if(!(0,h.SZ)(t)){const e=(0,xe.X)(t);throw new Error(`Introspection must provide output type for fields, but received: ${e}.`)}if(!e.args){const t=(0,xe.X)(e);throw new Error(`Introspection result missing field args: ${t}.`)}return{description:e.description,deprecationReason:e.deprecationReason,type:t,args:w(e.args)}}function w(e){return(0,Ne.w)(e,(e=>e.name),C)}function C(e){const t=c(e.type);if(!(0,h.j$)(t)){const e=(0,xe.X)(t);throw new Error(`Introspection must provide input type for arguments, but received: ${e}.`)}const n=null!=e.defaultValue?(0,_e.u)((0,s.H2)(e.defaultValue),t):void 0;return{description:e.description,type:t,defaultValue:n,deprecationReason:e.deprecationReason}}}var Ie=n(9815),De=n(9997);function Le(e,t,n){(0,m.EO)(e),null!=t&&t.kind===_.h.DOCUMENT||(0,o.a)(!1,"Must provide valid Document AST."),!0!==(null==n?void 0:n.assumeValid)&&!0!==(null==n?void 0:n.assumeValidSDL)&&(0,u.ED)(t,e);const r=e.toConfig(),i=Ae(r,t,n);return r===i?e:new m.XO(i)}function Ae(e,t,n){var r,i,o,a;const s=[],l=Object.create(null),u=[];let c;const d=[];for(const e of t.definitions)if(e.kind===_.h.SCHEMA_DEFINITION)c=e;else if(e.kind===_.h.SCHEMA_EXTENSION)d.push(e);else if((0,I.zT)(e))s.push(e);else if((0,I.D$)(e)){const t=e.name.value,n=l[t];l[t]=n?n.concat([e]):[e]}else e.kind===_.h.DIRECTIVE_DEFINITION&&u.push(e);if(0===Object.keys(l).length&&0===s.length&&0===u.length&&0===d.length&&null==c)return e;const f=Object.create(null);for(const t of e.types)f[t.name]=(p=t,(0,y.s9)(p)||(0,v.u1)(p)?p:(0,h.KA)(p)?function(e){var t;const n=e.toConfig(),r=null!==(t=l[n.name])&&void 0!==t?t:[];let i=n.specifiedByURL;for(const e of r){var o;i=null!==(o=Fe(e))&&void 0!==o?o:i}return new h.n2({...n,specifiedByURL:i,extensionASTNodes:n.extensionASTNodes.concat(r)})}(p):(0,h.lp)(p)?function(e){var t;const n=e.toConfig(),r=null!==(t=l[n.name])&&void 0!==t?t:[];return new h.h6({...n,interfaces:()=>[...e.getInterfaces().map(T),...A(r)],fields:()=>({...(0,De.j)(n.fields,w),...N(r)}),extensionASTNodes:n.extensionASTNodes.concat(r)})}(p):(0,h.oT)(p)?function(e){var t;const n=e.toConfig(),r=null!==(t=l[n.name])&&void 0!==t?t:[];return new h.oW({...n,interfaces:()=>[...e.getInterfaces().map(T),...A(r)],fields:()=>({...(0,De.j)(n.fields,w),...N(r)}),extensionASTNodes:n.extensionASTNodes.concat(r)})}(p):(0,h.EN)(p)?function(e){var t;const n=e.toConfig(),r=null!==(t=l[n.name])&&void 0!==t?t:[];return new h.Gp({...n,types:()=>[...e.getTypes().map(T),...R(r)],extensionASTNodes:n.extensionASTNodes.concat(r)})}(p):(0,h.EM)(p)?function(e){var t;const n=e.toConfig(),r=null!==(t=l[e.name])&&void 0!==t?t:[];return new h.mR({...n,values:{...n.values,...L(r)},extensionASTNodes:n.extensionASTNodes.concat(r)})}(p):(0,h.hL)(p)?function(e){var t;const n=e.toConfig(),r=null!==(t=l[n.name])&&void 0!==t?t:[];return new h.sR({...n,fields:()=>({...(0,De.j)(n.fields,(e=>({...e,type:E(e.type)}))),...D(r)}),extensionASTNodes:n.extensionASTNodes.concat(r)})}(p):void(0,M.k)(!1,"Unexpected type: "+(0,xe.X)(p)));var p;for(const e of s){var m;const t=e.name.value;f[t]=null!==(m=Me[t])&&void 0!==m?m:F(e)}const b={query:e.query&&T(e.query),mutation:e.mutation&&T(e.mutation),subscription:e.subscription&&T(e.subscription),...c&&S([c]),...S(d)};return{description:null===(r=c)||void 0===r||null===(i=r.description)||void 0===i?void 0:i.value,...b,types:Object.values(f),directives:[...e.directives.map((function(e){const t=e.toConfig();return new g.NZ({...t,args:(0,De.j)(t.args,C)})})),...u.map((function(e){var t;return new g.NZ({name:e.name.value,description:null===(t=e.description)||void 0===t?void 0:t.value,locations:e.locations.map((({value:e})=>e)),isRepeatable:e.repeatable,args:O(e.arguments),astNode:e})}))],extensions:Object.create(null),astNode:null!==(o=c)&&void 0!==o?o:e.astNode,extensionASTNodes:e.extensionASTNodes.concat(d),assumeValid:null!==(a=null==n?void 0:n.assumeValid)&&void 0!==a&&a};function E(e){return(0,h.HG)(e)?new h.p2(E(e.ofType)):(0,h.zM)(e)?new h.bM(E(e.ofType)):T(e)}function T(e){return f[e.name]}function w(e){return{...e,type:E(e.type),args:e.args&&(0,De.j)(e.args,C)}}function C(e){return{...e,type:E(e.type)}}function S(e){const t={};for(const r of e){var n;const e=null!==(n=r.operationTypes)&&void 0!==n?n:[];for(const n of e)t[n.operation]=x(n.type)}return t}function x(e){var t;const n=e.name.value,r=null!==(t=Me[n])&&void 0!==t?t:f[n];if(void 0===r)throw new Error(`Unknown type: "${n}".`);return r}function k(e){return e.kind===_.h.LIST_TYPE?new h.p2(k(e.type)):e.kind===_.h.NON_NULL_TYPE?new h.bM(k(e.type)):x(e)}function N(e){const t=Object.create(null);for(const i of e){var n;const e=null!==(n=i.fields)&&void 0!==n?n:[];for(const n of e){var r;t[n.name.value]={type:k(n.type),description:null===(r=n.description)||void 0===r?void 0:r.value,args:O(n.arguments),deprecationReason:Re(n),astNode:n}}}return t}function O(e){const t=null!=e?e:[],n=Object.create(null);for(const e of t){var r;const t=k(e.type);n[e.name.value]={type:t,description:null===(r=e.description)||void 0===r?void 0:r.value,defaultValue:(0,_e.u)(e.defaultValue,t),deprecationReason:Re(e),astNode:e}}return n}function D(e){const t=Object.create(null);for(const i of e){var n;const e=null!==(n=i.fields)&&void 0!==n?n:[];for(const n of e){var r;const e=k(n.type);t[n.name.value]={type:e,description:null===(r=n.description)||void 0===r?void 0:r.value,defaultValue:(0,_e.u)(n.defaultValue,e),deprecationReason:Re(n),astNode:n}}}return t}function L(e){const t=Object.create(null);for(const i of e){var n;const e=null!==(n=i.values)&&void 0!==n?n:[];for(const n of e){var r;t[n.name.value]={description:null===(r=n.description)||void 0===r?void 0:r.value,deprecationReason:Re(n),astNode:n}}}return t}function A(e){return e.flatMap((e=>{var t,n;return null!==(t=null===(n=e.interfaces)||void 0===n?void 0:n.map(x))&&void 0!==t?t:[]}))}function R(e){return e.flatMap((e=>{var t,n;return null!==(t=null===(n=e.types)||void 0===n?void 0:n.map(x))&&void 0!==t?t:[]}))}function F(e){var t;const n=e.name.value,r=null!==(t=l[n])&&void 0!==t?t:[];switch(e.kind){case _.h.OBJECT_TYPE_DEFINITION:{var i;const t=[e,...r];return new h.h6({name:n,description:null===(i=e.description)||void 0===i?void 0:i.value,interfaces:()=>A(t),fields:()=>N(t),astNode:e,extensionASTNodes:r})}case _.h.INTERFACE_TYPE_DEFINITION:{var o;const t=[e,...r];return new h.oW({name:n,description:null===(o=e.description)||void 0===o?void 0:o.value,interfaces:()=>A(t),fields:()=>N(t),astNode:e,extensionASTNodes:r})}case _.h.ENUM_TYPE_DEFINITION:{var a;const t=[e,...r];return new h.mR({name:n,description:null===(a=e.description)||void 0===a?void 0:a.value,values:L(t),astNode:e,extensionASTNodes:r})}case _.h.UNION_TYPE_DEFINITION:{var s;const t=[e,...r];return new h.Gp({name:n,description:null===(s=e.description)||void 0===s?void 0:s.value,types:()=>R(t),astNode:e,extensionASTNodes:r})}case _.h.SCALAR_TYPE_DEFINITION:var u;return new h.n2({name:n,description:null===(u=e.description)||void 0===u?void 0:u.value,specifiedByURL:Fe(e),astNode:e,extensionASTNodes:r});case _.h.INPUT_OBJECT_TYPE_DEFINITION:{var c;const t=[e,...r];return new h.sR({name:n,description:null===(c=e.description)||void 0===c?void 0:c.value,fields:()=>D(t),astNode:e,extensionASTNodes:r})}}}}const Me=(0,Ie.P)([...v.HS,...y.nL],(e=>e.name));function Re(e){const t=(0,L.zu)(g.fg,e);return null==t?void 0:t.reason}function Fe(e){const t=(0,L.zu)(g.df,e);return null==t?void 0:t.url}function Pe(e,t){null!=e&&e.kind===_.h.DOCUMENT||(0,o.a)(!1,"Must provide valid Document AST."),!0!==(null==t?void 0:t.assumeValid)&&!0!==(null==t?void 0:t.assumeValidSDL)&&(0,u.zo)(e);const n=Ae({description:void 0,types:[],directives:[],extensions:Object.create(null),extensionASTNodes:[],assumeValid:!1},e,t);if(null==n.astNode)for(const e of n.types)switch(e.name){case"Query":n.query=e;break;case"Mutation":n.mutation=e;break;case"Subscription":n.subscription=e}const r=[...n.directives,...g.V4.filter((e=>n.directives.every((t=>t.name!==e.name))))];return new m.XO({...n,directives:r})}function je(e,t){return Pe((0,s.Qc)(e,{noLocation:null==t?void 0:t.noLocation,allowLegacyFragmentVariables:null==t?void 0:t.allowLegacyFragmentVariables}),{assumeValidSDL:null==t?void 0:t.assumeValidSDL,assumeValid:null==t?void 0:t.assumeValid})}var Ve=n(6625);function Ue(e){const t=e.toConfig(),n=(0,Ne.w)($e(t.types),(e=>e.name),(function(e){if((0,h.KA)(e)||(0,y.s9)(e))return e;if((0,h.lp)(e)){const t=e.toConfig();return new h.h6({...t,interfaces:()=>l(t.interfaces),fields:()=>s(t.fields)})}if((0,h.oT)(e)){const t=e.toConfig();return new h.oW({...t,interfaces:()=>l(t.interfaces),fields:()=>s(t.fields)})}if((0,h.EN)(e)){const t=e.toConfig();return new h.Gp({...t,types:()=>l(t.types)})}if((0,h.EM)(e)){const t=e.toConfig();return new h.mR({...t,values:Be(t.values,(e=>e))})}if((0,h.hL)(e)){const t=e.toConfig();return new h.sR({...t,fields:()=>Be(t.fields,(e=>({...e,type:r(e.type)})))})}(0,M.k)(!1,"Unexpected type: "+(0,xe.X)(e))}));return new m.XO({...t,types:Object.values(n),directives:$e(t.directives).map((function(e){const t=e.toConfig();return new g.NZ({...t,locations:qe(t.locations,(e=>e)),args:a(t.args)})})),query:o(t.query),mutation:o(t.mutation),subscription:o(t.subscription)});function r(e){return(0,h.HG)(e)?new h.p2(r(e.ofType)):(0,h.zM)(e)?new h.bM(r(e.ofType)):i(e)}function i(e){return n[e.name]}function o(e){return e&&i(e)}function a(e){return Be(e,(e=>({...e,type:r(e.type)})))}function s(e){return Be(e,(e=>({...e,type:r(e.type),args:e.args&&a(e.args)})))}function l(e){return $e(e).map(i)}}function Be(e,t){const n=Object.create(null);for(const r of Object.keys(e).sort(Ve.K))n[r]=t(e[r]);return n}function $e(e){return qe(e,(e=>e.name))}function qe(e,t){return e.slice().sort(((e,n)=>{const r=t(e),i=t(n);return(0,Ve.K)(r,i)}))}var He=n(6303),Ge=n(3190);function ze(e){return Qe(e,(e=>!(0,g.xg)(e)),Ke)}function We(e){return Qe(e,g.xg,y.s9)}function Ke(e){return!(0,v.u1)(e)&&!(0,y.s9)(e)}function Qe(e,t,n){const r=e.getDirectives().filter(t),i=Object.values(e.getTypeMap()).filter(n);return[Xe(e),...r.map((e=>function(e){return it(e)+"directive @"+e.name+tt(e.args)+(e.isRepeatable?" repeatable":"")+" on "+e.locations.join(" | ")}(e))),...i.map((e=>Ye(e)))].filter(Boolean).join("\n\n")}function Xe(e){if(null==e.description&&function(e){const t=e.getQueryType();if(t&&"Query"!==t.name)return!1;const n=e.getMutationType();if(n&&"Mutation"!==n.name)return!1;const r=e.getSubscriptionType();return!r||"Subscription"===r.name}(e))return;const t=[],n=e.getQueryType();n&&t.push(` query: ${n.name}`);const r=e.getMutationType();r&&t.push(` mutation: ${r.name}`);const i=e.getSubscriptionType();return i&&t.push(` subscription: ${i.name}`),it(e)+`schema {\n${t.join("\n")}\n}`}function Ye(e){return(0,h.KA)(e)?function(e){return it(e)+`scalar ${e.name}`+(null==(t=e).specifiedByURL?"":` @specifiedBy(url: ${(0,k.S)({kind:_.h.STRING,value:t.specifiedByURL})})`);var t}(e):(0,h.lp)(e)?function(e){return it(e)+`type ${e.name}`+Je(e)+Ze(e)}(e):(0,h.oT)(e)?function(e){return it(e)+`interface ${e.name}`+Je(e)+Ze(e)}(e):(0,h.EN)(e)?function(e){const t=e.getTypes(),n=t.length?" = "+t.join(" | "):"";return it(e)+"union "+e.name+n}(e):(0,h.EM)(e)?function(e){const t=e.getValues().map(((e,t)=>it(e," ",!t)+" "+e.name+rt(e.deprecationReason)));return it(e)+`enum ${e.name}`+et(t)}(e):(0,h.hL)(e)?function(e){const t=Object.values(e.getFields()).map(((e,t)=>it(e," ",!t)+" "+nt(e)));return it(e)+`input ${e.name}`+et(t)}(e):void(0,M.k)(!1,"Unexpected type: "+(0,xe.X)(e))}function Je(e){const t=e.getInterfaces();return t.length?" implements "+t.map((e=>e.name)).join(" & "):""}function Ze(e){return et(Object.values(e.getFields()).map(((e,t)=>it(e," ",!t)+" "+e.name+tt(e.args," ")+": "+String(e.type)+rt(e.deprecationReason))))}function et(e){return 0!==e.length?" {\n"+e.join("\n")+"\n}":""}function tt(e,t=""){return 0===e.length?"":e.every((e=>!e.description))?"("+e.map(nt).join(", ")+")":"(\n"+e.map(((e,n)=>it(e," "+t,!n)+" "+t+nt(e))).join("\n")+"\n"+t+")"}function nt(e){const t=(0,Ge.J)(e.defaultValue,e.type);let n=e.name+": "+String(e.type);return t&&(n+=` = ${(0,k.S)(t)}`),n+rt(e.deprecationReason)}function rt(e){return null==e?"":e!==g.SY?` @deprecated(reason: ${(0,k.S)({kind:_.h.STRING,value:e})})`:" @deprecated"}function it(e,t="",n=!0){const{description:r}=e;return null==r?"":(t&&!n?"\n"+t:t)+(0,k.S)({kind:_.h.STRING,value:r,block:(0,He.MZ)(r)}).replace(/\n/g,"\n"+t)+"\n"}function ot(e){const t=[];for(const n of e)t.push(...n.definitions);return{kind:_.h.DOCUMENT,definitions:t}}function at(e){const t=[],n=Object.create(null);for(const r of e.definitions)switch(r.kind){case _.h.OPERATION_DEFINITION:t.push(r);break;case _.h.FRAGMENT_DEFINITION:n[r.name.value]=lt(r.selectionSet)}const r=Object.create(null);for(const i of t){const t=new Set;for(const e of lt(i.selectionSet))st(t,n,e);r[i.name?i.name.value:""]={kind:_.h.DOCUMENT,definitions:e.definitions.filter((e=>e===i||e.kind===_.h.FRAGMENT_DEFINITION&&t.has(e.name.value)))}}return r}function st(e,t,n){if(!e.has(n)){e.add(n);const r=t[n];if(void 0!==r)for(const n of r)st(e,t,n)}}function lt(e){const t=[];return(0,N.Vn)(e,{FragmentSpread(e){t.push(e.name.value)}}),t}function ut(e){const t=(0,T.T)(e)?e:new T.H(e),n=t.body,r=new S.h(t);let i="",o=!1;for(;r.advance().kind!==x.T.EOF;){const e=r.token,t=e.kind,a=!(0,S.u)(e.kind);o&&(a||e.kind===x.T.SPREAD)&&(i+=" ");const s=n.slice(e.start,e.end);t===x.T.BLOCK_STRING?i+=(0,He.LZ)(e.value,{minimize:!0}):i+=s,o=a}return i}function ct(e){const t=dt(e);if(t)throw t;return e}function dt(e){if("string"==typeof e||(0,o.a)(!1,"Expected name to be a string."),e.startsWith("__"))return new R.__(`Name "${e}" must not begin with "__", which is reserved by GraphQL introspection.`);try{(0,b.i)(e)}catch(e){return e}}var ft=n(4034);let pt,ht;function mt(e,t){return vt(e,t).filter((e=>e.type in pt))}function gt(e,t){return vt(e,t).filter((e=>e.type in ht))}function vt(e,t){return[...bt(e,t),...yt(e,t)]}function yt(e,t){const n=[],r=It(e.getDirectives(),t.getDirectives());for(const e of r.removed)n.push({type:pt.DIRECTIVE_REMOVED,description:`${e.name} was removed.`});for(const[e,t]of r.persisted){const r=It(e.args,t.args);for(const t of r.added)(0,h.dK)(t)&&n.push({type:pt.REQUIRED_DIRECTIVE_ARG_ADDED,description:`A required arg ${t.name} on directive ${e.name} was added.`});for(const t of r.removed)n.push({type:pt.DIRECTIVE_ARG_REMOVED,description:`${t.name} was removed from ${e.name}.`});e.isRepeatable&&!t.isRepeatable&&n.push({type:pt.DIRECTIVE_REPEATABLE_REMOVED,description:`Repeatable flag was removed from ${e.name}.`});for(const r of e.locations)t.locations.includes(r)||n.push({type:pt.DIRECTIVE_LOCATION_REMOVED,description:`${r} was removed from ${e.name}.`})}return n}function bt(e,t){const n=[],r=It(Object.values(e.getTypeMap()),Object.values(t.getTypeMap()));for(const e of r.removed)n.push({type:pt.TYPE_REMOVED,description:(0,v.u1)(e)?`Standard scalar ${e.name} was removed because it is not referenced anymore.`:`${e.name} was removed.`});for(const[e,t]of r.persisted)(0,h.EM)(e)&&(0,h.EM)(t)?n.push(...wt(e,t)):(0,h.EN)(e)&&(0,h.EN)(t)?n.push(...Tt(e,t)):(0,h.hL)(e)&&(0,h.hL)(t)?n.push(...Et(e,t)):(0,h.lp)(e)&&(0,h.lp)(t)||(0,h.oT)(e)&&(0,h.oT)(t)?n.push(...St(e,t),...Ct(e,t)):e.constructor!==t.constructor&&n.push({type:pt.TYPE_CHANGED_KIND,description:`${e.name} changed from ${_t(e)} to ${_t(t)}.`});return n}function Et(e,t){const n=[],r=It(Object.values(e.getFields()),Object.values(t.getFields()));for(const t of r.added)(0,h.Wd)(t)?n.push({type:pt.REQUIRED_INPUT_FIELD_ADDED,description:`A required field ${t.name} on input type ${e.name} was added.`}):n.push({type:ht.OPTIONAL_INPUT_FIELD_ADDED,description:`An optional field ${t.name} on input type ${e.name} was added.`});for(const t of r.removed)n.push({type:pt.FIELD_REMOVED,description:`${e.name}.${t.name} was removed.`});for(const[t,i]of r.persisted)Nt(t.type,i.type)||n.push({type:pt.FIELD_CHANGED_KIND,description:`${e.name}.${t.name} changed type from ${String(t.type)} to ${String(i.type)}.`});return n}function Tt(e,t){const n=[],r=It(e.getTypes(),t.getTypes());for(const t of r.added)n.push({type:ht.TYPE_ADDED_TO_UNION,description:`${t.name} was added to union type ${e.name}.`});for(const t of r.removed)n.push({type:pt.TYPE_REMOVED_FROM_UNION,description:`${t.name} was removed from union type ${e.name}.`});return n}function wt(e,t){const n=[],r=It(e.getValues(),t.getValues());for(const t of r.added)n.push({type:ht.VALUE_ADDED_TO_ENUM,description:`${t.name} was added to enum type ${e.name}.`});for(const t of r.removed)n.push({type:pt.VALUE_REMOVED_FROM_ENUM,description:`${t.name} was removed from enum type ${e.name}.`});return n}function Ct(e,t){const n=[],r=It(e.getInterfaces(),t.getInterfaces());for(const t of r.added)n.push({type:ht.IMPLEMENTED_INTERFACE_ADDED,description:`${t.name} added to interfaces implemented by ${e.name}.`});for(const t of r.removed)n.push({type:pt.IMPLEMENTED_INTERFACE_REMOVED,description:`${e.name} no longer implements interface ${t.name}.`});return n}function St(e,t){const n=[],r=It(Object.values(e.getFields()),Object.values(t.getFields()));for(const t of r.removed)n.push({type:pt.FIELD_REMOVED,description:`${e.name}.${t.name} was removed.`});for(const[t,i]of r.persisted)n.push(...xt(e,t,i)),kt(t.type,i.type)||n.push({type:pt.FIELD_CHANGED_KIND,description:`${e.name}.${t.name} changed type from ${String(t.type)} to ${String(i.type)}.`});return n}function xt(e,t,n){const r=[],i=It(t.args,n.args);for(const n of i.removed)r.push({type:pt.ARG_REMOVED,description:`${e.name}.${t.name} arg ${n.name} was removed.`});for(const[n,o]of i.persisted)if(Nt(n.type,o.type)){if(void 0!==n.defaultValue)if(void 0===o.defaultValue)r.push({type:ht.ARG_DEFAULT_VALUE_CHANGE,description:`${e.name}.${t.name} arg ${n.name} defaultValue was removed.`});else{const i=Ot(n.defaultValue,n.type),a=Ot(o.defaultValue,o.type);i!==a&&r.push({type:ht.ARG_DEFAULT_VALUE_CHANGE,description:`${e.name}.${t.name} arg ${n.name} has changed defaultValue from ${i} to ${a}.`})}}else r.push({type:pt.ARG_CHANGED_KIND,description:`${e.name}.${t.name} arg ${n.name} has changed type from ${String(n.type)} to ${String(o.type)}.`});for(const n of i.added)(0,h.dK)(n)?r.push({type:pt.REQUIRED_ARG_ADDED,description:`A required arg ${n.name} on ${e.name}.${t.name} was added.`}):r.push({type:ht.OPTIONAL_ARG_ADDED,description:`An optional arg ${n.name} on ${e.name}.${t.name} was added.`});return r}function kt(e,t){return(0,h.HG)(e)?(0,h.HG)(t)&&kt(e.ofType,t.ofType)||(0,h.zM)(t)&&kt(e,t.ofType):(0,h.zM)(e)?(0,h.zM)(t)&&kt(e.ofType,t.ofType):(0,h.Zs)(t)&&e.name===t.name||(0,h.zM)(t)&&kt(e,t.ofType)}function Nt(e,t){return(0,h.HG)(e)?(0,h.HG)(t)&&Nt(e.ofType,t.ofType):(0,h.zM)(e)?(0,h.zM)(t)&&Nt(e.ofType,t.ofType)||!(0,h.zM)(t)&&Nt(e.ofType,t):(0,h.Zs)(t)&&e.name===t.name}function _t(e){return(0,h.KA)(e)?"a Scalar type":(0,h.lp)(e)?"an Object type":(0,h.oT)(e)?"an Interface type":(0,h.EN)(e)?"a Union type":(0,h.EM)(e)?"an Enum type":(0,h.hL)(e)?"an Input type":void(0,M.k)(!1,"Unexpected type: "+(0,xe.X)(e))}function Ot(e,t){const n=(0,Ge.J)(e,t);return null!=n||(0,M.k)(!1),(0,k.S)((0,ft.n)(n))}function It(e,t){const n=[],r=[],i=[],o=(0,Ie.P)(e,(({name:e})=>e)),a=(0,Ie.P)(t,(({name:e})=>e));for(const t of e){const e=a[t.name];void 0===e?r.push(t):i.push([t,e])}for(const e of t)void 0===o[e.name]&&n.push(e);return{added:n,persisted:i,removed:r}}!function(e){e.TYPE_REMOVED="TYPE_REMOVED",e.TYPE_CHANGED_KIND="TYPE_CHANGED_KIND",e.TYPE_REMOVED_FROM_UNION="TYPE_REMOVED_FROM_UNION",e.VALUE_REMOVED_FROM_ENUM="VALUE_REMOVED_FROM_ENUM",e.REQUIRED_INPUT_FIELD_ADDED="REQUIRED_INPUT_FIELD_ADDED",e.IMPLEMENTED_INTERFACE_REMOVED="IMPLEMENTED_INTERFACE_REMOVED",e.FIELD_REMOVED="FIELD_REMOVED",e.FIELD_CHANGED_KIND="FIELD_CHANGED_KIND",e.REQUIRED_ARG_ADDED="REQUIRED_ARG_ADDED",e.ARG_REMOVED="ARG_REMOVED",e.ARG_CHANGED_KIND="ARG_CHANGED_KIND",e.DIRECTIVE_REMOVED="DIRECTIVE_REMOVED",e.DIRECTIVE_ARG_REMOVED="DIRECTIVE_ARG_REMOVED",e.REQUIRED_DIRECTIVE_ARG_ADDED="REQUIRED_DIRECTIVE_ARG_ADDED",e.DIRECTIVE_REPEATABLE_REMOVED="DIRECTIVE_REPEATABLE_REMOVED",e.DIRECTIVE_LOCATION_REMOVED="DIRECTIVE_LOCATION_REMOVED"}(pt||(pt={})),function(e){e.VALUE_ADDED_TO_ENUM="VALUE_ADDED_TO_ENUM",e.TYPE_ADDED_TO_UNION="TYPE_ADDED_TO_UNION",e.OPTIONAL_INPUT_FIELD_ADDED="OPTIONAL_INPUT_FIELD_ADDED",e.OPTIONAL_ARG_ADDED="OPTIONAL_ARG_ADDED",e.IMPLEMENTED_INTERFACE_ADDED="IMPLEMENTED_INTERFACE_ADDED",e.ARG_DEFAULT_VALUE_CHANGE="ARG_DEFAULT_VALUE_CHANGE"}(ht||(ht={}));var Dt=n(9458),Lt=n(5998),At=n(9426),Mt=n(1409),Rt=n(5925),Ft=n(2984)},9878:function(e,t,n){"use strict";function r(e,t,n){return{prev:e,key:t,typename:n}}function i(e){const t=[];let n=e;for(;n;)t.push(n.key),n=n.prev;return t.reverse()}n.d(t,{N:function(){return i},Q:function(){return r}})},1172:function(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw new Error(t)}n.d(t,{a:function(){return r}})},8063:function(e,t,n){"use strict";n.d(t,{l:function(){return i}});const r=5;function i(e,t){const[n,i]=t?[e,t]:[void 0,e];let o=" Did you mean ";n&&(o+=n+" ");const a=i.map((e=>`"${e}"`));switch(a.length){case 0:return"";case 1:return o+a[0]+"?";case 2:return o+a[0]+" or "+a[1]+"?"}const s=a.slice(0,r),l=s.pop();return o+s.join(", ")+", or "+l+"?"}},5839:function(e,t,n){"use strict";function r(e,t){const n=new Map;for(const r of e){const e=t(r),i=n.get(e);void 0===i?n.set(e,[r]):i.push(r)}return n}n.d(t,{v:function(){return r}})},5648:function(e,t,n){"use strict";n.d(t,{X:function(){return o}});const r=10,i=2;function o(e){return a(e,[])}function a(e,t){switch(typeof e){case"string":return JSON.stringify(e);case"function":return e.name?`[function ${e.name}]`:"[function]";case"object":return function(e,t){if(null===e)return"null";if(t.includes(e))return"[Circular]";const n=[...t,e];if(function(e){return"function"==typeof e.toJSON}(e)){const t=e.toJSON();if(t!==e)return"string"==typeof t?t:a(t,n)}else if(Array.isArray(e))return function(e,t){if(0===e.length)return"[]";if(t.length>i)return"[Array]";const n=Math.min(r,e.length),o=e.length-n,s=[];for(let r=0;r1&&s.push(`... ${o} more items`),"["+s.join(", ")+"]"}(e,n);return function(e,t){const n=Object.entries(e);if(0===n.length)return"{}";if(t.length>i)return"["+function(e){const t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){const t=e.constructor.name;if("string"==typeof t&&""!==t)return t}return t}(e)+"]";const r=n.map((([e,n])=>e+": "+a(n,t)));return"{ "+r.join(", ")+" }"}(e,n)}(e,t);default:return String(e)}}},1513:function(e,t,n){"use strict";n.d(t,{n:function(){return r}});const r=function(e,t){return e instanceof t}},5052:function(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw new Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{k:function(){return r}})},2910:function(e,t,n){"use strict";function r(e){return"object"==typeof e&&"function"==typeof(null==e?void 0:e[Symbol.iterator])}n.d(t,{i:function(){return r}})},1315:function(e,t,n){"use strict";function r(e){return"object"==typeof e&&null!==e}n.d(t,{y:function(){return r}})},1864:function(e,t,n){"use strict";function r(e){return"function"==typeof(null==e?void 0:e.then)}n.d(t,{t:function(){return r}})},9815:function(e,t,n){"use strict";function r(e,t){const n=Object.create(null);for(const r of e)n[t(r)]=r;return n}n.d(t,{P:function(){return r}})},8240:function(e,t,n){"use strict";function r(e,t,n){const r=Object.create(null);for(const i of e)r[t(i)]=n(i);return r}n.d(t,{w:function(){return r}})},9997:function(e,t,n){"use strict";function r(e,t){const n=Object.create(null);for(const r of Object.keys(e))n[r]=t(e[r],r);return n}n.d(t,{j:function(){return r}})},6625:function(e,t,n){"use strict";function r(e,t){let n=0,r=0;for(;n0);let u=0;do{++r,u=10*u+s-i,s=t.charCodeAt(r)}while(a(s)&&u>0);if(lu)return 1}else{if(os)return 1;++n,++r}}return e.length-t.length}n.d(t,{K:function(){return r}});const i=48,o=57;function a(e){return!isNaN(e)&&i<=e&&e<=o}},4987:function(e,t,n){"use strict";function r(e){return e.map((e=>"number"==typeof e?"["+e.toString()+"]":"."+e)).join("")}n.d(t,{F:function(){return r}})},3492:function(e,t,n){"use strict";n.d(t,{D:function(){return i}});var r=n(6625);function i(e,t){const n=Object.create(null),i=new o(e),a=Math.floor(.4*e.length)+1;for(const e of t){const t=i.measure(e,a);void 0!==t&&(n[e]=t)}return Object.keys(n).sort(((e,t)=>{const i=n[e]-n[t];return 0!==i?i:(0,r.K)(e,t)}))}class o{constructor(e){this._input=e,this._inputLowerCase=e.toLowerCase(),this._inputArray=a(this._inputLowerCase),this._rows=[new Array(e.length+1).fill(0),new Array(e.length+1).fill(0),new Array(e.length+1).fill(0)]}measure(e,t){if(this._input===e)return 0;const n=e.toLowerCase();if(this._inputLowerCase===n)return 1;let r=a(n),i=this._inputArray;if(r.lengtht)return;const l=this._rows;for(let e=0;e<=s;e++)l[0][e]=e;for(let e=1;e<=o;e++){const n=l[(e-1)%3],o=l[e%3];let a=o[0]=e;for(let t=1;t<=s;t++){const s=r[e-1]===i[t-1]?0:1;let u=Math.min(n[t]+1,o[t-1]+1,n[t-1]+s);if(e>1&&t>1&&r[e-1]===i[t-2]&&r[e-2]===i[t-1]){const n=l[(e-2)%3][t-2];u=Math.min(u,n+1)}ut)return}const u=l[o%3][s];return u<=t?u:void 0}}function a(e){const t=e.length,n=new Array(t);for(let r=0;r0===t?e:e.slice(n))).slice(null!==(t=r)&&void 0!==t?t:0,i+1)}function o(e){let t=0;for(;t1&&i.slice(1).every((e=>0===e.length||(0,r.FD)(e.charCodeAt(0)))),s=n.endsWith('\\"""'),l=e.endsWith('"')&&!s,u=e.endsWith("\\"),c=l||u,d=!(null!=t&&t.minimize)&&(!o||e.length>70||c||a||s);let f="";const p=o&&(0,r.FD)(e.charCodeAt(0));return(d&&!p||a)&&(f+="\n"),f+=n,(d||c)&&(f+="\n"),'"""'+f+'"""'}},1117:function(e,t,n){"use strict";function r(e){return 9===e||32===e}function i(e){return e>=48&&e<=57}function o(e){return e>=97&&e<=122||e>=65&&e<=90}function a(e){return o(e)||95===e}function s(e){return o(e)||i(e)||95===e}n.d(t,{FD:function(){return r},HQ:function(){return s},LQ:function(){return a},X1:function(){return i}})},3140:function(e,t,n){"use strict";let r;n.d(t,{B:function(){return r}}),function(e){e.QUERY="QUERY",e.MUTATION="MUTATION",e.SUBSCRIPTION="SUBSCRIPTION",e.FIELD="FIELD",e.FRAGMENT_DEFINITION="FRAGMENT_DEFINITION",e.FRAGMENT_SPREAD="FRAGMENT_SPREAD",e.INLINE_FRAGMENT="INLINE_FRAGMENT",e.VARIABLE_DEFINITION="VARIABLE_DEFINITION",e.SCHEMA="SCHEMA",e.SCALAR="SCALAR",e.OBJECT="OBJECT",e.FIELD_DEFINITION="FIELD_DEFINITION",e.ARGUMENT_DEFINITION="ARGUMENT_DEFINITION",e.INTERFACE="INTERFACE",e.UNION="UNION",e.ENUM="ENUM",e.ENUM_VALUE="ENUM_VALUE",e.INPUT_OBJECT="INPUT_OBJECT",e.INPUT_FIELD_DEFINITION="INPUT_FIELD_DEFINITION"}(r||(r={}))},3830:function(e,t,n){"use strict";let r;n.d(t,{h:function(){return r}}),function(e){e.NAME="Name",e.DOCUMENT="Document",e.OPERATION_DEFINITION="OperationDefinition",e.VARIABLE_DEFINITION="VariableDefinition",e.SELECTION_SET="SelectionSet",e.FIELD="Field",e.ARGUMENT="Argument",e.FRAGMENT_SPREAD="FragmentSpread",e.INLINE_FRAGMENT="InlineFragment",e.FRAGMENT_DEFINITION="FragmentDefinition",e.VARIABLE="Variable",e.INT="IntValue",e.FLOAT="FloatValue",e.STRING="StringValue",e.BOOLEAN="BooleanValue",e.NULL="NullValue",e.ENUM="EnumValue",e.LIST="ListValue",e.OBJECT="ObjectValue",e.OBJECT_FIELD="ObjectField",e.DIRECTIVE="Directive",e.NAMED_TYPE="NamedType",e.LIST_TYPE="ListType",e.NON_NULL_TYPE="NonNullType",e.SCHEMA_DEFINITION="SchemaDefinition",e.OPERATION_TYPE_DEFINITION="OperationTypeDefinition",e.SCALAR_TYPE_DEFINITION="ScalarTypeDefinition",e.OBJECT_TYPE_DEFINITION="ObjectTypeDefinition",e.FIELD_DEFINITION="FieldDefinition",e.INPUT_VALUE_DEFINITION="InputValueDefinition",e.INTERFACE_TYPE_DEFINITION="InterfaceTypeDefinition",e.UNION_TYPE_DEFINITION="UnionTypeDefinition",e.ENUM_TYPE_DEFINITION="EnumTypeDefinition",e.ENUM_VALUE_DEFINITION="EnumValueDefinition",e.INPUT_OBJECT_TYPE_DEFINITION="InputObjectTypeDefinition",e.DIRECTIVE_DEFINITION="DirectiveDefinition",e.SCHEMA_EXTENSION="SchemaExtension",e.SCALAR_TYPE_EXTENSION="ScalarTypeExtension",e.OBJECT_TYPE_EXTENSION="ObjectTypeExtension",e.INTERFACE_TYPE_EXTENSION="InterfaceTypeExtension",e.UNION_TYPE_EXTENSION="UnionTypeExtension",e.ENUM_TYPE_EXTENSION="EnumTypeExtension",e.INPUT_OBJECT_TYPE_EXTENSION="InputObjectTypeExtension"}(r||(r={}))},9230:function(e,t,n){"use strict";n.d(t,{h:function(){return l},u:function(){return u}});var r=n(2024),i=n(3526),o=n(6303),a=n(1117),s=n(5685);class l{constructor(e){const t=new i.WU(s.T.SOF,0,0,0,0);this.source=e,this.lastToken=t,this.token=t,this.line=1,this.lineStart=0}get[Symbol.toStringTag](){return"Lexer"}advance(){return this.lastToken=this.token,this.token=this.lookahead()}lookahead(){let e=this.token;if(e.kind!==s.T.EOF)do{if(e.next)e=e.next;else{const t=g(this,e.end);e.next=t,t.prev=e,e=t}}while(e.kind===s.T.COMMENT);return e}}function u(e){return e===s.T.BANG||e===s.T.DOLLAR||e===s.T.AMP||e===s.T.PAREN_L||e===s.T.PAREN_R||e===s.T.SPREAD||e===s.T.COLON||e===s.T.EQUALS||e===s.T.AT||e===s.T.BRACKET_L||e===s.T.BRACKET_R||e===s.T.BRACE_L||e===s.T.PIPE||e===s.T.BRACE_R}function c(e){return e>=0&&e<=55295||e>=57344&&e<=1114111}function d(e,t){return f(e.charCodeAt(t))&&p(e.charCodeAt(t+1))}function f(e){return e>=55296&&e<=56319}function p(e){return e>=56320&&e<=57343}function h(e,t){const n=e.source.body.codePointAt(t);if(void 0===n)return s.T.EOF;if(n>=32&&n<=126){const e=String.fromCodePoint(n);return'"'===e?"'\"'":`"${e}"`}return"U+"+n.toString(16).toUpperCase().padStart(4,"0")}function m(e,t,n,r,o){const a=e.line,s=1+n-e.lineStart;return new i.WU(t,n,r,a,s,o)}function g(e,t){const n=e.source.body,i=n.length;let o=t;for(;o=48&&e<=57?e-48:e>=65&&e<=70?e-55:e>=97&&e<=102?e-87:-1}function x(e,t){const n=e.source.body;switch(n.charCodeAt(t+1)){case 34:return{value:'"',size:2};case 92:return{value:"\\",size:2};case 47:return{value:"/",size:2};case 98:return{value:"\b",size:2};case 102:return{value:"\f",size:2};case 110:return{value:"\n",size:2};case 114:return{value:"\r",size:2};case 116:return{value:"\t",size:2}}throw(0,r.h)(e.source,t,`Invalid character escape sequence: "${n.slice(t,t+2)}".`)}function k(e,t){const n=e.source.body,i=n.length;let a=e.lineStart,l=t+3,u=l,f="";const p=[];for(;l=t)break;n=a.index+a[0].length,o+=1}return{line:o,column:t+1-n}}},953:function(e,t,n){"use strict";n.d(t,{H2:function(){return d},Qc:function(){return c},gZ:function(){return p},tl:function(){return f}});var r=n(2024),i=n(3526),o=n(3140),a=n(3830),s=n(9230),l=n(4680),u=n(5685);function c(e,t){return new h(e,t).parseDocument()}function d(e,t){const n=new h(e,t);n.expectToken(u.T.SOF);const r=n.parseValueLiteral(!1);return n.expectToken(u.T.EOF),r}function f(e,t){const n=new h(e,t);n.expectToken(u.T.SOF);const r=n.parseConstValueLiteral();return n.expectToken(u.T.EOF),r}function p(e,t){const n=new h(e,t);n.expectToken(u.T.SOF);const r=n.parseTypeReference();return n.expectToken(u.T.EOF),r}class h{constructor(e,t){const n=(0,l.T)(e)?e:new l.H(e);this._lexer=new s.h(n),this._options=t}parseName(){const e=this.expectToken(u.T.NAME);return this.node(e,{kind:a.h.NAME,value:e.value})}parseDocument(){return this.node(this._lexer.token,{kind:a.h.DOCUMENT,definitions:this.many(u.T.SOF,this.parseDefinition,u.T.EOF)})}parseDefinition(){if(this.peek(u.T.BRACE_L))return this.parseOperationDefinition();const e=this.peekDescription(),t=e?this._lexer.lookahead():this._lexer.token;if(t.kind===u.T.NAME){switch(t.value){case"schema":return this.parseSchemaDefinition();case"scalar":return this.parseScalarTypeDefinition();case"type":return this.parseObjectTypeDefinition();case"interface":return this.parseInterfaceTypeDefinition();case"union":return this.parseUnionTypeDefinition();case"enum":return this.parseEnumTypeDefinition();case"input":return this.parseInputObjectTypeDefinition();case"directive":return this.parseDirectiveDefinition()}if(e)throw(0,r.h)(this._lexer.source,this._lexer.token.start,"Unexpected description, descriptions are supported only on type definitions.");switch(t.value){case"query":case"mutation":case"subscription":return this.parseOperationDefinition();case"fragment":return this.parseFragmentDefinition();case"extend":return this.parseTypeSystemExtension()}}throw this.unexpected(t)}parseOperationDefinition(){const e=this._lexer.token;if(this.peek(u.T.BRACE_L))return this.node(e,{kind:a.h.OPERATION_DEFINITION,operation:i.ku.QUERY,name:void 0,variableDefinitions:[],directives:[],selectionSet:this.parseSelectionSet()});const t=this.parseOperationType();let n;return this.peek(u.T.NAME)&&(n=this.parseName()),this.node(e,{kind:a.h.OPERATION_DEFINITION,operation:t,name:n,variableDefinitions:this.parseVariableDefinitions(),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet()})}parseOperationType(){const e=this.expectToken(u.T.NAME);switch(e.value){case"query":return i.ku.QUERY;case"mutation":return i.ku.MUTATION;case"subscription":return i.ku.SUBSCRIPTION}throw this.unexpected(e)}parseVariableDefinitions(){return this.optionalMany(u.T.PAREN_L,this.parseVariableDefinition,u.T.PAREN_R)}parseVariableDefinition(){return this.node(this._lexer.token,{kind:a.h.VARIABLE_DEFINITION,variable:this.parseVariable(),type:(this.expectToken(u.T.COLON),this.parseTypeReference()),defaultValue:this.expectOptionalToken(u.T.EQUALS)?this.parseConstValueLiteral():void 0,directives:this.parseConstDirectives()})}parseVariable(){const e=this._lexer.token;return this.expectToken(u.T.DOLLAR),this.node(e,{kind:a.h.VARIABLE,name:this.parseName()})}parseSelectionSet(){return this.node(this._lexer.token,{kind:a.h.SELECTION_SET,selections:this.many(u.T.BRACE_L,this.parseSelection,u.T.BRACE_R)})}parseSelection(){return this.peek(u.T.SPREAD)?this.parseFragment():this.parseField()}parseField(){const e=this._lexer.token,t=this.parseName();let n,r;return this.expectOptionalToken(u.T.COLON)?(n=t,r=this.parseName()):r=t,this.node(e,{kind:a.h.FIELD,alias:n,name:r,arguments:this.parseArguments(!1),directives:this.parseDirectives(!1),selectionSet:this.peek(u.T.BRACE_L)?this.parseSelectionSet():void 0})}parseArguments(e){const t=e?this.parseConstArgument:this.parseArgument;return this.optionalMany(u.T.PAREN_L,t,u.T.PAREN_R)}parseArgument(e=!1){const t=this._lexer.token,n=this.parseName();return this.expectToken(u.T.COLON),this.node(t,{kind:a.h.ARGUMENT,name:n,value:this.parseValueLiteral(e)})}parseConstArgument(){return this.parseArgument(!0)}parseFragment(){const e=this._lexer.token;this.expectToken(u.T.SPREAD);const t=this.expectOptionalKeyword("on");return!t&&this.peek(u.T.NAME)?this.node(e,{kind:a.h.FRAGMENT_SPREAD,name:this.parseFragmentName(),directives:this.parseDirectives(!1)}):this.node(e,{kind:a.h.INLINE_FRAGMENT,typeCondition:t?this.parseNamedType():void 0,directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet()})}parseFragmentDefinition(){var e;const t=this._lexer.token;return this.expectKeyword("fragment"),!0===(null===(e=this._options)||void 0===e?void 0:e.allowLegacyFragmentVariables)?this.node(t,{kind:a.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),variableDefinitions:this.parseVariableDefinitions(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet()}):this.node(t,{kind:a.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet()})}parseFragmentName(){if("on"===this._lexer.token.value)throw this.unexpected();return this.parseName()}parseValueLiteral(e){const t=this._lexer.token;switch(t.kind){case u.T.BRACKET_L:return this.parseList(e);case u.T.BRACE_L:return this.parseObject(e);case u.T.INT:return this._lexer.advance(),this.node(t,{kind:a.h.INT,value:t.value});case u.T.FLOAT:return this._lexer.advance(),this.node(t,{kind:a.h.FLOAT,value:t.value});case u.T.STRING:case u.T.BLOCK_STRING:return this.parseStringLiteral();case u.T.NAME:switch(this._lexer.advance(),t.value){case"true":return this.node(t,{kind:a.h.BOOLEAN,value:!0});case"false":return this.node(t,{kind:a.h.BOOLEAN,value:!1});case"null":return this.node(t,{kind:a.h.NULL});default:return this.node(t,{kind:a.h.ENUM,value:t.value})}case u.T.DOLLAR:if(e){if(this.expectToken(u.T.DOLLAR),this._lexer.token.kind===u.T.NAME){const e=this._lexer.token.value;throw(0,r.h)(this._lexer.source,t.start,`Unexpected variable "$${e}" in constant value.`)}throw this.unexpected(t)}return this.parseVariable();default:throw this.unexpected()}}parseConstValueLiteral(){return this.parseValueLiteral(!0)}parseStringLiteral(){const e=this._lexer.token;return this._lexer.advance(),this.node(e,{kind:a.h.STRING,value:e.value,block:e.kind===u.T.BLOCK_STRING})}parseList(e){return this.node(this._lexer.token,{kind:a.h.LIST,values:this.any(u.T.BRACKET_L,(()=>this.parseValueLiteral(e)),u.T.BRACKET_R)})}parseObject(e){return this.node(this._lexer.token,{kind:a.h.OBJECT,fields:this.any(u.T.BRACE_L,(()=>this.parseObjectField(e)),u.T.BRACE_R)})}parseObjectField(e){const t=this._lexer.token,n=this.parseName();return this.expectToken(u.T.COLON),this.node(t,{kind:a.h.OBJECT_FIELD,name:n,value:this.parseValueLiteral(e)})}parseDirectives(e){const t=[];for(;this.peek(u.T.AT);)t.push(this.parseDirective(e));return t}parseConstDirectives(){return this.parseDirectives(!0)}parseDirective(e){const t=this._lexer.token;return this.expectToken(u.T.AT),this.node(t,{kind:a.h.DIRECTIVE,name:this.parseName(),arguments:this.parseArguments(e)})}parseTypeReference(){const e=this._lexer.token;let t;if(this.expectOptionalToken(u.T.BRACKET_L)){const n=this.parseTypeReference();this.expectToken(u.T.BRACKET_R),t=this.node(e,{kind:a.h.LIST_TYPE,type:n})}else t=this.parseNamedType();return this.expectOptionalToken(u.T.BANG)?this.node(e,{kind:a.h.NON_NULL_TYPE,type:t}):t}parseNamedType(){return this.node(this._lexer.token,{kind:a.h.NAMED_TYPE,name:this.parseName()})}peekDescription(){return this.peek(u.T.STRING)||this.peek(u.T.BLOCK_STRING)}parseDescription(){if(this.peekDescription())return this.parseStringLiteral()}parseSchemaDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("schema");const n=this.parseConstDirectives(),r=this.many(u.T.BRACE_L,this.parseOperationTypeDefinition,u.T.BRACE_R);return this.node(e,{kind:a.h.SCHEMA_DEFINITION,description:t,directives:n,operationTypes:r})}parseOperationTypeDefinition(){const e=this._lexer.token,t=this.parseOperationType();this.expectToken(u.T.COLON);const n=this.parseNamedType();return this.node(e,{kind:a.h.OPERATION_TYPE_DEFINITION,operation:t,type:n})}parseScalarTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("scalar");const n=this.parseName(),r=this.parseConstDirectives();return this.node(e,{kind:a.h.SCALAR_TYPE_DEFINITION,description:t,name:n,directives:r})}parseObjectTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("type");const n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseConstDirectives(),o=this.parseFieldsDefinition();return this.node(e,{kind:a.h.OBJECT_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:o})}parseImplementsInterfaces(){return this.expectOptionalKeyword("implements")?this.delimitedMany(u.T.AMP,this.parseNamedType):[]}parseFieldsDefinition(){return this.optionalMany(u.T.BRACE_L,this.parseFieldDefinition,u.T.BRACE_R)}parseFieldDefinition(){const e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseArgumentDefs();this.expectToken(u.T.COLON);const i=this.parseTypeReference(),o=this.parseConstDirectives();return this.node(e,{kind:a.h.FIELD_DEFINITION,description:t,name:n,arguments:r,type:i,directives:o})}parseArgumentDefs(){return this.optionalMany(u.T.PAREN_L,this.parseInputValueDef,u.T.PAREN_R)}parseInputValueDef(){const e=this._lexer.token,t=this.parseDescription(),n=this.parseName();this.expectToken(u.T.COLON);const r=this.parseTypeReference();let i;this.expectOptionalToken(u.T.EQUALS)&&(i=this.parseConstValueLiteral());const o=this.parseConstDirectives();return this.node(e,{kind:a.h.INPUT_VALUE_DEFINITION,description:t,name:n,type:r,defaultValue:i,directives:o})}parseInterfaceTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("interface");const n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseConstDirectives(),o=this.parseFieldsDefinition();return this.node(e,{kind:a.h.INTERFACE_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:o})}parseUnionTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("union");const n=this.parseName(),r=this.parseConstDirectives(),i=this.parseUnionMemberTypes();return this.node(e,{kind:a.h.UNION_TYPE_DEFINITION,description:t,name:n,directives:r,types:i})}parseUnionMemberTypes(){return this.expectOptionalToken(u.T.EQUALS)?this.delimitedMany(u.T.PIPE,this.parseNamedType):[]}parseEnumTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("enum");const n=this.parseName(),r=this.parseConstDirectives(),i=this.parseEnumValuesDefinition();return this.node(e,{kind:a.h.ENUM_TYPE_DEFINITION,description:t,name:n,directives:r,values:i})}parseEnumValuesDefinition(){return this.optionalMany(u.T.BRACE_L,this.parseEnumValueDefinition,u.T.BRACE_R)}parseEnumValueDefinition(){const e=this._lexer.token,t=this.parseDescription(),n=this.parseEnumValueName(),r=this.parseConstDirectives();return this.node(e,{kind:a.h.ENUM_VALUE_DEFINITION,description:t,name:n,directives:r})}parseEnumValueName(){if("true"===this._lexer.token.value||"false"===this._lexer.token.value||"null"===this._lexer.token.value)throw(0,r.h)(this._lexer.source,this._lexer.token.start,`${m(this._lexer.token)} is reserved and cannot be used for an enum value.`);return this.parseName()}parseInputObjectTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("input");const n=this.parseName(),r=this.parseConstDirectives(),i=this.parseInputFieldsDefinition();return this.node(e,{kind:a.h.INPUT_OBJECT_TYPE_DEFINITION,description:t,name:n,directives:r,fields:i})}parseInputFieldsDefinition(){return this.optionalMany(u.T.BRACE_L,this.parseInputValueDef,u.T.BRACE_R)}parseTypeSystemExtension(){const e=this._lexer.lookahead();if(e.kind===u.T.NAME)switch(e.value){case"schema":return this.parseSchemaExtension();case"scalar":return this.parseScalarTypeExtension();case"type":return this.parseObjectTypeExtension();case"interface":return this.parseInterfaceTypeExtension();case"union":return this.parseUnionTypeExtension();case"enum":return this.parseEnumTypeExtension();case"input":return this.parseInputObjectTypeExtension()}throw this.unexpected(e)}parseSchemaExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("schema");const t=this.parseConstDirectives(),n=this.optionalMany(u.T.BRACE_L,this.parseOperationTypeDefinition,u.T.BRACE_R);if(0===t.length&&0===n.length)throw this.unexpected();return this.node(e,{kind:a.h.SCHEMA_EXTENSION,directives:t,operationTypes:n})}parseScalarTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("scalar");const t=this.parseName(),n=this.parseConstDirectives();if(0===n.length)throw this.unexpected();return this.node(e,{kind:a.h.SCALAR_TYPE_EXTENSION,name:t,directives:n})}parseObjectTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("type");const t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseConstDirectives(),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return this.node(e,{kind:a.h.OBJECT_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i})}parseInterfaceTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("interface");const t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseConstDirectives(),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return this.node(e,{kind:a.h.INTERFACE_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i})}parseUnionTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("union");const t=this.parseName(),n=this.parseConstDirectives(),r=this.parseUnionMemberTypes();if(0===n.length&&0===r.length)throw this.unexpected();return this.node(e,{kind:a.h.UNION_TYPE_EXTENSION,name:t,directives:n,types:r})}parseEnumTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("enum");const t=this.parseName(),n=this.parseConstDirectives(),r=this.parseEnumValuesDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return this.node(e,{kind:a.h.ENUM_TYPE_EXTENSION,name:t,directives:n,values:r})}parseInputObjectTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("input");const t=this.parseName(),n=this.parseConstDirectives(),r=this.parseInputFieldsDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return this.node(e,{kind:a.h.INPUT_OBJECT_TYPE_EXTENSION,name:t,directives:n,fields:r})}parseDirectiveDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("directive"),this.expectToken(u.T.AT);const n=this.parseName(),r=this.parseArgumentDefs(),i=this.expectOptionalKeyword("repeatable");this.expectKeyword("on");const o=this.parseDirectiveLocations();return this.node(e,{kind:a.h.DIRECTIVE_DEFINITION,description:t,name:n,arguments:r,repeatable:i,locations:o})}parseDirectiveLocations(){return this.delimitedMany(u.T.PIPE,this.parseDirectiveLocation)}parseDirectiveLocation(){const e=this._lexer.token,t=this.parseName();if(Object.prototype.hasOwnProperty.call(o.B,t.value))return t;throw this.unexpected(e)}node(e,t){var n;return!0!==(null===(n=this._options)||void 0===n?void 0:n.noLocation)&&(t.loc=new i.Ye(e,this._lexer.lastToken,this._lexer.source)),t}peek(e){return this._lexer.token.kind===e}expectToken(e){const t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t;throw(0,r.h)(this._lexer.source,t.start,`Expected ${g(e)}, found ${m(t)}.`)}expectOptionalToken(e){return this._lexer.token.kind===e&&(this._lexer.advance(),!0)}expectKeyword(e){const t=this._lexer.token;if(t.kind!==u.T.NAME||t.value!==e)throw(0,r.h)(this._lexer.source,t.start,`Expected "${e}", found ${m(t)}.`);this._lexer.advance()}expectOptionalKeyword(e){const t=this._lexer.token;return t.kind===u.T.NAME&&t.value===e&&(this._lexer.advance(),!0)}unexpected(e){const t=null!=e?e:this._lexer.token;return(0,r.h)(this._lexer.source,t.start,`Unexpected ${m(t)}.`)}any(e,t,n){this.expectToken(e);const r=[];for(;!this.expectOptionalToken(n);)r.push(t.call(this));return r}optionalMany(e,t,n){if(this.expectOptionalToken(e)){const e=[];do{e.push(t.call(this))}while(!this.expectOptionalToken(n));return e}return[]}many(e,t,n){this.expectToken(e);const r=[];do{r.push(t.call(this))}while(!this.expectOptionalToken(n));return r}delimitedMany(e,t){this.expectOptionalToken(e);const n=[];do{n.push(t.call(this))}while(this.expectOptionalToken(e));return n}}function m(e){const t=e.value;return g(e.kind)+(null!=t?` "${t}"`:"")}function g(e){return(0,s.u)(e)?`"${e}"`:e}},9615:function(e,t,n){"use strict";n.d(t,{D$:function(){return p},G4:function(){return c},Ir:function(){return i},Of:function(){return l},VB:function(){return u},Wk:function(){return o},aU:function(){return f},nr:function(){return s},pO:function(){return a},zT:function(){return d}});var r=n(3830);function i(e){return o(e)||c(e)||f(e)}function o(e){return e.kind===r.h.OPERATION_DEFINITION||e.kind===r.h.FRAGMENT_DEFINITION}function a(e){return e.kind===r.h.FIELD||e.kind===r.h.FRAGMENT_SPREAD||e.kind===r.h.INLINE_FRAGMENT}function s(e){return e.kind===r.h.VARIABLE||e.kind===r.h.INT||e.kind===r.h.FLOAT||e.kind===r.h.STRING||e.kind===r.h.BOOLEAN||e.kind===r.h.NULL||e.kind===r.h.ENUM||e.kind===r.h.LIST||e.kind===r.h.OBJECT}function l(e){return s(e)&&(e.kind===r.h.LIST?e.values.some(l):e.kind===r.h.OBJECT?e.fields.some((e=>l(e.value))):e.kind!==r.h.VARIABLE)}function u(e){return e.kind===r.h.NAMED_TYPE||e.kind===r.h.LIST_TYPE||e.kind===r.h.NON_NULL_TYPE}function c(e){return e.kind===r.h.SCHEMA_DEFINITION||d(e)||e.kind===r.h.DIRECTIVE_DEFINITION}function d(e){return e.kind===r.h.SCALAR_TYPE_DEFINITION||e.kind===r.h.OBJECT_TYPE_DEFINITION||e.kind===r.h.INTERFACE_TYPE_DEFINITION||e.kind===r.h.UNION_TYPE_DEFINITION||e.kind===r.h.ENUM_TYPE_DEFINITION||e.kind===r.h.INPUT_OBJECT_TYPE_DEFINITION}function f(e){return e.kind===r.h.SCHEMA_EXTENSION||p(e)}function p(e){return e.kind===r.h.SCALAR_TYPE_EXTENSION||e.kind===r.h.OBJECT_TYPE_EXTENSION||e.kind===r.h.INTERFACE_TYPE_EXTENSION||e.kind===r.h.UNION_TYPE_EXTENSION||e.kind===r.h.ENUM_TYPE_EXTENSION||e.kind===r.h.INPUT_OBJECT_TYPE_EXTENSION}},7026:function(e,t,n){"use strict";n.d(t,{Q:function(){return i},z:function(){return o}});var r=n(3302);function i(e){return o(e.source,(0,r.k)(e.source,e.start))}function o(e,t){const n=e.locationOffset.column-1,r="".padStart(n)+e.body,i=t.line-1,o=e.locationOffset.line-1,s=t.line+o,l=1===t.line?n:0,u=t.column+l,c=`${e.name}:${s}:${u}\n`,d=r.split(/\r\n|[\n\r]/g),f=d[i];if(f.length>120){const e=Math.floor(u/80),t=u%80,n=[];for(let e=0;e["|",e])),["|","^".padStart(t)],["|",n[e+1]]])}return c+a([[s-1+" |",d[i-1]],[`${s} |`,f],["|","^".padStart(u)],[`${s+1} |`,d[i+1]]])}function a(e){const t=e.filter((([e,t])=>void 0!==t)),n=Math.max(...t.map((([e])=>e.length)));return t.map((([e,t])=>e.padStart(n)+(t?" "+t:""))).join("\n")}},5895:function(e,t,n){"use strict";n.d(t,{S:function(){return l}});var r=n(6303);const i=/[\x00-\x1f\x22\x5c\x7f-\x9f]/g;function o(e){return a[e.charCodeAt(0)]}const a=["\\u0000","\\u0001","\\u0002","\\u0003","\\u0004","\\u0005","\\u0006","\\u0007","\\b","\\t","\\n","\\u000B","\\f","\\r","\\u000E","\\u000F","\\u0010","\\u0011","\\u0012","\\u0013","\\u0014","\\u0015","\\u0016","\\u0017","\\u0018","\\u0019","\\u001A","\\u001B","\\u001C","\\u001D","\\u001E","\\u001F","","",'\\"',"","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","\\\\","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","\\u007F","\\u0080","\\u0081","\\u0082","\\u0083","\\u0084","\\u0085","\\u0086","\\u0087","\\u0088","\\u0089","\\u008A","\\u008B","\\u008C","\\u008D","\\u008E","\\u008F","\\u0090","\\u0091","\\u0092","\\u0093","\\u0094","\\u0095","\\u0096","\\u0097","\\u0098","\\u0099","\\u009A","\\u009B","\\u009C","\\u009D","\\u009E","\\u009F"];var s=n(9685);function l(e){return(0,s.Vn)(e,u)}const u={Name:{leave:e=>e.value},Variable:{leave:e=>"$"+e.name},Document:{leave:e=>c(e.definitions,"\n\n")},OperationDefinition:{leave(e){const t=f("(",c(e.variableDefinitions,", "),")"),n=c([e.operation,c([e.name,t]),c(e.directives," ")]," ");return("query"===n?"":n+" ")+e.selectionSet}},VariableDefinition:{leave:({variable:e,type:t,defaultValue:n,directives:r})=>e+": "+t+f(" = ",n)+f(" ",c(r," "))},SelectionSet:{leave:({selections:e})=>d(e)},Field:{leave({alias:e,name:t,arguments:n,directives:r,selectionSet:i}){const o=f("",e,": ")+t;let a=o+f("(",c(n,", "),")");return a.length>80&&(a=o+f("(\n",p(c(n,"\n")),"\n)")),c([a,c(r," "),i]," ")}},Argument:{leave:({name:e,value:t})=>e+": "+t},FragmentSpread:{leave:({name:e,directives:t})=>"..."+e+f(" ",c(t," "))},InlineFragment:{leave:({typeCondition:e,directives:t,selectionSet:n})=>c(["...",f("on ",e),c(t," "),n]," ")},FragmentDefinition:{leave:({name:e,typeCondition:t,variableDefinitions:n,directives:r,selectionSet:i})=>`fragment ${e}${f("(",c(n,", "),")")} on ${t} ${f("",c(r," ")," ")}`+i},IntValue:{leave:({value:e})=>e},FloatValue:{leave:({value:e})=>e},StringValue:{leave:({value:e,block:t})=>t?(0,r.LZ)(e):`"${e.replace(i,o)}"`},BooleanValue:{leave:({value:e})=>e?"true":"false"},NullValue:{leave:()=>"null"},EnumValue:{leave:({value:e})=>e},ListValue:{leave:({values:e})=>"["+c(e,", ")+"]"},ObjectValue:{leave:({fields:e})=>"{"+c(e,", ")+"}"},ObjectField:{leave:({name:e,value:t})=>e+": "+t},Directive:{leave:({name:e,arguments:t})=>"@"+e+f("(",c(t,", "),")")},NamedType:{leave:({name:e})=>e},ListType:{leave:({type:e})=>"["+e+"]"},NonNullType:{leave:({type:e})=>e+"!"},SchemaDefinition:{leave:({description:e,directives:t,operationTypes:n})=>f("",e,"\n")+c(["schema",c(t," "),d(n)]," ")},OperationTypeDefinition:{leave:({operation:e,type:t})=>e+": "+t},ScalarTypeDefinition:{leave:({description:e,name:t,directives:n})=>f("",e,"\n")+c(["scalar",t,c(n," ")]," ")},ObjectTypeDefinition:{leave:({description:e,name:t,interfaces:n,directives:r,fields:i})=>f("",e,"\n")+c(["type",t,f("implements ",c(n," & ")),c(r," "),d(i)]," ")},FieldDefinition:{leave:({description:e,name:t,arguments:n,type:r,directives:i})=>f("",e,"\n")+t+(h(n)?f("(\n",p(c(n,"\n")),"\n)"):f("(",c(n,", "),")"))+": "+r+f(" ",c(i," "))},InputValueDefinition:{leave:({description:e,name:t,type:n,defaultValue:r,directives:i})=>f("",e,"\n")+c([t+": "+n,f("= ",r),c(i," ")]," ")},InterfaceTypeDefinition:{leave:({description:e,name:t,interfaces:n,directives:r,fields:i})=>f("",e,"\n")+c(["interface",t,f("implements ",c(n," & ")),c(r," "),d(i)]," ")},UnionTypeDefinition:{leave:({description:e,name:t,directives:n,types:r})=>f("",e,"\n")+c(["union",t,c(n," "),f("= ",c(r," | "))]," ")},EnumTypeDefinition:{leave:({description:e,name:t,directives:n,values:r})=>f("",e,"\n")+c(["enum",t,c(n," "),d(r)]," ")},EnumValueDefinition:{leave:({description:e,name:t,directives:n})=>f("",e,"\n")+c([t,c(n," ")]," ")},InputObjectTypeDefinition:{leave:({description:e,name:t,directives:n,fields:r})=>f("",e,"\n")+c(["input",t,c(n," "),d(r)]," ")},DirectiveDefinition:{leave:({description:e,name:t,arguments:n,repeatable:r,locations:i})=>f("",e,"\n")+"directive @"+t+(h(n)?f("(\n",p(c(n,"\n")),"\n)"):f("(",c(n,", "),")"))+(r?" repeatable":"")+" on "+c(i," | ")},SchemaExtension:{leave:({directives:e,operationTypes:t})=>c(["extend schema",c(e," "),d(t)]," ")},ScalarTypeExtension:{leave:({name:e,directives:t})=>c(["extend scalar",e,c(t," ")]," ")},ObjectTypeExtension:{leave:({name:e,interfaces:t,directives:n,fields:r})=>c(["extend type",e,f("implements ",c(t," & ")),c(n," "),d(r)]," ")},InterfaceTypeExtension:{leave:({name:e,interfaces:t,directives:n,fields:r})=>c(["extend interface",e,f("implements ",c(t," & ")),c(n," "),d(r)]," ")},UnionTypeExtension:{leave:({name:e,directives:t,types:n})=>c(["extend union",e,c(t," "),f("= ",c(n," | "))]," ")},EnumTypeExtension:{leave:({name:e,directives:t,values:n})=>c(["extend enum",e,c(t," "),d(n)]," ")},InputObjectTypeExtension:{leave:({name:e,directives:t,fields:n})=>c(["extend input",e,c(t," "),d(n)]," ")}};function c(e,t=""){var n;return null!==(n=null==e?void 0:e.filter((e=>e)).join(t))&&void 0!==n?n:""}function d(e){return f("{\n",p(c(e,"\n")),"\n}")}function f(e,t,n=""){return null!=t&&""!==t?e+t+n:""}function p(e){return f(" ",e.replace(/\n/g,"\n "))}function h(e){var t;return null!==(t=null==e?void 0:e.some((e=>e.includes("\n"))))&&void 0!==t&&t}},4680:function(e,t,n){"use strict";n.d(t,{H:function(){return a},T:function(){return s}});var r=n(1172),i=n(5648),o=n(1513);class a{constructor(e,t="GraphQL request",n={line:1,column:1}){"string"==typeof e||(0,r.a)(!1,`Body must be a string. Received: ${(0,i.X)(e)}.`),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||(0,r.a)(!1,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||(0,r.a)(!1,"column in locationOffset is 1-indexed and must be positive.")}get[Symbol.toStringTag](){return"Source"}}function s(e){return(0,o.n)(e,a)}},5685:function(e,t,n){"use strict";let r;n.d(t,{T:function(){return r}}),function(e){e.SOF="",e.EOF="",e.BANG="!",e.DOLLAR="$",e.AMP="&",e.PAREN_L="(",e.PAREN_R=")",e.SPREAD="...",e.COLON=":",e.EQUALS="=",e.AT="@",e.BRACKET_L="[",e.BRACKET_R="]",e.BRACE_L="{",e.PIPE="|",e.BRACE_R="}",e.NAME="Name",e.INT="Int",e.FLOAT="Float",e.STRING="String",e.BLOCK_STRING="BlockString",e.COMMENT="Comment"}(r||(r={}))},9685:function(e,t,n){"use strict";n.d(t,{$_:function(){return s},CK:function(){return d},Eu:function(){return c},Vn:function(){return l},j1:function(){return u}});var r=n(1172),i=n(5648),o=n(3526),a=n(3830);const s=Object.freeze({});function l(e,t,n=o.h8){const l=new Map;for(const e of Object.values(a.h))l.set(e,c(t,e));let u,d,f,p=Array.isArray(e),h=[e],m=-1,g=[],v=e;const y=[],b=[];do{m++;const e=m===h.length,a=e&&0!==g.length;if(e){if(d=0===b.length?void 0:y[y.length-1],v=f,f=b.pop(),a)if(p){v=v.slice();let e=0;for(const[t,n]of g){const r=t-e;null===n?(v.splice(r,1),e++):v[r]=n}}else{v=Object.defineProperties({},Object.getOwnPropertyDescriptors(v));for(const[e,t]of g)v[e]=t}m=u.index,h=u.keys,g=u.edits,p=u.inArray,u=u.prev}else if(f){if(d=p?m:h[m],v=f[d],null==v)continue;y.push(d)}let c;if(!Array.isArray(v)){var E,T;(0,o.UG)(v)||(0,r.a)(!1,`Invalid AST Node: ${(0,i.X)(v)}.`);const n=e?null===(E=l.get(v.kind))||void 0===E?void 0:E.leave:null===(T=l.get(v.kind))||void 0===T?void 0:T.enter;if(c=null==n?void 0:n.call(t,v,d,f,y,b),c===s)break;if(!1===c){if(!e){y.pop();continue}}else if(void 0!==c&&(g.push([d,c]),!e)){if(!(0,o.UG)(c)){y.pop();continue}v=c}}var w;void 0===c&&a&&g.push([d,v]),e?y.pop():(u={inArray:p,index:m,keys:h,edits:g,prev:u},p=Array.isArray(v),h=p?v:null!==(w=n[v.kind])&&void 0!==w?w:[],m=-1,g=[],f&&b.push(f),f=v)}while(void 0!==u);return 0!==g.length?g[g.length-1][1]:e}function u(e){const t=new Array(e.length).fill(null),n=Object.create(null);for(const r of Object.values(a.h)){let i=!1;const o=new Array(e.length).fill(void 0),a=new Array(e.length).fill(void 0);for(let t=0;tl((0,v.M)(e,t)),this.extensions=(0,p.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(s=e.extensionASTNodes)&&void 0!==s?s:[],null==e.specifiedByURL||"string"==typeof e.specifiedByURL||(0,r.a)(!1,`${this.name} must provide "specifiedByURL" as a string, but got: ${(0,a.X)(e.specifiedByURL)}.`),null==e.serialize||"function"==typeof e.serialize||(0,r.a)(!1,`${this.name} must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.`),e.parseLiteral&&("function"==typeof e.parseValue&&"function"==typeof e.parseLiteral||(0,r.a)(!1,`${this.name} must provide both "parseValue" and "parseLiteral" functions.`))}get[Symbol.toStringTag](){return"GraphQLScalarType"}toConfig(){return{name:this.name,description:this.description,specifiedByURL:this.specifiedByURL,serialize:this.serialize,parseValue:this.parseValue,parseLiteral:this.parseLiteral,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}class ae{constructor(e){var t;this.name=(0,y.i)(e.name),this.description=e.description,this.isTypeOf=e.isTypeOf,this.extensions=(0,p.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._fields=()=>le(e),this._interfaces=()=>se(e),null==e.isTypeOf||"function"==typeof e.isTypeOf||(0,r.a)(!1,`${this.name} must provide "isTypeOf" as a function, but got: ${(0,a.X)(e.isTypeOf)}.`)}get[Symbol.toStringTag](){return"GraphQLObjectType"}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}getInterfaces(){return"function"==typeof this._interfaces&&(this._interfaces=this._interfaces()),this._interfaces}toConfig(){return{name:this.name,description:this.description,interfaces:this.getInterfaces(),fields:de(this.getFields()),isTypeOf:this.isTypeOf,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function se(e){var t;const n=re(null!==(t=e.interfaces)&&void 0!==t?t:[]);return Array.isArray(n)||(0,r.a)(!1,`${e.name} interfaces must be an Array or a function which returns an Array.`),n}function le(e){const t=ie(e.fields);return ce(t)||(0,r.a)(!1,`${e.name} fields must be an object with field names as keys or a function which returns such an object.`),(0,d.j)(t,((t,n)=>{var i;ce(t)||(0,r.a)(!1,`${e.name}.${n} field config must be an object.`),null==t.resolve||"function"==typeof t.resolve||(0,r.a)(!1,`${e.name}.${n} field resolver must be a function if provided, but got: ${(0,a.X)(t.resolve)}.`);const o=null!==(i=t.args)&&void 0!==i?i:{};return ce(o)||(0,r.a)(!1,`${e.name}.${n} args must be an object with argument names as keys.`),{name:(0,y.i)(n),description:t.description,type:t.type,args:ue(o),resolve:t.resolve,subscribe:t.subscribe,deprecationReason:t.deprecationReason,extensions:(0,p.u)(t.extensions),astNode:t.astNode}}))}function ue(e){return Object.entries(e).map((([e,t])=>({name:(0,y.i)(e),description:t.description,type:t.type,defaultValue:t.defaultValue,deprecationReason:t.deprecationReason,extensions:(0,p.u)(t.extensions),astNode:t.astNode})))}function ce(e){return(0,l.y)(e)&&!Array.isArray(e)}function de(e){return(0,d.j)(e,(e=>({description:e.description,type:e.type,args:fe(e.args),resolve:e.resolve,subscribe:e.subscribe,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})))}function fe(e){return(0,c.w)(e,(e=>e.name),(e=>({description:e.description,type:e.type,defaultValue:e.defaultValue,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})))}function pe(e){return R(e.type)&&void 0===e.defaultValue}class he{constructor(e){var t;this.name=(0,y.i)(e.name),this.description=e.description,this.resolveType=e.resolveType,this.extensions=(0,p.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._fields=le.bind(void 0,e),this._interfaces=se.bind(void 0,e),null==e.resolveType||"function"==typeof e.resolveType||(0,r.a)(!1,`${this.name} must provide "resolveType" as a function, but got: ${(0,a.X)(e.resolveType)}.`)}get[Symbol.toStringTag](){return"GraphQLInterfaceType"}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}getInterfaces(){return"function"==typeof this._interfaces&&(this._interfaces=this._interfaces()),this._interfaces}toConfig(){return{name:this.name,description:this.description,interfaces:this.getInterfaces(),fields:de(this.getFields()),resolveType:this.resolveType,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}class me{constructor(e){var t;this.name=(0,y.i)(e.name),this.description=e.description,this.resolveType=e.resolveType,this.extensions=(0,p.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._types=ge.bind(void 0,e),null==e.resolveType||"function"==typeof e.resolveType||(0,r.a)(!1,`${this.name} must provide "resolveType" as a function, but got: ${(0,a.X)(e.resolveType)}.`)}get[Symbol.toStringTag](){return"GraphQLUnionType"}getTypes(){return"function"==typeof this._types&&(this._types=this._types()),this._types}toConfig(){return{name:this.name,description:this.description,types:this.getTypes(),resolveType:this.resolveType,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function ge(e){const t=re(e.types);return Array.isArray(t)||(0,r.a)(!1,`Must provide Array of types or a function which returns such an array for Union ${e.name}.`),t}class ve{constructor(e){var t,n,i;this.name=(0,y.i)(e.name),this.description=e.description,this.extensions=(0,p.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._values=(n=this.name,ce(i=e.values)||(0,r.a)(!1,`${n} values must be an object with value names as keys.`),Object.entries(i).map((([e,t])=>(ce(t)||(0,r.a)(!1,`${n}.${e} must refer to an object with a "value" key representing an internal value but got: ${(0,a.X)(t)}.`),{name:(0,y.g)(e),description:t.description,value:void 0!==t.value?t.value:e,deprecationReason:t.deprecationReason,extensions:(0,p.u)(t.extensions),astNode:t.astNode})))),this._valueLookup=new Map(this._values.map((e=>[e.value,e]))),this._nameLookup=(0,u.P)(this._values,(e=>e.name))}get[Symbol.toStringTag](){return"GraphQLEnumType"}getValues(){return this._values}getValue(e){return this._nameLookup[e]}serialize(e){const t=this._valueLookup.get(e);if(void 0===t)throw new h.__(`Enum "${this.name}" cannot represent value: ${(0,a.X)(e)}`);return t.name}parseValue(e){if("string"!=typeof e){const t=(0,a.X)(e);throw new h.__(`Enum "${this.name}" cannot represent non-string value: ${t}.`+ye(this,t))}const t=this.getValue(e);if(null==t)throw new h.__(`Value "${e}" does not exist in "${this.name}" enum.`+ye(this,e));return t.value}parseLiteral(e,t){if(e.kind!==m.h.ENUM){const t=(0,g.S)(e);throw new h.__(`Enum "${this.name}" cannot represent non-enum value: ${t}.`+ye(this,t),{nodes:e})}const n=this.getValue(e.value);if(null==n){const t=(0,g.S)(e);throw new h.__(`Value "${t}" does not exist in "${this.name}" enum.`+ye(this,t),{nodes:e})}return n.value}toConfig(){const e=(0,c.w)(this.getValues(),(e=>e.name),(e=>({description:e.description,value:e.value,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})));return{name:this.name,description:this.description,values:e,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function ye(e,t){const n=e.getValues().map((e=>e.name)),r=(0,f.D)(t,n);return(0,i.l)("the enum value",r)}class be{constructor(e){var t;this.name=(0,y.i)(e.name),this.description=e.description,this.extensions=(0,p.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._fields=Ee.bind(void 0,e)}get[Symbol.toStringTag](){return"GraphQLInputObjectType"}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}toConfig(){const e=(0,d.j)(this.getFields(),(e=>({description:e.description,type:e.type,defaultValue:e.defaultValue,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})));return{name:this.name,description:this.description,fields:e,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes}}toString(){return this.name}toJSON(){return this.toString()}}function Ee(e){const t=ie(e.fields);return ce(t)||(0,r.a)(!1,`${e.name} fields must be an object with field names as keys or a function which returns such an object.`),(0,d.j)(t,((t,n)=>(!("resolve"in t)||(0,r.a)(!1,`${e.name}.${n} field has a resolve property, but Input Types cannot define resolvers.`),{name:(0,y.i)(n),description:t.description,type:t.type,defaultValue:t.defaultValue,deprecationReason:t.deprecationReason,extensions:(0,p.u)(t.extensions),astNode:t.astNode})))}function Te(e){return R(e.type)&&void 0===e.defaultValue}},5946:function(e,t,n){"use strict";n.d(t,{CO:function(){return p},NZ:function(){return h},QE:function(){return g},SY:function(){return v},V4:function(){return E},Yf:function(){return m},df:function(){return b},fg:function(){return y},wX:function(){return f},xg:function(){return T}});var r=n(1172),i=n(5648),o=n(1513),a=n(1315),s=n(1140),l=n(3140),u=n(3228),c=n(755),d=n(1774);function f(e){return(0,o.n)(e,h)}function p(e){if(!f(e))throw new Error(`Expected ${(0,i.X)(e)} to be a GraphQL directive.`);return e}class h{constructor(e){var t,n;this.name=(0,u.i)(e.name),this.description=e.description,this.locations=e.locations,this.isRepeatable=null!==(t=e.isRepeatable)&&void 0!==t&&t,this.extensions=(0,s.u)(e.extensions),this.astNode=e.astNode,Array.isArray(e.locations)||(0,r.a)(!1,`@${e.name} locations must be an Array.`);const i=null!==(n=e.args)&&void 0!==n?n:{};(0,a.y)(i)&&!Array.isArray(i)||(0,r.a)(!1,`@${e.name} args must be an object with argument names as keys.`),this.args=(0,c.WO)(i)}get[Symbol.toStringTag](){return"GraphQLDirective"}toConfig(){return{name:this.name,description:this.description,locations:this.locations,args:(0,c.DM)(this.args),isRepeatable:this.isRepeatable,extensions:this.extensions,astNode:this.astNode}}toString(){return"@"+this.name}toJSON(){return this.toString()}}const m=new h({name:"include",description:"Directs the executor to include this field or fragment only when the `if` argument is true.",locations:[l.B.FIELD,l.B.FRAGMENT_SPREAD,l.B.INLINE_FRAGMENT],args:{if:{type:new c.bM(d.EZ),description:"Included when true."}}}),g=new h({name:"skip",description:"Directs the executor to skip this field or fragment when the `if` argument is true.",locations:[l.B.FIELD,l.B.FRAGMENT_SPREAD,l.B.INLINE_FRAGMENT],args:{if:{type:new c.bM(d.EZ),description:"Skipped when true."}}}),v="No longer supported",y=new h({name:"deprecated",description:"Marks an element of a GraphQL schema as no longer supported.",locations:[l.B.FIELD_DEFINITION,l.B.ARGUMENT_DEFINITION,l.B.INPUT_FIELD_DEFINITION,l.B.ENUM_VALUE],args:{reason:{type:d.kH,description:"Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).",defaultValue:v}}}),b=new h({name:"specifiedBy",description:"Exposes a URL that specifies the behavior of this scalar.",locations:[l.B.SCALAR],args:{url:{type:new c.bM(d.kH),description:"The URL that specifies the behavior of this scalar."}}}),E=Object.freeze([m,g,y,b]);function T(e){return E.some((({name:t})=>t===e.name))}},8078:function(e,t,n){"use strict";n.d(t,{Az:function(){return b},PX:function(){return y},TK:function(){return c},XQ:function(){return m},e_:function(){return h},hU:function(){return T},jT:function(){return g},l3:function(){return d},nL:function(){return w},qz:function(){return p},s9:function(){return C},tF:function(){return E},x2:function(){return f},zU:function(){return v}});var r=n(5648),i=n(5052),o=n(3140),a=n(5895),s=n(3190),l=n(755),u=n(1774);const c=new l.h6({name:"__Schema",description:"A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.",fields:()=>({description:{type:u.kH,resolve:e=>e.description},types:{description:"A list of all types supported by this server.",type:new l.bM(new l.p2(new l.bM(p))),resolve(e){return Object.values(e.getTypeMap())}},queryType:{description:"The type that query operations will be rooted at.",type:new l.bM(p),resolve:e=>e.getQueryType()},mutationType:{description:"If this server supports mutation, the type that mutation operations will be rooted at.",type:p,resolve:e=>e.getMutationType()},subscriptionType:{description:"If this server support subscription, the type that subscription operations will be rooted at.",type:p,resolve:e=>e.getSubscriptionType()},directives:{description:"A list of all directives supported by this server.",type:new l.bM(new l.p2(new l.bM(d))),resolve:e=>e.getDirectives()}})}),d=new l.h6({name:"__Directive",description:"A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.",fields:()=>({name:{type:new l.bM(u.kH),resolve:e=>e.name},description:{type:u.kH,resolve:e=>e.description},isRepeatable:{type:new l.bM(u.EZ),resolve:e=>e.isRepeatable},locations:{type:new l.bM(new l.p2(new l.bM(f))),resolve:e=>e.locations},args:{type:new l.bM(new l.p2(new l.bM(m))),args:{includeDeprecated:{type:u.EZ,defaultValue:!1}},resolve(e,{includeDeprecated:t}){return t?e.args:e.args.filter((e=>null==e.deprecationReason))}}})}),f=new l.mR({name:"__DirectiveLocation",description:"A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.",values:{QUERY:{value:o.B.QUERY,description:"Location adjacent to a query operation."},MUTATION:{value:o.B.MUTATION,description:"Location adjacent to a mutation operation."},SUBSCRIPTION:{value:o.B.SUBSCRIPTION,description:"Location adjacent to a subscription operation."},FIELD:{value:o.B.FIELD,description:"Location adjacent to a field."},FRAGMENT_DEFINITION:{value:o.B.FRAGMENT_DEFINITION,description:"Location adjacent to a fragment definition."},FRAGMENT_SPREAD:{value:o.B.FRAGMENT_SPREAD,description:"Location adjacent to a fragment spread."},INLINE_FRAGMENT:{value:o.B.INLINE_FRAGMENT,description:"Location adjacent to an inline fragment."},VARIABLE_DEFINITION:{value:o.B.VARIABLE_DEFINITION,description:"Location adjacent to a variable definition."},SCHEMA:{value:o.B.SCHEMA,description:"Location adjacent to a schema definition."},SCALAR:{value:o.B.SCALAR,description:"Location adjacent to a scalar definition."},OBJECT:{value:o.B.OBJECT,description:"Location adjacent to an object type definition."},FIELD_DEFINITION:{value:o.B.FIELD_DEFINITION,description:"Location adjacent to a field definition."},ARGUMENT_DEFINITION:{value:o.B.ARGUMENT_DEFINITION,description:"Location adjacent to an argument definition."},INTERFACE:{value:o.B.INTERFACE,description:"Location adjacent to an interface definition."},UNION:{value:o.B.UNION,description:"Location adjacent to a union definition."},ENUM:{value:o.B.ENUM,description:"Location adjacent to an enum definition."},ENUM_VALUE:{value:o.B.ENUM_VALUE,description:"Location adjacent to an enum value definition."},INPUT_OBJECT:{value:o.B.INPUT_OBJECT,description:"Location adjacent to an input object type definition."},INPUT_FIELD_DEFINITION:{value:o.B.INPUT_FIELD_DEFINITION,description:"Location adjacent to an input object field definition."}}}),p=new l.h6({name:"__Type",description:"The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional `specifiedByURL`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.",fields:()=>({kind:{type:new l.bM(y),resolve(e){return(0,l.KA)(e)?v.SCALAR:(0,l.lp)(e)?v.OBJECT:(0,l.oT)(e)?v.INTERFACE:(0,l.EN)(e)?v.UNION:(0,l.EM)(e)?v.ENUM:(0,l.hL)(e)?v.INPUT_OBJECT:(0,l.HG)(e)?v.LIST:(0,l.zM)(e)?v.NON_NULL:void(0,i.k)(!1,`Unexpected type: "${(0,r.X)(e)}".`)}},name:{type:u.kH,resolve:e=>"name"in e?e.name:void 0},description:{type:u.kH,resolve:e=>"description"in e?e.description:void 0},specifiedByURL:{type:u.kH,resolve:e=>"specifiedByURL"in e?e.specifiedByURL:void 0},fields:{type:new l.p2(new l.bM(h)),args:{includeDeprecated:{type:u.EZ,defaultValue:!1}},resolve(e,{includeDeprecated:t}){if((0,l.lp)(e)||(0,l.oT)(e)){const n=Object.values(e.getFields());return t?n:n.filter((e=>null==e.deprecationReason))}}},interfaces:{type:new l.p2(new l.bM(p)),resolve(e){if((0,l.lp)(e)||(0,l.oT)(e))return e.getInterfaces()}},possibleTypes:{type:new l.p2(new l.bM(p)),resolve(e,t,n,{schema:r}){if((0,l.m0)(e))return r.getPossibleTypes(e)}},enumValues:{type:new l.p2(new l.bM(g)),args:{includeDeprecated:{type:u.EZ,defaultValue:!1}},resolve(e,{includeDeprecated:t}){if((0,l.EM)(e)){const n=e.getValues();return t?n:n.filter((e=>null==e.deprecationReason))}}},inputFields:{type:new l.p2(new l.bM(m)),args:{includeDeprecated:{type:u.EZ,defaultValue:!1}},resolve(e,{includeDeprecated:t}){if((0,l.hL)(e)){const n=Object.values(e.getFields());return t?n:n.filter((e=>null==e.deprecationReason))}}},ofType:{type:p,resolve:e=>"ofType"in e?e.ofType:void 0}})}),h=new l.h6({name:"__Field",description:"Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.",fields:()=>({name:{type:new l.bM(u.kH),resolve:e=>e.name},description:{type:u.kH,resolve:e=>e.description},args:{type:new l.bM(new l.p2(new l.bM(m))),args:{includeDeprecated:{type:u.EZ,defaultValue:!1}},resolve(e,{includeDeprecated:t}){return t?e.args:e.args.filter((e=>null==e.deprecationReason))}},type:{type:new l.bM(p),resolve:e=>e.type},isDeprecated:{type:new l.bM(u.EZ),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:u.kH,resolve:e=>e.deprecationReason}})}),m=new l.h6({name:"__InputValue",description:"Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.",fields:()=>({name:{type:new l.bM(u.kH),resolve:e=>e.name},description:{type:u.kH,resolve:e=>e.description},type:{type:new l.bM(p),resolve:e=>e.type},defaultValue:{type:u.kH,description:"A GraphQL-formatted string representing the default value for this input value.",resolve(e){const{type:t,defaultValue:n}=e,r=(0,s.J)(n,t);return r?(0,a.S)(r):null}},isDeprecated:{type:new l.bM(u.EZ),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:u.kH,resolve:e=>e.deprecationReason}})}),g=new l.h6({name:"__EnumValue",description:"One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.",fields:()=>({name:{type:new l.bM(u.kH),resolve:e=>e.name},description:{type:u.kH,resolve:e=>e.description},isDeprecated:{type:new l.bM(u.EZ),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:u.kH,resolve:e=>e.deprecationReason}})});let v;!function(e){e.SCALAR="SCALAR",e.OBJECT="OBJECT",e.INTERFACE="INTERFACE",e.UNION="UNION",e.ENUM="ENUM",e.INPUT_OBJECT="INPUT_OBJECT",e.LIST="LIST",e.NON_NULL="NON_NULL"}(v||(v={}));const y=new l.mR({name:"__TypeKind",description:"An enum describing what kind of type a given `__Type` is.",values:{SCALAR:{value:v.SCALAR,description:"Indicates this type is a scalar."},OBJECT:{value:v.OBJECT,description:"Indicates this type is an object. `fields` and `interfaces` are valid fields."},INTERFACE:{value:v.INTERFACE,description:"Indicates this type is an interface. `fields`, `interfaces`, and `possibleTypes` are valid fields."},UNION:{value:v.UNION,description:"Indicates this type is a union. `possibleTypes` is a valid field."},ENUM:{value:v.ENUM,description:"Indicates this type is an enum. `enumValues` is a valid field."},INPUT_OBJECT:{value:v.INPUT_OBJECT,description:"Indicates this type is an input object. `inputFields` is a valid field."},LIST:{value:v.LIST,description:"Indicates this type is a list. `ofType` is a valid field."},NON_NULL:{value:v.NON_NULL,description:"Indicates this type is a non-null. `ofType` is a valid field."}}}),b={name:"__schema",type:new l.bM(c),description:"Access the current type schema of this server.",args:[],resolve:(e,t,n,{schema:r})=>r,deprecationReason:void 0,extensions:Object.create(null),astNode:void 0},E={name:"__type",type:p,description:"Request the type information of a single type.",args:[{name:"name",description:void 0,type:new l.bM(u.kH),defaultValue:void 0,deprecationReason:void 0,extensions:Object.create(null),astNode:void 0}],resolve:(e,{name:t},n,{schema:r})=>r.getType(t),deprecationReason:void 0,extensions:Object.create(null),astNode:void 0},T={name:"__typename",type:new l.bM(u.kH),description:"The name of the current Object type at runtime.",args:[],resolve:(e,t,n,{parentType:r})=>r.name,deprecationReason:void 0,extensions:Object.create(null),astNode:void 0},w=Object.freeze([c,d,f,p,h,m,g,y]);function C(e){return w.some((({name:t})=>e.name===t))}},1774:function(e,t,n){"use strict";n.d(t,{EZ:function(){return h},HI:function(){return u},HS:function(){return g},_o:function(){return d},av:function(){return f},kH:function(){return p},km:function(){return m},st:function(){return c},u1:function(){return v}});var r=n(5648),i=n(1315),o=n(4117),a=n(3830),s=n(5895),l=n(755);const u=2147483647,c=-2147483648,d=new l.n2({name:"Int",description:"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",serialize(e){const t=y(e);if("boolean"==typeof t)return t?1:0;let n=t;if("string"==typeof t&&""!==t&&(n=Number(t)),"number"!=typeof n||!Number.isInteger(n))throw new o.__(`Int cannot represent non-integer value: ${(0,r.X)(t)}`);if(n>u||nu||eu||te.name===t))}function y(e){if((0,i.y)(e)){if("function"==typeof e.valueOf){const t=e.valueOf();if(!(0,i.y)(t))return t}if("function"==typeof e.toJSON)return e.toJSON()}return e}},773:function(e,t,n){"use strict";n.d(t,{EO:function(){return p},XO:function(){return h},nN:function(){return f}});var r=n(1172),i=n(5648),o=n(1513),a=n(1315),s=n(1140),l=n(3526),u=n(755),c=n(5946),d=n(8078);function f(e){return(0,o.n)(e,h)}function p(e){if(!f(e))throw new Error(`Expected ${(0,i.X)(e)} to be a GraphQL schema.`);return e}class h{constructor(e){var t,n;this.__validationErrors=!0===e.assumeValid?[]:void 0,(0,a.y)(e)||(0,r.a)(!1,"Must provide configuration object."),!e.types||Array.isArray(e.types)||(0,r.a)(!1,`"types" must be Array if provided but got: ${(0,i.X)(e.types)}.`),!e.directives||Array.isArray(e.directives)||(0,r.a)(!1,`"directives" must be Array if provided but got: ${(0,i.X)(e.directives)}.`),this.description=e.description,this.extensions=(0,s.u)(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=null!==(t=e.extensionASTNodes)&&void 0!==t?t:[],this._queryType=e.query,this._mutationType=e.mutation,this._subscriptionType=e.subscription,this._directives=null!==(n=e.directives)&&void 0!==n?n:c.V4;const o=new Set(e.types);if(null!=e.types)for(const t of e.types)o.delete(t),m(t,o);null!=this._queryType&&m(this._queryType,o),null!=this._mutationType&&m(this._mutationType,o),null!=this._subscriptionType&&m(this._subscriptionType,o);for(const e of this._directives)if((0,c.wX)(e))for(const t of e.args)m(t.type,o);m(d.TK,o),this._typeMap=Object.create(null),this._subTypeMap=Object.create(null),this._implementationsMap=Object.create(null);for(const e of o){if(null==e)continue;const t=e.name;if(t||(0,r.a)(!1,"One of the provided types for building the Schema is missing a name."),void 0!==this._typeMap[t])throw new Error(`Schema must contain uniquely named types but contains multiple types named "${t}".`);if(this._typeMap[t]=e,(0,u.oT)(e)){for(const t of e.getInterfaces())if((0,u.oT)(t)){let n=this._implementationsMap[t.name];void 0===n&&(n=this._implementationsMap[t.name]={objects:[],interfaces:[]}),n.interfaces.push(e)}}else if((0,u.lp)(e))for(const t of e.getInterfaces())if((0,u.oT)(t)){let n=this._implementationsMap[t.name];void 0===n&&(n=this._implementationsMap[t.name]={objects:[],interfaces:[]}),n.objects.push(e)}}}get[Symbol.toStringTag](){return"GraphQLSchema"}getQueryType(){return this._queryType}getMutationType(){return this._mutationType}getSubscriptionType(){return this._subscriptionType}getRootType(e){switch(e){case l.ku.QUERY:return this.getQueryType();case l.ku.MUTATION:return this.getMutationType();case l.ku.SUBSCRIPTION:return this.getSubscriptionType()}}getTypeMap(){return this._typeMap}getType(e){return this.getTypeMap()[e]}getPossibleTypes(e){return(0,u.EN)(e)?e.getTypes():this.getImplementations(e).objects}getImplementations(e){const t=this._implementationsMap[e.name];return null!=t?t:{objects:[],interfaces:[]}}isSubType(e,t){let n=this._subTypeMap[e.name];if(void 0===n){if(n=Object.create(null),(0,u.EN)(e))for(const t of e.getTypes())n[t.name]=!0;else{const t=this.getImplementations(e);for(const e of t.objects)n[e.name]=!0;for(const e of t.interfaces)n[e.name]=!0}this._subTypeMap[e.name]=n}return void 0!==n[t.name]}getDirectives(){return this._directives}getDirective(e){return this.getDirectives().find((t=>t.name===e))}toConfig(){return{description:this.description,query:this.getQueryType(),mutation:this.getMutationType(),subscription:this.getSubscriptionType(),types:Object.values(this.getTypeMap()),directives:this.getDirectives(),extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes,assumeValid:void 0!==this.__validationErrors}}}function m(e,t){const n=(0,u.xC)(e);if(!t.has(n))if(t.add(n),(0,u.EN)(n))for(const e of n.getTypes())m(e,t);else if((0,u.lp)(n)||(0,u.oT)(n)){for(const e of n.getInterfaces())m(e,t);for(const e of Object.values(n.getFields())){m(e.type,t);for(const n of e.args)m(n.type,t)}}else if((0,u.hL)(n))for(const e of Object.values(n.getFields()))m(e.type,t);return t}},8555:function(e,t,n){"use strict";n.d(t,{F:function(){return d},J:function(){return f}});var r=n(5648),i=n(4117),o=n(3526),a=n(2984),s=n(755),l=n(5946),u=n(8078),c=n(773);function d(e){if((0,c.EO)(e),e.__validationErrors)return e.__validationErrors;const t=new p(e);!function(e){const t=e.schema,n=t.getQueryType();if(n){if(!(0,s.lp)(n)){var i;e.reportError(`Query root type must be Object type, it cannot be ${(0,r.X)(n)}.`,null!==(i=h(t,o.ku.QUERY))&&void 0!==i?i:n.astNode)}}else e.reportError("Query root type must be provided.",t.astNode);const a=t.getMutationType();var l;a&&!(0,s.lp)(a)&&e.reportError(`Mutation root type must be Object type if provided, it cannot be ${(0,r.X)(a)}.`,null!==(l=h(t,o.ku.MUTATION))&&void 0!==l?l:a.astNode);const u=t.getSubscriptionType();var c;u&&!(0,s.lp)(u)&&e.reportError(`Subscription root type must be Object type if provided, it cannot be ${(0,r.X)(u)}.`,null!==(c=h(t,o.ku.SUBSCRIPTION))&&void 0!==c?c:u.astNode)}(t),function(e){for(const n of e.schema.getDirectives())if((0,l.wX)(n)){m(e,n);for(const i of n.args){var t;m(e,i),(0,s.j$)(i.type)||e.reportError(`The type of @${n.name}(${i.name}:) must be Input Type but got: ${(0,r.X)(i.type)}.`,i.astNode),(0,s.dK)(i)&&null!=i.deprecationReason&&e.reportError(`Required argument @${n.name}(${i.name}:) cannot be deprecated.`,[x(i.astNode),null===(t=i.astNode)||void 0===t?void 0:t.type])}}else e.reportError(`Expected directive but got: ${(0,r.X)(n)}.`,null==n?void 0:n.astNode)}(t),function(e){const t=function(e){const t=Object.create(null),n=[],r=Object.create(null);return function i(o){if(t[o.name])return;t[o.name]=!0,r[o.name]=n.length;const a=Object.values(o.getFields());for(const t of a)if((0,s.zM)(t.type)&&(0,s.hL)(t.type.ofType)){const o=t.type.ofType,a=r[o.name];if(n.push(t),void 0===a)i(o);else{const t=n.slice(a),r=t.map((e=>e.name)).join(".");e.reportError(`Cannot reference Input Object "${o.name}" within itself through a series of non-null fields: "${r}".`,t.map((e=>e.astNode)))}n.pop()}r[o.name]=void 0}}(e),n=e.schema.getTypeMap();for(const i of Object.values(n))(0,s.Zs)(i)?((0,u.s9)(i)||m(e,i),(0,s.lp)(i)||(0,s.oT)(i)?(g(e,i),v(e,i)):(0,s.EN)(i)?E(e,i):(0,s.EM)(i)?T(e,i):(0,s.hL)(i)&&(w(e,i),t(i))):e.reportError(`Expected GraphQL named type but got: ${(0,r.X)(i)}.`,i.astNode)}(t);const n=t.getErrors();return e.__validationErrors=n,n}function f(e){const t=d(e);if(0!==t.length)throw new Error(t.map((e=>e.message)).join("\n\n"))}class p{constructor(e){this._errors=[],this.schema=e}reportError(e,t){const n=Array.isArray(t)?t.filter(Boolean):t;this._errors.push(new i.__(e,{nodes:n}))}getErrors(){return this._errors}}function h(e,t){var n;return null===(n=[e.astNode,...e.extensionASTNodes].flatMap((e=>{var t;return null!==(t=null==e?void 0:e.operationTypes)&&void 0!==t?t:[]})).find((e=>e.operation===t)))||void 0===n?void 0:n.type}function m(e,t){t.name.startsWith("__")&&e.reportError(`Name "${t.name}" must not begin with "__", which is reserved by GraphQL introspection.`,t.astNode)}function g(e,t){const n=Object.values(t.getFields());0===n.length&&e.reportError(`Type ${t.name} must define one or more fields.`,[t.astNode,...t.extensionASTNodes]);for(const l of n){var i;m(e,l),(0,s.SZ)(l.type)||e.reportError(`The type of ${t.name}.${l.name} must be Output Type but got: ${(0,r.X)(l.type)}.`,null===(i=l.astNode)||void 0===i?void 0:i.type);for(const n of l.args){const i=n.name;var o,a;m(e,n),(0,s.j$)(n.type)||e.reportError(`The type of ${t.name}.${l.name}(${i}:) must be Input Type but got: ${(0,r.X)(n.type)}.`,null===(o=n.astNode)||void 0===o?void 0:o.type),(0,s.dK)(n)&&null!=n.deprecationReason&&e.reportError(`Required argument ${t.name}.${l.name}(${i}:) cannot be deprecated.`,[x(n.astNode),null===(a=n.astNode)||void 0===a?void 0:a.type])}}}function v(e,t){const n=Object.create(null);for(const i of t.getInterfaces())(0,s.oT)(i)?t!==i?n[i.name]?e.reportError(`Type ${t.name} can only implement ${i.name} once.`,C(t,i)):(n[i.name]=!0,b(e,t,i),y(e,t,i)):e.reportError(`Type ${t.name} cannot implement itself because it would create a circular reference.`,C(t,i)):e.reportError(`Type ${(0,r.X)(t)} must only implement Interface types, it cannot implement ${(0,r.X)(i)}.`,C(t,i))}function y(e,t,n){const i=t.getFields();for(const d of Object.values(n.getFields())){const f=d.name,p=i[f];if(p){var o,l;(0,a.uJ)(e.schema,p.type,d.type)||e.reportError(`Interface field ${n.name}.${f} expects type ${(0,r.X)(d.type)} but ${t.name}.${f} is type ${(0,r.X)(p.type)}.`,[null===(o=d.astNode)||void 0===o?void 0:o.type,null===(l=p.astNode)||void 0===l?void 0:l.type]);for(const i of d.args){const o=i.name,s=p.args.find((e=>e.name===o));var u,c;s?(0,a._7)(i.type,s.type)||e.reportError(`Interface field argument ${n.name}.${f}(${o}:) expects type ${(0,r.X)(i.type)} but ${t.name}.${f}(${o}:) is type ${(0,r.X)(s.type)}.`,[null===(u=i.astNode)||void 0===u?void 0:u.type,null===(c=s.astNode)||void 0===c?void 0:c.type]):e.reportError(`Interface field argument ${n.name}.${f}(${o}:) expected but ${t.name}.${f} does not provide it.`,[i.astNode,p.astNode])}for(const r of p.args){const i=r.name;!d.args.find((e=>e.name===i))&&(0,s.dK)(r)&&e.reportError(`Object field ${t.name}.${f} includes required argument ${i} that is missing from the Interface field ${n.name}.${f}.`,[r.astNode,d.astNode])}}else e.reportError(`Interface field ${n.name}.${f} expected but ${t.name} does not provide it.`,[d.astNode,t.astNode,...t.extensionASTNodes])}}function b(e,t,n){const r=t.getInterfaces();for(const i of n.getInterfaces())r.includes(i)||e.reportError(i===t?`Type ${t.name} cannot implement ${n.name} because it would create a circular reference.`:`Type ${t.name} must implement ${i.name} because it is implemented by ${n.name}.`,[...C(n,i),...C(t,n)])}function E(e,t){const n=t.getTypes();0===n.length&&e.reportError(`Union type ${t.name} must define one or more member types.`,[t.astNode,...t.extensionASTNodes]);const i=Object.create(null);for(const o of n)i[o.name]?e.reportError(`Union type ${t.name} can only include type ${o.name} once.`,S(t,o.name)):(i[o.name]=!0,(0,s.lp)(o)||e.reportError(`Union type ${t.name} can only include Object types, it cannot include ${(0,r.X)(o)}.`,S(t,String(o))))}function T(e,t){const n=t.getValues();0===n.length&&e.reportError(`Enum type ${t.name} must define one or more values.`,[t.astNode,...t.extensionASTNodes]);for(const t of n)m(e,t)}function w(e,t){const n=Object.values(t.getFields());0===n.length&&e.reportError(`Input Object type ${t.name} must define one or more fields.`,[t.astNode,...t.extensionASTNodes]);for(const a of n){var i,o;m(e,a),(0,s.j$)(a.type)||e.reportError(`The type of ${t.name}.${a.name} must be Input Type but got: ${(0,r.X)(a.type)}.`,null===(i=a.astNode)||void 0===i?void 0:i.type),(0,s.Wd)(a)&&null!=a.deprecationReason&&e.reportError(`Required input field ${t.name}.${a.name} cannot be deprecated.`,[x(a.astNode),null===(o=a.astNode)||void 0===o?void 0:o.type])}}function C(e,t){const{astNode:n,extensionASTNodes:r}=e;return(null!=n?[n,...r]:r).flatMap((e=>{var t;return null!==(t=e.interfaces)&&void 0!==t?t:[]})).filter((e=>e.name.value===t.name))}function S(e,t){const{astNode:n,extensionASTNodes:r}=e;return(null!=n?[n,...r]:r).flatMap((e=>{var t;return null!==(t=e.types)&&void 0!==t?t:[]})).filter((e=>e.name.value===t))}function x(e){var t;return null==e||null===(t=e.directives)||void 0===t?void 0:t.find((e=>e.name.value===l.fg.name))}},1409:function(e,t,n){"use strict";n.d(t,{a:function(){return u},y:function(){return d}});var r=n(3526),i=n(3830),o=n(9685),a=n(755),s=n(8078),l=n(5998);class u{constructor(e,t,n){this._schema=e,this._typeStack=[],this._parentTypeStack=[],this._inputTypeStack=[],this._fieldDefStack=[],this._defaultValueStack=[],this._directive=null,this._argument=null,this._enumValue=null,this._getFieldDef=null!=n?n:c,t&&((0,a.j$)(t)&&this._inputTypeStack.push(t),(0,a.Gv)(t)&&this._parentTypeStack.push(t),(0,a.SZ)(t)&&this._typeStack.push(t))}get[Symbol.toStringTag](){return"TypeInfo"}getType(){if(this._typeStack.length>0)return this._typeStack[this._typeStack.length-1]}getParentType(){if(this._parentTypeStack.length>0)return this._parentTypeStack[this._parentTypeStack.length-1]}getInputType(){if(this._inputTypeStack.length>0)return this._inputTypeStack[this._inputTypeStack.length-1]}getParentInputType(){if(this._inputTypeStack.length>1)return this._inputTypeStack[this._inputTypeStack.length-2]}getFieldDef(){if(this._fieldDefStack.length>0)return this._fieldDefStack[this._fieldDefStack.length-1]}getDefaultValue(){if(this._defaultValueStack.length>0)return this._defaultValueStack[this._defaultValueStack.length-1]}getDirective(){return this._directive}getArgument(){return this._argument}getEnumValue(){return this._enumValue}enter(e){const t=this._schema;switch(e.kind){case i.h.SELECTION_SET:{const e=(0,a.xC)(this.getType());this._parentTypeStack.push((0,a.Gv)(e)?e:void 0);break}case i.h.FIELD:{const n=this.getParentType();let r,i;n&&(r=this._getFieldDef(t,n,e),r&&(i=r.type)),this._fieldDefStack.push(r),this._typeStack.push((0,a.SZ)(i)?i:void 0);break}case i.h.DIRECTIVE:this._directive=t.getDirective(e.name.value);break;case i.h.OPERATION_DEFINITION:{const n=t.getRootType(e.operation);this._typeStack.push((0,a.lp)(n)?n:void 0);break}case i.h.INLINE_FRAGMENT:case i.h.FRAGMENT_DEFINITION:{const n=e.typeCondition,r=n?(0,l._)(t,n):(0,a.xC)(this.getType());this._typeStack.push((0,a.SZ)(r)?r:void 0);break}case i.h.VARIABLE_DEFINITION:{const n=(0,l._)(t,e.type);this._inputTypeStack.push((0,a.j$)(n)?n:void 0);break}case i.h.ARGUMENT:{var n;let t,r;const i=null!==(n=this.getDirective())&&void 0!==n?n:this.getFieldDef();i&&(t=i.args.find((t=>t.name===e.name.value)),t&&(r=t.type)),this._argument=t,this._defaultValueStack.push(t?t.defaultValue:void 0),this._inputTypeStack.push((0,a.j$)(r)?r:void 0);break}case i.h.LIST:{const e=(0,a.tf)(this.getInputType()),t=(0,a.HG)(e)?e.ofType:e;this._defaultValueStack.push(void 0),this._inputTypeStack.push((0,a.j$)(t)?t:void 0);break}case i.h.OBJECT_FIELD:{const t=(0,a.xC)(this.getInputType());let n,r;(0,a.hL)(t)&&(r=t.getFields()[e.name.value],r&&(n=r.type)),this._defaultValueStack.push(r?r.defaultValue:void 0),this._inputTypeStack.push((0,a.j$)(n)?n:void 0);break}case i.h.ENUM:{const t=(0,a.xC)(this.getInputType());let n;(0,a.EM)(t)&&(n=t.getValue(e.value)),this._enumValue=n;break}}}leave(e){switch(e.kind){case i.h.SELECTION_SET:this._parentTypeStack.pop();break;case i.h.FIELD:this._fieldDefStack.pop(),this._typeStack.pop();break;case i.h.DIRECTIVE:this._directive=null;break;case i.h.OPERATION_DEFINITION:case i.h.INLINE_FRAGMENT:case i.h.FRAGMENT_DEFINITION:this._typeStack.pop();break;case i.h.VARIABLE_DEFINITION:this._inputTypeStack.pop();break;case i.h.ARGUMENT:this._argument=null,this._defaultValueStack.pop(),this._inputTypeStack.pop();break;case i.h.LIST:case i.h.OBJECT_FIELD:this._defaultValueStack.pop(),this._inputTypeStack.pop();break;case i.h.ENUM:this._enumValue=null}}}function c(e,t,n){const r=n.name.value;return r===s.Az.name&&e.getQueryType()===t?s.Az:r===s.tF.name&&e.getQueryType()===t?s.tF:r===s.hU.name&&(0,a.Gv)(t)?s.hU:(0,a.lp)(t)||(0,a.oT)(t)?t.getFields()[r]:void 0}function d(e,t){return{enter(...n){const i=n[0];e.enter(i);const a=(0,o.Eu)(t,i.kind).enter;if(a){const o=a.apply(t,n);return void 0!==o&&(e.leave(i),(0,r.UG)(o)&&e.enter(o)),o}},leave(...n){const r=n[0],i=(0,o.Eu)(t,r.kind).leave;let a;return i&&(a=i.apply(t,n)),e.leave(r),a}}}},3190:function(e,t,n){"use strict";n.d(t,{J:function(){return c}});var r=n(5648),i=n(5052),o=n(2910),a=n(1315),s=n(3830),l=n(755),u=n(1774);function c(e,t){if((0,l.zM)(t)){const n=c(e,t.ofType);return(null==n?void 0:n.kind)===s.h.NULL?null:n}if(null===e)return{kind:s.h.NULL};if(void 0===e)return null;if((0,l.HG)(t)){const n=t.ofType;if((0,o.i)(e)){const t=[];for(const r of e){const e=c(r,n);null!=e&&t.push(e)}return{kind:s.h.LIST,values:t}}return c(e,n)}if((0,l.hL)(t)){if(!(0,a.y)(e))return null;const n=[];for(const r of Object.values(t.getFields())){const t=c(e[r.name],r.type);t&&n.push({kind:s.h.OBJECT_FIELD,name:{kind:s.h.NAME,value:r.name},value:t})}return{kind:s.h.OBJECT,fields:n}}if((0,l.UT)(t)){const n=t.serialize(e);if(null==n)return null;if("boolean"==typeof n)return{kind:s.h.BOOLEAN,value:n};if("number"==typeof n&&Number.isFinite(n)){const e=String(n);return d.test(e)?{kind:s.h.INT,value:e}:{kind:s.h.FLOAT,value:e}}if("string"==typeof n)return(0,l.EM)(t)?{kind:s.h.ENUM,value:n}:t===u.km&&d.test(n)?{kind:s.h.INT,value:n}:{kind:s.h.STRING,value:n};throw new TypeError(`Cannot convert value to AST: ${(0,r.X)(n)}.`)}(0,i.k)(!1,"Unexpected input type: "+(0,r.X)(t))}const d=/^-?(?:0|[1-9][0-9]*)$/},5925:function(e,t,n){"use strict";n.d(t,{K:function(){return p}});var r=n(8063),i=n(5648),o=n(5052),a=n(2910),s=n(1315),l=n(9878),u=n(4987),c=n(3492),d=n(4117),f=n(755);function p(e,t,n=h){return m(e,t,n,void 0)}function h(e,t,n){let r="Invalid value "+(0,i.X)(t);throw e.length>0&&(r+=` at "value${(0,u.F)(e)}"`),n.message=r+": "+n.message,n}function m(e,t,n,u){if((0,f.zM)(t))return null!=e?m(e,t.ofType,n,u):void n((0,l.N)(u),e,new d.__(`Expected non-nullable type "${(0,i.X)(t)}" not to be null.`));if(null==e)return null;if((0,f.HG)(t)){const r=t.ofType;return(0,a.i)(e)?Array.from(e,((e,t)=>{const i=(0,l.Q)(u,t,void 0);return m(e,r,n,i)})):[m(e,r,n,u)]}if((0,f.hL)(t)){if(!(0,s.y)(e))return void n((0,l.N)(u),e,new d.__(`Expected type "${t.name}" to be an object.`));const o={},a=t.getFields();for(const r of Object.values(a)){const a=e[r.name];if(void 0!==a)o[r.name]=m(a,r.type,n,(0,l.Q)(u,r.name,t.name));else if(void 0!==r.defaultValue)o[r.name]=r.defaultValue;else if((0,f.zM)(r.type)){const t=(0,i.X)(r.type);n((0,l.N)(u),e,new d.__(`Field "${r.name}" of required type "${t}" was not provided.`))}}for(const i of Object.keys(e))if(!a[i]){const o=(0,c.D)(i,Object.keys(t.getFields()));n((0,l.N)(u),e,new d.__(`Field "${i}" is not defined by type "${t.name}".`+(0,r.l)(o)))}return o}if((0,f.UT)(t)){let r;try{r=t.parseValue(e)}catch(r){return void(r instanceof d.__?n((0,l.N)(u),e,r):n((0,l.N)(u),e,new d.__(`Expected type "${t.name}". `+r.message,{originalError:r})))}return void 0===r&&n((0,l.N)(u),e,new d.__(`Expected type "${t.name}".`)),r}(0,o.k)(!1,"Unexpected input type: "+(0,i.X)(t))}},9458:function(e,t,n){"use strict";n.d(t,{S:function(){return i}});var r=n(3830);function i(e,t){let n=null;for(const o of e.definitions){var i;if(o.kind===r.h.OPERATION_DEFINITION)if(null==t){if(n)return null;n=o}else if((null===(i=o.name)||void 0===i?void 0:i.value)===t)return o}return n}},4034:function(e,t,n){"use strict";n.d(t,{n:function(){return o}});var r=n(6625),i=n(3830);function o(e){switch(e.kind){case i.h.OBJECT:return{...e,fields:(t=e.fields,t.map((e=>({...e,value:o(e.value)}))).sort(((e,t)=>(0,r.K)(e.name.value,t.name.value))))};case i.h.LIST:return{...e,values:e.values.map(o)};case i.h.INT:case i.h.FLOAT:case i.h.STRING:case i.h.BOOLEAN:case i.h.NULL:case i.h.ENUM:case i.h.VARIABLE:return e}var t}},2984:function(e,t,n){"use strict";n.d(t,{_7:function(){return i},uJ:function(){return o},zR:function(){return a}});var r=n(755);function i(e,t){return e===t||((0,r.zM)(e)&&(0,r.zM)(t)||!(!(0,r.HG)(e)||!(0,r.HG)(t)))&&i(e.ofType,t.ofType)}function o(e,t,n){return t===n||((0,r.zM)(n)?!!(0,r.zM)(t)&&o(e,t.ofType,n.ofType):(0,r.zM)(t)?o(e,t.ofType,n):(0,r.HG)(n)?!!(0,r.HG)(t)&&o(e,t.ofType,n.ofType):!(0,r.HG)(t)&&(0,r.m0)(n)&&((0,r.oT)(t)||(0,r.lp)(t))&&e.isSubType(n,t))}function a(e,t,n){return t===n||((0,r.m0)(t)?(0,r.m0)(n)?e.getPossibleTypes(t).some((t=>e.isSubType(n,t))):e.isSubType(t,n):!!(0,r.m0)(n)&&e.isSubType(n,t))}},5998:function(e,t,n){"use strict";n.d(t,{_:function(){return o}});var r=n(3830),i=n(755);function o(e,t){switch(t.kind){case r.h.LIST_TYPE:{const n=o(e,t.type);return n&&new i.p2(n)}case r.h.NON_NULL_TYPE:{const n=o(e,t.type);return n&&new i.bM(n)}case r.h.NAMED_TYPE:return e.getType(t.name.value)}}},5284:function(e,t,n){"use strict";n.d(t,{u:function(){return l}});var r=n(5648),i=n(5052),o=n(9815),a=n(3830),s=n(755);function l(e,t,n){if(e){if(e.kind===a.h.VARIABLE){const r=e.name.value;if(null==n||void 0===n[r])return;const i=n[r];if(null===i&&(0,s.zM)(t))return;return i}if((0,s.zM)(t)){if(e.kind===a.h.NULL)return;return l(e,t.ofType,n)}if(e.kind===a.h.NULL)return null;if((0,s.HG)(t)){const r=t.ofType;if(e.kind===a.h.LIST){const t=[];for(const i of e.values)if(u(i,n)){if((0,s.zM)(r))return;t.push(null)}else{const e=l(i,r,n);if(void 0===e)return;t.push(e)}return t}const i=l(e,r,n);if(void 0===i)return;return[i]}if((0,s.hL)(t)){if(e.kind!==a.h.OBJECT)return;const r=Object.create(null),i=(0,o.P)(e.fields,(e=>e.name.value));for(const e of Object.values(t.getFields())){const t=i[e.name];if(!t||u(t.value,n)){if(void 0!==e.defaultValue)r[e.name]=e.defaultValue;else if((0,s.zM)(e.type))return;continue}const o=l(t.value,e.type,n);if(void 0===o)return;r[e.name]=o}return r}if((0,s.UT)(t)){let r;try{r=t.parseLiteral(e,n)}catch(e){return}if(void 0===r)return;return r}(0,i.k)(!1,"Unexpected input type: "+(0,r.X)(t))}}function u(e,t){return e.kind===a.h.VARIABLE&&(null==t||void 0===t[e.name.value])}},9426:function(e,t,n){"use strict";n.d(t,{M:function(){return o}});var r=n(8240),i=n(3830);function o(e,t){switch(e.kind){case i.h.NULL:return null;case i.h.INT:return parseInt(e.value,10);case i.h.FLOAT:return parseFloat(e.value);case i.h.STRING:case i.h.ENUM:case i.h.BOOLEAN:return e.value;case i.h.LIST:return e.values.map((e=>o(e,t)));case i.h.OBJECT:return(0,r.w)(e.fields,(e=>e.name.value),(e=>o(e.value,t)));case i.h.VARIABLE:return null==t?void 0:t[e.name.value]}}},2716:function(e,t,n){"use strict";n.d(t,{_t:function(){return l},yv:function(){return s}});var r=n(3830),i=n(9685),o=n(1409);class a{constructor(e,t){this._ast=e,this._fragments=void 0,this._fragmentSpreads=new Map,this._recursivelyReferencedFragments=new Map,this._onError=t}get[Symbol.toStringTag](){return"ASTValidationContext"}reportError(e){this._onError(e)}getDocument(){return this._ast}getFragment(e){let t;if(this._fragments)t=this._fragments;else{t=Object.create(null);for(const e of this.getDocument().definitions)e.kind===r.h.FRAGMENT_DEFINITION&&(t[e.name.value]=e);this._fragments=t}return t[e]}getFragmentSpreads(e){let t=this._fragmentSpreads.get(e);if(!t){t=[];const n=[e];let i;for(;i=n.pop();)for(const e of i.selections)e.kind===r.h.FRAGMENT_SPREAD?t.push(e):e.selectionSet&&n.push(e.selectionSet);this._fragmentSpreads.set(e,t)}return t}getRecursivelyReferencedFragments(e){let t=this._recursivelyReferencedFragments.get(e);if(!t){t=[];const n=Object.create(null),r=[e.selectionSet];let i;for(;i=r.pop();)for(const e of this.getFragmentSpreads(i)){const i=e.name.value;if(!0!==n[i]){n[i]=!0;const e=this.getFragment(i);e&&(t.push(e),r.push(e.selectionSet))}}this._recursivelyReferencedFragments.set(e,t)}return t}}class s extends a{constructor(e,t,n){super(e,n),this._schema=t}get[Symbol.toStringTag](){return"SDLValidationContext"}getSchema(){return this._schema}}class l extends a{constructor(e,t,n,r){super(t,r),this._schema=e,this._typeInfo=n,this._variableUsages=new Map,this._recursiveVariableUsages=new Map}get[Symbol.toStringTag](){return"ValidationContext"}getSchema(){return this._schema}getVariableUsages(e){let t=this._variableUsages.get(e);if(!t){const n=[],r=new o.a(this._schema);(0,i.Vn)(e,(0,o.y)(r,{VariableDefinition:()=>!1,Variable(e){n.push({node:e,type:r.getInputType(),defaultValue:r.getDefaultValue()})}})),t=n,this._variableUsages.set(e,t)}return t}getRecursiveVariableUsages(e){let t=this._recursiveVariableUsages.get(e);if(!t){t=this.getVariableUsages(e);for(const n of this.getRecursivelyReferencedFragments(e))t=t.concat(this.getVariableUsages(n));this._recursiveVariableUsages.set(e,t)}return t}getType(){return this._typeInfo.getType()}getParentType(){return this._typeInfo.getParentType()}getInputType(){return this._typeInfo.getInputType()}getParentInputType(){return this._typeInfo.getParentInputType()}getFieldDef(){return this._typeInfo.getFieldDef()}getDirective(){return this._typeInfo.getDirective()}getArgument(){return this._typeInfo.getArgument()}getEnumValue(){return this._typeInfo.getEnumValue()}}},3857:function(e,t,n){"use strict";n.d(t,{i:function(){return a}});var r=n(4117),i=n(3830),o=n(9615);function a(e){return{Document(t){for(const n of t.definitions)if(!(0,o.Wk)(n)){const t=n.kind===i.h.SCHEMA_DEFINITION||n.kind===i.h.SCHEMA_EXTENSION?"schema":'"'+n.name.value+'"';e.reportError(new r.__(`The ${t} definition is not executable.`,{nodes:n}))}return!1}}}},1870:function(e,t,n){"use strict";n.d(t,{A:function(){return l}});var r=n(8063),i=n(6625),o=n(3492),a=n(4117),s=n(755);function l(e){return{Field(t){const n=e.getParentType();if(n&&!e.getFieldDef()){const l=e.getSchema(),u=t.name.value;let c=(0,r.l)("to use an inline fragment on",function(e,t,n){if(!(0,s.m0)(t))return[];const r=new Set,o=Object.create(null);for(const i of e.getPossibleTypes(t))if(i.getFields()[n]){r.add(i),o[i.name]=1;for(const e of i.getInterfaces()){var a;e.getFields()[n]&&(r.add(e),o[e.name]=(null!==(a=o[e.name])&&void 0!==a?a:0)+1)}}return[...r].sort(((t,n)=>{const r=o[n.name]-o[t.name];return 0!==r?r:(0,s.oT)(t)&&e.isSubType(t,n)?-1:(0,s.oT)(n)&&e.isSubType(n,t)?1:(0,i.K)(t.name,n.name)})).map((e=>e.name))}(l,n,u));""===c&&(c=(0,r.l)(function(e,t){if((0,s.lp)(e)||(0,s.oT)(e)){const n=Object.keys(e.getFields());return(0,o.D)(t,n)}return[]}(n,u))),e.reportError(new a.__(`Cannot query field "${u}" on type "${n.name}".`+c,{nodes:t}))}}}}},5167:function(e,t,n){"use strict";n.d(t,{T:function(){return s}});var r=n(4117),i=n(5895),o=n(755),a=n(5998);function s(e){return{InlineFragment(t){const n=t.typeCondition;if(n){const t=(0,a._)(e.getSchema(),n);if(t&&!(0,o.Gv)(t)){const t=(0,i.S)(n);e.reportError(new r.__(`Fragment cannot condition on non composite type "${t}".`,{nodes:n}))}}},FragmentDefinition(t){const n=(0,a._)(e.getSchema(),t.typeCondition);if(n&&!(0,o.Gv)(n)){const n=(0,i.S)(t.typeCondition);e.reportError(new r.__(`Fragment "${t.name.value}" cannot condition on non composite type "${n}".`,{nodes:t.typeCondition}))}}}}},4875:function(e,t,n){"use strict";n.d(t,{e:function(){return l},o:function(){return u}});var r=n(8063),i=n(3492),o=n(4117),a=n(3830),s=n(5946);function l(e){return{...u(e),Argument(t){const n=e.getArgument(),a=e.getFieldDef(),s=e.getParentType();if(!n&&a&&s){const n=t.name.value,l=a.args.map((e=>e.name)),u=(0,i.D)(n,l);e.reportError(new o.__(`Unknown argument "${n}" on field "${s.name}.${a.name}".`+(0,r.l)(u),{nodes:t}))}}}}function u(e){const t=Object.create(null),n=e.getSchema(),l=n?n.getDirectives():s.V4;for(const e of l)t[e.name]=e.args.map((e=>e.name));const u=e.getDocument().definitions;for(const e of u)if(e.kind===a.h.DIRECTIVE_DEFINITION){var c;const n=null!==(c=e.arguments)&&void 0!==c?c:[];t[e.name.value]=n.map((e=>e.name.value))}return{Directive(n){const a=n.name.value,s=t[a];if(n.arguments&&s)for(const t of n.arguments){const n=t.name.value;if(!s.includes(n)){const l=(0,i.D)(n,s);e.reportError(new o.__(`Unknown argument "${n}" on directive "@${a}".`+(0,r.l)(l),{nodes:t}))}}return!1}}}},7513:function(e,t,n){"use strict";n.d(t,{J:function(){return c}});var r=n(5648),i=n(5052),o=n(4117),a=n(3526),s=n(3140),l=n(3830),u=n(5946);function c(e){const t=Object.create(null),n=e.getSchema(),c=n?n.getDirectives():u.V4;for(const e of c)t[e.name]=e.locations;const d=e.getDocument().definitions;for(const e of d)e.kind===l.h.DIRECTIVE_DEFINITION&&(t[e.name.value]=e.locations.map((e=>e.value)));return{Directive(n,u,c,d,f){const p=n.name.value,h=t[p];if(!h)return void e.reportError(new o.__(`Unknown directive "@${p}".`,{nodes:n}));const m=function(e){const t=e[e.length-1];switch("kind"in t||(0,i.k)(!1),t.kind){case l.h.OPERATION_DEFINITION:return function(e){switch(e){case a.ku.QUERY:return s.B.QUERY;case a.ku.MUTATION:return s.B.MUTATION;case a.ku.SUBSCRIPTION:return s.B.SUBSCRIPTION}}(t.operation);case l.h.FIELD:return s.B.FIELD;case l.h.FRAGMENT_SPREAD:return s.B.FRAGMENT_SPREAD;case l.h.INLINE_FRAGMENT:return s.B.INLINE_FRAGMENT;case l.h.FRAGMENT_DEFINITION:return s.B.FRAGMENT_DEFINITION;case l.h.VARIABLE_DEFINITION:return s.B.VARIABLE_DEFINITION;case l.h.SCHEMA_DEFINITION:case l.h.SCHEMA_EXTENSION:return s.B.SCHEMA;case l.h.SCALAR_TYPE_DEFINITION:case l.h.SCALAR_TYPE_EXTENSION:return s.B.SCALAR;case l.h.OBJECT_TYPE_DEFINITION:case l.h.OBJECT_TYPE_EXTENSION:return s.B.OBJECT;case l.h.FIELD_DEFINITION:return s.B.FIELD_DEFINITION;case l.h.INTERFACE_TYPE_DEFINITION:case l.h.INTERFACE_TYPE_EXTENSION:return s.B.INTERFACE;case l.h.UNION_TYPE_DEFINITION:case l.h.UNION_TYPE_EXTENSION:return s.B.UNION;case l.h.ENUM_TYPE_DEFINITION:case l.h.ENUM_TYPE_EXTENSION:return s.B.ENUM;case l.h.ENUM_VALUE_DEFINITION:return s.B.ENUM_VALUE;case l.h.INPUT_OBJECT_TYPE_DEFINITION:case l.h.INPUT_OBJECT_TYPE_EXTENSION:return s.B.INPUT_OBJECT;case l.h.INPUT_VALUE_DEFINITION:{const t=e[e.length-3];return"kind"in t||(0,i.k)(!1),t.kind===l.h.INPUT_OBJECT_TYPE_DEFINITION?s.B.INPUT_FIELD_DEFINITION:s.B.ARGUMENT_DEFINITION}default:(0,i.k)(!1,"Unexpected kind: "+(0,r.X)(t.kind))}}(f);m&&!h.includes(m)&&e.reportError(new o.__(`Directive "@${p}" may not be used on ${m}.`,{nodes:n}))}}}},1435:function(e,t,n){"use strict";n.d(t,{a:function(){return i}});var r=n(4117);function i(e){return{FragmentSpread(t){const n=t.name.value;e.getFragment(n)||e.reportError(new r.__(`Unknown fragment "${n}".`,{nodes:t.name}))}}}},591:function(e,t,n){"use strict";n.d(t,{I:function(){return l}});var r=n(8063),i=n(3492),o=n(4117),a=n(9615),s=n(8078);function l(e){const t=e.getSchema(),n=t?t.getTypeMap():Object.create(null),s=Object.create(null);for(const t of e.getDocument().definitions)(0,a.zT)(t)&&(s[t.name.value]=!0);const l=[...Object.keys(n),...Object.keys(s)];return{NamedType(t,c,d,f,p){const h=t.name.value;if(!n[h]&&!s[h]){var m;const n=null!==(m=p[2])&&void 0!==m?m:d,s=null!=n&&"kind"in(g=n)&&((0,a.G4)(g)||(0,a.aU)(g));if(s&&u.includes(h))return;const c=(0,i.D)(h,s?u.concat(l):l);e.reportError(new o.__(`Unknown type "${h}".`+(0,r.l)(c),{nodes:t}))}var g}}}const u=[...n(1774).HS,...s.nL].map((e=>e.name))},831:function(e,t,n){"use strict";n.d(t,{F:function(){return o}});var r=n(4117),i=n(3830);function o(e){let t=0;return{Document(e){t=e.definitions.filter((e=>e.kind===i.h.OPERATION_DEFINITION)).length},OperationDefinition(n){!n.name&&t>1&&e.reportError(new r.__("This anonymous operation must be the only defined operation.",{nodes:n}))}}}},3402:function(e,t,n){"use strict";n.d(t,{t:function(){return i}});var r=n(4117);function i(e){var t,n,i;const o=e.getSchema(),a=null!==(t=null!==(n=null!==(i=null==o?void 0:o.astNode)&&void 0!==i?i:null==o?void 0:o.getQueryType())&&void 0!==n?n:null==o?void 0:o.getMutationType())&&void 0!==t?t:null==o?void 0:o.getSubscriptionType();let s=0;return{SchemaDefinition(t){a?e.reportError(new r.__("Cannot define a new schema within a schema extension.",{nodes:t})):(s>0&&e.reportError(new r.__("Must provide only one schema definition.",{nodes:t})),++s)}}}},9316:function(e,t,n){"use strict";n.d(t,{H:function(){return i}});var r=n(4117);function i(e){const t=Object.create(null),n=[],i=Object.create(null);return{OperationDefinition:()=>!1,FragmentDefinition(e){return o(e),!1}};function o(a){if(t[a.name.value])return;const s=a.name.value;t[s]=!0;const l=e.getFragmentSpreads(a.selectionSet);if(0!==l.length){i[s]=n.length;for(const t of l){const a=t.name.value,s=i[a];if(n.push(t),void 0===s){const t=e.getFragment(a);t&&o(t)}else{const t=n.slice(s),i=t.slice(0,-1).map((e=>'"'+e.name.value+'"')).join(", ");e.reportError(new r.__(`Cannot spread fragment "${a}" within itself`+(""!==i?` via ${i}.`:"."),{nodes:t}))}n.pop()}i[s]=void 0}}}},9518:function(e,t,n){"use strict";n.d(t,{$:function(){return i}});var r=n(4117);function i(e){let t=Object.create(null);return{OperationDefinition:{enter(){t=Object.create(null)},leave(n){const i=e.getRecursiveVariableUsages(n);for(const{node:o}of i){const i=o.name.value;!0!==t[i]&&e.reportError(new r.__(n.name?`Variable "$${i}" is not defined by operation "${n.name.value}".`:`Variable "$${i}" is not defined.`,{nodes:[o,n]}))}}},VariableDefinition(e){t[e.variable.name.value]=!0}}}},3447:function(e,t,n){"use strict";n.d(t,{J:function(){return i}});var r=n(4117);function i(e){const t=[],n=[];return{OperationDefinition(e){return t.push(e),!1},FragmentDefinition(e){return n.push(e),!1},Document:{leave(){const i=Object.create(null);for(const n of t)for(const t of e.getRecursivelyReferencedFragments(n))i[t.name.value]=!0;for(const t of n){const n=t.name.value;!0!==i[n]&&e.reportError(new r.__(`Fragment "${n}" is never used.`,{nodes:t}))}}}}}},7114:function(e,t,n){"use strict";n.d(t,{p:function(){return i}});var r=n(4117);function i(e){let t=[];return{OperationDefinition:{enter(){t=[]},leave(n){const i=Object.create(null),o=e.getRecursiveVariableUsages(n);for(const{node:e}of o)i[e.name.value]=!0;for(const o of t){const t=o.variable.name.value;!0!==i[t]&&e.reportError(new r.__(n.name?`Variable "$${t}" is never used in operation "${n.name.value}".`:`Variable "$${t}" is never used.`,{nodes:o}))}}},VariableDefinition(e){t.push(e)}}}},7163:function(e,t,n){"use strict";n.d(t,{y:function(){return d}});var r=n(5648),i=n(4117),o=n(3830),a=n(5895),s=n(755),l=n(4034),u=n(5998);function c(e){return Array.isArray(e)?e.map((([e,t])=>`subfields "${e}" conflict because `+c(t))).join(" and "):e}function d(e){const t=new T,n=new Map;return{SelectionSet(r){const o=function(e,t,n,r,i){const o=[],[a,s]=y(e,t,r,i);if(function(e,t,n,r,i){for(const[o,a]of Object.entries(i))if(a.length>1)for(let i=0;i0)return[[t,e.map((([e])=>e))],[n,...e.map((([,e])=>e)).flat()],[r,...e.map((([,,e])=>e)).flat()]]}(r,o,c,b)}}function g(e){var t;const n=null!==(t=e.arguments)&&void 0!==t?t:[],r={kind:o.h.OBJECT,fields:n.map((e=>({kind:o.h.OBJECT_FIELD,name:e.name,value:e.value})))};return(0,a.S)((0,l.n)(r))}function v(e,t){return(0,s.HG)(e)?!(0,s.HG)(t)||v(e.ofType,t.ofType):!!(0,s.HG)(t)||((0,s.zM)(e)?!(0,s.zM)(t)||v(e.ofType,t.ofType):!!(0,s.zM)(t)||!(!(0,s.UT)(e)&&!(0,s.UT)(t))&&e!==t)}function y(e,t,n,r){const i=t.get(r);if(i)return i;const o=Object.create(null),a=Object.create(null);E(e,n,r,o,a);const s=[o,Object.keys(a)];return t.set(r,s),s}function b(e,t,n){const r=t.get(n.selectionSet);if(r)return r;const i=(0,u._)(e.getSchema(),n.typeCondition);return y(e,t,i,n.selectionSet)}function E(e,t,n,r,i){for(const a of n.selections)switch(a.kind){case o.h.FIELD:{const e=a.name.value;let n;((0,s.lp)(t)||(0,s.oT)(t))&&(n=t.getFields()[e]);const i=a.alias?a.alias.value:e;r[i]||(r[i]=[]),r[i].push([t,a,n]);break}case o.h.FRAGMENT_SPREAD:i[a.name.value]=!0;break;case o.h.INLINE_FRAGMENT:{const n=a.typeCondition,o=n?(0,u._)(e.getSchema(),n):t;E(e,o,a.selectionSet,r,i);break}}}class T{constructor(){this._data=new Map}has(e,t,n){var r;const[i,o]=ee.name.value)));for(const n of i.args)if(!a.has(n.name)&&(0,l.dK)(n)){const a=(0,r.X)(n.type);e.reportError(new o.__(`Field "${i.name}" argument "${n.name}" of type "${a}" is required, but it was not provided.`,{nodes:t}))}}}}}function d(e){var t;const n=Object.create(null),c=e.getSchema(),d=null!==(t=null==c?void 0:c.getDirectives())&&void 0!==t?t:u.V4;for(const e of d)n[e.name]=(0,i.P)(e.args.filter(l.dK),(e=>e.name));const p=e.getDocument().definitions;for(const e of p)if(e.kind===a.h.DIRECTIVE_DEFINITION){var h;const t=null!==(h=e.arguments)&&void 0!==h?h:[];n[e.name.value]=(0,i.P)(t.filter(f),(e=>e.name.value))}return{Directive:{leave(t){const i=t.name.value,a=n[i];if(a){var u;const n=null!==(u=t.arguments)&&void 0!==u?u:[],c=new Set(n.map((e=>e.name.value)));for(const[n,u]of Object.entries(a))if(!c.has(n)){const a=(0,l.P9)(u.type)?(0,r.X)(u.type):(0,s.S)(u.type);e.reportError(new o.__(`Directive "@${i}" argument "${n}" of type "${a}" is required, but it was not provided.`,{nodes:t}))}}}}}}function f(e){return e.type.kind===a.h.NON_NULL_TYPE&&null==e.defaultValue}},3989:function(e,t,n){"use strict";n.d(t,{O:function(){return a}});var r=n(5648),i=n(4117),o=n(755);function a(e){return{Field(t){const n=e.getType(),a=t.selectionSet;if(n)if((0,o.UT)((0,o.xC)(n))){if(a){const o=t.name.value,s=(0,r.X)(n);e.reportError(new i.__(`Field "${o}" must not have a selection since type "${s}" has no subfields.`,{nodes:a}))}}else if(!a){const o=t.name.value,a=(0,r.X)(n);e.reportError(new i.__(`Field "${o}" of type "${a}" must have a selection of subfields. Did you mean "${o} { ... }"?`,{nodes:t}))}}}}},9309:function(e,t,n){"use strict";n.d(t,{Z:function(){return a}});var r=n(4117),i=n(3830),o=n(5267);function a(e){return{OperationDefinition(t){if("subscription"===t.operation){const n=e.getSchema(),a=n.getSubscriptionType();if(a){const s=t.name?t.name.value:null,l=Object.create(null),u=e.getDocument(),c=Object.create(null);for(const e of u.definitions)e.kind===i.h.FRAGMENT_DEFINITION&&(c[e.name.value]=e);const d=(0,o.g)(n,c,l,a,t.selectionSet);if(d.size>1){const t=[...d.values()].slice(1).flat();e.reportError(new r.__(null!=s?`Subscription "${s}" must select only one top level field.`:"Anonymous Subscription must select only one top level field.",{nodes:t}))}for(const t of d.values())t[0].name.value.startsWith("__")&&e.reportError(new r.__(null!=s?`Subscription "${s}" must not select an introspection top level field.`:"Anonymous Subscription must not select an introspection top level field.",{nodes:t}))}}}}}},5947:function(e,t,n){"use strict";n.d(t,{L:function(){return o}});var r=n(5839),i=n(4117);function o(e){return{DirectiveDefinition(e){var t;const r=null!==(t=e.arguments)&&void 0!==t?t:[];return n(`@${e.name.value}`,r)},InterfaceTypeDefinition:t,InterfaceTypeExtension:t,ObjectTypeDefinition:t,ObjectTypeExtension:t};function t(e){var t;const r=e.name.value,i=null!==(t=e.fields)&&void 0!==t?t:[];for(const e of i){var o;n(`${r}.${e.name.value}`,null!==(o=e.arguments)&&void 0!==o?o:[])}return!1}function n(t,n){const o=(0,r.v)(n,(e=>e.name.value));for(const[n,r]of o)r.length>1&&e.reportError(new i.__(`Argument "${t}(${n}:)" can only be defined once.`,{nodes:r.map((e=>e.name))}));return!1}}},9168:function(e,t,n){"use strict";n.d(t,{L:function(){return o}});var r=n(5839),i=n(4117);function o(e){return{Field:t,Directive:t};function t(t){var n;const o=null!==(n=t.arguments)&&void 0!==n?n:[],a=(0,r.v)(o,(e=>e.name.value));for(const[t,n]of a)n.length>1&&e.reportError(new i.__(`There can be only one argument named "${t}".`,{nodes:n.map((e=>e.name))}))}}},5681:function(e,t,n){"use strict";n.d(t,{o:function(){return i}});var r=n(4117);function i(e){const t=Object.create(null),n=e.getSchema();return{DirectiveDefinition(i){const o=i.name.value;if(null==n||!n.getDirective(o))return t[o]?e.reportError(new r.__(`There can be only one directive named "@${o}".`,{nodes:[t[o],i.name]})):t[o]=i.name,!1;e.reportError(new r.__(`Directive "@${o}" already exists in the schema. It cannot be redefined.`,{nodes:i.name}))}}}},5673:function(e,t,n){"use strict";n.d(t,{k:function(){return s}});var r=n(4117),i=n(3830),o=n(9615),a=n(5946);function s(e){const t=Object.create(null),n=e.getSchema(),s=n?n.getDirectives():a.V4;for(const e of s)t[e.name]=!e.isRepeatable;const l=e.getDocument().definitions;for(const e of l)e.kind===i.h.DIRECTIVE_DEFINITION&&(t[e.name.value]=!e.repeatable);const u=Object.create(null),c=Object.create(null);return{enter(n){if(!("directives"in n)||!n.directives)return;let a;if(n.kind===i.h.SCHEMA_DEFINITION||n.kind===i.h.SCHEMA_EXTENSION)a=u;else if((0,o.zT)(n)||(0,o.D$)(n)){const e=n.name.value;a=c[e],void 0===a&&(c[e]=a=Object.create(null))}else a=Object.create(null);for(const i of n.directives){const n=i.name.value;t[n]&&(a[n]?e.reportError(new r.__(`The directive "@${n}" can only be used once at this location.`,{nodes:[a[n],i]})):a[n]=i)}}}}},4560:function(e,t,n){"use strict";n.d(t,{L:function(){return o}});var r=n(4117),i=n(755);function o(e){const t=e.getSchema(),n=t?t.getTypeMap():Object.create(null),o=Object.create(null);return{EnumTypeDefinition:a,EnumTypeExtension:a};function a(t){var a;const s=t.name.value;o[s]||(o[s]=Object.create(null));const l=null!==(a=t.values)&&void 0!==a?a:[],u=o[s];for(const t of l){const o=t.name.value,a=n[s];(0,i.EM)(a)&&a.getValue(o)?e.reportError(new r.__(`Enum value "${s}.${o}" already exists in the schema. It cannot also be defined in this type extension.`,{nodes:t.name})):u[o]?e.reportError(new r.__(`Enum value "${s}.${o}" can only be defined once.`,{nodes:[u[o],t.name]})):u[o]=t.name}return!1}}},5240:function(e,t,n){"use strict";n.d(t,{y:function(){return o}});var r=n(4117),i=n(755);function o(e){const t=e.getSchema(),n=t?t.getTypeMap():Object.create(null),i=Object.create(null);return{InputObjectTypeDefinition:o,InputObjectTypeExtension:o,InterfaceTypeDefinition:o,InterfaceTypeExtension:o,ObjectTypeDefinition:o,ObjectTypeExtension:o};function o(t){var o;const s=t.name.value;i[s]||(i[s]=Object.create(null));const l=null!==(o=t.fields)&&void 0!==o?o:[],u=i[s];for(const t of l){const i=t.name.value;a(n[s],i)?e.reportError(new r.__(`Field "${s}.${i}" already exists in the schema. It cannot also be defined in this type extension.`,{nodes:t.name})):u[i]?e.reportError(new r.__(`Field "${s}.${i}" can only be defined once.`,{nodes:[u[i],t.name]})):u[i]=t.name}return!1}}function a(e,t){return!!((0,i.lp)(e)||(0,i.oT)(e)||(0,i.hL)(e))&&null!=e.getFields()[t]}},614:function(e,t,n){"use strict";n.d(t,{N:function(){return i}});var r=n(4117);function i(e){const t=Object.create(null);return{OperationDefinition:()=>!1,FragmentDefinition(n){const i=n.name.value;return t[i]?e.reportError(new r.__(`There can be only one fragment named "${i}".`,{nodes:[t[i],n.name]})):t[i]=n.name,!1}}}},5707:function(e,t,n){"use strict";n.d(t,{P:function(){return o}});var r=n(5052),i=n(4117);function o(e){const t=[];let n=Object.create(null);return{ObjectValue:{enter(){t.push(n),n=Object.create(null)},leave(){const e=t.pop();e||(0,r.k)(!1),n=e}},ObjectField(t){const r=t.name.value;n[r]?e.reportError(new i.__(`There can be only one input field named "${r}".`,{nodes:[n[r],t.name]})):n[r]=t.name}}}},2355:function(e,t,n){"use strict";n.d(t,{H:function(){return i}});var r=n(4117);function i(e){const t=Object.create(null);return{OperationDefinition(n){const i=n.name;return i&&(t[i.value]?e.reportError(new r.__(`There can be only one operation named "${i.value}".`,{nodes:[t[i.value],i]})):t[i.value]=i),!1},FragmentDefinition:()=>!1}}},5427:function(e,t,n){"use strict";n.d(t,{q:function(){return i}});var r=n(4117);function i(e){const t=e.getSchema(),n=Object.create(null),i=t?{query:t.getQueryType(),mutation:t.getMutationType(),subscription:t.getSubscriptionType()}:{};return{SchemaDefinition:o,SchemaExtension:o};function o(t){var o;const a=null!==(o=t.operationTypes)&&void 0!==o?o:[];for(const t of a){const o=t.operation,a=n[o];i[o]?e.reportError(new r.__(`Type for ${o} already defined in the schema. It cannot be redefined.`,{nodes:t})):a?e.reportError(new r.__(`There can be only one ${o} type in schema.`,{nodes:[a,t]})):n[o]=t}return!1}}},4519:function(e,t,n){"use strict";n.d(t,{P:function(){return i}});var r=n(4117);function i(e){const t=Object.create(null),n=e.getSchema();return{ScalarTypeDefinition:i,ObjectTypeDefinition:i,InterfaceTypeDefinition:i,UnionTypeDefinition:i,EnumTypeDefinition:i,InputObjectTypeDefinition:i};function i(i){const o=i.name.value;if(null==n||!n.getType(o))return t[o]?e.reportError(new r.__(`There can be only one type named "${o}".`,{nodes:[t[o],i.name]})):t[o]=i.name,!1;e.reportError(new r.__(`Type "${o}" already exists in the schema. It cannot also be defined in this type definition.`,{nodes:i.name}))}}},7417:function(e,t,n){"use strict";n.d(t,{H:function(){return o}});var r=n(5839),i=n(4117);function o(e){return{OperationDefinition(t){var n;const o=null!==(n=t.variableDefinitions)&&void 0!==n?n:[],a=(0,r.v)(o,(e=>e.variable.name.value));for(const[t,n]of a)n.length>1&&e.reportError(new i.__(`There can be only one variable named "$${t}".`,{nodes:n.map((e=>e.variable.name))}))}}}},4697:function(e,t,n){"use strict";n.d(t,{j:function(){return c}});var r=n(8063),i=n(5648),o=n(9815),a=n(3492),s=n(4117),l=n(5895),u=n(755);function c(e){return{ListValue(t){const n=(0,u.tf)(e.getParentInputType());if(!(0,u.HG)(n))return d(e,t),!1},ObjectValue(t){const n=(0,u.xC)(e.getInputType());if(!(0,u.hL)(n))return d(e,t),!1;const r=(0,o.P)(t.fields,(e=>e.name.value));for(const o of Object.values(n.getFields()))if(!r[o.name]&&(0,u.Wd)(o)){const r=(0,i.X)(o.type);e.reportError(new s.__(`Field "${n.name}.${o.name}" of required type "${r}" was not provided.`,{nodes:t}))}},ObjectField(t){const n=(0,u.xC)(e.getParentInputType());if(!e.getInputType()&&(0,u.hL)(n)){const i=(0,a.D)(t.name.value,Object.keys(n.getFields()));e.reportError(new s.__(`Field "${t.name.value}" is not defined by type "${n.name}".`+(0,r.l)(i),{nodes:t}))}},NullValue(t){const n=e.getInputType();(0,u.zM)(n)&&e.reportError(new s.__(`Expected value of type "${(0,i.X)(n)}", found ${(0,l.S)(t)}.`,{nodes:t}))},EnumValue:t=>d(e,t),IntValue:t=>d(e,t),FloatValue:t=>d(e,t),StringValue:t=>d(e,t),BooleanValue:t=>d(e,t)}}function d(e,t){const n=e.getInputType();if(!n)return;const r=(0,u.xC)(n);if((0,u.UT)(r))try{if(void 0===r.parseLiteral(t,void 0)){const r=(0,i.X)(n);e.reportError(new s.__(`Expected value of type "${r}", found ${(0,l.S)(t)}.`,{nodes:t}))}}catch(r){const o=(0,i.X)(n);r instanceof s.__?e.reportError(r):e.reportError(new s.__(`Expected value of type "${o}", found ${(0,l.S)(t)}; `+r.message,{nodes:t,originalError:r}))}else{const r=(0,i.X)(n);e.reportError(new s.__(`Expected value of type "${r}", found ${(0,l.S)(t)}.`,{nodes:t}))}}},6192:function(e,t,n){"use strict";n.d(t,{I:function(){return s}});var r=n(4117),i=n(5895),o=n(755),a=n(5998);function s(e){return{VariableDefinition(t){const n=(0,a._)(e.getSchema(),t.type);if(void 0!==n&&!(0,o.j$)(n)){const n=t.variable.name.value,o=(0,i.S)(t.type);e.reportError(new r.__(`Variable "$${n}" cannot be non-input type "${o}".`,{nodes:t.type}))}}}}},377:function(e,t,n){"use strict";n.d(t,{w:function(){return u}});var r=n(5648),i=n(4117),o=n(3830),a=n(755),s=n(2984),l=n(5998);function u(e){let t=Object.create(null);return{OperationDefinition:{enter(){t=Object.create(null)},leave(n){const o=e.getRecursiveVariableUsages(n);for(const{node:n,type:a,defaultValue:s}of o){const o=n.name.value,u=t[o];if(u&&a){const t=e.getSchema(),d=(0,l._)(t,u.type);if(d&&!c(t,d,u.defaultValue,a,s)){const t=(0,r.X)(d),s=(0,r.X)(a);e.reportError(new i.__(`Variable "$${o}" of type "${t}" used in position expecting type "${s}".`,{nodes:[u,n]}))}}}}},VariableDefinition(e){t[e.variable.name.value]=e}}}function c(e,t,n,r,i){if((0,a.zM)(r)&&!(0,a.zM)(t)){if((null==n||n.kind===o.h.NULL)&&void 0===i)return!1;const a=r.ofType;return(0,s.uJ)(e,t,a)}return(0,s.uJ)(e,t,r)}},9299:function(e,t,n){"use strict";n.d(t,{M:function(){return j},i:function(){return P}});var r=n(3857),i=n(1870),o=n(5167),a=n(4875),s=n(7513),l=n(1435),u=n(591),c=n(831),d=n(3402),f=n(9316),p=n(9518),h=n(3447),m=n(7114),g=n(7163),v=n(5961),y=n(3721),b=n(16),E=n(3989),T=n(9309),w=n(5947),C=n(9168),S=n(5681),x=n(5673),k=n(4560),N=n(5240),_=n(614),O=n(5707),I=n(2355),D=n(5427),L=n(4519),A=n(7417),M=n(4697),R=n(6192),F=n(377);const P=Object.freeze([r.i,I.H,c.F,T.Z,u.I,o.T,R.I,E.O,i.A,_.N,l.a,h.J,v.a,f.H,A.H,p.$,m.p,s.J,x.k,a.e,C.L,M.j,b.s,F.w,g.y,O.P]),j=Object.freeze([d.t,D.q,L.P,k.L,N.y,w.L,S.o,u.I,s.J,x.k,y.g,a.o,C.L,O.P,b.c])},2780:function(e,t,n){"use strict";n.d(t,{ED:function(){return p},Gu:function(){return c},zo:function(){return f}});var r=n(1172),i=n(4117),o=n(9685),a=n(8555),s=n(1409),l=n(9299),u=n(2716);function c(e,t,n=l.i,c,d=new s.a(e)){var f;const p=null!==(f=null==c?void 0:c.maxErrors)&&void 0!==f?f:100;t||(0,r.a)(!1,"Must provide document."),(0,a.J)(e);const h=Object.freeze({}),m=[],g=new u._t(e,t,d,(e=>{if(m.length>=p)throw m.push(new i.__("Too many validation errors, error limit reached. Validation aborted.")),h;m.push(e)})),v=(0,o.j1)(n.map((e=>e(g))));try{(0,o.Vn)(t,(0,s.y)(d,v))}catch(e){if(e!==h)throw e}return m}function d(e,t,n=l.M){const r=[],i=new u.yv(e,t,(e=>{r.push(e)})),a=n.map((e=>e(i)));return(0,o.Vn)(e,(0,o.j1)(a)),r}function f(e){const t=d(e);if(0!==t.length)throw new Error(t.map((e=>e.message)).join("\n\n"))}function p(e,t){const n=d(e,t);if(0!==n.length)throw new Error(n.map((e=>e.message)).join("\n\n"))}},8488:function(e,t,n){"use strict";n.r(t),n.d(t,{meros:function(){return o}});const r="\r\n\r\n",i=new TextDecoder;async function o(e,t){if(!e.ok||!e.body||e.bodyUsed)return e;const n=e.headers.get("content-type");if(!n||!~n.indexOf("multipart/mixed"))return e;const o=n.indexOf("boundary=");return async function*(e,t,n){const o=e.getReader(),a=!n||!n.multiple;let s="",l=!0,u=[];try{let e;e:for(;!(e=await o.read()).done;){const n=i.decode(e.value),o=n.indexOf(t);let c=s.length;for(s+=n,~o?c+=o:c=s.indexOf(t),u=[];~c;){const e=s.substring(0,c),n=s.substring(c+t.length);if(l)l=!1;else{const t={},i=e.indexOf(r),o=s.slice(0,i).toString().trim().split(/\r\n/);let l;for(;l=o.shift();)l=l.split(": "),t[l.shift().toLowerCase()]=l.join(": ");let c=e.substring(i+r.length,e.lastIndexOf("\r\n")),d=!1;if(l=t["content-type"],l&&~l.indexOf("application/json"))try{c=JSON.parse(c),d=!0}catch(e){}if(l={headers:t,body:c,json:d},a?yield l:u.push(l),"--"===n.substring(0,2))break e}s=n,c=s.indexOf(t)}u.length&&(yield u)}}finally{u.length&&(yield u),o.releaseLock()}}(e.body,`--${~o?n.substring(o+9).trim().replace(/['"]/g,""):"-"}`,t)}},6785:function(e,t,n){"use strict";n.r(t)},5605:function(e,t,n){"use strict";n.r(t)},2162:function(e,t,n){"use strict";n.r(t)},5251:function(e,t,n){"use strict";n.r(t)},9196:function(e){"use strict";e.exports=window.React},1850:function(e){"use strict";e.exports=window.ReactDOM}},r={};function i(e){var t=r[e];if(void 0!==t)return t.exports;var o=r[e]={exports:{}};return n[e].call(o.exports,o,o.exports,i),o.exports}t=Object.getPrototypeOf?function(e){return Object.getPrototypeOf(e)}:function(e){return e.__proto__},i.t=function(n,r){if(1&r&&(n=this(n)),8&r)return n;if("object"==typeof n&&n){if(4&r&&n.__esModule)return n;if(16&r&&"function"==typeof n.then)return n}var o=Object.create(null);i.r(o);var a={};e=e||[null,t({}),t([]),t(t)];for(var s=2&r&&n;"object"==typeof s&&!~e.indexOf(s);s=t(s))Object.getOwnPropertyNames(s).forEach((function(e){a[e]=function(){return n[e]}}));return a.default=function(){return n},i.d(o,a),o},i.d=function(e,t){for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.nc=void 0;var o=i(6676);window.GraphiQL=o.default}(); +//# sourceMappingURL=graphiql.min.js.map \ No newline at end of file diff --git a/graphql/internal/graphiql/index.html b/graphql/internal/graphiql/index.html new file mode 100644 index 0000000000..fabe61e7f2 --- /dev/null +++ b/graphql/internal/graphiql/index.html @@ -0,0 +1,46 @@ + + + + + GraphiQL + + + + + + + + + +
Loading...
+ + + + \ No newline at end of file diff --git a/graphql/internal/graphiql/react-dom.production.min.js b/graphql/internal/graphiql/react-dom.production.min.js new file mode 100644 index 0000000000..e38d120b23 --- /dev/null +++ b/graphql/internal/graphiql/react-dom.production.min.js @@ -0,0 +1,245 @@ +/** @license React v17.0.2 + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +(function(){/* + Modernizr 3.0.0pre (Custom Build) | MIT +*/ +'use strict';(function(M,ha){"object"===typeof exports&&"undefined"!==typeof module?ha(exports,require("react")):"function"===typeof define&&define.amd?define(["exports","react"],ha):(M=M||self,ha(M.ReactDOM={},M.React))})(this,function(M,ha){function m(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;cb}return!1}function Q(a,b,c,d,e,f,g){this.acceptsBooleans=2===b||3===b||4===b;this.attributeName=d;this.attributeNamespace=e;this.mustUseProperty=c;this.propertyName=a;this.type=b;this.sanitizeURL=f;this.removeEmptyString=g}function Ed(a,b,c,d){var e=I.hasOwnProperty(b)?I[b]:null;var f=null!==e?0===e.type:d?!1:!(2h||e[g]!==f[h])return"\n"+e[g].replace(" at new "," at ");while(1<=g&&0<=h)}break}}}finally{Gd=!1,Error.prepareStackTrace=c}return(a=a?a.displayName||a.name:"")?Kb(a):""}function pi(a){switch(a.tag){case 5:return Kb(a.type);case 16:return Kb("Lazy");case 13:return Kb("Suspense"); +case 19:return Kb("SuspenseList");case 0:case 2:case 15:return a=Bc(a.type,!1),a;case 11:return a=Bc(a.type.render,!1),a;case 22:return a=Bc(a.type._render,!1),a;case 1:return a=Bc(a.type,!0),a;default:return""}}function hb(a){if(null==a)return null;if("function"===typeof a)return a.displayName||a.name||null;if("string"===typeof a)return a;switch(a){case wa:return"Fragment";case Ua:return"Portal";case Lb:return"Profiler";case Hd:return"StrictMode";case Mb:return"Suspense";case Cc:return"SuspenseList"}if("object"=== +typeof a)switch(a.$$typeof){case Id:return(a.displayName||"Context")+".Consumer";case Jd:return(a._context.displayName||"Context")+".Provider";case Dc:var b=a.render;b=b.displayName||b.name||"";return a.displayName||(""!==b?"ForwardRef("+b+")":"ForwardRef");case Ec:return hb(a.type);case Kd:return hb(a._render);case Ld:b=a._payload;a=a._init;try{return hb(a(b))}catch(c){}}return null}function xa(a){switch(typeof a){case "boolean":case "number":case "object":case "string":case "undefined":return a; +default:return""}}function Ef(a){var b=a.type;return(a=a.nodeName)&&"input"===a.toLowerCase()&&("checkbox"===b||"radio"===b)}function qi(a){var b=Ef(a)?"checked":"value",c=Object.getOwnPropertyDescriptor(a.constructor.prototype,b),d=""+a[b];if(!a.hasOwnProperty(b)&&"undefined"!==typeof c&&"function"===typeof c.get&&"function"===typeof c.set){var e=c.get,f=c.set;Object.defineProperty(a,b,{configurable:!0,get:function(){return e.call(this)},set:function(a){d=""+a;f.call(this,a)}});Object.defineProperty(a, +b,{enumerable:c.enumerable});return{getValue:function(){return d},setValue:function(a){d=""+a},stopTracking:function(){a._valueTracker=null;delete a[b]}}}}function Fc(a){a._valueTracker||(a._valueTracker=qi(a))}function Ff(a){if(!a)return!1;var b=a._valueTracker;if(!b)return!0;var c=b.getValue();var d="";a&&(d=Ef(a)?a.checked?"true":"false":a.value);a=d;return a!==c?(b.setValue(a),!0):!1}function Gc(a){a=a||("undefined"!==typeof document?document:void 0);if("undefined"===typeof a)return null;try{return a.activeElement|| +a.body}catch(b){return a.body}}function Md(a,b){var c=b.checked;return B({},b,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=c?c:a._wrapperState.initialChecked})}function Gf(a,b){var c=null==b.defaultValue?"":b.defaultValue,d=null!=b.checked?b.checked:b.defaultChecked;c=xa(null!=b.value?b.value:c);a._wrapperState={initialChecked:d,initialValue:c,controlled:"checkbox"===b.type||"radio"===b.type?null!=b.checked:null!=b.value}}function Hf(a,b){b=b.checked;null!=b&&Ed(a,"checked", +b,!1)}function Nd(a,b){Hf(a,b);var c=xa(b.value),d=b.type;if(null!=c)if("number"===d){if(0===c&&""===a.value||a.value!=c)a.value=""+c}else a.value!==""+c&&(a.value=""+c);else if("submit"===d||"reset"===d){a.removeAttribute("value");return}b.hasOwnProperty("value")?Od(a,b.type,c):b.hasOwnProperty("defaultValue")&&Od(a,b.type,xa(b.defaultValue));null==b.checked&&null!=b.defaultChecked&&(a.defaultChecked=!!b.defaultChecked)}function If(a,b,c){if(b.hasOwnProperty("value")||b.hasOwnProperty("defaultValue")){var d= +b.type;if(!("submit"!==d&&"reset"!==d||void 0!==b.value&&null!==b.value))return;b=""+a._wrapperState.initialValue;c||b===a.value||(a.value=b);a.defaultValue=b}c=a.name;""!==c&&(a.name="");a.defaultChecked=!!a._wrapperState.initialChecked;""!==c&&(a.name=c)}function Od(a,b,c){if("number"!==b||Gc(a.ownerDocument)!==a)null==c?a.defaultValue=""+a._wrapperState.initialValue:a.defaultValue!==""+c&&(a.defaultValue=""+c)}function ri(a){var b="";ha.Children.forEach(a,function(a){null!=a&&(b+=a)});return b} +function Pd(a,b){a=B({children:void 0},b);if(b=ri(b.children))a.children=b;return a}function ib(a,b,c,d){a=a.options;if(b){b={};for(var e=0;e=c.length))throw Error(m(93));c=c[0]}b=c}null==b&&(b="");c=b}a._wrapperState={initialValue:xa(c)}}function Kf(a,b){var c=xa(b.value),d=xa(b.defaultValue);null!=c&&(c=""+c,c!==a.value&&(a.value=c),null==b.defaultValue&&a.defaultValue!== +c&&(a.defaultValue=c));null!=d&&(a.defaultValue=""+d)}function Lf(a,b){b=a.textContent;b===a._wrapperState.initialValue&&""!==b&&null!==b&&(a.value=b)}function Mf(a){switch(a){case "svg":return"http://www.w3.org/2000/svg";case "math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function Rd(a,b){return null==a||"http://www.w3.org/1999/xhtml"===a?Mf(b):"http://www.w3.org/2000/svg"===a&&"foreignObject"===b?"http://www.w3.org/1999/xhtml":a}function Nf(a,b,c){return null== +b||"boolean"===typeof b||""===b?"":c||"number"!==typeof b||0===b||Nb.hasOwnProperty(a)&&Nb[a]?(""+b).trim():b+"px"}function Of(a,b){a=a.style;for(var c in b)if(b.hasOwnProperty(c)){var d=0===c.indexOf("--"),e=Nf(c,b[c],d);"float"===c&&(c="cssFloat");d?a.setProperty(c,e):a[c]=e}}function Sd(a,b){if(b){if(si[a]&&(null!=b.children||null!=b.dangerouslySetInnerHTML))throw Error(m(137,a));if(null!=b.dangerouslySetInnerHTML){if(null!=b.children)throw Error(m(60));if(!("object"===typeof b.dangerouslySetInnerHTML&& +"__html"in b.dangerouslySetInnerHTML))throw Error(m(61));}if(null!=b.style&&"object"!==typeof b.style)throw Error(m(62));}}function Td(a,b){if(-1===a.indexOf("-"))return"string"===typeof b.is;switch(a){case "annotation-xml":case "color-profile":case "font-face":case "font-face-src":case "font-face-uri":case "font-face-format":case "font-face-name":case "missing-glyph":return!1;default:return!0}}function Ud(a){a=a.target||a.srcElement||window;a.correspondingUseElement&&(a=a.correspondingUseElement); +return 3===a.nodeType?a.parentNode:a}function Pf(a){if(a=Ob(a)){if("function"!==typeof Vd)throw Error(m(280));var b=a.stateNode;b&&(b=Hc(b),Vd(a.stateNode,a.type,b))}}function Qf(a){jb?kb?kb.push(a):kb=[a]:jb=a}function Rf(){if(jb){var a=jb,b=kb;kb=jb=null;Pf(a);if(b)for(a=0;ad?0:1<c;c++)b.push(a);return b}function Oc(a,b,c){a.pendingLanes|=b;var d=b-1;a.suspendedLanes&=d;a.pingedLanes&=d;a=a.eventTimes;b=31-Ba(b);a[b]=c}function Hi(a){return 0===a?32:31-(Ii(a)/Ji|0)|0}function Ki(a,b,c,d){Xa||Xd();var e=he,f=Xa;Xa=!0;try{fg(e,a,b,c,d)}finally{(Xa=f)||Wd()}}function Li(a,b,c,d){Mi(Ni,he.bind(null,a,b,c,d))}function he(a, +b,c,d){if(Pc){var e;if((e=0===(b&4))&&0=b)return{node:c,offset:b-a};a=d}a:{for(;c;){if(c.nextSibling){c=c.nextSibling;break a}c=c.parentNode}c=void 0}c=ug(c)}}function wg(a,b){return a&&b?a===b?!0:a&&3===a.nodeType?!1:b&&3===b.nodeType?wg(a,b.parentNode):"contains"in a?a.contains(b):a.compareDocumentPosition?!!(a.compareDocumentPosition(b)&16):!1:!1}function xg(){for(var a=window,b=Gc();b instanceof a.HTMLIFrameElement;){try{var c= +"string"===typeof b.contentWindow.location.href}catch(d){c=!1}if(c)a=b.contentWindow;else break;b=Gc(a.document)}return b}function ne(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return b&&("input"===b&&("text"===a.type||"search"===a.type||"tel"===a.type||"url"===a.type||"password"===a.type)||"textarea"===b||"true"===a.contentEditable)}function yg(a,b,c){var d=c.window===c?c.document:9===c.nodeType?c:c.ownerDocument;oe||null==qb||qb!==Gc(d)||(d=qb,"selectionStart"in d&&ne(d)?d={start:d.selectionStart, +end:d.selectionEnd}:(d=(d.ownerDocument&&d.ownerDocument.defaultView||window).getSelection(),d={anchorNode:d.anchorNode,anchorOffset:d.anchorOffset,focusNode:d.focusNode,focusOffset:d.focusOffset}),$b&&Zb($b,d)||($b=d,d=Tc(pe,"onSelect"),0ub||(a.current=ve[ub],ve[ub]=null,ub--)}function A(a,b,c){ub++;ve[ub]=a.current;a.current=b}function vb(a,b){var c=a.type.contextTypes;if(!c)return Ha;var d=a.stateNode;if(d&&d.__reactInternalMemoizedUnmaskedChildContext===b)return d.__reactInternalMemoizedMaskedChildContext;var e={},f;for(f in c)e[f]=b[f];d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext= +b,a.__reactInternalMemoizedMaskedChildContext=e);return e}function S(a){a=a.childContextTypes;return null!==a&&void 0!==a}function Sg(a,b,c){if(D.current!==Ha)throw Error(m(168));A(D,b);A(J,c)}function Tg(a,b,c){var d=a.stateNode;a=b.childContextTypes;if("function"!==typeof d.getChildContext)return c;d=d.getChildContext();for(var e in d)if(!(e in a))throw Error(m(108,hb(b)||"Unknown",e));return B({},c,d)}function Xc(a){a=(a=a.stateNode)&&a.__reactInternalMemoizedMergedChildContext||Ha;Ya=D.current; +A(D,a);A(J,J.current);return!0}function Ug(a,b,c){var d=a.stateNode;if(!d)throw Error(m(169));c?(a=Tg(a,b,Ya),d.__reactInternalMemoizedMergedChildContext=a,t(J),t(D),A(D,a)):t(J);A(J,c)}function wb(){switch(oj()){case Yc:return 99;case Vg:return 98;case Wg:return 97;case Xg:return 96;case Yg:return 95;default:throw Error(m(332));}}function Zg(a){switch(a){case 99:return Yc;case 98:return Vg;case 97:return Wg;case 96:return Xg;case 95:return Yg;default:throw Error(m(332));}}function Za(a,b){a=Zg(a); +return pj(a,b)}function bc(a,b,c){a=Zg(a);return we(a,b,c)}function ja(){if(null!==Zc){var a=Zc;Zc=null;xe(a)}$g()}function $g(){if(!ye&&null!==pa){ye=!0;var a=0;try{var b=pa;Za(99,function(){for(;ap?(x=l,l=null):x=l.sibling;var C=r(e,l,h[p],k);if(null===C){null===l&&(l=x);break}a&&l&&null=== +C.alternate&&b(e,l);g=f(C,g,p);null===v?m=C:v.sibling=C;v=C;l=x}if(p===h.length)return c(e,l),m;if(null===l){for(;px?(C=p,p=null):C=p.sibling;var Da=r(e,p,q.value,k);if(null===Da){null===p&&(p=C);break}a&&p&&null===Da.alternate&&b(e,p);g=f(Da,g,x);null===v?l=Da:v.sibling=Da;v=Da;p=C}if(q.done)return c(e,p),l;if(null===p){for(;!q.done;x++,q=h.next())q=n(e,q.value,k),null!==q&&(g=f(q,g,x),null===v?l=q:v.sibling=q,v=q);return l}for(p=d(e,p);!q.done;x++,q=h.next())q=t(p,e,x,q.value,k),null!==q&&(a&&null!== +q.alternate&&p.delete(null===q.key?x:q.key),g=f(q,g,x),null===v?l=q:v.sibling=q,v=q);a&&p.forEach(function(a){return b(e,a)});return l}return function(a,d,f,h){var k="object"===typeof f&&null!==f&&f.type===wa&&null===f.key;k&&(f=f.props.children);var l="object"===typeof f&&null!==f;if(l)switch(f.$$typeof){case ec:a:{l=f.key;for(k=d;null!==k;){if(k.key===l){switch(k.tag){case 7:if(f.type===wa){c(a,k.sibling);d=e(k,f.props.children);d.return=a;a=d;break a}break;default:if(k.elementType===f.type){c(a, +k.sibling);d=e(k,f.props);d.ref=dc(a,k,f);d.return=a;a=d;break a}}c(a,k);break}else b(a,k);k=k.sibling}f.type===wa?(d=zb(f.props.children,a.mode,h,f.key),d.return=a,a=d):(h=fd(f.type,f.key,f.props,null,a.mode,h),h.ref=dc(a,d,f),h.return=a,a=h)}return g(a);case Ua:a:{for(k=f.key;null!==d;){if(d.key===k)if(4===d.tag&&d.stateNode.containerInfo===f.containerInfo&&d.stateNode.implementation===f.implementation){c(a,d.sibling);d=e(d,f.children||[]);d.return=a;a=d;break a}else{c(a,d);break}else b(a,d);d= +d.sibling}d=Ee(f,a.mode,h);d.return=a;a=d}return g(a)}if("string"===typeof f||"number"===typeof f)return f=""+f,null!==d&&6===d.tag?(c(a,d.sibling),d=e(d,f),d.return=a,a=d):(c(a,d),d=De(f,a.mode,h),d.return=a,a=d),g(a);if(gd(f))return w(a,d,f,h);if(Jb(f))return z(a,d,f,h);l&&ed(a,f);if("undefined"===typeof f&&!k)switch(a.tag){case 1:case 22:case 0:case 11:case 15:throw Error(m(152,hb(a.type)||"Component"));}return c(a,d)}}function $a(a){if(a===fc)throw Error(m(174));return a}function Fe(a,b){A(gc, +b);A(hc,a);A(ka,fc);a=b.nodeType;switch(a){case 9:case 11:b=(b=b.documentElement)?b.namespaceURI:Rd(null,"");break;default:a=8===a?b.parentNode:b,b=a.namespaceURI||null,a=a.tagName,b=Rd(b,a)}t(ka);A(ka,b)}function Ab(a){t(ka);t(hc);t(gc)}function jh(a){$a(gc.current);var b=$a(ka.current);var c=Rd(b,a.type);b!==c&&(A(hc,a),A(ka,c))}function Ge(a){hc.current===a&&(t(ka),t(hc))}function hd(a){for(var b=a;null!==b;){if(13===b.tag){var c=b.memoizedState;if(null!==c&&(c=c.dehydrated,null===c||"$?"===c.data|| +"$!"===c.data))return b}else if(19===b.tag&&void 0!==b.memoizedProps.revealOrder){if(0!==(b.flags&64))return b}else if(null!==b.child){b.child.return=b;b=b.child;continue}if(b===a)break;for(;null===b.sibling;){if(null===b.return||b.return===a)return null;b=b.return}b.sibling.return=b.return;b=b.sibling}return null}function kh(a,b){var c=Z(5,null,null,0);c.elementType="DELETED";c.type="DELETED";c.stateNode=b;c.return=a;c.flags=8;null!==a.lastEffect?(a.lastEffect.nextEffect=c,a.lastEffect=c):a.firstEffect= +a.lastEffect=c}function lh(a,b){switch(a.tag){case 5:var c=a.type;b=1!==b.nodeType||c.toLowerCase()!==b.nodeName.toLowerCase()?null:b;return null!==b?(a.stateNode=b,!0):!1;case 6:return b=""===a.pendingProps||3!==b.nodeType?null:b,null!==b?(a.stateNode=b,!0):!1;case 13:return!1;default:return!1}}function He(a){if(la){var b=Na;if(b){var c=b;if(!lh(a,b)){b=tb(c.nextSibling);if(!b||!lh(a,b)){a.flags=a.flags&-1025|2;la=!1;ra=a;return}kh(ra,c)}ra=a;Na=tb(b.firstChild)}else a.flags=a.flags&-1025|2,la=!1, +ra=a}}function mh(a){for(a=a.return;null!==a&&5!==a.tag&&3!==a.tag&&13!==a.tag;)a=a.return;ra=a}function id(a){if(a!==ra)return!1;if(!la)return mh(a),la=!0,!1;var b=a.type;if(5!==a.tag||"head"!==b&&"body"!==b&&!se(b,a.memoizedProps))for(b=Na;b;)kh(a,b),b=tb(b.nextSibling);mh(a);if(13===a.tag){a=a.memoizedState;a=null!==a?a.dehydrated:null;if(!a)throw Error(m(317));a:{a=a.nextSibling;for(b=0;a;){if(8===a.nodeType){var c=a.data;if("/$"===c){if(0===b){Na=tb(a.nextSibling);break a}b--}else"$"!==c&&"$!"!== +c&&"$?"!==c||b++}a=a.nextSibling}Na=null}}else Na=ra?tb(a.stateNode.nextSibling):null;return!0}function Ie(){Na=ra=null;la=!1}function Je(){for(var a=0;af))throw Error(m(301));f+=1;K=N=null;b.updateQueue=null;jc.current=sj;a=c(d,e)}while(kc)}jc.current=jd;b=null!==N&&null!==N.next;ic=0;K=N=y=null;kd=!1;if(b)throw Error(m(300));return a}function ab(){var a={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};null===K?y.memoizedState=K=a:K=K.next=a;return K}function bb(){if(null===N){var a=y.alternate;a=null!==a?a.memoizedState:null}else a=N.next;var b=null===K?y.memoizedState:K.next;if(null!== +b)K=b,N=a;else{if(null===a)throw Error(m(310));N=a;a={memoizedState:N.memoizedState,baseState:N.baseState,baseQueue:N.baseQueue,queue:N.queue,next:null};null===K?y.memoizedState=K=a:K=K.next=a}return K}function ma(a,b){return"function"===typeof b?b(a):b}function lc(a,b,c){b=bb();c=b.queue;if(null===c)throw Error(m(311));c.lastRenderedReducer=a;var d=N,e=d.baseQueue,f=c.pending;if(null!==f){if(null!==e){var g=e.next;e.next=f.next;f.next=g}d.baseQueue=e=f;c.pending=null}if(null!==e){e=e.next;d=d.baseState; +var h=g=f=null,k=e;do{var l=k.lane;if((ic&l)===l)null!==h&&(h=h.next={lane:0,action:k.action,eagerReducer:k.eagerReducer,eagerState:k.eagerState,next:null}),d=k.eagerReducer===a?k.eagerState:a(d,k.action);else{var n={lane:l,action:k.action,eagerReducer:k.eagerReducer,eagerState:k.eagerState,next:null};null===h?(g=h=n,f=d):h=h.next=n;y.lanes|=l;La|=l}k=k.next}while(null!==k&&k!==e);null===h?f=d:h.next=g;X(d,b.memoizedState)||(fa=!0);b.memoizedState=d;b.baseState=f;b.baseQueue=h;c.lastRenderedState= +d}return[b.memoizedState,c.dispatch]}function mc(a,b,c){b=bb();c=b.queue;if(null===c)throw Error(m(311));c.lastRenderedReducer=a;var d=c.dispatch,e=c.pending,f=b.memoizedState;if(null!==e){c.pending=null;var g=e=e.next;do f=a(f,g.action),g=g.next;while(g!==e);X(f,b.memoizedState)||(fa=!0);b.memoizedState=f;null===b.baseQueue&&(b.baseState=f);c.lastRenderedState=f}return[f,d]}function nh(a,b,c){var d=b._getVersion;d=d(b._source);var e=b._workInProgressVersionPrimary;if(null!==e)a=e===d;else if(a=a.mutableReadLanes, +a=(ic&a)===a)b._workInProgressVersionPrimary=d,Bb.push(b);if(a)return c(b._source);Bb.push(b);throw Error(m(350));}function oh(a,b,c,d){var e=R;if(null===e)throw Error(m(349));var f=b._getVersion,g=f(b._source),h=jc.current,k=h.useState(function(){return nh(e,b,c)}),l=k[1],n=k[0];k=K;var t=a.memoizedState,r=t.refs,w=r.getSnapshot,z=t.source;t=t.subscribe;var B=y;a.memoizedState={refs:r,source:b,subscribe:d};h.useEffect(function(){r.getSnapshot=c;r.setSnapshot=l;var a=f(b._source);if(!X(g,a)){a=c(b._source); +X(n,a)||(l(a),a=Oa(B),e.mutableReadLanes|=a&e.pendingLanes);a=e.mutableReadLanes;e.entangledLanes|=a;for(var d=e.entanglements,h=a;0c?98:c,function(){a(!0)});Za(97\x3c/script>",a=a.removeChild(a.firstChild)):"string"===typeof d.is?a=g.createElement(c,{is:d.is}):(a=g.createElement(c),"select"===c&&(g=a,d.multiple? +g.multiple=!0:d.size&&(g.size=d.size))):a=g.createElementNS(a,c);a[Fa]=b;a[Wc]=d;xj(a,b,!1,!1);b.stateNode=a;g=Td(c,d);switch(c){case "dialog":z("cancel",a);z("close",a);e=d;break;case "iframe":case "object":case "embed":z("load",a);e=d;break;case "video":case "audio":for(e=0;eWe&&(b.flags|=64,f=!0,oc(d,!1),b.lanes=33554432)}else{if(!f)if(a=hd(g),null!==a){if(b.flags|=64,f=!0,c=a.updateQueue,null!==c&&(b.updateQueue=c,b.flags|=4),oc(d,!0),null===d.tail&&"hidden"===d.tailMode&& +!g.alternate&&!la)return b=b.lastEffect=d.lastEffect,null!==b&&(b.nextEffect=null),null}else 2*P()-d.renderingStartTime>We&&1073741824!==c&&(b.flags|=64,f=!0,oc(d,!1),b.lanes=33554432);d.isBackwards?(g.sibling=b.child,b.child=g):(c=d.last,null!==c?c.sibling=g:b.child=g,d.last=g)}return null!==d.tail?(c=d.tail,d.rendering=c,d.tail=c.sibling,d.lastEffect=b.lastEffect,d.renderingStartTime=P(),c.sibling=null,b=E.current,A(E,f?b&1|2:b&1),c):null;case 23:case 24:return ta=cb.current,t(cb),null!==a&&null!== +a.memoizedState!==(null!==b.memoizedState)&&"unstable-defer-without-hiding"!==d.mode&&(b.flags|=4),null}throw Error(m(156,b.tag));}function zj(a,b){switch(a.tag){case 1:return S(a.type)&&(t(J),t(D)),b=a.flags,b&4096?(a.flags=b&-4097|64,a):null;case 3:Ab();t(J);t(D);Je();b=a.flags;if(0!==(b&64))throw Error(m(285));a.flags=b&-4097|64;return a;case 5:return Ge(a),null;case 13:return t(E),b=a.flags,b&4096?(a.flags=b&-4097|64,a):null;case 19:return t(E),null;case 4:return Ab(),null;case 10:return Ae(a), +null;case 23:case 24:return ta=cb.current,t(cb),null;default:return null}}function Xe(a,b){try{var c="",d=b;do c+=pi(d),d=d.return;while(d);var e=c}catch(f){e="\nError generating stack: "+f.message+"\n"+f.stack}return{value:a,source:b,stack:e}}function Ye(a,b){try{console.error(b.value)}catch(c){setTimeout(function(){throw c;})}}function Mh(a,b,c){c=Ia(-1,c);c.tag=3;c.payload={element:null};var d=b.value;c.callback=function(){rd||(rd=!0,Ze=d);Ye(a,b)};return c}function Nh(a,b,c){c=Ia(-1,c);c.tag= +3;var d=a.type.getDerivedStateFromError;if("function"===typeof d){var e=b.value;c.payload=function(){Ye(a,b);return d(e)}}var f=a.stateNode;null!==f&&"function"===typeof f.componentDidCatch&&(c.callback=function(){"function"!==typeof d&&(null===na?na=new Set([this]):na.add(this),Ye(a,b));var c=b.stack;this.componentDidCatch(b.value,{componentStack:null!==c?c:""})});return c}function Oh(a){var b=a.ref;if(null!==b)if("function"===typeof b)try{b(null)}catch(c){Qa(a,c)}else b.current=null}function Aj(a, +b){switch(b.tag){case 0:case 11:case 15:case 22:return;case 1:if(b.flags&256&&null!==a){var c=a.memoizedProps,d=a.memoizedState;a=b.stateNode;b=a.getSnapshotBeforeUpdate(b.elementType===b.type?c:ea(b.type,c),d);a.__reactInternalSnapshotBeforeUpdate=b}return;case 3:b.flags&256&&te(b.stateNode.containerInfo);return;case 5:case 6:case 4:case 17:return}throw Error(m(163));}function Bj(a,b,c,d){switch(c.tag){case 0:case 11:case 15:case 22:b=c.updateQueue;b=null!==b?b.lastEffect:null;if(null!==b){a=b=b.next; +do 3===(a.tag&3)&&(d=a.create,a.destroy=d()),a=a.next;while(a!==b)}b=c.updateQueue;b=null!==b?b.lastEffect:null;if(null!==b){a=b=b.next;do{var e=a;d=e.next;e=e.tag;0!==(e&4)&&0!==(e&1)&&(Ph(c,a),Cj(c,a));a=d}while(a!==b)}return;case 1:a=c.stateNode;c.flags&4&&(null===b?a.componentDidMount():(d=c.elementType===c.type?b.memoizedProps:ea(c.type,b.memoizedProps),a.componentDidUpdate(d,b.memoizedState,a.__reactInternalSnapshotBeforeUpdate)));b=c.updateQueue;null!==b&&dh(c,b,a);return;case 3:b=c.updateQueue; +if(null!==b){a=null;if(null!==c.child)switch(c.child.tag){case 5:a=c.child.stateNode;break;case 1:a=c.child.stateNode}dh(c,b,a)}return;case 5:a=c.stateNode;null===b&&c.flags&4&&Pg(c.type,c.memoizedProps)&&a.focus();return;case 6:return;case 4:return;case 12:return;case 13:null===c.memoizedState&&(c=c.alternate,null!==c&&(c=c.memoizedState,null!==c&&(c=c.dehydrated,null!==c&&bg(c))));return;case 19:case 17:case 20:case 21:case 23:case 24:return}throw Error(m(163));}function Qh(a,b){for(var c=a;;){if(5=== +c.tag){var d=c.stateNode;if(b)d=d.style,"function"===typeof d.setProperty?d.setProperty("display","none","important"):d.display="none";else{d=c.stateNode;var e=c.memoizedProps.style;e=void 0!==e&&null!==e&&e.hasOwnProperty("display")?e.display:null;d.style.display=Nf("display",e)}}else if(6===c.tag)c.stateNode.nodeValue=b?"":c.memoizedProps;else if((23!==c.tag&&24!==c.tag||null===c.memoizedState||c===a)&&null!==c.child){c.child.return=c;c=c.child;continue}if(c===a)break;for(;null===c.sibling;){if(null=== +c.return||c.return===a)return;c=c.return}c.sibling.return=c.return;c=c.sibling}}function Rh(a,b,c){if(db&&"function"===typeof db.onCommitFiberUnmount)try{db.onCommitFiberUnmount($e,b)}catch(f){}switch(b.tag){case 0:case 11:case 14:case 15:case 22:a=b.updateQueue;if(null!==a&&(a=a.lastEffect,null!==a)){c=a=a.next;do{var d=c,e=d.destroy;d=d.tag;if(void 0!==e)if(0!==(d&4))Ph(b,c);else{d=b;try{e()}catch(f){Qa(d,f)}}c=c.next}while(c!==a)}break;case 1:Oh(b);a=b.stateNode;if("function"===typeof a.componentWillUnmount)try{a.props= +b.memoizedProps,a.state=b.memoizedState,a.componentWillUnmount()}catch(f){Qa(b,f)}break;case 5:Oh(b);break;case 4:Sh(a,b)}}function Th(a){a.alternate=null;a.child=null;a.dependencies=null;a.firstEffect=null;a.lastEffect=null;a.memoizedProps=null;a.memoizedState=null;a.pendingProps=null;a.return=null;a.updateQueue=null}function Uh(a){return 5===a.tag||3===a.tag||4===a.tag}function Vh(a){a:{for(var b=a.return;null!==b;){if(Uh(b))break a;b=b.return}throw Error(m(160));}var c=b;b=c.stateNode;switch(c.tag){case 5:var d= +!1;break;case 3:b=b.containerInfo;d=!0;break;case 4:b=b.containerInfo;d=!0;break;default:throw Error(m(161));}c.flags&16&&(qc(b,""),c.flags&=-17);a:b:for(c=a;;){for(;null===c.sibling;){if(null===c.return||Uh(c.return)){c=null;break a}c=c.return}c.sibling.return=c.return;for(c=c.sibling;5!==c.tag&&6!==c.tag&&18!==c.tag;){if(c.flags&2)continue b;if(null===c.child||4===c.tag)continue b;else c.child.return=c,c=c.child}if(!(c.flags&2)){c=c.stateNode;break a}}d?af(a,c,b):bf(a,c,b)}function af(a,b,c){var d= +a.tag,e=5===d||6===d;if(e)a=e?a.stateNode:a.stateNode.instance,b?8===c.nodeType?c.parentNode.insertBefore(a,b):c.insertBefore(a,b):(8===c.nodeType?(b=c.parentNode,b.insertBefore(a,c)):(b=c,b.appendChild(a)),c=c._reactRootContainer,null!==c&&void 0!==c||null!==b.onclick||(b.onclick=Vc));else if(4!==d&&(a=a.child,null!==a))for(af(a,b,c),a=a.sibling;null!==a;)af(a,b,c),a=a.sibling}function bf(a,b,c){var d=a.tag,e=5===d||6===d;if(e)a=e?a.stateNode:a.stateNode.instance,b?c.insertBefore(a,b):c.appendChild(a); +else if(4!==d&&(a=a.child,null!==a))for(bf(a,b,c),a=a.sibling;null!==a;)bf(a,b,c),a=a.sibling}function Sh(a,b,c){c=b;for(var d=!1,e,f;;){if(!d){e=c.return;a:for(;;){if(null===e)throw Error(m(160));f=e.stateNode;switch(e.tag){case 5:e=f;f=!1;break a;case 3:e=f.containerInfo;f=!0;break a;case 4:e=f.containerInfo;f=!0;break a}e=e.return}d=!0}if(5===c.tag||6===c.tag){a:for(var g=a,h=c,k=h;;)if(Rh(g,k),null!==k.child&&4!==k.tag)k.child.return=k,k=k.child;else{if(k===h)break a;for(;null===k.sibling;){if(null=== +k.return||k.return===h)break a;k=k.return}k.sibling.return=k.return;k=k.sibling}f?(g=e,h=c.stateNode,8===g.nodeType?g.parentNode.removeChild(h):g.removeChild(h)):e.removeChild(c.stateNode)}else if(4===c.tag){if(null!==c.child){e=c.stateNode.containerInfo;f=!0;c.child.return=c;c=c.child;continue}}else if(Rh(a,c),null!==c.child){c.child.return=c;c=c.child;continue}if(c===b)break;for(;null===c.sibling;){if(null===c.return||c.return===b)return;c=c.return;4===c.tag&&(d=!1)}c.sibling.return=c.return;c= +c.sibling}}function cf(a,b){switch(b.tag){case 0:case 11:case 14:case 15:case 22:var c=b.updateQueue;c=null!==c?c.lastEffect:null;if(null!==c){var d=c=c.next;do 3===(d.tag&3)&&(a=d.destroy,d.destroy=void 0,void 0!==a&&a()),d=d.next;while(d!==c)}return;case 1:return;case 5:c=b.stateNode;if(null!=c){d=b.memoizedProps;var e=null!==a?a.memoizedProps:d;a=b.type;var f=b.updateQueue;b.updateQueue=null;if(null!==f){c[Wc]=d;"input"===a&&"radio"===d.type&&null!=d.name&&Hf(c,d);Td(a,e);b=Td(a,d);for(e=0;ee&&(e=g);c&=~f}c=e;c=P()-c;c=(120>c?120:480>c?480:1080>c?1080:1920>c?1920:3E3>c?3E3:4320>c?4320:1960*Ij(c/1960))-c;if(10 component higher in the tree to provide a loading indicator or placeholder to display.")}5!== +L&&(L=2);k=Xe(k,h);r=g;do{switch(r.tag){case 3:f=k;r.flags|=4096;b&=-b;r.lanes|=b;var B=Mh(r,f,b);ch(r,B);break a;case 1:f=k;var A=r.type,D=r.stateNode;if(0===(r.flags&64)&&("function"===typeof A.getDerivedStateFromError||null!==D&&"function"===typeof D.componentDidCatch&&(null===na||!na.has(D)))){r.flags|=4096;b&=-b;r.lanes|=b;var F=Nh(r,f,b);ch(r,F);break a}}r=r.return}while(null!==r)}ci(c)}catch(qa){b=qa;G===c&&null!==c&&(G=c=c.return);continue}break}while(1)}function Yh(){var a=vd.current;vd.current= +jd;return null===a?jd:a}function sc(a,b){var c=n;n|=16;var d=Yh();R===a&&O===b||Gb(a,b);do try{Nj();break}catch(e){Zh(a,e)}while(1);ze();n=c;vd.current=d;if(null!==G)throw Error(m(261));R=null;O=0;return L}function Nj(){for(;null!==G;)di(G)}function Hj(){for(;null!==G&&!Oj();)di(G)}function di(a){var b=Pj(a.alternate,a,ta);a.memoizedProps=a.pendingProps;null===b?ci(a):G=b;kf.current=null}function ci(a){var b=a;do{var c=b.alternate;a=b.return;if(0===(b.flags&2048)){c=vj(c,b,ta);if(null!==c){G=c;return}c= +b;if(24!==c.tag&&23!==c.tag||null===c.memoizedState||0!==(ta&1073741824)||0===(c.mode&4)){for(var d=0,e=c.child;null!==e;)d|=e.lanes|e.childLanes,e=e.sibling;c.childLanes=d}null!==a&&0===(a.flags&2048)&&(null===a.firstEffect&&(a.firstEffect=b.firstEffect),null!==b.lastEffect&&(null!==a.lastEffect&&(a.lastEffect.nextEffect=b.firstEffect),a.lastEffect=b.lastEffect),1g&&(h=g,g=A,A=h),h=vg(p,A),f=vg(p,g),h&&f&&(1!==u.rangeCount||u.anchorNode!==h.node||u.anchorOffset!==h.offset||u.focusNode!==f.node||u.focusOffset!==f.offset)&&(q=q.createRange(),q.setStart(h.node,h.offset),u.removeAllRanges(),A>g?(u.addRange(q),u.extend(f.node, +f.offset)):(q.setEnd(f.node,f.offset),u.addRange(q))))));q=[];for(u=p;u=u.parentNode;)1===u.nodeType&&q.push({element:u,left:u.scrollLeft,top:u.scrollTop});"function"===typeof p.focus&&p.focus();for(p=0;pP()-df?Gb(a,0):jf|=c);ba(a,b)}function Ej(a,b){var c=a.stateNode;null!==c&&c.delete(b);b=0;0===b&&(b=a.mode,0===(b&2)?b=1:0===(b&4)?b=99===wb()?1:2:(0===ua&&(ua=Fb),b=nb(62914560&~ua),0===b&&(b=4194304))); +c=W();a=ud(a,b);null!==a&&(Oc(a,b,c),ba(a,c))}function Uj(a,b,c,d){this.tag=a;this.key=c;this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null;this.index=0;this.ref=null;this.pendingProps=b;this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null;this.mode=d;this.flags=0;this.lastEffect=this.firstEffect=this.nextEffect=null;this.childLanes=this.lanes=0;this.alternate=null}function Qe(a){a=a.prototype;return!(!a||!a.isReactComponent)}function Vj(a){if("function"=== +typeof a)return Qe(a)?1:0;if(void 0!==a&&null!==a){a=a.$$typeof;if(a===Dc)return 11;if(a===Ec)return 14}return 2}function Ma(a,b){var c=a.alternate;null===c?(c=Z(a.tag,b,a.key,a.mode),c.elementType=a.elementType,c.type=a.type,c.stateNode=a.stateNode,c.alternate=a,a.alternate=c):(c.pendingProps=b,c.type=a.type,c.flags=0,c.nextEffect=null,c.firstEffect=null,c.lastEffect=null);c.childLanes=a.childLanes;c.lanes=a.lanes;c.child=a.child;c.memoizedProps=a.memoizedProps;c.memoizedState=a.memoizedState;c.updateQueue= +a.updateQueue;b=a.dependencies;c.dependencies=null===b?null:{lanes:b.lanes,firstContext:b.firstContext};c.sibling=a.sibling;c.index=a.index;c.ref=a.ref;return c}function fd(a,b,c,d,e,f){var g=2;d=a;if("function"===typeof a)Qe(a)&&(g=1);else if("string"===typeof a)g=5;else a:switch(a){case wa:return zb(c.children,e,f,b);case fi:g=8;e|=16;break;case Hd:g=8;e|=1;break;case Lb:return a=Z(12,c,b,e|8),a.elementType=Lb,a.type=Lb,a.lanes=f,a;case Mb:return a=Z(13,c,b,e),a.type=Mb,a.elementType=Mb,a.lanes= +f,a;case Cc:return a=Z(19,c,b,e),a.elementType=Cc,a.lanes=f,a;case pf:return Ue(c,e,f,b);case qf:return a=Z(24,c,b,e),a.elementType=qf,a.lanes=f,a;default:if("object"===typeof a&&null!==a)switch(a.$$typeof){case Jd:g=10;break a;case Id:g=9;break a;case Dc:g=11;break a;case Ec:g=14;break a;case Ld:g=16;d=null;break a;case Kd:g=22;break a}throw Error(m(130,null==a?a:typeof a,""));}b=Z(g,c,b,e);b.elementType=a;b.type=d;b.lanes=f;return b}function zb(a,b,c,d){a=Z(7,a,d,b);a.lanes=c;return a}function Ue(a, +b,c,d){a=Z(23,a,d,b);a.elementType=pf;a.lanes=c;return a}function De(a,b,c){a=Z(6,a,null,b);a.lanes=c;return a}function Ee(a,b,c){b=Z(4,null!==a.children?a.children:[],a.key,b);b.lanes=c;b.stateNode={containerInfo:a.containerInfo,pendingChildren:null,implementation:a.implementation};return b}function Wj(a,b,c){this.tag=b;this.containerInfo=a;this.finishedWork=this.pingCache=this.current=this.pendingChildren=null;this.timeoutHandle=-1;this.pendingContext=this.context=null;this.hydrate=c;this.callbackNode= +null;this.callbackPriority=0;this.eventTimes=ge(0);this.expirationTimes=ge(-1);this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0;this.entanglements=ge(0);this.mutableSourceEagerHydrationData=null}function Xj(a,b,c){var d=3