diff --git a/.gitignore b/.gitignore index c678610..9a81394 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ .idea/ .vscode/ ipld-eth-state-snapshot -mocks/ -.vscode output_dir*/ log_file recovery_file diff --git a/Makefile b/Makefile index 69dfd00..5e7710c 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,13 @@ -BIN = $(GOPATH)/bin +MOCKGEN ?= mockgen +MOCKS_DIR := $(CURDIR)/internal/mocks -## Mockgen tool -MOCKGEN = $(BIN)/mockgen -$(BIN)/mockgen: - go install github.com/golang/mock/mockgen@v1.6.0 +mocks: $(MOCKS_DIR)/gen_indexer.go +.PHONY: mocks -MOCKS_DIR = $(CURDIR)/mocks - -.PHONY: mocks test - -mocks: $(MOCKGEN) mocks/snapshot/publisher.go - -mocks/snapshot/publisher.go: pkg/types/publisher.go - $(MOCKGEN) -package snapshot_mock -destination $@ -source $< Publisher Tx +$(MOCKS_DIR)/gen_indexer.go: + $(MOCKGEN) --package mocks --destination $@ \ + --mock_names Indexer=MockgenIndexer \ + github.com/cerc-io/plugeth-statediff/indexer Indexer clean: rm -f mocks/snapshot/publisher.go diff --git a/fixture/leaf_keys.go b/fixture/leaf_keys.go index 8fcd4c1..7f403f0 100644 --- a/fixture/leaf_keys.go +++ b/fixture/leaf_keys.go @@ -1,264 +1,619 @@ package fixture var Block1_StateNodeLeafKeys = []string{ - "0x291b6bbca879d684337ee5e2bca5d18cfb2d3b7a97c8187e703309564280295e", - "0x021fe3360ba8c02e194f8e7facdeb9088b3cf433b6498bd6900d50df0266ffe3", - "0x7820b41394d7f30f2b02f24f8a33afe8b98cd68827ec651aec3ba33e41206fe2", - "0xf908d785cef1abc9fcea55c07490d16b4825e8a6a7c8fb157ed2900bf4af58b9", - "0xd207b05b684ba18361df8e81e846d10365ffcf04f7840403c5bacf77add4c50f", - "0x5037b71f063bfe647233f570aa06602b1e6b5124db0b1fe998975f93b0fb1084", - "0xb02c4d58a3800d93f95f2eb4850b3d242756bf1ca3099bc43907af6dff0bf337", - "0x300d2dbe83a6ba7fd75737c8d7453d984e7938ba7ae113d3da2ad7433061157b", - "0x80382280e2f4a8ea9001c8e22332a3dc3d3a692b549d3c90f65796270e1eb770", - "0x087fb108e6836a088e06156b1a26210d1f5284296b30b0bb0b3d1c2a7e01ac11", - "0x71a3c7f8d0fe8abc9fbab1860ad576eddff2144763937195ea4f012fc625b053", - "0xb8864cb7c6215e99ffe5db7b22b3129e93b9a38b9b54193a0e3d7c8251657173", - "0x881a506039e25a818f35aa0e3ec58c64df5c106245dc25ef6fa4cf1eb1aab56a", - "0x40637a529320dace54763c2e6ac52c522c8a446ba9b6f54daf84c0e442124b93", - "0xa092c3f36135f79c57aa5683d97e5d5750c37d0bd0ada215e9a96856c56d7e91", - "0x684272547bac4c083b7380f054d08a5030862a5f06a2367f3b8e880c4b7370ed", - "0x18dcd435bf7d1820085f6c46d587cae669ca7c2d3ad4cea9db320a0b3c8bd21d", - "0xc00c28a6bfe2829613432a2c21eefc25da5bad983c5430ca28bc1a92d2b65ec5", - "0xf03db4f61547c9d8c58b4f37f84f74eff767c24cf81b957662e96622f2ac4d19", - "0x38401b4e97e67c4a6d8095979b4c1ecb9eaf5726fc8a12798975a7653e980872", - "0x992470b3e52c94f7bd5d4962a1798a41425bea74ad087a7f53aebb785401df3d", - "0xe015d2e4c085291611298460602b913b5f19272715fcaa48258efe24cf21885e", - "0x2092b5602121cc484fa55b90cea0be17d931184263925a864e0d5d43a20d67b0", - "0xe83c2c56f351d8c25863a55ece938ffcb6cdf2978eb34ea1a19591884d3885f3", - "0x489fe686547f4a999d2818aedbc18b735ed2cd502c30124a0b8af861b2251f91", - "0x90b0d289ea211dca8e020c9cc8c5d6ba2f416fe15fa692b47184a4b946b2214d", - "0x6042501054831920bc9d50a33d6be1b5a8214c31ba9416958f8996cdb6ddb05c", - "0x125adc67efe8bf6808c02bd3ae20262953b5e45dab4eb9386441cf6ec7381844", - "0xd81c5d559ba870e90a2b617cf0542695e9a626619b59148b40295a0ba55ca66e", - "0x5839262442bd87bdce9bcd8e97628a84fd07aaf55ba8c4c29e1ae91cb17cb222", - "0xa876da518a393dbd067dc72abfa08d475ed6447fca96d92ec3f9e7eba503ca61", - "0xc93e183a9dd09cdd44ca2a9eb6b94f970f8fa309b0f9cfd823572c23aad58fb2", - "0x75422a3d36c93fcbccad2e502775226f375e264e35fc55ac20df1e9f050e8b8c", - "0x20ebfef43639215aeb35e1e00bc96174f52155afb781659f34628d1f3f7ae018", - "0x20ebfef43639215aeb35e1e00bc96174f52155afb781659f34628d1f3f7ae018", "0x005e54f1867fd030f90673b8b625ac8f0656e44a88cfc0b3af3e3f3c3d486960", - "0x1a6d9674aec5c8329252cb634022308bf4c98e70edec613d925ab781483445a4", - "0x5095b76023974440e6c155e26b3f7084f0b1901a0df2183dcfebe01f326d5e96", - "0x58bb8d7ba2f52228853238b26bfe3eb9607cea944e7020458981618efe8280a1", - "0xf92f9911e6d5b40e46f574db0a406d360f91c8de842ded48c8c699080985b4cf", - "0x785a32bf0f42bd6c986b900070bd70ff4ed5eaad448e57cf5d997224c3f87c2c", - "0x9546dea22f2479752816b65aa9db1b835efefbc1ed11804699683897cda4227e", - "0x39c8bb92227ba91a2657f29c5498f5c5b07ae36369c8d9283444f477930c79be", - "0x75422a3d36c93fcbccad2e502775226f375e264e35fc55ac20df1e9f050e8b8c", - "0x9ee40dcbc49746e31a754155515aaa232bf0bdbfd5a7ab77ea9cd39f4b7282a1", - "0xe8c07bab8822eeeb875236e148f781341157f9bfc56c1c53972489ff4009695b", - "0xb0fe18e510f695dbf24ad56fb3b647aa09f8e19021abe80686a66a2e653cb12d", - "0xf5b693085beb21b0878c7e5fab7519ce0d6105354cf6744dbfb73e3745e929e4", - "0xa0a22226f85371b5e5e4173b33a1b9629d745961f36e9b0510c591f11e3dd95b", - "0x08b3f9a96baba12f47430f2b0e2851f407e8ca355bb8a9a69242bc99aecc2cf3", - "0xc01318ac6e0d2cc08468abc1df6f2c9ec3fc5cfbfe5efec83aab250cfc83ef3f", - "0x8938be2ad9950390d6d92213ca102fc21a4304c88354d0e74f4b3ff696ce5791", - "0x623f300bf600b7b050b9b70fa57140c59a5f0b9fc5b9d0bdab11d108a71fc1a3", - "0xb8f37a61c26d388306ad9dee25e72aa86a49903a1fbbe6205211b47d1f39f77f", - "0x127ec70ea0d8a7b6244ae7d951b2204f75336cf21f49df6370ab920534c95728", - "0x68492f20c1d7597425c8a53a7f5e380fbce058d1bfea2521a7e8af03c387e1a0", - "0xf93d447fcf86f847e6609bfb3100aa5d07df37f2c72cbc4961e3a0f86a7c24b7", - "0x3a2c7d5164f6a1d8cbc5d9e228253eae4a66d8b0d550d07c53ec84d47ed17172", - "0xf93d447fcf86f847e6609bfb3100aa5d07df37f2c72cbc4961e3a0f86a7c24b7", - "0x4b6029773e7175f32398422fd18c6cb095e5278ac7be41ca4a5a6c0a6dda1a71", - "0xd222125724b9df1f4a92e1284dbc871a9156c253572df0a38ae146ac03b62af4", - "0x5a4be2322eb50cfea1051978c284526cd5a6e28caca681855736a5d3c31d9bad", - "0x89d04bcba396d12de1ed36f41df60ce0ae0449bae83f14c740451cf19362ae8f", - "0xd8ffcbc0be38306e539da616161c64ef7bc0f0281d62e5296bc8eb6ea709cb0b", - "0x96ad0b27ef10fa7a9940299df122d31222cc911bd2c91d2740f25a0dc931f4c0", - "0x40f85cb8136e95238cea4cb951a2ee645a4998c108831d5abe1d8f48696864c3", - "0xcb44297958c82fe80fb882f2c8a085a38556247b3c3f665eca382d27e26e3bbc", - "0x6298deb7c736dc50b4590ca066b72173d4e2c3f75bb109396f32eaaf9ad11bc8", - "0x3019c0a91ba30d346a55890b1b07287d8aae35baa8c4068ef8f1de66084aca75", - "0xb9af72fc0534a4a5a94eb1f64cb1bd6c425acba3249fb8441e7411e9be9ec1f3", - "0x80be858ab09789d26cf1128775756a8abe1c8ffc4218d3e990b3d25a82583255", - "0x0999f18de77e9451867cb1935f9acd56f79cbc11d04826c3da6b420a4f4bbe21", - "0xb14d9fdc657d712208d6e7c2cfbf62f7ad7ba1bfff2e63e6caee2b0bf5bad0fd", - "0xa93db8611e8d0c159eb724d2aea72763dfb5a6909a8516467c79d0386d61a511", - "0xc01b3857946cb77af9fb09394c4a359fba6df202c77d3e07e53177f3f18a55f2", - "0x79deb2f042f1717cc882c5a38bbb6c524932352ff25baeb8b8fd2225095e29ae", - "0x50ff4d47a46c9cd35b029e95ef9c957e57da987491f6e7be242e72bc5d3e8086", - "0xe8c6b410e2984be3bed9a84b76fbbd647f5fa56e65e36c264903275aa22cdb0d", - "0xe1e23690e890cdec6eb19b06f5d31d422b5c17bd4c435afb2a2532180011453f", - "0x9f0dbaecc6581cfbb57cd6c6f50e24c23ad4fcdf228140c0cb51a8a4edf5d0b0", - "0xf67f470df15c88b9beaf3fad72890a64f8851d01ece546b0c9fb3bdf92041a35", - "0x1d50131be868de2741cb775d0ff800631f96065f40b60845bce72e782718af23", - "0xa0f1ddc6e3aad69109e0e8c5d15e8800e220b192f85f369e0bef5cf858dccf9a", - "0x689802d6ed1a28b049e9d4fe5334c5902fd9bc00c42821c82f82ee2da10be908", - "0x1318a4c2bc731718857238ec2c42e4a95c0aeb7290a60c8abb110c2e638341c2", - "0x21120e1be03d384ee32a9bd7268578d8829f271540c848c97a495990bc48f582", - "0x297d3acffb942c7e6f3fb029b735338ac34e39c4ce9e852f64d50fb57cc97ec0", - "0x7744be2427cacf17062cb030d30e34c3b543b28a83707df04e64d3f7ddb471b8", + "0x021fe3360ba8c02e194f8e7facdeb9088b3cf433b6498bd6900d50df0266ffe3", "0x028e62cb4665fce19ae1fc13a604618d7d20be037fc68b63beb3384dfa5ab776", - "0xcce46204baa86f733abf208b358ba8b807081d6d46a407745238aef2c133fd4d", - "0xaa546817dabffc9c4249830a0af5cf43c6ece6562720990736199e570f621d7c", - "0xfb1d6797796ad9edd1b8b41030035a003eb6286ae2fc1a8296b509891acfa033", - "0xb25939867994cd8e5a18f341628420fa8ab88b2f5d05ffe51291654922f5454f", - "0x2b7afbb14b4c902f37163b15f70fe8335dec4e26fbae4718c03f19da5aecbe8b", - "0x1e22733f173fbc95fa079ed50ec24c498a8aad2515d827e5ff8200c240e9cdc9", - "0x4b945ef2e8c78482bbffcbdf4921cd375065e3b5024a3bed469a9f34b2e773e7", - "0x13b8f5750961b5588bc69fbd0b701461854e110fd78c14767515bdd882725975", - "0x41351b958be1e95cdc37f7d2d654315e33ff7f45bac9179f9242fdc828c8d2e3", - "0x9f4e60123db23e3f3055f75087248fd5923d469e76d344d28b4f24a449ca6398", - "0x7d1009331195f6a3c2eee6ac4b4664f61c777500c163ee84769913578a33bdf2", - "0xbb62e8d8d0eb3d7432758c244131f1649874367cc52a4fa4fd0609def9e57389", - "0xe22d496c425479acb445c4040bdb5e17fa461de175eaaa77aa79e23b5b19f761", - "0xd24e8fff20c5317074c54fd54ca9f1fc8fef36bb70c44b55f90a70c621b91f9a", - "0xd90bcdecb44a3402e2a1b5d3a321b51e415e298ebaca3c95d91443adc03f6cec", - "0x826ce1d60ac9f0ab5944acf1c06700a585f8407d670495c7811b97cf8263b434", - "0x2139fa1aaa3d60e53d070d5a1f1ac9c8211f41b2dd5a1813416c8447a7759557", - "0x96e16af9aa5f894c43514d940687dafaa5ad04ea78a3b0080319370e454602d2", - "0x6400fc32c5b2d3580c0e19889487cf9e057d6b82a99bf30eb6e539b7cde52655", "0x02cb51767354e1fe6bd4a49b64b3721ffddbc95fed1b8ead005c39bbc07bc4d8", - "0x3a82e1e58ae6f14fbbeb35b6d833330c4fb5b3cb770391f5cc340949c6254e83", - "0xa216c0a47b12c20d5ac5c381464a89521d8b0c1a5cb328aeabb29b70bc3347d4", - "0xea674e603f60ba1e252419d86d0485fd3f46ca6abbf4c65afee0a9ba29059655", - "0x8ae586aa1ec2c29aced4feb5adf9336541769b93cd5b8cc1b64b7d831c7b0ec2", - "0x323e393774eeec8e9d596258267d0133a5b2f01c567822a4ff018488671ecb6e", - "0x51ee1e08db014fc699587667b7256e7b9090e1755c587420cff5fbe0e20194fc", - "0x6a1c4e8b7c710531c9e66166d0629ff443df19cefa081eb4fffcc7d267ce7c92", - "0x09af9e7ea2370ab3e3ee7f0a465a7dacb6c9b7e65196dc496d5570a0d8020bda", - "0x5b70e80538acdabd6137353b0f9d8d149f4dba91e8be2e7946e409bfdbe685b9", - "0xc0f4fde474181fca3d1fb6e0dc118a71457fe7cc5d4f1e426c92e1767eb885a0", - "0x4bce4e0299e5362578a95a27bcb779b9a89232296388db803909696f90635581", - "0x1ebfd7dbb6804351804443df01a482e6451912b884cd26b31504bb77bbec9862", "0x03089e01be9eb2af5ff5fa1c5983c6c6fb78dd734658d1f8f11d4f8d27a23fd5", - "0xb31ba6d576dbde0542d30a9264e2c71be270e3eb4f5910567a8c1c0619a2e5ec", - "0xaa8d9c947771632a645c67655595b61da72837bfa97f30f417dbaed82f2f11c3", - "0x32fc4fd3fc836c6db0058fd20ff7e8ca611885eb7215b39f97d2b4e797dca254", - "0x5c33820c3d76f4de8d1e0eca24c7d2fbef76189b6a43a7afea4dfda5b50edb96", - "0x6aefc729e28e1bbd2e63dd0803314deb808ab044909af882b7935dd05f5939a4", - "0x0c3a3c99f34afe9d2c8cecc90524ef63afc9fc13384d5d931281f414d5d487c0", - "0x9fa95d10732f34365f34f5a2f7702a9dae40c583105c40921a5052dca1f9f793", - "0xeacbb86ec518baa710dea5ed986162f21df2a98d2119f6cacbb01e8d9a77a629", - "0x7d1d5f3a14c0ab133b65698c2d62c818c65f13306ccbfd61aa4b7590bb78660c", - "0xfb6ab511cf5bcb157f833241e74ead7128a21818c2b5080be21ee9f85ff5d523", - "0x21ea8bdf8a4ea6dc9e204591d88c3b5b19533d33bfbc59c08cca266c3c87a960", - "0x9782bb006174ed014c59e6eee381c6e10bc9304226edb99edd6f8e9041e9d9a7", - "0xbc0cb591a67822e88dcebb8991bca5b7305b5858d65bc2b5e6605e481a650588", - "0x8484452e4f0c1a9f115c52b4ac78a0de2f1b0ab1a4aae8390426ac71e03f8779", - "0x2bd9aebde44794e6db317be6d83c5a266e1a96e18e04bc7073998bb779cfe2fe", - "0xd9ed35852650f28d7a8f73c7ba49bcd72d97edf8d731797e5a2728559b865552", - "0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d", - "0xfc39bbcf08818ec3329e5769dff3fbdad66e6312a961acb32c1b203edf70aeba", - "0x5d9114e8c0b1e858bf7322eec122e3fc4b0988f146620def0fde9dbd322f3a03", - "0x4e09550da9ca55ba375e56c525b49b27814d20165528e4e7f309878221b2878b", - "0xe2c8bbf962c30afe9c35e9d7e036ef496b52cb770c645a76f2cee5f8811a9830", - "0xbddec651652e0aa17e056de1790554aeca5fa248cecc4131d189dacd26c4ca55", - "0x51f0e21d8c8aeef60da6ae58d10dcf1f42e7d9a0cb8ee2b4a97caa566a152b61", - "0x421df1fa259221d02aa4956eb0d35ace318ca24c0a33a64c1af96cf67cf245b6", - "0xd37476a178ee68b02b3de0edee1ebb57e1638eebf58b3e256322e0da1189f272", - "0xa3b41c13f6e16fd2242a43b041cfd1f02cbb4cf06943d14365bb8f0a30ff507a", - "0x3ac3fe84c663607ebbe01c6b008d02b92ed4feab26ed8171014853c0f9419cc8", - "0xad00cf4d7db523f20b5000bd1469a11d70b73feadd36578abdb9f3558bdd3674", - "0x8c3ab0970b73895b8c9959bae685c3a19f45eb5ad89d42b52a340ec4ac204d19", - "0x2d15e1e82ca50b7334be8990b93a8b043e771340cc9398baa23845763c696d22", - "0x331d99c6bec3aecbec962be74b25448511983b013c0876f6f4e6029773dfad61", - "0x258487f1d48945c7743c412b0f026d722a4641d5978f11a0b44dbf7c1d274d41", - "0x528b55564e8518548e42b534da3a526179b820f264ee7c6929d00b0b6a31cfc2", - "0xc2911b75be7d3fdb9442b900ca8f7205d6d52fdb3505e77ea8676f811a6d5ea1", - "0xda0d7fc05c32bbba16518f9f2936fd75140d5c99b95ae536205ba9caf1868378", - "0x26dbcce1b599ebed46e2569579562031255ea9a1c1c575fdddb0003f4d389165", - "0x8cfefa9806c99db8bea1ed8e534f6dcdb835cd1410f1f287ea4293e29a3eacc0", - "0xbe017710d6bfb0ac7a8d140333127571809eaf2b590900f168545daea3865f60", - "0x42b45de6853d406783b6b50c378bfb61d6ce5271b3bf813cc2b959055fc12f98", - "0x2df378e8ecee785e1d65200d738178432cbc9ad55c49ea5af905629d348416c2", - "0xe36c0f154a365e086c687050cee74bddde9997a1dedeb0e55217368c0ab6baa4", - "0xa62e9dc15a35c1ab9d0ac4345b1f02fd8e8070883a33651c0c143b2582708268", "0x04242954a5cb9748d3f66bcd4583fd3830287aa585bebd9dd06fa6625976be49", - "0xb41089e529c1ff6c4d6583ecfca7ea6419bf39e0d418686bb7a24424c670b332", - "0xd3a7e59f888a7ac07a211c717c07b82970d94597f6365cf8c93d51ac9d45c597", - "0xaddb0d4b14749bb4b5cd858f29a4b4225138c3953090ce45204458dcd53749e4", - "0x34275c313c5286317794f0154f8e4ffacfc80d9d0c5b184d2482e7f9211ffc3e", - "0xfce7321f278a2973bf5c67757ea7690649295d53967daa3ae858695be336abe2", - "0x1f99af2df2da9c0176bdb3e995bdfa47ffbfe6a3aacf8e54401f4dac2ece9338", - "0x6b2c03103b55a45cc1e4550889a9396e7e331b5cf1729e4871ff4dee701139e9", - "0x640528e5cf143f173d29cd8b4f896a1c6128f3416c887c10d4a11898841b4a82", - "0xe4295c5aa043a60d279854f7424e21250d5c1e1f9959549e90bc926d70e97068", - "0xae49f4417048cacc01716a2d804f699d8ec34ead735e1c61604996ac37f35157", - "0x52a6fb56e13d45fe16456e828c8c375b0decaae2d644b76f8a9b0a741de1ed89", - "0x5f9e4ee172469cfda38a7457ef192b6efb169fedb73943e4c987d4eb910189d4", - "0x43926296aa3c8efab7e2ff9bc644236193fa657726127559ba0668734d1b2790", - "0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62", - "0xb53f6bc81ecfaf0cf4c3dcd9527e3c0f6910383acf964ed14b194fa660d30b10", - "0x0d21eb4f7c202eeccd6d87627f3d512e630d4d05578585847168758fd1aaed22", - "0x1ffff1a455b66d52107a26231feefb0f3565067e9544cf9470d975f01111b1cf", - "0xdc8829261b6bfd53ab7daac305c2ad0ed15423234128bdc5b86a2e9eaf6157e4", - "0x6bcfd58769c6966e31aabe28addce6151f2dd2ea1d9c307e09c6c9db95b6b103", - "0x7d766503b9158ee06b0a587859f6e24974c78c3a64b6e4d8aefbcb8ad3bc2127", - "0xeb885fa37ef7e686a7f8dd3d9004de555526310e78dcbf857c9b0a31e40b9736", - "0x34447afb686b4074d3b93b99076a60b5f5a902fa32df18d85fc1d13ada8cdb71", - "0x2f1b6a8f228675a171126d1781aeb52756d6fe5685af8c7ec23dc8187d783d1f", - "0x6545d98b7c7dd9e023753a64c515e69e19e72b18f163831c08c7f559dd8134b5", - "0x15b381b518c6b754185d6903caf17b4f8dc30babfedf8072b118bbc3eec3013f", "0x06339935111b4a563a28a91c253b638af868b3af7c372cab497cac4f6cb2c0aa", - "0x45b0937bfe39b0fdadcaa8974daf324193624b47f4918234645819823dbec07f", - "0x8dd81a60355138e9a80054603fe23d7896544254f66e236d478a9b033c3a0330", - "0x3ba5ac70a18399817ccbe8bd4d9c78115136cc61699d51af87608af520226c32", - "0x0e8271a44c634b7fedcd00cb09afea2a70ac8380b6bf5f61ff07e793ee3f6d4c", - "0x34562e3ace608bdd75a10eb153cbc2c00e69b935d42f57c193c38ef6d674abac", "0x06d9e4b9abc0b8978120d451eb4cca4f72ff1d97321713e0ef379a157b8f2b60", - "0x65a1c5667776dd9a726a67038e45e040b1fa463ed55f753c2156b355616f2c82", - "0xdcbad7acc8ff4bb5562dc1a37e87244df11ed754f8f25ebb6fc23320e5268b3f", - "0xe55b734df35ab6d576607e01c42f21d275cd9c0f86fbb3100241a14ba0c7672f", - "0xb7c8c273af675612bc8ee68c7a419b671e678e63fb9ed62646358d70adb82434", - "0x15c53c582284ec93075084bae0536b5ab7ae44a44ee2718489b72be3aa78c3c7", - "0xfced34088582b4a78f611c7366195e3e94f9080637f4104bbbd0d07ffb783d49", - "0xbe03f50d58fee6912ddb6cdfd5c26302db94c986ad69eb4e7fb32768636bc9e6", - "0x6be4eb2fb308fd641346533a4acb9c4cca3e2d478e9075522646c972a2062985", - "0xebd4d964df19c1598d3ce8354498f4f0cadb39d700af15ba6a42f8f6444c27d0", - "0x5380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a", - "0x7e833b9b867caae3d5e2b64c13a744f0e5cc1bff50fdb3713e3c505114a07de1", - "0xaeb868cc8cd000167af8b0f4dadd2e348e543a019cd0b1312dbedeb4ecdc592a", - "0xb7fc8b1cc055dd94a0f598f5ce4f8e121a8e3e4ac752b027ba3e2e99ed10c7b8", - "0x3c9bd268aedc8dbb36db0a4664e17b83abcfd87e404901eee7bd5704a95064ee", - "0xc2cf8e05450be6d2c98edc5df219a4cbd86dc60667b4a7810257177dc73217ed", "0x07c57780db2d0b81258ad3be5df2c3a9e89e4c06bfaddc3a1f4e3b9401215947", - "0x7eb6fdadc6703ad64a7ccd5feddc788dc92efac7e066e01d5eb7176e91a6331d", - "0x6d2032b002dda8c5280bf48213d7b981476a9a8e53a69a39c625e5c8129e9287", - "0x65ca73153cb8f02233c0d12f996e3dc1584f0426285f63bf41bec91a86d3c36e", - "0xaebe9973fc4849a27521c2a71aab7673ddab83cc88e91abec675c1c471abf927", - "0xe690b239ba3aaf993e443ae14aeffc44cf8d9931a79baed9fa141d0e4506e131", - "0xbe8f0a3d1c2d7a0fc2342f9a4c78e00fe38a7f26da345758cb2b8efd052bcd55", - "0xeca6cdd9768090f90960cf9bad47705ca3b19a54c8ec8186e2987ffdd3a8435b", + "0x087fb108e6836a088e06156b1a26210d1f5284296b30b0bb0b3d1c2a7e01ac11", + "0x08b3f9a96baba12f47430f2b0e2851f407e8ca355bb8a9a69242bc99aecc2cf3", + "0x0999f18de77e9451867cb1935f9acd56f79cbc11d04826c3da6b420a4f4bbe21", + "0x09af9e7ea2370ab3e3ee7f0a465a7dacb6c9b7e65196dc496d5570a0d8020bda", + "0x0c3a3c99f34afe9d2c8cecc90524ef63afc9fc13384d5d931281f414d5d487c0", + "0x0d21eb4f7c202eeccd6d87627f3d512e630d4d05578585847168758fd1aaed22", + "0x0e8271a44c634b7fedcd00cb09afea2a70ac8380b6bf5f61ff07e793ee3f6d4c", + "0x125adc67efe8bf6808c02bd3ae20262953b5e45dab4eb9386441cf6ec7381844", + "0x127ec70ea0d8a7b6244ae7d951b2204f75336cf21f49df6370ab920534c95728", + "0x1318a4c2bc731718857238ec2c42e4a95c0aeb7290a60c8abb110c2e638341c2", + "0x13b8f5750961b5588bc69fbd0b701461854e110fd78c14767515bdd882725975", + "0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d", + "0x15b381b518c6b754185d6903caf17b4f8dc30babfedf8072b118bbc3eec3013f", + "0x15c53c582284ec93075084bae0536b5ab7ae44a44ee2718489b72be3aa78c3c7", "0x15fefe8613a1e673567aac83294fa0da6d048e5c7642227017441c9f899fed1b", - "0xfdfacf5483fdda2fc98d08bcce1a68d5d308d3ad88ee21b50004fd694ba6f805", - "0x36b3096c912adc7674ca92b68ddb3b0494e9b988fbef1bed7938e8fac4c2df7a", - "0x8f8755e5d8418704774f38ac79dd944c223bae9ae361c5efdd614d09c60fdcfc", - "0xdd7ad9673f823444e5194d5ab0eca9a1fb7bd3770d0fdc62ce3e180037158773", - "0x46f3f8cc486e8047567212c0f011c065466bcb76647dcf87d42756d7fbbfcb4b", - "0x546690cf9510b4b7732d2c99c7c2d994f6668b7d7f75a1d28c0eba53f784fe1e", - "0xc49241829446ad570b5b97d38a504782a6522204c67d5f29b61515246d0410dc", - "0x8fd56ff474602c98136f4a9389e3e2b5d7e78ec55d5edb63fb477d7281424515", - "0x471703c5eda8644a64cec152c58f5aacec93d72fb0bfa705f0473f9043a8357c", - "0xddc48afbdb1661c8789b447f581ae07eb1863b24e50865dfacacf0aef7a4f9dc", - "0xe6c05c2ebac68df110b9966cbf92414a6ddcf3b67fc77901a5fa049da0cfb109", - "0x3da06a67e7fee9c938155c50e6cec9da70b66679e777da6f02149c6674cd9105", - "0xaf03175444dc43cc33391c4c4010eac15d401b2eb5ffc7bc778abe372f28ce37", - "0xee317a72c6604e9e4abcba1ad9d6159a00d9168558be819e4393936aa1eee432", "0x162386be0a525c5a9e6110c7244a375038c525fe102df224286161b1289bc716", - "0x54c901f415ecf89c46159b356a4a95e9e5666bc88f8bf4bf5d9c15aac8709e0a", - "0xbeda4b34674f3b9d0aaf6c3946c05b73b4e7ac680c7084d41dc8f0bd3bb38031", - "0x65d07b4d81508c24f55172afab2935db210689baba6270991f0218356705dc1c", - "0xfe6a58207750197f48cb90864096850259845c2c8e90c74433325c0b144bf8bb", - "0xc57975ae690f9a6554015459db6c13e8c6dbf6e4cc0f5cf986afd1210c233abf", - "0xee9d69f02d1245985cab3ed816bc86177c83e0701cc5515de9932aa065886407", - "0x6dc809012cc91335a5ea4e186bd04479aac7dae1bcbd023bf660213a69f4fdbd", + "0x18dcd435bf7d1820085f6c46d587cae669ca7c2d3ad4cea9db320a0b3c8bd21d", + "0x1a6d9674aec5c8329252cb634022308bf4c98e70edec613d925ab781483445a4", + "0x1d50131be868de2741cb775d0ff800631f96065f40b60845bce72e782718af23", + "0x1e22733f173fbc95fa079ed50ec24c498a8aad2515d827e5ff8200c240e9cdc9", + "0x1ebfd7dbb6804351804443df01a482e6451912b884cd26b31504bb77bbec9862", + "0x1f99af2df2da9c0176bdb3e995bdfa47ffbfe6a3aacf8e54401f4dac2ece9338", + "0x1ffff1a455b66d52107a26231feefb0f3565067e9544cf9470d975f01111b1cf", + "0x2092b5602121cc484fa55b90cea0be17d931184263925a864e0d5d43a20d67b0", + "0x20ebfef43639215aeb35e1e00bc96174f52155afb781659f34628d1f3f7ae018", + "0x21120e1be03d384ee32a9bd7268578d8829f271540c848c97a495990bc48f582", + "0x2139fa1aaa3d60e53d070d5a1f1ac9c8211f41b2dd5a1813416c8447a7759557", + "0x21ea8bdf8a4ea6dc9e204591d88c3b5b19533d33bfbc59c08cca266c3c87a960", + "0x258487f1d48945c7743c412b0f026d722a4641d5978f11a0b44dbf7c1d274d41", + "0x26dbcce1b599ebed46e2569579562031255ea9a1c1c575fdddb0003f4d389165", + "0x291b6bbca879d684337ee5e2bca5d18cfb2d3b7a97c8187e703309564280295e", + "0x297d3acffb942c7e6f3fb029b735338ac34e39c4ce9e852f64d50fb57cc97ec0", + "0x2b7afbb14b4c902f37163b15f70fe8335dec4e26fbae4718c03f19da5aecbe8b", + "0x2bd9aebde44794e6db317be6d83c5a266e1a96e18e04bc7073998bb779cfe2fe", + "0x2d15e1e82ca50b7334be8990b93a8b043e771340cc9398baa23845763c696d22", + "0x2df378e8ecee785e1d65200d738178432cbc9ad55c49ea5af905629d348416c2", + "0x2f1b6a8f228675a171126d1781aeb52756d6fe5685af8c7ec23dc8187d783d1f", + "0x300d2dbe83a6ba7fd75737c8d7453d984e7938ba7ae113d3da2ad7433061157b", + "0x3019c0a91ba30d346a55890b1b07287d8aae35baa8c4068ef8f1de66084aca75", + "0x323e393774eeec8e9d596258267d0133a5b2f01c567822a4ff018488671ecb6e", + "0x32fc4fd3fc836c6db0058fd20ff7e8ca611885eb7215b39f97d2b4e797dca254", + "0x331d99c6bec3aecbec962be74b25448511983b013c0876f6f4e6029773dfad61", + "0x34275c313c5286317794f0154f8e4ffacfc80d9d0c5b184d2482e7f9211ffc3e", + "0x34447afb686b4074d3b93b99076a60b5f5a902fa32df18d85fc1d13ada8cdb71", + "0x34562e3ace608bdd75a10eb153cbc2c00e69b935d42f57c193c38ef6d674abac", + "0x36b3096c912adc7674ca92b68ddb3b0494e9b988fbef1bed7938e8fac4c2df7a", + "0x38401b4e97e67c4a6d8095979b4c1ecb9eaf5726fc8a12798975a7653e980872", + "0x39c8bb92227ba91a2657f29c5498f5c5b07ae36369c8d9283444f477930c79be", + "0x3a2c7d5164f6a1d8cbc5d9e228253eae4a66d8b0d550d07c53ec84d47ed17172", + "0x3a82e1e58ae6f14fbbeb35b6d833330c4fb5b3cb770391f5cc340949c6254e83", + "0x3ac3fe84c663607ebbe01c6b008d02b92ed4feab26ed8171014853c0f9419cc8", + "0x3ba5ac70a18399817ccbe8bd4d9c78115136cc61699d51af87608af520226c32", + "0x3c9bd268aedc8dbb36db0a4664e17b83abcfd87e404901eee7bd5704a95064ee", + "0x3da06a67e7fee9c938155c50e6cec9da70b66679e777da6f02149c6674cd9105", "0x3e400fa3269849dec0cbf4edbd663657c73bdc8c97c07aa166dd8b49f0b14028", - "0x56d423ba59df7075b27e5d573ad8399ac6ab8a7541efb9a1e646a67244301fed", - "0xe748320edc6a9c30d249d75af74a19ade7f69c56e5e0d3a9adb17fee1b0a4bef", - "0xde6e6fcaefc39f05e5912014093f38926987bb7b125e51b49ddfb49b03e36c50", - "0xfffa0eae268038cfa984647a1d0635beb86eda9fb7b500688f3189520cfa9ee5", - "0x660f4f93865ad80d0c9f1159bc17ecaa398a0f4af3a374dd033b20029378980a", - "0xe7cf18b96a1c12507c9a95b7f48c3e012651793a196ce2b81aaa6cb185dc03b6", - "0xc60f70699042477727e7230f64b5c94d8dcb2c7815f8c2542722fcef900dd238", - "0x6688c7b8c02428a3ba7e0b83237978a46faf9a632fc615dfcf7226473c244004", "0x3e9a637c5898b70506a347ae7b5768d1a84022f9702e8268e8a5bade8194dd47", "0x3eea7e8e2ca3e385fe39d605086b049b99df1adab85a1c6569873424f488c5ad", - "0xc6474110edeef59c48841b35aed37057feb211e738124285a233e77e53152a57", "0x3eef5a1ec65e8ae1c87be5edc45099ac9e7783d4b8075810ba688eb479e7a730", + "0x40637a529320dace54763c2e6ac52c522c8a446ba9b6f54daf84c0e442124b93", + "0x40f85cb8136e95238cea4cb951a2ee645a4998c108831d5abe1d8f48696864c3", + "0x41351b958be1e95cdc37f7d2d654315e33ff7f45bac9179f9242fdc828c8d2e3", + "0x421df1fa259221d02aa4956eb0d35ace318ca24c0a33a64c1af96cf67cf245b6", + "0x42b45de6853d406783b6b50c378bfb61d6ce5271b3bf813cc2b959055fc12f98", + "0x43926296aa3c8efab7e2ff9bc644236193fa657726127559ba0668734d1b2790", + "0x45b0937bfe39b0fdadcaa8974daf324193624b47f4918234645819823dbec07f", + "0x46f3f8cc486e8047567212c0f011c065466bcb76647dcf87d42756d7fbbfcb4b", + "0x471703c5eda8644a64cec152c58f5aacec93d72fb0bfa705f0473f9043a8357c", + "0x489fe686547f4a999d2818aedbc18b735ed2cd502c30124a0b8af861b2251f91", + "0x4b6029773e7175f32398422fd18c6cb095e5278ac7be41ca4a5a6c0a6dda1a71", + "0x4b945ef2e8c78482bbffcbdf4921cd375065e3b5024a3bed469a9f34b2e773e7", + "0x4bce4e0299e5362578a95a27bcb779b9a89232296388db803909696f90635581", + "0x4e09550da9ca55ba375e56c525b49b27814d20165528e4e7f309878221b2878b", + "0x5037b71f063bfe647233f570aa06602b1e6b5124db0b1fe998975f93b0fb1084", + "0x5095b76023974440e6c155e26b3f7084f0b1901a0df2183dcfebe01f326d5e96", + "0x50ff4d47a46c9cd35b029e95ef9c957e57da987491f6e7be242e72bc5d3e8086", + "0x51ee1e08db014fc699587667b7256e7b9090e1755c587420cff5fbe0e20194fc", + "0x51f0e21d8c8aeef60da6ae58d10dcf1f42e7d9a0cb8ee2b4a97caa566a152b61", + "0x528b55564e8518548e42b534da3a526179b820f264ee7c6929d00b0b6a31cfc2", + "0x52a6fb56e13d45fe16456e828c8c375b0decaae2d644b76f8a9b0a741de1ed89", + "0x5380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a", + "0x546690cf9510b4b7732d2c99c7c2d994f6668b7d7f75a1d28c0eba53f784fe1e", + "0x54c901f415ecf89c46159b356a4a95e9e5666bc88f8bf4bf5d9c15aac8709e0a", + "0x56d423ba59df7075b27e5d573ad8399ac6ab8a7541efb9a1e646a67244301fed", + "0x5839262442bd87bdce9bcd8e97628a84fd07aaf55ba8c4c29e1ae91cb17cb222", + "0x58bb8d7ba2f52228853238b26bfe3eb9607cea944e7020458981618efe8280a1", + "0x5a4be2322eb50cfea1051978c284526cd5a6e28caca681855736a5d3c31d9bad", + "0x5b70e80538acdabd6137353b0f9d8d149f4dba91e8be2e7946e409bfdbe685b9", + "0x5c33820c3d76f4de8d1e0eca24c7d2fbef76189b6a43a7afea4dfda5b50edb96", + "0x5d9114e8c0b1e858bf7322eec122e3fc4b0988f146620def0fde9dbd322f3a03", + "0x5f9e4ee172469cfda38a7457ef192b6efb169fedb73943e4c987d4eb910189d4", + "0x6042501054831920bc9d50a33d6be1b5a8214c31ba9416958f8996cdb6ddb05c", + "0x623f300bf600b7b050b9b70fa57140c59a5f0b9fc5b9d0bdab11d108a71fc1a3", + "0x6298deb7c736dc50b4590ca066b72173d4e2c3f75bb109396f32eaaf9ad11bc8", + "0x6400fc32c5b2d3580c0e19889487cf9e057d6b82a99bf30eb6e539b7cde52655", + "0x640528e5cf143f173d29cd8b4f896a1c6128f3416c887c10d4a11898841b4a82", + "0x6545d98b7c7dd9e023753a64c515e69e19e72b18f163831c08c7f559dd8134b5", + "0x65a1c5667776dd9a726a67038e45e040b1fa463ed55f753c2156b355616f2c82", + "0x65ca73153cb8f02233c0d12f996e3dc1584f0426285f63bf41bec91a86d3c36e", + "0x65d07b4d81508c24f55172afab2935db210689baba6270991f0218356705dc1c", + "0x660f4f93865ad80d0c9f1159bc17ecaa398a0f4af3a374dd033b20029378980a", + "0x6688c7b8c02428a3ba7e0b83237978a46faf9a632fc615dfcf7226473c244004", + "0x684272547bac4c083b7380f054d08a5030862a5f06a2367f3b8e880c4b7370ed", + "0x68492f20c1d7597425c8a53a7f5e380fbce058d1bfea2521a7e8af03c387e1a0", + "0x689802d6ed1a28b049e9d4fe5334c5902fd9bc00c42821c82f82ee2da10be908", + "0x6a1c4e8b7c710531c9e66166d0629ff443df19cefa081eb4fffcc7d267ce7c92", + "0x6aefc729e28e1bbd2e63dd0803314deb808ab044909af882b7935dd05f5939a4", + "0x6b2c03103b55a45cc1e4550889a9396e7e331b5cf1729e4871ff4dee701139e9", + "0x6bcfd58769c6966e31aabe28addce6151f2dd2ea1d9c307e09c6c9db95b6b103", + "0x6be4eb2fb308fd641346533a4acb9c4cca3e2d478e9075522646c972a2062985", + "0x6d2032b002dda8c5280bf48213d7b981476a9a8e53a69a39c625e5c8129e9287", + "0x6dc809012cc91335a5ea4e186bd04479aac7dae1bcbd023bf660213a69f4fdbd", + "0x71a3c7f8d0fe8abc9fbab1860ad576eddff2144763937195ea4f012fc625b053", + "0x75422a3d36c93fcbccad2e502775226f375e264e35fc55ac20df1e9f050e8b8c", + "0x7744be2427cacf17062cb030d30e34c3b543b28a83707df04e64d3f7ddb471b8", + "0x7820b41394d7f30f2b02f24f8a33afe8b98cd68827ec651aec3ba33e41206fe2", + "0x785a32bf0f42bd6c986b900070bd70ff4ed5eaad448e57cf5d997224c3f87c2c", + "0x79deb2f042f1717cc882c5a38bbb6c524932352ff25baeb8b8fd2225095e29ae", + "0x7d1009331195f6a3c2eee6ac4b4664f61c777500c163ee84769913578a33bdf2", + "0x7d1d5f3a14c0ab133b65698c2d62c818c65f13306ccbfd61aa4b7590bb78660c", + "0x7d766503b9158ee06b0a587859f6e24974c78c3a64b6e4d8aefbcb8ad3bc2127", + "0x7e833b9b867caae3d5e2b64c13a744f0e5cc1bff50fdb3713e3c505114a07de1", + "0x7eb6fdadc6703ad64a7ccd5feddc788dc92efac7e066e01d5eb7176e91a6331d", + "0x80382280e2f4a8ea9001c8e22332a3dc3d3a692b549d3c90f65796270e1eb770", + "0x80be858ab09789d26cf1128775756a8abe1c8ffc4218d3e990b3d25a82583255", + "0x826ce1d60ac9f0ab5944acf1c06700a585f8407d670495c7811b97cf8263b434", + "0x8484452e4f0c1a9f115c52b4ac78a0de2f1b0ab1a4aae8390426ac71e03f8779", + "0x881a506039e25a818f35aa0e3ec58c64df5c106245dc25ef6fa4cf1eb1aab56a", + "0x8938be2ad9950390d6d92213ca102fc21a4304c88354d0e74f4b3ff696ce5791", + "0x89d04bcba396d12de1ed36f41df60ce0ae0449bae83f14c740451cf19362ae8f", + "0x8ae586aa1ec2c29aced4feb5adf9336541769b93cd5b8cc1b64b7d831c7b0ec2", + "0x8c3ab0970b73895b8c9959bae685c3a19f45eb5ad89d42b52a340ec4ac204d19", + "0x8cfefa9806c99db8bea1ed8e534f6dcdb835cd1410f1f287ea4293e29a3eacc0", + "0x8dd81a60355138e9a80054603fe23d7896544254f66e236d478a9b033c3a0330", + "0x8f8755e5d8418704774f38ac79dd944c223bae9ae361c5efdd614d09c60fdcfc", + "0x8fd56ff474602c98136f4a9389e3e2b5d7e78ec55d5edb63fb477d7281424515", + "0x90b0d289ea211dca8e020c9cc8c5d6ba2f416fe15fa692b47184a4b946b2214d", + "0x9546dea22f2479752816b65aa9db1b835efefbc1ed11804699683897cda4227e", + "0x96ad0b27ef10fa7a9940299df122d31222cc911bd2c91d2740f25a0dc931f4c0", + "0x96e16af9aa5f894c43514d940687dafaa5ad04ea78a3b0080319370e454602d2", + "0x9782bb006174ed014c59e6eee381c6e10bc9304226edb99edd6f8e9041e9d9a7", + "0x992470b3e52c94f7bd5d4962a1798a41425bea74ad087a7f53aebb785401df3d", + "0x9ee40dcbc49746e31a754155515aaa232bf0bdbfd5a7ab77ea9cd39f4b7282a1", + "0x9f0dbaecc6581cfbb57cd6c6f50e24c23ad4fcdf228140c0cb51a8a4edf5d0b0", + "0x9f4e60123db23e3f3055f75087248fd5923d469e76d344d28b4f24a449ca6398", + "0x9fa95d10732f34365f34f5a2f7702a9dae40c583105c40921a5052dca1f9f793", + "0xa092c3f36135f79c57aa5683d97e5d5750c37d0bd0ada215e9a96856c56d7e91", + "0xa0a22226f85371b5e5e4173b33a1b9629d745961f36e9b0510c591f11e3dd95b", + "0xa0f1ddc6e3aad69109e0e8c5d15e8800e220b192f85f369e0bef5cf858dccf9a", + "0xa216c0a47b12c20d5ac5c381464a89521d8b0c1a5cb328aeabb29b70bc3347d4", + "0xa3b41c13f6e16fd2242a43b041cfd1f02cbb4cf06943d14365bb8f0a30ff507a", + "0xa62e9dc15a35c1ab9d0ac4345b1f02fd8e8070883a33651c0c143b2582708268", + "0xa876da518a393dbd067dc72abfa08d475ed6447fca96d92ec3f9e7eba503ca61", + "0xa93db8611e8d0c159eb724d2aea72763dfb5a6909a8516467c79d0386d61a511", + "0xaa546817dabffc9c4249830a0af5cf43c6ece6562720990736199e570f621d7c", + "0xaa8d9c947771632a645c67655595b61da72837bfa97f30f417dbaed82f2f11c3", + "0xad00cf4d7db523f20b5000bd1469a11d70b73feadd36578abdb9f3558bdd3674", + "0xaddb0d4b14749bb4b5cd858f29a4b4225138c3953090ce45204458dcd53749e4", + "0xae49f4417048cacc01716a2d804f699d8ec34ead735e1c61604996ac37f35157", + "0xaeb868cc8cd000167af8b0f4dadd2e348e543a019cd0b1312dbedeb4ecdc592a", + "0xaebe9973fc4849a27521c2a71aab7673ddab83cc88e91abec675c1c471abf927", + "0xaf03175444dc43cc33391c4c4010eac15d401b2eb5ffc7bc778abe372f28ce37", + "0xb02c4d58a3800d93f95f2eb4850b3d242756bf1ca3099bc43907af6dff0bf337", + "0xb0fe18e510f695dbf24ad56fb3b647aa09f8e19021abe80686a66a2e653cb12d", + "0xb14d9fdc657d712208d6e7c2cfbf62f7ad7ba1bfff2e63e6caee2b0bf5bad0fd", + "0xb25939867994cd8e5a18f341628420fa8ab88b2f5d05ffe51291654922f5454f", + "0xb31ba6d576dbde0542d30a9264e2c71be270e3eb4f5910567a8c1c0619a2e5ec", + "0xb41089e529c1ff6c4d6583ecfca7ea6419bf39e0d418686bb7a24424c670b332", + "0xb53f6bc81ecfaf0cf4c3dcd9527e3c0f6910383acf964ed14b194fa660d30b10", + "0xb7c8c273af675612bc8ee68c7a419b671e678e63fb9ed62646358d70adb82434", + "0xb7fc8b1cc055dd94a0f598f5ce4f8e121a8e3e4ac752b027ba3e2e99ed10c7b8", + "0xb8864cb7c6215e99ffe5db7b22b3129e93b9a38b9b54193a0e3d7c8251657173", + "0xb8f37a61c26d388306ad9dee25e72aa86a49903a1fbbe6205211b47d1f39f77f", + "0xb9af72fc0534a4a5a94eb1f64cb1bd6c425acba3249fb8441e7411e9be9ec1f3", + "0xbb62e8d8d0eb3d7432758c244131f1649874367cc52a4fa4fd0609def9e57389", + "0xbc0cb591a67822e88dcebb8991bca5b7305b5858d65bc2b5e6605e481a650588", + "0xbddec651652e0aa17e056de1790554aeca5fa248cecc4131d189dacd26c4ca55", + "0xbe017710d6bfb0ac7a8d140333127571809eaf2b590900f168545daea3865f60", + "0xbe03f50d58fee6912ddb6cdfd5c26302db94c986ad69eb4e7fb32768636bc9e6", + "0xbe8f0a3d1c2d7a0fc2342f9a4c78e00fe38a7f26da345758cb2b8efd052bcd55", + "0xbeda4b34674f3b9d0aaf6c3946c05b73b4e7ac680c7084d41dc8f0bd3bb38031", + "0xc00c28a6bfe2829613432a2c21eefc25da5bad983c5430ca28bc1a92d2b65ec5", + "0xc01318ac6e0d2cc08468abc1df6f2c9ec3fc5cfbfe5efec83aab250cfc83ef3f", + "0xc01b3857946cb77af9fb09394c4a359fba6df202c77d3e07e53177f3f18a55f2", + "0xc0f4fde474181fca3d1fb6e0dc118a71457fe7cc5d4f1e426c92e1767eb885a0", + "0xc2911b75be7d3fdb9442b900ca8f7205d6d52fdb3505e77ea8676f811a6d5ea1", + "0xc2cf8e05450be6d2c98edc5df219a4cbd86dc60667b4a7810257177dc73217ed", + "0xc49241829446ad570b5b97d38a504782a6522204c67d5f29b61515246d0410dc", + "0xc57975ae690f9a6554015459db6c13e8c6dbf6e4cc0f5cf986afd1210c233abf", + "0xc60f70699042477727e7230f64b5c94d8dcb2c7815f8c2542722fcef900dd238", + "0xc6474110edeef59c48841b35aed37057feb211e738124285a233e77e53152a57", "0xc6e7f2ef75851a2b752eb247b5701aa5f24d0c867534330c74c51c1ae91319f7", "0xc705619eb7a97a01d24e21cda98066d40aeb6d6ce6fb9e9a4880d86fe4432b13", "0xc7caa90744f6b0e1fadfc5c21ccc5de0057447d6160835e35e25a82fc391d051", "0xc7dd5ab81d775d5c8b283ddf787bc88c61e766b7b418c0d6375683f59fe6e5a9", + "0xc93e183a9dd09cdd44ca2a9eb6b94f970f8fa309b0f9cfd823572c23aad58fb2", + "0xcb44297958c82fe80fb882f2c8a085a38556247b3c3f665eca382d27e26e3bbc", + "0xcce46204baa86f733abf208b358ba8b807081d6d46a407745238aef2c133fd4d", + "0xd207b05b684ba18361df8e81e846d10365ffcf04f7840403c5bacf77add4c50f", + "0xd222125724b9df1f4a92e1284dbc871a9156c253572df0a38ae146ac03b62af4", + "0xd24e8fff20c5317074c54fd54ca9f1fc8fef36bb70c44b55f90a70c621b91f9a", + "0xd37476a178ee68b02b3de0edee1ebb57e1638eebf58b3e256322e0da1189f272", + "0xd3a7e59f888a7ac07a211c717c07b82970d94597f6365cf8c93d51ac9d45c597", + "0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62", + "0xd81c5d559ba870e90a2b617cf0542695e9a626619b59148b40295a0ba55ca66e", + "0xd8ffcbc0be38306e539da616161c64ef7bc0f0281d62e5296bc8eb6ea709cb0b", + "0xd90bcdecb44a3402e2a1b5d3a321b51e415e298ebaca3c95d91443adc03f6cec", + "0xd9ed35852650f28d7a8f73c7ba49bcd72d97edf8d731797e5a2728559b865552", + "0xda0d7fc05c32bbba16518f9f2936fd75140d5c99b95ae536205ba9caf1868378", + "0xdc8829261b6bfd53ab7daac305c2ad0ed15423234128bdc5b86a2e9eaf6157e4", + "0xdcbad7acc8ff4bb5562dc1a37e87244df11ed754f8f25ebb6fc23320e5268b3f", + "0xdd7ad9673f823444e5194d5ab0eca9a1fb7bd3770d0fdc62ce3e180037158773", + "0xddc48afbdb1661c8789b447f581ae07eb1863b24e50865dfacacf0aef7a4f9dc", + "0xde6e6fcaefc39f05e5912014093f38926987bb7b125e51b49ddfb49b03e36c50", + "0xe015d2e4c085291611298460602b913b5f19272715fcaa48258efe24cf21885e", + "0xe1e23690e890cdec6eb19b06f5d31d422b5c17bd4c435afb2a2532180011453f", + "0xe22d496c425479acb445c4040bdb5e17fa461de175eaaa77aa79e23b5b19f761", + "0xe2c8bbf962c30afe9c35e9d7e036ef496b52cb770c645a76f2cee5f8811a9830", + "0xe36c0f154a365e086c687050cee74bddde9997a1dedeb0e55217368c0ab6baa4", + "0xe4295c5aa043a60d279854f7424e21250d5c1e1f9959549e90bc926d70e97068", + "0xe55b734df35ab6d576607e01c42f21d275cd9c0f86fbb3100241a14ba0c7672f", + "0xe690b239ba3aaf993e443ae14aeffc44cf8d9931a79baed9fa141d0e4506e131", + "0xe6c05c2ebac68df110b9966cbf92414a6ddcf3b67fc77901a5fa049da0cfb109", + "0xe748320edc6a9c30d249d75af74a19ade7f69c56e5e0d3a9adb17fee1b0a4bef", + "0xe7cf18b96a1c12507c9a95b7f48c3e012651793a196ce2b81aaa6cb185dc03b6", + "0xe83c2c56f351d8c25863a55ece938ffcb6cdf2978eb34ea1a19591884d3885f3", + "0xe8c07bab8822eeeb875236e148f781341157f9bfc56c1c53972489ff4009695b", + "0xe8c6b410e2984be3bed9a84b76fbbd647f5fa56e65e36c264903275aa22cdb0d", + "0xea674e603f60ba1e252419d86d0485fd3f46ca6abbf4c65afee0a9ba29059655", + "0xeacbb86ec518baa710dea5ed986162f21df2a98d2119f6cacbb01e8d9a77a629", + "0xeb885fa37ef7e686a7f8dd3d9004de555526310e78dcbf857c9b0a31e40b9736", + "0xebd4d964df19c1598d3ce8354498f4f0cadb39d700af15ba6a42f8f6444c27d0", + "0xeca6cdd9768090f90960cf9bad47705ca3b19a54c8ec8186e2987ffdd3a8435b", + "0xee317a72c6604e9e4abcba1ad9d6159a00d9168558be819e4393936aa1eee432", + "0xee9d69f02d1245985cab3ed816bc86177c83e0701cc5515de9932aa065886407", + "0xf03db4f61547c9d8c58b4f37f84f74eff767c24cf81b957662e96622f2ac4d19", + "0xf5b693085beb21b0878c7e5fab7519ce0d6105354cf6744dbfb73e3745e929e4", + "0xf67f470df15c88b9beaf3fad72890a64f8851d01ece546b0c9fb3bdf92041a35", + "0xf908d785cef1abc9fcea55c07490d16b4825e8a6a7c8fb157ed2900bf4af58b9", + "0xf92f9911e6d5b40e46f574db0a406d360f91c8de842ded48c8c699080985b4cf", + "0xf93d447fcf86f847e6609bfb3100aa5d07df37f2c72cbc4961e3a0f86a7c24b7", + "0xfb1d6797796ad9edd1b8b41030035a003eb6286ae2fc1a8296b509891acfa033", + "0xfb6ab511cf5bcb157f833241e74ead7128a21818c2b5080be21ee9f85ff5d523", + "0xfc39bbcf08818ec3329e5769dff3fbdad66e6312a961acb32c1b203edf70aeba", + "0xfce7321f278a2973bf5c67757ea7690649295d53967daa3ae858695be336abe2", + "0xfced34088582b4a78f611c7366195e3e94f9080637f4104bbbd0d07ffb783d49", + "0xfdfacf5483fdda2fc98d08bcce1a68d5d308d3ad88ee21b50004fd694ba6f805", + "0xfe6a58207750197f48cb90864096850259845c2c8e90c74433325c0b144bf8bb", + "0xfffa0eae268038cfa984647a1d0635beb86eda9fb7b500688f3189520cfa9ee5", +} + +var Block1_IpldCids = []string{ + "baglacgza22ifq7h6bot66tpn5xudjfcqtydvk7bcang7lxosyfum4ifhd4cq", + "baglacgza245jp2gg7wvxvbuvdxxynbsfzynj767o5dv6tkgsaghgsfsmvfya", + "baglacgza267mwypnyml7gmua2bifcmpndmtwzzw2dfjox3dfixo25uopnmda", + "baglacgza2dbonmaqxik2vhbnfzd4dhcpyjm47rlbuz35cha3jy7jyxvrsoxa", + "baglacgza2g5mo2mblvbfjjrm6xk2ppf6jplupamowaqb4j67szvaytx3wfra", + "baglacgza2gxxoee4k2cxdf24whfylc7x2eb6eshvrunugemjp766sxhbx6qq", + "baglacgza2jleouo2qqbrfv7uc73q6aw4svm74ltjhzhsqhpmqdcsxmvjxurq", + "baglacgza2lsx6yk2i5iiy3tasnjvgqult7a4y5lhpi7lr5pxhvq52cvp6x2q", + "baglacgza2ovtxz2bp6yccm56iacbpp4kgthyz4k6evyp5lq4rzmp2c23mnhq", + "baglacgza2pm53c2petiwutv3cn32jucrzd4fvemvj5zbrw5hn7rvmzhwtntq", + "baglacgza2u7imlxl3apzarjovwuegtp52a5h546qnvw3hzumxr6qlx7yd3aa", + "baglacgza2wso6cd6qxxk7kwtcgcx6gg3nztqk7h3kepb7if653mn7magazfq", + "baglacgza2zihxbb2gl2daaft5miumsjqbps3xgmip2r52ubrpii5zkpshpvq", + "baglacgza37tily665vel2tvvcavpqtj7n3qot3zxvpsog63iqkxmfldastva", + "baglacgza3ask2jt3sjqfdiuxxx3fjipnxzp2u3in6z5d3qflo5fxh7ihmf6a", + "baglacgza3esavhjnlbi5awux74zqkm2n7wybahq6gip4e6osxm6k22x2r7ea", + "baglacgza3gzwbd36gsmp72aqky7qycjfx2qcq7g6uv7kd45ofgxulimsmz7q", + "baglacgza3ieihinvg2srwi7dupigwsahksvrlhninkyxt4ewb426uqmqtjnq", + "baglacgza3oids2arkgomy6bblcggrwooaqyj3foxbxiawhckxhyc5phxqzgq", + "baglacgza3tax6aemhf6t2lqknaazzsksu2c4fjllgjx2izlkv47qmhzfgtwq", + "baglacgza3zbafsnpvwa5xw4xpjmx3ndhmuhynaoxxrzwcnfxi6o4rbwpu2hq", + "baglacgza424ea7tewjqbcwi5fwcticsbiinwh7ffdf2jeqrmjzrpv7xpo75q", + "baglacgza44bydaixin7ymaidhsaawjsemc2wkds62ahiaqrtctpvzo6xitaq", + "baglacgza4eanzp6ludjfoqr4h67bzlsxjartrqqeq5t4pv2q3b4x2padxbiq", + "baglacgza4fxgo45wl7zhyqula5ahuljoi6lreftfcwskipwmhrcejv35j42a", + "baglacgza4fxgurqdgfxs7ja427ikr7e2rxfhzi3hmov6hg4z55l3qow7kaiq", + "baglacgza4rw4nllzvg5j3kvvrsisd3jcwgq7htdege42ris6ddkpiti65ala", + "baglacgza4wczwxeuvdhklly5renpmti4x34ilhhmgdlcro5jjpyhowgvdwpa", + "baglacgza4x65ftjd3telo3eyyzrgosshvnlu7kj7enzezkwiowxsentq2twa", + "baglacgza4ypfm4rxwsoejwhza3housicojqliaimccsupm4nrmjrxhj3n6ca", + "baglacgza5efjepjsmz2y65dfccco56i5jvrkn3wochllzfze6k3o54qkvlaq", + "baglacgza5fhbdiu6o3ibtl7jahjwagqs27knhtmehxvoyt6qg7wuodaek2qq", + "baglacgza5gn7vz4ksy4go5joxn3zn2hgzf7sudxlq7fthztqhj2ikql3spva", + "baglacgza5n2ivltmbqypzfjptsvbzvlvhpbcbzlr7xj6xb7zaallj3q3bu4a", + "baglacgza5n7yqni36tyi7clfxxfqciib6j4e3fru6ye3eticdb4b5i6k4m4q", + "baglacgza5ndtrasv47fgrnbpuvqyaam4mhrn2ma37yqce3lkotlzl5vqc2ta", + "baglacgza5nzqr7e7b3h2gmbxz24vdcmfcoadnzbie6nbtvigpyfigqerrxja", + "baglacgza5oahzgmmqeqqszmqsfbwaq36gbirizq6aii3zm3jyud3pgndchlq", + "baglacgza5psrwfh6u2vklqex6jigq5hjscatynwnge4z5y6xeztn4lo6h7ga", + "baglacgza5ux3uey7vxvn5miif5lf77ywz2yar5utavxdcqbai4lma4446hqa", + "baglacgza5vqm4jugxseggsbniznupli2bivz4drwupzzyfubqmt2cggrk7wa", + "baglacgza5wvocvjvd6bdjteyzt3y7sdimlfxra6c4ndihqlk3oewgwclny3q", + "baglacgza5yyio2rxxtbrkpk7vvv2iyp7pfp4bkismdma3mk6qkxlhsiy4f2a", + "baglacgza5zaewwegrxjtaezosakyqpplolmav35eqfdyjju5okk3tmogbtkq", + "baglacgza636axkok5ao37hjupoeksmk73f3rpimd745avfcoxzwz53bp3xiq", + "baglacgza66vjwzsh6wgfv72zygbwgh2vufhfuagmf36q6r3ycnwxx7yaxqnq", + "baglacgza6anvax7pis7sukuzo6t27drgmckh2ahdork3wmzhqquidlakjpqq", + "baglacgza6coc33lehemkv73byblozayqgaclz6xko4kla5pcptbgwhkyoibq", + "baglacgza6gta5cebz7fs3riluwgde3gmtjw2qkd4dzpvnuqbovr344aaldca", + "baglacgza6l4kyy7nsrg2lahabyhvclpuncic2sqtzvmefqofpuq5lnsdhmra", + "baglacgza6ogjls57pq4k35agbzpeydujoq65lpoimp4iv2d6cegrdjk4frwa", + "baglacgza6oydtjhtene6qxdyfuiwjqmjbzn7c25nzhxez6bh3nvp2irj3xta", + "baglacgza6ta2auxqjgh7o2oj6x3ogcrx4cgfxlupdccrq4j3p5zjnahnq7mq", + "baglacgza6twdmxbxie5v7ht5hdb4mqezel5cuwjxk7xwc5vxfepn4wxcwllq", + "baglacgza6wjkyvgipgaxhclghpthoftpkarjiprp4g2smf5b2foc6nj7e7oq", + "baglacgza6wtl5yiy32ruo22c75ysjtnxrghptmimp6fp2pq3ilpaxqyn6c2q", + "baglacgza6z2kpaqbk2lezgrkqrznv3c7uaomvab6646z7qo6n3rsbz3qpbka", + "baglacgza72em77piwedfycox3l4y7qbskqlptpcy7r725im2tpsj23si57ga", + "baglacgza7hvenpvtima4lqksljjfeiou2lwhy6h7qvmdaxrvp6iglprd5ecq", + "baglacgza7hx5cpakzowq2h26ocionl2t2p6ifhui6pju5xug6wgifi2xkv7a", + "baglacgza7lwpiwksommncl7ofw4nqxcu7qse2aqhxizwuapds5mtxaa24ypq", + "baglacgza7p3a62673mtcsidsps3ep3atul26nzldgscxv66rvkmqj2gjdejq", + "baglacgza7q5xdqz6fzvxprpesta5w763wrduopyahwxtpdd2mo5jx47qasoq", + "baglacgza7uco7rtze752545y336slgt7pczgdpmkb6j65x3yydfsprerba5a", + "baglacgza7wkyigp25224rkrivwellawayv3y3r4mobbqc6xxmgscxgiq3gea", + "baglacgzaa5igkis4qk25v4ko6eryts6watdot3ark5uzlxm3o7j3izolxala", + "baglacgzaajspycacn5bhe4dpspprjoayo72z54wmrxz5n7m2g7of3eazijqq", + "baglacgzaaju4hfbrfcsgxp2dqrqdjrrfdjwjhbcubmmum3wsveqgsisv5sjq", + "baglacgzaan3c7frug6yo5tyyv7kzn6bzrxtwkwy35bmuvikkq3v4i6suovpa", + "baglacgzaao5djij6f4x3jp3qszkawqwusvofe2mhloopb55yoyzfqxkezgsq", + "baglacgzaaokqnkj6sgq57ikquob6w6uhvo6v7ni6uy677pqzr24f3nyll5eq", + "baglacgzaapcyag7sitbiyxcdbbj5m6l64vhx4gt4hbhvdwgjuhoezwlmw5hq", + "baglacgzaaqtskzrmoaoexhra66tmvdxne353oxcxuzq2dca75ldjrqqhoiaq", + "baglacgzaaqveulltjfdqenhsig3nzfwdwxso3ndbgovg2gnczkqop7vpbbvq", + "baglacgzaarg23ok2cd5nr6jc4ocetujiqb7nnrft42xvfuh2vbs35dfyqr2a", + "baglacgzab2hdhand5g57pqt4uslpy2mz6rqnkwlvw27bczvsc2tj2m3pr3ba", + "baglacgzab2orhwmiw5gxfsqb3bwckhf3tf5jztbbdn2i5eyk2kvd3zfi7hlq", + "baglacgzab5yedqfwm3pczaqnqfvsondxhdyorywu27q6strjbc4ixq3glizq", + "baglacgzab7lroi2stb2cmi6awpfpwpsl3bwawwvr64ijpng5dhz5nes5owgq", + "baglacgzab7rmzczswht4isr63gea5uoww4pmqsxrvgzn74wheqwopl36mela", + "baglacgzabadhauzo4lxjpslyal3fb5gfrs55hsycsd5r2mj4mkvcgypcvs4q", + "baglacgzabbcknaso72duwyoeqd4i2gyghf4avilk565nkzduap6h5jwcosza", + "baglacgzabi63cfckdctmkqdhbcdwszzatr3bfcyyuaocrgnypedvjmjog2za", + "baglacgzabirgkutruwdjfcpl6bkujicvpsixkwfjh5hmuy7xoamdysl23dsq", + "baglacgzabmrd6yhbgxhmghn5nguatwnzhrondlaxmagzxyzqdm24gooneucq", + "baglacgzabnitw6kehgnmpyrjdk343qnzt4cekjlmypymhnvvylkq5k2ptcdq", + "baglacgzabqho5affvmsfef3cnd4xsw66l42d6ena4g2xedujct6qsd7o4a2q", + "baglacgzabqzaabcpgd4pnucu3izbykoognju5kc5qwtfkualy5r6todywowq", + "baglacgzabsc4xuh7rbvblytwkhn4swzctyu43ba36xoehvuc7cpmbnkd3ska", + "baglacgzabu6rq7xkdr5uoe2eunlx773yg2kk2h2lho53ef3c4adky2jhs6fq", + "baglacgzac2cndcn3vq5mnjfoz7kdnboebmshmdmvnb6aatzkwnegyfug3cqq", + "baglacgzac2lofvuakrf675xzz6hh2ahgbd3z77gxc3ofrjolqjqj7dqhzopa", + "baglacgzacahqtmufgqhyzdgynhxsezldqc4merrerrf3y4jw5d64umjg24oa", + "baglacgzacgrm2zlg4dogiza57lwcti5r7ga6ucswdsp3mp2277jfa7yx77fa", + "baglacgzacj4uv2ru2opsecdduklxkbxl4vkvyk3ercuunh7nsgfxit3h23mq", + "baglacgzacq4j5rfibfkuxvwa5ui6zpeq7h6edgmquy3oguz6zxxbdkfw6upa", + "baglacgzacqbsc6t7cqligdehacd4kjg2xlpdtbjhd5xtngqswaiiqpdrsj5a", + "baglacgzacsbz24qw6iy2vviclvzaegksg22ryng66bhuxpj4dl6pcg32wzxq", + "baglacgzacthcbn5p3sqfzmpzrndyhbcmneuptrfwr7s5disl54oz5nxm5s2q", + "baglacgzacuetfnthnppfxkfzgfza3exvy7gselbqv2s5b6czidll5exmqwza", + "baglacgzacuyuir4l6vee5vuf5elh7tvnwzymf44c4qpzu2ipo2tbbyp4e3oq", + "baglacgzad3w24kle2itl3jm2kxq6cysoj4xoflsrhrw55msc6meagt6laetq", + "baglacgzadcjenr5pr6xnfr6t7b64rnnfdv4h634k2zm2y34roiuuwpp75vga", + "baglacgzadqjwms4qs2lz4ctklcizsqfsjbuhtevpsurqqwa676oq5daucgna", + "baglacgzadztftc3rxrphupebphkbwuzdtnthtyl4pfxga7wghxthe463ncya", + "baglacgzae27ionu7mlu3ojudqd4a2ywhyrenxw7zrshr4jhy4ld2fqpgkkia", + "baglacgzaecczvtf4q7l2mhitw2tn4y26ysaolmicnoc542wkyvvrs47o7a3a", + "baglacgzaeggi6pqszfefbd2or7verp6bbz6b7ctkszxi6yalsypnivkrc47a", + "baglacgzaegino24jsful2fjnpe3haf3hhztdzzm626rdtmksxauccfzv335a", + "baglacgzaeifznjadvk52cuv3qvbitazdkkavu4q3detg7xqhmsuykaemme3q", + "baglacgzaelxcuf3wfrqavkk2uunaqjwp3wiuisjreuarwnbiqtdbrq5kwkuq", + "baglacgzaeph54ay7tbgyox3437nbngzluz2k4kkqmjh6ymgbuakg2c3mf2da", + "baglacgzaeqh6atyhyht4qqqvcyuxdg3uqfu5x2mujowput5bjcuor4vnzrla", + "baglacgzaeqyhcnkoumzym36selclrief3po2p4yj62juga6r7ueszzq7fsaq", + "baglacgzaerhefaw75qz4to3wkfrm53spfzrzaaz2ss3cbvikf7djipv5ql6a", + "baglacgzaesmlkiauyhvwce4j7n3vqdaiupsbesk7ehoxjpqpoyyfsuboejza", + "baglacgzaesu7doagjxn3mknma6nifhvfjoznwlgjqomq6jpxlcejioxu2upq", + "baglacgzaet376qv35issfdnd44lpe3xxtmzycg56mibqh3ehd6pxbxj6bpda", + "baglacgzaeuvjvxxqf42qg44zjlnpje3ls7kpu2hx36uho45n27jjikys2jiq", + "baglacgzaew7pv5vcxev3udk3dh4eaezwpjgi2pxwqa3umwmtoiw25q5foqwq", + "baglacgzaf2bu6l5bt57gstxyudjbbrj6jddfac3qmr5jnkt6tgwbj3qpfavq", + "baglacgzaf4sjbg7ya3pq737z7im3pmp5vubrly25hfkvea6n7pfapib63kyq", + "baglacgzafelbojewhho2qlzz2d7txvh7ycbjntfmqkwdxkiw6raesraqfznq", + "baglacgzafgf6pv43422ibuujti24hazwtn3ohwylzgo3mt6qu7dven4zlqdq", + "baglacgzafiiwa2wygo4qm76xt3tekscp4ioub4u34vz2aqptp56frudzgjkq", + "baglacgzafjhvq54vejfj2vrvtidr6nlt3e4azkw5jg6kdnr2dot6edm6mzsa", + "baglacgzafkeckix5qfiuuorchl6xdg2o6vis2qknjirq63vryuqcyl24kwxa", + "baglacgzafkusmmr2rw7vijysdeldocemzrvwszho6nbvxakcy3buf3ytk4oq", + "baglacgzafnsgu5ksxa4sv2kcmn2x62m2e7losf3ljqdlt7akoixyso4wi6kq", + "baglacgzafokb5hx5vy5ltj4ee6ndad7c5fbak3j34ap2j4u2i3mbt5oeqkzq", + "baglacgzafqw6zh6ijntmwvxue4u2k7wzp4qeqq3zjw33uzyt6xixepdlegka", + "baglacgzafufkadgo6qcmddvnavloopfzmozwxi3p4h3mjn5jw2xmj5ws2ipq", + "baglacgzagf4zu7uebnql22h7pmuxotzjcs2y7y7o3dz3nsogfou4dqxa7pja", + "baglacgzagfnw4qkfwuqlrd7v7nryxergohxb5s6lmw2xxgsl4zikwh6odu4q", + "baglacgzagfqonr7vtlbdofwm34pkoz325axn2v4pxyxbdly5enjbfnwo6eyq", + "baglacgzagp3wukeubt7wqrdq5okknvbyh6rueyo5t2np5rg2whot573jq2qq", + "baglacgzagpnopg2w6cmfzi3avh7c7ovd6rlwmnpu45kkb3wmlx3etchiggkq", + "baglacgzagrolvdnsflcwzcmqnbbyon3enber2hlamdf77kvhwousoyznwika", + "baglacgzagz2qudg5ucppkpoeu5iq5nu6q7527mltt5i5kldaeffx4djhnxoq", + "baglacgzahax3xfs4df4ywelodmzk2zgztppqt6hu5vgihyntrd722dxixrra", + "baglacgzahbvb5fbnx2ddikyx4lulfcrftvw3mxpy4bpziskruce3xhz5tcpq", + "baglacgzahkj5ojwxjb4hjzi3klmnkngghkrknco7ddr3gb6a23fquoeladzq", + "baglacgzahkjgb63xoh6ke37ztl4npobu2gkyh3ae3jjii4daodh7utnujiqa", + "baglacgzahlzt3rfhisvv5xkcyxc73sm6ijh54n42zfsq76ysi3jisro646fa", + "baglacgzahmtj2kckjq6pr6g6vsx3mn6g257wa7xmrv26qveno6hgffqsgeca", + "baglacgzahojkgpcys6csj4cos62mt6fwb32xsoca3l42qci34zqjmtyvd7gq", + "baglacgzahsh7cceh3en65fkgjesotsxs3pqbhflxzv5kdkxnz67jd7c4pczq", + "baglacgzahtfb5mhojo7zknjhyhnf6o6d65wkz22ellgvxvz2cf32dhrno35q", + "baglacgzai2u7cil4gzmzbas3pulb7qr4vzlirt5wwiyh57slomwhepqdpfma", + "baglacgzai3dvv53agiud47vx3fs6gpqg5gvjze5xsecatnh5l34e6pgocbia", + "baglacgzai5bxsipie422mzr6u2itm3wgfyg7p425rcqn2hg4453fxnepaa2q", + "baglacgzaidbvljbgsc2tpdyjwzcsqpszjotijnbls37ropeazffsoi2wamkq", + "baglacgzaihrnrw2zuaucifxzmpyg5kz2evaagrybgq2nm4sif3jhr7mljnka", + "baglacgzaimssao3zceshkgh6gltjqqqh2x5qiodirixcvjqutgvdphog7dma", + "baglacgzairaleq3xeadqowm7ec7kvxmbjsmqrltobjcqjso545a3zdcge72a", + "baglacgzaisv2zdtclyzxlffct55zevsfb6wxmu462ft7et5qahpdqrnmcsba", + "baglacgzaivd7643lhy6s535ukinqa24onqywzkfnfhhi5r7uvawxtiw7urza", + "baglacgzaivgvcrgjwicuf4aremv2hbggrnzntrddmydzud6rkbpb3xrbpdia", + "baglacgzaixcais2z6gwyafi6bpptra65xswthhpd5g26yr3d6ahn3bl2uvca", + "baglacgzaixlti7he2ffvgp6raqotxkdsekh5qy4duv3tmtn6kvn4n6sjuu2a", + "baglacgzaizfqoqu2aubz4iutcsjnnrrfdkdayamouoiaixkznmnmcg24pktq", + "baglacgzaj2yfzqrtpjd6luyv7spcs4xyrmrifsxm663zznegzt2omto7ktgq", + "baglacgzaj46wxqbpstd5eicctecpdxhffmbuenzqmd3bt5jdjykdr7aeo3aa", + "baglacgzajblmw25dyrzwsfymo74y5h67v4nrfgxs35eevemvqfui3y7rkszq", + "baglacgzajdmyteoo6aovcp4w2wfnqlwp7hhncrgkajtqm3fzbxo3zhoko5na", + "baglacgzajf3sy2bvf2vu2d4hqvj3rvq5lblzp4qptxfb4ulcyayhrrdszghq", + "baglacgzajg3cp7yoxohz7luw4hzvg5cnzcduabrogcqy7ilhwhp64nmsn72a", + "baglacgzajno3x77dsi7inf4voolwgevuslix7ays2u6oh3z5mq2klkwbj6hq", + "baglacgzajshfqz2lgrejfi37nhstsxmjeh7c2jfok4znn4fezhmr2mlwpzhq", + "baglacgzajv4bm22iarh5ykhneljp2ooi35xyvkqezny5hilsq2cw62et76bq", + "baglacgzajwya3t5k5mqyvipqqlahodjmmsljwe4df42igrc7pdgqzbc725sa", + "baglacgzak7v5o37lheriih5julg5c37gc3wpxmxudysjo6fttnju65efl4ma", + "baglacgzakbsr5nin4suyz7r3xxzcxkuel6fghs6zrbw2yi5ez2xo7nloerpa", + "baglacgzakho5pd5qpbxs7mo3ujd7ejcjyhstznb3xx3fluukdjyybxn4aexa", + "baglacgzakhvmbzxior7nsroicglbhkbvts3weihhcrqqz54dhcgosaavgiea", + "baglacgzakncmprlqvhlj4nfejd7odbude6hmeykm6wspwqpm7bg3xoqi5dxq", + "baglacgzaknmalbebn5qxffpke3aoc5sb4ajazkzpbkh7wu5im36vhkuorqwq", + "baglacgzakuwsijjghgtk4522uhpxad73slbechnou4ug6fmniqebzals2bza", + "baglacgzakxelvpgmk3loheqewteco3z4pusavgv3cjj4xzylahmsiqkwovxq", + "baglacgzal5gkbdbs4srzs7iostmji3r5gypmlubclwonqxdn5dkxfoyktheq", + "baglacgzal6llyltmvocfvqgxq5ltwunaus5ntfhl5ze5f35kd67oj6y5lq6q", + "baglacgzalc42jtx44sibtcvjjhz6drbt54y6lcxy6ucmngi7cvdbajiebndq", + "baglacgzalc6y4rmk42q6ix5cxhpinwyhlbnjobwb4knsqr3xe6qv7m6qkibq", + "baglacgzalihtntqwaqxyc5z3olm3odzztqlq6d27rx5mdt4gu2bdxgwwp7xa", + "baglacgzaljiw3say55ek5m3x64e66wcifr5na7vbutyuu3m74gimlh47g44q", + "baglacgzaljokkpwqxdoaoyrmsml6b7b7zfiqefbhwxlmexxepy2d5wuyekya", + "baglacgzalodtjmdplb7dy2p5arsxk7nyszh6lhsyzxe4lgkdgrp6rymxzela", + "baglacgzalvkdmoxvvqpflgq235nahqiw4xofhxzhuio2eljusr7uhrch7nnq", + "baglacgzam24ldzjqb3puomhwshglrtjcyrcpkpva2wybbkltfws6tor5tp7a", + "baglacgzam2xbzezi7l6vlyicgx6i3kpiqceh5veonhmpa4pjny3eibaeolwq", + "baglacgzam3qbvtektatlypk7kkdidh6fra67umeugmy7dz77fful7rl6ulia", + "baglacgzamet5xv7ury7dnkqy5yltgbvalcl4ricsvdduy7hskmyxslvsa5sa", + "baglacgzamfflp7uex2uddjuoly44nywthhnugk4u3tjjvr2542km7rtecsla", + "baglacgzamfrwerukgoisehrxqlnefyww7ohkihngxxjnm6pcbpydoxagcwda", + "baglacgzami2ovudshhpsyi6vbuq5fycfgmv3hyx3bjacvlsxqc4chz6vgcda", + "baglacgzamidvfvv6vdpeagumkeadfy4sek3fwba5wnuegt6mcsrcl2y3qxfq", + "baglacgzamknqvkqe37lskybr6dimt5ngmihfsmnoe5mi4yvtu7dq7tylh5ua", + "baglacgzamwsrbjbo7pyf4ftaizzj2lsqdqhivh7pu2evcgraenjg6sx573oa", + "baglacgzamxpcef5svw5bshjcmx5dtw3jvdnsqxyqdoystvutgpk3dbxaddsa", + "baglacgzamyk5sdzyg2vnuzaqmbwwzqbbh2xxgfcouukhmcjcudy2jdw2dy7q", + "baglacgzamzsn226lwcfyh6cdetnyzoxsz2zcdze6m2lrg2o5ejl6sr5dwe6q", + "baglacgzanax447kk5lah6ed5gqzg2eefwyygfn3l3w6n7eio3w5ohhluo7ca", + "baglacgzanbkitjrv36vsbyxc2fazsncuapltoqi5yxyntfjtp52dfmw5z64a", + "baglacgzaniotnde2dyyjhdnud5batwqnq3njuh2gotx6hivafivq4qtt22oq", + "baglacgzankthcaoqchi4el7hhhxyhmclkikkhyxy4grgexml7wyrnnch5bxq", + "baglacgzanm2vfedt2eqsljbb3iwri7hu73bnb3rqgrurkmrsacfzejju2nda", + "baglacgzanrcxybniprkx7bhw3ggpwn2uuigb33ifkdxuavbt2niu6mzmo7pq", + "baglacgzanynqqlgddfsdtm27kvidm35d75yocvndtsdeijt7z64xkilxin4a", + "baglacgzao4txzget4reg6nj6uwptwdu2n6sohzyfeivkdwdzvziouna2uvua", + "baglacgzao4vipuem6ogey2f73z3qs2cxdk6rn7jygxfzajegxuxfcxktyewq", + "baglacgzao7aftivtmdu4sz3inijqfjajstgwhka2vafiigmr3dz5on43ndvq", + "baglacgzaoao7i2mmwuopg2gfx5m3xn34fayjdrov2yolscqtz7vi5emdqdna", + "baglacgzaokokv2ioov6fjlkgkufj4yrplnxdw47r4rqhighqnb354ea4jaaq", + "baglacgzaom4zyvyb6kn2hoiyvwg2ywrwgr7o5fe5c3p42z4vuhfzuxmlaoaa", + "baglacgzaoocvbederlpqaufwkwso5pl7qkfnrpd76zj6zbwgj5f4qcygis3a", + "baglacgzaov7f7oz4onncim5hhnlbjlz7ozpom26kfh66vjow3w2s2cok6ska", + "baglacgzaovc4t2yesyqvzvdsybtp5k2y4tb6xy676gwnwsr5qoztogehxj4q", + "baglacgzaovkdfxjerufbq24zzqm767juiyt4hcu4ivlpvxh447w66rpfvtka", + "baglacgzaoyn5xje7zjq52lswouegf3w64k4zhyqp6iclfsyj7wgjfjwyvicq", + "baglacgzaoyoxana7gxkhxwj47iiqjv76y3ktnk3kootf3pzfpxcpmzp6ptma", + "baglacgzap3uhrl4uj77cnts4mqcc3tdz352ifbw6lahfmeihlfcetwhnkfxq", + "baglacgzapdoq2uowvqcis3dlzxug57bwzas2dyhefu3f4frrqdz3yknzdxtq", + "baglacgzape6j3mhckl4plr42twds57ctqwvwgku5ymjboy33gue7z5xqwaia", + "baglacgzapevdnthqwueqltoge7dt2cuxvijmhep7rw6cnp44pemp6sluitka", + "baglacgzapexdm6koz42fosvv4qjbqhnhsuevh7oqmqwonspl63t2vpjqitha", + "baglacgzapngkev2hcarm7bmcwdrvagxu27mgu5tp25y76kzkvjmrggrora4a", + "baglacgzapohhuiobc6gsqb2pcv5vb7fil3rfyeswr74os4dnzpg2zn337bka", + "baglacgzapsts4gledg5dyjaileaqdcffv5zcw6qooifqxgl26bxsoi2n4waq", + "baglacgzapxzpwc5xrysx6y74fs6pybyqlfly3olnv5zaazqsbuztbopuc6jq", + "baglacgzaq4oyzbuduaeeg3ww6bzspstpbtcb7tiyswmaaymfpvao2hqwxcva", + "baglacgzaqbgeg6rmbd2zxpucpdd73kb5bmmo6p2p6eonafojtqkwi563ycoq", + "baglacgzaqdcmhkhjwdwatfshq4axfenrhggqceqrz47yiupwweqknnrvqfya", + "baglacgzaqeijuarx6vrtycc5267h5g3xzgskgaylrftmyjq7vjouxvkb5cvq", + "baglacgzaqhglxiq5ptweegtm64wuezj7spc2u2g5prw6zdgnwmjwfxdbn5nq", + "baglacgzaqi5dqutwokxefveag2nibmfzylw6szglsntiybeh4e2bmb6f2xxa", + "baglacgzaqlswzpybvsbc3fqkr4iekizldlug3ak6qsuthtu5qtybmtij2lia", + "baglacgzaqm4ijihatant626rqycd33xaerqj77zivb5iwmgyaqwgysc3zf6q", + "baglacgzaqm53klhsbyfek6wnzmzsah7iz2km2euk75yapvez7fyl73gfxhxa", + "baglacgzaqp33qaf7bfj5w6e4k63cbrc3oqemubyxgjmv7wjcroatsqflba3q", + "baglacgzaqr6cfr453mxviwkqsjfz3riq3nw3lrh7lmev2nuwoop34mjmgjta", + "baglacgzaqrzyy5uetfwsqgfvv624scsdw7dx7z42pf47p2m3xuhqwuei27ha", + "baglacgzaqw7dbrzdyxhjsdn22orpgfzxxwdqcf7hn7ugy4hl665cckc5oxja", + "baglacgzaqwe44wrh2zpa7ogoka44yx6hox6w55jnndhymz4nerazqjgxedua", + "baglacgzaqwwwnlav6alcw7r2umugzbxppixu6mqp6w6qyriffo27mummjmca", + "baglacgzar2p263trvudcq3qwjppcpfgzmxc4taacjtekhkfzsqtatl2wp27q", + "baglacgzargpxdk5rrrwjkyiyx5lh7ldctn27p2ksnbz6ikot3cv3nw5vqaqq", + "baglacgzark7ier7445klswjg5eqx5qxoiibq5mrmbctybd2ffu4gwffqkwyq", + "baglacgzarr6a6fovyug5em3cqkzmggna2nvjohihdin5ffn4f7k3cm2qc5gq", + "baglacgzarrbzhd34po574cixc6tk2wd4escxarqzoqnlmplqkirhq2ms6wla", + "baglacgzarwmkoc2al7nxgjxdysbzdiq4yfcbthxhbs4hkquxxnevsoxnwc7a", + "baglacgzas4zhiutice4t5if7jai4vedxkmo3adigxbrdpixm22b7kw5exsya", + "baglacgzas6yxvcp5fqb65gglmrm4bd2rwju5uxhoizsq5bchb5rl7a5uh37a", + "baglacgzasb5vgdsv56jygtmspwoswmezrfnp2kray7xhuszshqa2dfrs3ypa", + "baglacgzasdc5a3pa4mtp46bpsru56aojakeucvy57654mq5o2bjp5mop6l3a", + "baglacgzasfdhsvcjbujhmmosulzzu3w2xvyccu66qf76rwrkxgrqke7fy3oq", + "baglacgzasfy3a6qvsisuwzgjm3w7vukbubffxx7ei3eqh7f3v2ftrqrfhiwa", + "baglacgzasoghibkt6mikv6sjvnvv6zci47gjmnkumjzxhlei4tvq53e4jstq", + "baglacgzasogvybtxh67x26ob42m56mlgnxwdelfb24oobk3po3te6yysmmca", + "baglacgzasrizkrumchv6zypcuhr5fmtz66ej5cnup5sjbapxpj27ttj3u5xq", + "baglacgzast2lxo3sgtk5qtnp64mwxyjuozwyt5v3rg4ytrnleporcqmb62ua", + "baglacgzasvs7p7bsxtnrb5fz25cx5gyh43tqja74ywrhwpmt27gnni4z3qda", + "baglacgzasvwqbzd4k6hoheken36oszbb6b6dvfc46acsyhfqssajcqd4xzcq", + "baglacgzasx2czupgncbldxwxkqkxez6tt2oldw4iocqrhc7gk6bgp26g2slq", + "baglacgzaszpquuoaaaq3auktxvag6h3fuwpnnrv3chfrymdwb5khdqwfxa7q", + "baglacgzat2pxiuhdayqh4ma4ss3wxk2uyipuciqonxig3z6jitc5kdmrozha", + "baglacgzat2wiom6pryjqdoptciek3ckt3ctgdeujprivuey6ypgfsjypr65a", + "baglacgzat5btacphq4ie5kecajgxjfgvooqza4zb47w24ibv5yvz2dy7zyea", + "baglacgzatcbgkfcnzesrtyfe5hxe2yuqek2hvgmwvla2zjo3i4rvhnb2k7yq", + "baglacgzatghruydgf4lodn6vmjtvfpvf755goj3jkeusdwia5pixldcqjmtq", + "baglacgzathtbu757wgovtxofbnlsnsyad662vbnn6aqk3oyyx6xixtxsw3oq", + "baglacgzatnjb6dg7fsz4pesso63i63c3t2agwybbgd3i5u4ezthjuvddspea", + "baglacgzatou7j5blylumwrr5hfsck3hqrasegy55ewwgldtwew3uykaszcmq", + "baglacgzatwt5s5k74dcvrm6d32p5zx47fcxgihzyzf4hwbnxhkzcvzj26pra", + "baglacgzatxyuvssxlehlznynti47jiaoyj5kqevfdmu7yj4npmjr6l6uyhfq", + "baglacgzaty5w2ykcxoxf2zfdcr742hzezg32vyanvv2qz6hbox7atjqknqrq", + "baglacgzatymnlewdcj7uqohfdcrcszva7nzezhgib6risqpenllqdfch3i3q", + "baglacgzau4tmywowb37dv47edd7pl5af222ba23pfrlukvkbersc6vrv4qwa", + "baglacgzauckhnf4srmqecrryxiflfpf6kavfhm3d4qmjzkxg27f5dj3546cq", + "baglacgzauefudv2ingzufqe36jloewm3xketyjvnc4e4djtpbathwjm66a2a", + "baglacgzaufpcg6e6rm62ybb2a35vwtk2ptqt4z74pj3zmii6rx3a3dwnnw7a", + "baglacgzaugsxw7cthfl3fg2rlhemgut2hhitktn3bovkjd5hawrvi5ss7gsa", + "baglacgzaui2r4k54xxqxadyjt25kzovmlelw4obn3fpda6gecswheklvrhia", + "baglacgzauiscf2uzdir25zlogw4qpzwriy6mtgsyzl7omehok3jpmskk3knq", + "baglacgzauokbnjmp7gn4sz7e247j7ift5hrueq4zzq577m557j3bmqnwfixq", + "baglacgzauwwnb3h5pxhm2h3tmcxrc3t52jlbpibalnpywnu34p74pbge6wuq", + "baglacgzauyqu2gqzcc2xtmahbe4bnlubzp2thteevnp6bfd3kxpnxozq74rq", + "baglacgzauzvc7x64vjf6wlwaisddf4vf6hjsfmtlypnadtb5i7kbbasizmma", + "baglacgzav3o4q33y7amd7bgpfs5xc3kog57nnhbruh2s36pziymkmv32dpgq", + "baglacgzav5zidj27tlfukw2ot7es7b6ckgcyhkdlai77rkqq24skkdda64lq", + "baglacgzav7vn47ouq6zebmg3img7nmada6ag4hx25uouzqxttyptyudr46bq", + "baglacgzavcbrgucanfxqhbshrz2hv62vfkrtrhlv5qx6swbc3zavqvcn6zta", + "baglacgzavs7qjikqvxuxkpz5liqdyqrzaonkllqw6kd4lf2cxjltxxlgz2gq", + "baglacgzavsgqcwu6m2hvq574yoi7vyzzqhaak5yjn4cflnbn6t4oqce6zysa", + "baglacgzavtfwj5dsgw4vpplzv3zsw6fwiykcpz2lpclspzq55u42vij2g2pq", + "baglacgzavtod2r5swzrok7fapkssy4mufrtid37trvz2jxzhnifxh7rdgxdq", + "baglacgzavwgvvyakic262434m7kigrzlmqautwbknymr4fyngjkobh3cyl7a", + "baglacgzavwymwhn2owqnbm43vvqtxgd3ab5caqalvs4sz2tzc4cs74b43q5q", + "baglacgzavx7pxqr4m7pfzcn6tcc7o5pq4g5tp6qvsykkhe6rugqat4a2kuxq", + "baglacgzavxzbb6zhtlf42msx27zozxk4a6twphs4qsxchlrt2ny6t5we2t3q", + "baglacgzavy2t2fxjdf7pgnx6dzz46eczpnjdwveeiihq5ev42guggtnivpxa", + "baglacgzavz4xq4u5fosiyz7ldtzluikmtco4k3mv4xsrnppjz5omgutz6abq", + "baglacgzavzdzgv2mihwc6qop5hkv37hhx26dmnq75sfg3jf4nkq5vd4pjvja", + "baglacgzaw7it5iumtdpxyfxvlizcwsthfsemmyjqmb5cq24hemei6dftsjtq", + "baglacgzawaf7gawvue34nkiksyyrpizlmtkuu275e2xxhaxiirhsmmoeo5zq", + "baglacgzawat7pexa2n2lq74lyoq6axky2qzzyf3h6sa6hrucjc3z45elm6zq", + "baglacgzawez7iipzfpgi2jirdwusmbvhdjporhu77ejvoam7duwmequa4isa", + "baglacgzawf46giyla7nssrdtvzl7afycmj4y7dcvdr2vwvtfvtqscxhocdfa", + "baglacgzawj7icprvylimlisn2p2626vxy7ukwps4t67gvrhduz5hlk4aecyq", + "baglacgzawksvmxhdtwfx7k5silyip4c3ojz255cast2bmycgzxozpb2rys7a", + "baglacgzawoe2dh7qxrmhymrexqkykhpfsvxaqm45sxqwdpk47nqwr673onva", + "baglacgzawug56abirtemcm2skgyexstfmmrvivru3xjcgdyxqtj7ef3jxnjq", + "baglacgzawwi2ftqcgz7numopfulozj6cp7ke3pyims3e5kbftljwnfxlfica", + "baglacgzawx34khb3fvi5s7yxduvtrjg7dj6avtc6wdpenpxp6tih6xwsbymq", + "baglacgzawxfq5gj2pt53idroosz6eahmfmrwxuz5fpciiwmiuts7l4a6k2eq", + "baglacgzawxgpzpbsbi43icxcrchpoxxcaugcsvh6eusiswwjrtkdlugveana", + "baglacgzax2eoi4sdey4cvc2w4izi53xqvvi7ddk3vyhiiklk7ykmiaumjl4q", + "baglacgzax6ioorxkqyls3kmv2ntmfhsbptavrrtit2vy6zmgbnltjjbyogpa", + "baglacgzax7i3elt7nndzjenb5xkogpgelmcmmtn6lqp5v6kvyfqe7m5k5sya", + "baglacgzaxh6czvlet4gmuorror6l6m7qrr4ymkolyr4lzofbme763w2peijq", + "baglacgzaxjrq5medoijedijmlrkevn32vsthf6vhgtojvtlttxo2ze5brbja", + "baglacgzaxl62rn4xijbrpvuzkbb5awzhuasuihynltlwwau4lij3rn64rb3a", + "baglacgzaxq3k23qmqsllx7iz2ymhliqz2jewob2nckhdd2wkxtf3rb5drpwq", + "baglacgzaxrwu73uyvnvmbfuepvcxeryunic3ozbn6t5uxwypoy4puej6z52a", + "baglacgzaxt5p24gzgsgqqpd5fyheuufvaex4gfojqntngvewfdhe54poe7jq", + "baglacgzaxxsmknpbqxei7ffyjb7fhqtvfrwxr4t6zloyavtkt3jygvsldlra", + "baglacgzaxyyowwmsdsveoyjw7ywj67krm3x77iqyy3gzj7fdc4xnzjyirsfa", + "baglacgzaxzceixddm72q4dlup2gwlsoxfykcejxavmskrbravtwa5xcvnktq", + "baglacgzay2b7jkphp4kufkhmwiriduyg5kgmqyzjojikd6hvib4bycl6fkga", + "baglacgzay2imkpytg6m7kmq7oloogxzgfc6t7sm77spappsm2iajkdsqif7a", + "baglacgzay5ujimrt4qi2ksavtfjysqjsn5m6ysxizi6hg3gqhpnuj362d7nq", + "baglacgzaydqlktfraw5nig2lsjmigudumpo7vzy4mgn2fza5nvl5ukri577a", + "baglacgzayesgx5kytkdemwcwmhxd435ka4aqqpwm6qugtirlnpyoyjexg2ka", + "baglacgzayfhjayggwn4e4nnz42xcvuuyifbkowiqztej5oe5yhrpis3mldba", + "baglacgzaylywcq6e2hnqgj3mim3jnxo3h2ptwej3zwcuwetzmitc5ghugfdq", + "baglacgzayrdorxqktwlfykcpqo3uhyfds3rlsjy6rcapz42x2lsc64otdonq", + "baglacgzayunrwjhott4rnqk7fniizbsv55apaqalgup2fnf66qip6aartkcq", + "baglacgzaywc4cisesa54dmxrzulfzvg37ldoe3vebiqoncqtrhdxaypepf6q", + "baglacgzaywze5wn2o5cvdrdekjdjeet3tt36r3wfzwpcop54iumbvrex6zpa", + "baglacgzayxrz3npxgaz2byd4onx5phnjyfwxfovjbztg6ddrhwew7pvynq7q", + "baglacgzaz5yvtye7y27sz7oitmxfgt5yvqdzcn6z6x2vxar7rvluzqoh6dfa", + "baglacgzaz6agggjviebqoyw3sdos6z3jprjr5fe5vprt7dlarq5gxm2swdvq", + "baglacgzaz6ajmdnij27zbfrxugyesam5i6m6cezxfveoxjadnolwjelszw4a", + "baglacgzaz6sqay6zefbflfsyrt43nsszivnrywlokmridmcox45ehavr2bxq", + "baglacgzaz7hm3bnvwozlapazmwe5hu5zxtin37ab6aam32p6hsvudxdkbila", + "baglacgzazcudtwhvet6q264rgjonf6nt2a3omigym5wpabkq23kdeyvxqr6a", + "baglacgzazikph4bqhr7vgs2xiqpebvoyazj27mftysmy6mzoigkutxdxt7ma", + "baglacgzazixckhuckariike5abthcbdjgmgz5rcysbuaucijz5d7a3avqvpa", + "baglacgzazklwtf65v4dpdcms6yqh4t3kawlz2b5m5lmwk2afq6eqc7gg2bvq", + "baglacgzazlnsvtqu4zd5tjtz5bct7d2aqiotmfsfg4eg62bki6qiti6fdl4q", + "baglacgzazrli3jvfluavjdjwgkt3qktktnuh6set2t7ib7hzhanobmwxwvla", + "baglacgzazrwcvecxj5bq6pyshnxvp35apsxcdtfzacvfbvsrnaa2vag4wnza", + "baglacgzazswo2typlq7izwoll6w4xnd3dszwktreiszh3b7w2kt2ucll5okq", + "baglacgzazsxzdrr4wtg24th2crzvzt66fhg7dy3zppagpy2nn5eesdrsaq5a", + "baglacgzazvm5p6m3ynh74glcwhuxtw7b3hv47ml5y6mtif2whmklebfd2mka", + "baglacgzazy26zckarnz3jfpcwpqo6rwr5r4wy7bonmc3rljbkr77uoiyoxca", } diff --git a/fixture/service.go b/fixture/service.go index 20ceb64..de133e5 100644 --- a/fixture/service.go +++ b/fixture/service.go @@ -150,6 +150,7 @@ var Chain2_Block32_StateIPLDs = []models.IPLDModel{ Data: Chain2_Block32_stateNode6RLP, }, } + var Chain2_Block32_StateNodes = []models.StateNodeModel{ { BlockNumber: Chain2_Block32_Header.Number.String(), @@ -344,6 +345,7 @@ var Chain2_Block32_StorageIPLDs = []models.IPLDModel{ Data: chain2_Block32_storageNode17RLP, }, } + var Chain2_Block32_StorageNodes = []models.StorageNodeModel{ { BlockNumber: Chain2_Block32_Header.Number.String(), diff --git a/internal/mocks/indexer.go b/internal/mocks/indexer.go new file mode 100644 index 0000000..2a1f194 --- /dev/null +++ b/internal/mocks/indexer.go @@ -0,0 +1,88 @@ +package mocks + +import ( + "context" + "fmt" + "math/big" + "sync" + "testing" + + "github.com/cerc-io/plugeth-statediff/indexer" + sdtypes "github.com/cerc-io/plugeth-statediff/types" + "github.com/ethereum/go-ethereum/core/types" + "github.com/golang/mock/gomock" +) + +// Indexer just caches data but wraps a gomock instance, so we can mock other methods if needed +type Indexer struct { + *MockgenIndexer + sync.RWMutex + + IndexerData +} + +type IndexerData struct { + Headers map[uint64]*types.Header + StateNodes []sdtypes.StateLeafNode + IPLDs []sdtypes.IPLD +} + +// no-op mock Batch +type Batch struct{} + +// NewIndexer returns a mock indexer that caches data in lists +func NewIndexer(t *testing.T) *Indexer { + ctl := gomock.NewController(t) + return &Indexer{ + MockgenIndexer: NewMockgenIndexer(ctl), + IndexerData: IndexerData{ + Headers: make(map[uint64]*types.Header), + }, + } +} + +func (i *Indexer) PushHeader(_ indexer.Batch, header *types.Header, _, _ *big.Int) (string, error) { + i.Lock() + defer i.Unlock() + i.Headers[header.Number.Uint64()] = header + return header.Hash().String(), nil +} + +func (i *Indexer) PushStateNode(_ indexer.Batch, stateNode sdtypes.StateLeafNode, _ string) error { + i.Lock() + defer i.Unlock() + i.StateNodes = append(i.StateNodes, stateNode) + return nil +} + +func (i *Indexer) PushIPLD(_ indexer.Batch, ipld sdtypes.IPLD) error { + i.Lock() + defer i.Unlock() + i.IPLDs = append(i.IPLDs, ipld) + return nil +} + +func (i *Indexer) BeginTx(_ *big.Int, _ context.Context) indexer.Batch { + return Batch{} +} + +func (Batch) Submit() error { return nil } +func (Batch) BlockNumber() string { return "0" } +func (Batch) RollbackOnFailure(error) {} + +// InterruptingIndexer triggers an artificial failure at a specific node count +type InterruptingIndexer struct { + *Indexer + + InterruptAfter uint +} + +func (i *InterruptingIndexer) PushStateNode(b indexer.Batch, stateNode sdtypes.StateLeafNode, h string) error { + i.RLock() + indexedCount := len(i.StateNodes) + i.RUnlock() + if indexedCount >= int(i.InterruptAfter) { + return fmt.Errorf("mock interrupt") + } + return i.Indexer.PushStateNode(b, stateNode, h) +} diff --git a/pkg/snapshot/config_test.go b/pkg/snapshot/config_test.go new file mode 100644 index 0000000..c5a1174 --- /dev/null +++ b/pkg/snapshot/config_test.go @@ -0,0 +1,27 @@ +package snapshot_test + +import ( + "github.com/cerc-io/plugeth-statediff/indexer/database/sql/postgres" + ethnode "github.com/cerc-io/plugeth-statediff/indexer/node" +) + +var ( + DefaultNodeInfo = ethnode.Info{ + ID: "test_nodeid", + ClientName: "test_client", + GenesisBlock: "TEST_GENESIS", + NetworkID: "test_network", + ChainID: 0, + } + DefaultPgConfig = postgres.Config{ + Hostname: "localhost", + Port: 8077, + DatabaseName: "cerc_testing", + Username: "vdbm", + Password: "password", + + MaxIdle: 0, + MaxConnLifetime: 0, + MaxConns: 4, + } +) diff --git a/pkg/snapshot/service.go b/pkg/snapshot/service.go index f3e781f..89afdee 100644 --- a/pkg/snapshot/service.go +++ b/pkg/snapshot/service.go @@ -49,7 +49,7 @@ type Service struct { ethDB ethdb.Database stateDB state.Database // ipfsPublisher Publisher - indexer indexer.StateDiffIndexer + indexer indexer.Indexer maxBatchSize uint // tracker *tracker.Tracker recoveryFile string @@ -65,7 +65,7 @@ func NewLevelDB(con *EthConfig) (ethdb.Database, error) { } // NewSnapshotService creates Service. -func NewSnapshotService(edb ethdb.Database, indexer indexer.StateDiffIndexer, recoveryFile string) (*Service, error) { +func NewSnapshotService(edb ethdb.Database, indexer indexer.Indexer, recoveryFile string) (*Service, error) { return &Service{ ethDB: edb, stateDB: state.NewDatabase(edb), @@ -140,6 +140,7 @@ func (s *Service) CreateSnapshot(params SnapshotParams) error { } sdparams.ComputeWatchedAddressesLeafPaths() builder := statediff.NewBuilder(adapt.GethStateView(s.stateDB)) + builder.SetSubtrieWorkers(params.Workers) if err = builder.WriteStateDiffTracked(sdargs, sdparams, nodeSink, ipldSink, &tracker); err != nil { return err } diff --git a/pkg/snapshot/service_test.go b/pkg/snapshot/service_test.go index 44cd74c..d51bfb8 100644 --- a/pkg/snapshot/service_test.go +++ b/pkg/snapshot/service_test.go @@ -1,28 +1,26 @@ -package snapshot +package snapshot_test import ( - "errors" "fmt" - "math/big" "math/rand" - "os" "path/filepath" - "sync" - "sync/atomic" + "sort" "testing" "time" "github.com/cerc-io/plugeth-statediff/indexer/models" "github.com/ethereum/go-ethereum/common" - "github.com/golang/mock/gomock" - "github.com/ipfs/go-cid" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/require" - fixt "github.com/cerc-io/ipld-eth-state-snapshot/fixture" - snapt "github.com/cerc-io/ipld-eth-state-snapshot/pkg/types" - "github.com/cerc-io/ipld-eth-state-snapshot/test" + "github.com/cerc-io/ipld-eth-state-snapshot/fixture" + "github.com/cerc-io/ipld-eth-state-snapshot/internal/mocks" + + . "github.com/cerc-io/ipld-eth-state-snapshot/pkg/snapshot" ) var ( + // TODO refactor stateNodeDuplicateErr = "state node indexed multiple times (%d) for state key %v" storageNodeDuplicateErr = "storage node indexed multiple times (%d) for state key %v and storage key %v" stateNodeNotIndexedErr = "state node not indexed for state key %v" @@ -32,637 +30,266 @@ var ( unexpectedStorageNodeErr = "got unexpected storage node for state key %v, storage key %v" extraNodesIndexedErr = "number of nodes indexed (%v) is more than expected (max %v)" + + // Note: block 1 doesn't have storage nodes. TODO: add fixtures with storage nodes + chain1block1StateKeys = sliceToSet(fixture.Block1_StateNodeLeafKeys) + chain1block1IpldCids = sliceToSet(fixture.Block1_IpldCids) + + subtrieWorkerCases = []uint{1, 4, 8, 16, 32} ) +func init() { + rand.Seed(time.Now().UnixNano()) +} + func testConfig(leveldbpath, ancientdbpath string) *Config { return &Config{ Eth: &EthConfig{ LevelDBPath: leveldbpath, AncientDBPath: ancientdbpath, - NodeInfo: test.DefaultNodeInfo, + NodeInfo: DefaultNodeInfo, }, - DB: &test.DefaultPgConfig, + DB: &DefaultPgConfig, } } -func makeMocks(t *testing.T) (*mock.MockPublisher, *mock.MockTx) { - ctl := gomock.NewController(t) - pub := mock.NewMockPublisher(ctl) - tx := mock.NewMockTx(ctl) - return pub, tx +func sliceToSet[T comparable](slice []T) map[T]struct{} { + set := make(map[T]struct{}) + for _, v := range slice { + set[v] = struct{}{} + } + return set } -func TestCreateSnapshot(t *testing.T) { - runCase := func(t *testing.T, workers int) { - expectedStateLeafKeys := sync.Map{} - for _, key := range fixt.Block1_StateNodeLeafKeys { - expectedStateLeafKeys.Store(key, struct{}{}) - } +type selectiveData struct { + StateNodes map[string]*models.StateNodeModel + StorageNodes map[string]map[string]*models.StorageNodeModel +} - pub, tx := makeMocks(t) - pub.EXPECT().PublishHeader(gomock.Eq(&fixt.Block1_Header)) - pub.EXPECT().BeginTx().Return(tx, nil). - Times(workers) - pub.EXPECT().PrepareTxForBatch(gomock.Any(), gomock.Any()).Return(tx, nil). - AnyTimes() - tx.EXPECT().Commit(). - Times(workers) - pub.EXPECT().PublishStateLeafNode( - gomock.Any(), - gomock.Eq(tx)). - Do(func(stateNode *models.StateNodeModel, _ snapt.Tx) error { - if stateNode.BlockNumber != fixt.Block1_Header.Number.String() { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - if stateNode.HeaderID != fixt.Block1_Header.Hash().String() { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - if _, ok := expectedStateLeafKeys.Load(stateNode.StateKey); ok { - expectedStateLeafKeys.Delete(stateNode.StateKey) - } else { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - return nil - }). - AnyTimes() - pub.EXPECT().PublishIPLD(gomock.Any(), gomock.Any(), gomock.Eq(fixt.Block1_Header.Number), gomock.Eq(tx)). - AnyTimes() - // Note: block 1 doesn't have storage nodes. TODO: add fixtures with storage nodes +func verifyChain1Block1(t *testing.T, data mocks.IndexerData) { + // Extract indexed keys and sort them for comparison + var indexedStateKeys []string + for _, stateNode := range data.StateNodes { + stateKey := common.BytesToHash(stateNode.AccountWrapper.LeafKey).String() + indexedStateKeys = append(indexedStateKeys, stateKey) + } + sort.Slice(indexedStateKeys, func(i, j int) bool { return indexedStateKeys[i] < indexedStateKeys[j] }) + require.Equal(t, fixture.Block1_StateNodeLeafKeys, indexedStateKeys) - chainDataPath, ancientDataPath := fixt.GetChainDataPath("chaindata") - config := testConfig(chainDataPath, ancientDataPath) - edb, err := NewLevelDB(config.Eth) - if err != nil { - t.Fatal(err) - } - defer edb.Close() + ipldCids := make(map[string]struct{}) + for _, ipld := range data.IPLDs { + ipldCids[ipld.CID] = struct{}{} + } + require.Equal(t, chain1block1IpldCids, ipldCids) +} - recovery := filepath.Join(t.TempDir(), "recover.csv") - service, err := NewSnapshotService(edb, pub, recovery) - if err != nil { - t.Fatal(err) - } - - params := SnapshotParams{Height: 1, Workers: uint(workers)} - err = service.CreateSnapshot(params) - if err != nil { - t.Fatal(err) - } - - // Check if all expected state nodes are indexed - expectedStateLeafKeys.Range(func(key, value any) bool { - t.Fatalf(stateNodeNotIndexedErr, key.(string)) - return true - }) +func chain2WatchedAccountData() ([]common.Address, selectiveData) { + watchedAddresses := []common.Address{ + // hash 0xcabc5edb305583e33f66322ceee43088aa99277da772feb5053512d03a0a702b + common.HexToAddress("0x825a6eec09e44Cb0fa19b84353ad0f7858d7F61a"), + // hash 0x33153abc667e873b6036c8a46bdd847e2ade3f89b9331c78ef2553fea194c50d + common.HexToAddress("0x0616F59D291a898e796a1FAD044C5926ed2103eC"), + } + var expected selectiveData + // expectedStateNodeIndexes := []int{0, 4} + expected.StateNodes = make(map[string]*models.StateNodeModel) + for _, index := range []int{0, 4} { + node := &fixture.Chain2_Block32_StateNodes[index] + expected.StateNodes[node.StateKey] = node } - testCases := []int{1, 4, 8, 16, 32} - for _, tc := range testCases { - t.Run("case", func(t *testing.T) { runCase(t, tc) }) + // Map account leaf keys to corresponding storage + expectedStorageNodeIndexes := []struct { + address common.Address + indexes []int + }{ + {watchedAddresses[0], []int{9, 11}}, + {watchedAddresses[1], []int{0, 1, 2, 4, 6}}, + } + expected.StorageNodes = make(map[string]map[string]*models.StorageNodeModel) + for _, account := range expectedStorageNodeIndexes { + leafKey := crypto.Keccak256Hash(account.address[:]).String() + storageNodes := make(map[string]*models.StorageNodeModel) + for _, index := range account.indexes { + node := &fixture.Chain2_Block32_StorageNodes[index] + storageNodes[node.StorageKey] = node + } + expected.StorageNodes[leafKey] = storageNodes + } + return watchedAddresses, expected +} + +func (expected selectiveData) verify(t *testing.T, data mocks.IndexerData) { + // check that all indexed nodes are expected and correct + indexedStateKeys := make(map[string]struct{}) + for _, stateNode := range data.StateNodes { + stateKey := common.BytesToHash(stateNode.AccountWrapper.LeafKey).String() + indexedStateKeys[stateKey] = struct{}{} + require.Contains(t, expected.StateNodes, stateKey, "unexpected state node") + + model := expected.StateNodes[stateKey] + require.Equal(t, model.CID, stateNode.AccountWrapper.CID) + require.Equal(t, model.Balance, stateNode.AccountWrapper.Account.Balance.String()) + require.Equal(t, model.StorageRoot, stateNode.AccountWrapper.Account.Root.String()) + + expectedStorage := expected.StorageNodes[stateKey] + indexedStorageKeys := make(map[string]struct{}) + for _, storageNode := range stateNode.StorageDiff { + storageKey := common.BytesToHash(storageNode.LeafKey).String() + indexedStorageKeys[storageKey] = struct{}{} + require.Contains(t, expectedStorage, storageKey, "unexpected storage node") + + require.Equal(t, expectedStorage[storageKey].CID, storageNode.CID) + require.Equal(t, expectedStorage[storageKey].Value, storageNode.Value) + } + // check for completeness + for storageNode := range expectedStorage { + require.Contains(t, indexedStorageKeys, storageNode, "missing storage node") + } + } + // check for completeness + for stateNode := range expected.StateNodes { + require.Contains(t, indexedStateKeys, stateNode, "missing state node") } } -type indexedStateLeafNode struct { - value models.StateNodeModel - isIndexed bool +func doSnapshot(t *testing.T, dataName string, params SnapshotParams) mocks.IndexerData { + chainDataPath, ancientDataPath := fixture.GetChainDataPath(dataName) + config := testConfig(chainDataPath, ancientDataPath) + edb, err := NewLevelDB(config.Eth) + if err != nil { + t.Fatal(err) + } + defer edb.Close() + + idx := mocks.NewIndexer(t) + recovery := filepath.Join(t.TempDir(), "recover.csv") + service, err := NewSnapshotService(edb, idx, recovery) + if err != nil { + t.Fatal(err) + } + + if err = service.CreateSnapshot(params); err != nil { + t.Fatal(err) + } + return idx.IndexerData } -type indexedStorageLeafNode struct { - value models.StorageNodeModel - isIndexed bool +func doSnapshotWithRecovery( + t *testing.T, + dataName string, + params SnapshotParams, + failAfter uint, +) mocks.IndexerData { + chainDataPath, ancientDataPath := fixture.GetChainDataPath(dataName) + config := testConfig(chainDataPath, ancientDataPath) + edb, err := NewLevelDB(config.Eth) + if err != nil { + t.Fatal(err) + } + defer edb.Close() + + indexer := &mocks.InterruptingIndexer{ + Indexer: mocks.NewIndexer(t), + InterruptAfter: failAfter, + } + t.Logf("Will interrupt after %d state nodes", failAfter) + + recoveryFile := filepath.Join(t.TempDir(), "recover.csv") + service, err := NewSnapshotService(edb, indexer, recoveryFile) + if err != nil { + t.Fatal(err) + } + if err = service.CreateSnapshot(params); err == nil { + t.Fatal("expected an error") + } + + require.FileExists(t, recoveryFile) + require.LessOrEqual(t, len(indexer.StateNodes), int(indexer.InterruptAfter+params.Workers)) + + // use the nested mock indexer, to continue where it left off + recoveryIndexer := indexer.Indexer + if service, err = NewSnapshotService(edb, recoveryIndexer, recoveryFile); err != nil { + t.Fatal(err) + } + if err = service.CreateSnapshot(params); err != nil { + t.Fatal(err) + } + return recoveryIndexer.IndexerData } -type storageNodeKey struct { - stateKey string - storageKey string +func TestSnapshot(t *testing.T) { + runCase := func(t *testing.T, workers uint) { + params := SnapshotParams{Height: 1, Workers: workers} + data := doSnapshot(t, "chaindata", params) + verifyChain1Block1(t, data) + } + + for _, tc := range subtrieWorkerCases { + t.Run(fmt.Sprintf("with %d subtries", tc), func(t *testing.T) { runCase(t, tc) }) + } } func TestAccountSelectiveSnapshot(t *testing.T) { - snapShotHeight := uint64(32) - // watchedAddresses := map[common.Address]struct{}{ - watchedAddresses := []common.Address{ - common.HexToAddress("0x825a6eec09e44Cb0fa19b84353ad0f7858d7F61a"), - common.HexToAddress("0x0616F59D291a898e796a1FAD044C5926ed2103eC"), - } - expectedStateNodeIndexes := []int{0, 4} + height := uint64(32) + watchedAddresses, expected := chain2WatchedAccountData() - stateKey33 := common.HexToHash("0x33153abc667e873b6036c8a46bdd847e2ade3f89b9331c78ef2553fea194c50d").String() - expectedStorageNodeIndexes33 := []int{0, 1, 2, 4, 6} - - stateKey12 := common.HexToHash("0xcabc5edb305583e33f66322ceee43088aa99277da772feb5053512d03a0a702b").String() - expectedStorageNodeIndexes12 := []int{9, 11} - - runCase := func(t *testing.T, workers int) { - expectedStateNodes := sync.Map{} - - for _, expectedStateNodeIndex := range expectedStateNodeIndexes { - key := fixt.Chain2_Block32_StateNodes[expectedStateNodeIndex].StateKey - expectedStateNodes.Store(key, indexedStateLeafNode{ - value: fixt.Chain2_Block32_StateNodes[expectedStateNodeIndex], - isIndexed: false, - }) + runCase := func(t *testing.T, workers uint) { + params := SnapshotParams{ + Height: height, + Workers: workers, + WatchedAddresses: watchedAddresses, } - - expectedStorageNodes := sync.Map{} - - for _, expectedStorageNodeIndex := range expectedStorageNodeIndexes33 { - key := fixt.Chain2_Block32_StorageNodes[expectedStorageNodeIndex].StorageKey - keys := storageNodeKey{ - stateKey: stateKey33, - storageKey: key, - } - value := indexedStorageLeafNode{ - value: fixt.Chain2_Block32_StorageNodes[expectedStorageNodeIndex], - isIndexed: false, - } - expectedStorageNodes.Store(keys, value) - } - - for _, expectedStorageNodeIndex := range expectedStorageNodeIndexes12 { - key := fixt.Chain2_Block32_StorageNodes[expectedStorageNodeIndex].StorageKey - keys := storageNodeKey{ - stateKey: stateKey12, - storageKey: key, - } - value := indexedStorageLeafNode{ - value: fixt.Chain2_Block32_StorageNodes[expectedStorageNodeIndex], - isIndexed: false, - } - expectedStorageNodes.Store(keys, value) - } - - pub, tx := makeMocks(t) - pub.EXPECT().PublishHeader(gomock.Eq(&fixt.Chain2_Block32_Header)) - pub.EXPECT().BeginTx().Return(tx, nil). - Times(workers) - pub.EXPECT().PrepareTxForBatch(gomock.Any(), gomock.Any()).Return(tx, nil). - AnyTimes() - tx.EXPECT().Commit(). - Times(workers) - pub.EXPECT().PublishStateLeafNode( - gomock.Any(), - gomock.Eq(tx)). - Do(func(stateNode *models.StateNodeModel, _ snapt.Tx) error { - if stateNode.BlockNumber != fixt.Chain2_Block32_Header.Number.String() { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - if stateNode.HeaderID != fixt.Chain2_Block32_Header.Hash().String() { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - key := stateNode.StateKey - // Check published nodes - if expectedStateNode, ok := expectedStateNodes.Load(key); ok { - expectedVal := expectedStateNode.(indexedStateLeafNode).value - test.ExpectEqual(t, expectedVal, *stateNode) - - // Mark expected node as indexed - expectedStateNodes.Store(key, indexedStateLeafNode{ - value: expectedVal, - isIndexed: true, - }) - } else { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - return nil - }). - AnyTimes() - pub.EXPECT().PublishStorageLeafNode( - gomock.Any(), - gomock.Eq(tx)). - Do(func(storageNode *models.StorageNodeModel, _ snapt.Tx) error { - if storageNode.BlockNumber != fixt.Chain2_Block32_Header.Number.String() { - t.Fatalf(unexpectedStorageNodeErr, storageNode.StateKey, storageNode.StorageKey) - } - if storageNode.HeaderID != fixt.Chain2_Block32_Header.Hash().String() { - t.Fatalf(unexpectedStorageNodeErr, storageNode.StateKey, storageNode.StorageKey) - } - key := storageNodeKey{ - stateKey: storageNode.StateKey, - storageKey: storageNode.StorageKey, - } - // Check published nodes - if expectedStorageNode, ok := expectedStorageNodes.Load(key); ok { - expectedVal := expectedStorageNode.(indexedStorageLeafNode).value - test.ExpectEqual(t, expectedVal, *storageNode) - - // Mark expected node as indexed - expectedStorageNodes.Store(key, indexedStorageLeafNode{ - value: expectedVal, - isIndexed: true, - }) - } else { - t.Fatalf(unexpectedStorageNodeErr, storageNode.StateKey, storageNode.StorageKey) - } - return nil - }). - AnyTimes() - pub.EXPECT().PublishIPLD(gomock.Any(), gomock.Any(), gomock.Eq(fixt.Chain2_Block32_Header.Number), gomock.Eq(tx)). - Do(func(_ cid.Cid, _ []byte, height *big.Int, _ snapt.Tx) { - if height.String() != fixt.Chain2_Block32_Header.Number.String() { - t.Fatalf("wrong blockheight for ipld publish: %s", height.String()) - } - }). - MaxTimes(len(fixt.Chain2_Block32_StateIPLDs) + len(fixt.Chain2_Block32_StorageIPLDs) + 1 + 2) - - chainDataPath, ancientDataPath := fixt.GetChainDataPath("chain2data") - config := testConfig(chainDataPath, ancientDataPath) - edb, err := NewLevelDB(config.Eth) - if err != nil { - t.Fatal(err) - } - defer edb.Close() - - recovery := filepath.Join(t.TempDir(), "recover.csv") - service, err := NewSnapshotService(edb, pub, recovery) - if err != nil { - t.Fatal(err) - } - - params := SnapshotParams{Height: snapShotHeight, Workers: uint(workers), WatchedAddresses: watchedAddresses} - err = service.CreateSnapshot(params) - if err != nil { - t.Fatal(err) - } - - expectedStateNodes.Range(func(key, value any) bool { - if !value.(indexedStateLeafNode).isIndexed { - t.Fatalf(stateNodeNotIndexedErr, key) - return false - } - return true - }) - expectedStorageNodes.Range(func(key, value any) bool { - if !value.(indexedStorageLeafNode).isIndexed { - t.Fatalf(storageNodeNotIndexedErr, key.(storageNodeKey).stateKey, key.(storageNodeKey).storageKey) - return false - } - return true - }) + data := doSnapshot(t, "chain2data", params) + expected.verify(t, data) } - testCases := []int{1, 4, 8, 16, 32} - for _, tc := range testCases { - t.Run("case", func(t *testing.T) { runCase(t, tc) }) + for _, tc := range subtrieWorkerCases { + t.Run(fmt.Sprintf("with %d subtries", tc), func(t *testing.T) { runCase(t, tc) }) } } -func TestRecovery(t *testing.T) { - runCase := func(t *testing.T, workers int, interruptAt int32) { - // map: expected state path -> number of times it got published - expectedStateNodeKeys := sync.Map{} - for _, key := range fixt.Block1_StateNodeLeafKeys { - expectedStateNodeKeys.Store(key, 0) - } - var indexedStateNodesCount int32 - - pub, tx := makeMocks(t) - pub.EXPECT().PublishHeader(gomock.Eq(&fixt.Block1_Header)) - pub.EXPECT().BeginTx().Return(tx, nil).MaxTimes(workers) - pub.EXPECT().PrepareTxForBatch(gomock.Any(), gomock.Any()).Return(tx, nil).AnyTimes() - tx.EXPECT().Rollback().MaxTimes(workers) - tx.EXPECT().Commit().MaxTimes(workers) - pub.EXPECT().PublishStateLeafNode( - gomock.Any(), - gomock.Eq(tx)). - DoAndReturn(func(stateNode *models.StateNodeModel, _ snapt.Tx) error { - if stateNode.BlockNumber != fixt.Block1_Header.Number.String() { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - if stateNode.HeaderID != fixt.Block1_Header.Hash().String() { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - // Start throwing an error after a certain number of state nodes have been indexed - if indexedStateNodesCount >= interruptAt { - return errors.New("failingPublishStateLeafNode") - } else { - if prevCount, ok := expectedStateNodeKeys.Load(stateNode.StateKey); ok { - expectedStateNodeKeys.Store(stateNode.StateKey, prevCount.(int)+1) - atomic.AddInt32(&indexedStateNodesCount, 1) - } else { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - } - return nil - }). - MaxTimes(int(interruptAt) + workers) - pub.EXPECT().PublishIPLD(gomock.Any(), gomock.Any(), gomock.Eq(fixt.Block1_Header.Number), gomock.Eq(tx)). - AnyTimes() - - chainDataPath, ancientDataPath := fixt.GetChainDataPath("chaindata") - config := testConfig(chainDataPath, ancientDataPath) - edb, err := NewLevelDB(config.Eth) - if err != nil { - t.Fatal(err) - } - defer edb.Close() - - recovery := filepath.Join(t.TempDir(), "recover.csv") - service, err := NewSnapshotService(edb, pub, recovery) - if err != nil { - t.Fatal(err) - } - - params := SnapshotParams{Height: 1, Workers: uint(workers)} - err = service.CreateSnapshot(params) - if err == nil { - t.Fatal("expected an error") - } - - if _, err = os.Stat(recovery); err != nil { - t.Fatal("cannot stat recovery file:", err) - } - - // Create new mocks for recovery - recoveryPub, tx := makeMocks(t) - recoveryPub.EXPECT().PublishHeader(gomock.Eq(&fixt.Block1_Header)) - recoveryPub.EXPECT().BeginTx().Return(tx, nil).AnyTimes() - recoveryPub.EXPECT().PrepareTxForBatch(gomock.Any(), gomock.Any()).Return(tx, nil).AnyTimes() - tx.EXPECT().Commit().AnyTimes() - recoveryPub.EXPECT().PublishStateLeafNode( - gomock.Any(), - gomock.Eq(tx)). - DoAndReturn(func(stateNode *models.StateNodeModel, _ snapt.Tx) error { - if stateNode.BlockNumber != fixt.Block1_Header.Number.String() { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - if stateNode.HeaderID != fixt.Block1_Header.Hash().String() { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - if prevCount, ok := expectedStateNodeKeys.Load(stateNode.StateKey); ok { - expectedStateNodeKeys.Store(stateNode.StateKey, prevCount.(int)+1) - atomic.AddInt32(&indexedStateNodesCount, 1) - } else { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - return nil - }). - AnyTimes() - recoveryPub.EXPECT().PublishIPLD(gomock.Any(), gomock.Any(), gomock.Eq(fixt.Block1_Header.Number), gomock.Eq(tx)). - AnyTimes() - - // Create a new snapshot service for recovery - recoveryService, err := NewSnapshotService(edb, recoveryPub, recovery) - if err != nil { - t.Fatal(err) - } - err = recoveryService.CreateSnapshot(params) - if err != nil { - t.Fatal(err) - } - - // Check if recovery file has been deleted - _, err = os.Stat(recovery) - if err == nil { - t.Fatal("recovery file still present") - } else { - if !os.IsNotExist(err) { - t.Fatal(err) - } - } - - // Check if all state nodes are indexed after recovery - expectedStateNodeKeys.Range(func(key, value any) bool { - if value.(int) == 0 { - t.Fatalf(stateNodeNotIndexedErr, key.(string)) - } - return true - }) - - // nodes along the recovery path get reindexed - maxStateNodesCount := len(fixt.Block1_StateNodeLeafKeys) - if indexedStateNodesCount > int32(maxStateNodesCount) { - t.Fatalf(extraNodesIndexedErr, indexedStateNodesCount, maxStateNodesCount) - } +func TestSnapshotRecovery(t *testing.T) { + runCase := func(t *testing.T, workers uint, interruptAt uint) { + params := SnapshotParams{Height: 1, Workers: workers} + data := doSnapshotWithRecovery(t, "chaindata", params, interruptAt) + verifyChain1Block1(t, data) } - testCases := []int{1, 2, 4, 8, 16, 32} - numInterrupts := 3 - interrupts := make([]int32, numInterrupts) - for i := 0; i < numInterrupts; i++ { - rand.Seed(time.Now().UnixNano()) - interrupts[i] = rand.Int31n(int32(len(fixt.Block1_StateNodeLeafKeys) / 2)) + interrupts := make([]uint, 4) + for i := 0; i < len(interrupts); i++ { + N := fixture.Block1_StateNodeLeafKeys + interrupts[i] = uint(rand.Intn(len(N)/2) + len(N)/4) } - for _, tc := range testCases { - for _, interrupt := range interrupts { - t.Run(fmt.Sprint("case", tc, interrupt), func(t *testing.T) { runCase(t, tc, interrupt) }) + for _, tc := range subtrieWorkerCases { + for i, interrupt := range interrupts { + t.Run( + fmt.Sprintf("with %d subtries %d", tc, i), + func(t *testing.T) { runCase(t, tc, interrupt) }, + ) } } } -func TestAccountSelectiveRecovery(t *testing.T) { - snapShotHeight := uint64(32) - watchedAddresses := []common.Address{ - common.HexToAddress("0x825a6eec09e44Cb0fa19b84353ad0f7858d7F61a"), - common.HexToAddress("0x0616F59D291a898e796a1FAD044C5926ed2103eC"), +func TestAccountSelectiveSnapshotRecovery(t *testing.T) { + height := uint64(32) + watchedAddresses, expected := chain2WatchedAccountData() + + runCase := func(t *testing.T, workers uint, interruptAt uint) { + params := SnapshotParams{ + Height: height, + Workers: workers, + WatchedAddresses: watchedAddresses, + } + data := doSnapshotWithRecovery(t, "chain2data", params, interruptAt) + expected.verify(t, data) } - expectedStateNodeIndexes := []int{0, 4} - expectedStorageNodeIndexes := []int{0, 1, 2, 4, 6, 9, 11} - - runCase := func(t *testing.T, workers int, interruptAt int32) { - // map: expected state path -> number of times it got published - expectedStateNodeKeys := sync.Map{} - for _, expectedStateNodeIndex := range expectedStateNodeIndexes { - key := fixt.Chain2_Block32_StateNodes[expectedStateNodeIndex].StateKey - expectedStateNodeKeys.Store(key, 0) - } - expectedStorageNodeKeys := sync.Map{} - for _, expectedStorageNodeIndex := range expectedStorageNodeIndexes { - stateKey := fixt.Chain2_Block32_StorageNodes[expectedStorageNodeIndex].StateKey - storageKey := fixt.Chain2_Block32_StorageNodes[expectedStorageNodeIndex].StorageKey - keys := storageNodeKey{ - stateKey: stateKey, - storageKey: storageKey, - } - expectedStorageNodeKeys.Store(keys, 0) - } - var indexedStateNodesCount, indexedStorageNodesCount int32 - - pub, tx := makeMocks(t) - pub.EXPECT().PublishHeader(gomock.Eq(&fixt.Chain2_Block32_Header)) - pub.EXPECT().BeginTx().Return(tx, nil).Times(workers) - pub.EXPECT().PrepareTxForBatch(gomock.Any(), gomock.Any()).Return(tx, nil).AnyTimes() - tx.EXPECT().Commit().MaxTimes(workers) - tx.EXPECT().Rollback().MaxTimes(workers) - pub.EXPECT().PublishStateLeafNode( - gomock.Any(), - gomock.Eq(tx)). - DoAndReturn(func(stateNode *models.StateNodeModel, _ snapt.Tx) error { - if stateNode.BlockNumber != fixt.Chain2_Block32_Header.Number.String() { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - if stateNode.HeaderID != fixt.Chain2_Block32_Header.Hash().String() { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - // Start throwing an error after a certain number of state nodes have been indexed - if indexedStateNodesCount >= interruptAt { - return errors.New("failingPublishStateLeafNode") - } else { - if prevCount, ok := expectedStateNodeKeys.Load(stateNode.StateKey); ok { - expectedStateNodeKeys.Store(stateNode.StateKey, prevCount.(int)+1) - atomic.AddInt32(&indexedStateNodesCount, 1) - } else { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - } - return nil - }). - MaxTimes(int(interruptAt) + workers) - pub.EXPECT().PublishStorageLeafNode( - gomock.Any(), - gomock.Eq(tx)). - Do(func(storageNode *models.StorageNodeModel, _ snapt.Tx) error { - if storageNode.BlockNumber != fixt.Chain2_Block32_Header.Number.String() { - t.Fatalf(unexpectedStorageNodeErr, storageNode.StateKey, storageNode.StorageKey) - } - if storageNode.HeaderID != fixt.Chain2_Block32_Header.Hash().String() { - t.Fatalf(unexpectedStorageNodeErr, storageNode.StateKey, storageNode.StorageKey) - } - keys := storageNodeKey{ - stateKey: storageNode.StateKey, - storageKey: storageNode.StorageKey, - } - if prevCount, ok := expectedStorageNodeKeys.Load(keys); ok { - expectedStorageNodeKeys.Store(keys, prevCount.(int)+1) - atomic.AddInt32(&indexedStorageNodesCount, 1) - } else { - t.Fatalf(unexpectedStorageNodeErr, storageNode.StateKey, storageNode.StorageKey) - } - return nil - }). - AnyTimes() - pub.EXPECT().PublishIPLD(gomock.Any(), gomock.Any(), gomock.Eq(fixt.Chain2_Block32_Header.Number), gomock.Eq(tx)). - AnyTimes() - - chainDataPath, ancientDataPath := fixt.GetChainDataPath("chain2data") - config := testConfig(chainDataPath, ancientDataPath) - edb, err := NewLevelDB(config.Eth) - if err != nil { - t.Fatal(err) - } - defer edb.Close() - - recovery := filepath.Join(t.TempDir(), "recover.csv") - service, err := NewSnapshotService(edb, pub, recovery) - if err != nil { - t.Fatal(err) - } - - params := SnapshotParams{Height: snapShotHeight, Workers: uint(workers), WatchedAddresses: watchedAddresses} - err = service.CreateSnapshot(params) - if err == nil { - t.Fatal("expected an error") - } - - if _, err = os.Stat(recovery); err != nil { - t.Fatal("cannot stat recovery file:", err) - } - - // Create new mocks for recovery - recoveryPub, tx := makeMocks(t) - recoveryPub.EXPECT().PublishHeader(gomock.Eq(&fixt.Chain2_Block32_Header)) - recoveryPub.EXPECT().BeginTx().Return(tx, nil).MaxTimes(workers) - recoveryPub.EXPECT().PrepareTxForBatch(gomock.Any(), gomock.Any()).Return(tx, nil).AnyTimes() - tx.EXPECT().Commit().MaxTimes(workers) - recoveryPub.EXPECT().PublishStateLeafNode( - gomock.Any(), - gomock.Eq(tx)). - DoAndReturn(func(stateNode *models.StateNodeModel, _ snapt.Tx) error { - if stateNode.BlockNumber != fixt.Chain2_Block32_Header.Number.String() { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - if stateNode.HeaderID != fixt.Chain2_Block32_Header.Hash().String() { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - if prevCount, ok := expectedStateNodeKeys.Load(stateNode.StateKey); ok { - expectedStateNodeKeys.Store(stateNode.StateKey, prevCount.(int)+1) - atomic.AddInt32(&indexedStateNodesCount, 1) - } else { - t.Fatalf(unexpectedStateNodeErr, stateNode.StateKey) - } - return nil - }). - AnyTimes() - recoveryPub.EXPECT().PublishStorageLeafNode( - gomock.Any(), - gomock.Eq(tx)). - Do(func(storageNode *models.StorageNodeModel, _ snapt.Tx) error { - if storageNode.BlockNumber != fixt.Chain2_Block32_Header.Number.String() { - t.Fatalf(unexpectedStorageNodeErr, storageNode.StateKey, storageNode.StorageKey) - } - if storageNode.HeaderID != fixt.Chain2_Block32_Header.Hash().String() { - t.Fatalf(unexpectedStorageNodeErr, storageNode.StateKey, storageNode.StorageKey) - } - keys := storageNodeKey{ - stateKey: storageNode.StateKey, - storageKey: storageNode.StorageKey, - } - if prevCount, ok := expectedStorageNodeKeys.Load(keys); ok { - expectedStorageNodeKeys.Store(keys, prevCount.(int)+1) - atomic.AddInt32(&indexedStorageNodesCount, 1) - } else { - t.Fatalf(unexpectedStorageNodeErr, storageNode.StateKey, storageNode.StorageKey) - } - return nil - }). - AnyTimes() - recoveryPub.EXPECT().PublishIPLD(gomock.Any(), gomock.Any(), gomock.Eq(fixt.Chain2_Block32_Header.Number), gomock.Eq(tx)). - AnyTimes() - - // Create a new snapshot service for recovery - recoveryService, err := NewSnapshotService(edb, recoveryPub, recovery) - if err != nil { - t.Fatal(err) - } - err = recoveryService.CreateSnapshot(params) - if err != nil { - t.Fatal(err) - } - - // Check if recovery file has been deleted - _, err = os.Stat(recovery) - if err == nil { - t.Fatal("recovery file still present") - } else { - if !os.IsNotExist(err) { - t.Fatal(err) - } - } - - // Check if all expected state nodes are indexed after recovery, but not in duplicate - expectedStateNodeKeys.Range(func(key, value any) bool { - if value.(int) == 0 { - t.Fatalf(stateNodeNotIndexedErr, key.(string)) - } - /* TODO: fix/figure out - if value.(int) > 1 { - t.Fatalf(stateNodeDuplicateErr, value.(int), key.(string)) - } - */ - return true - }) - expectedStorageNodeKeys.Range(func(key, value any) bool { - if value.(int) == 0 { - t.Fatalf(storageNodeNotIndexedErr, key.(storageNodeKey).stateKey, key.(storageNodeKey).storageKey) - } - /* TODO: fix/figure out - if value.(int) > 1 { - t.Fatalf(storageNodeDuplicateErr, value.(int), key.(storageNodeKey).stateKey, key.(storageNodeKey).storageKey) - } - */ - return true - }) - - maxStateNodesCount := len(expectedStateNodeIndexes) + workers - if indexedStateNodesCount > int32(maxStateNodesCount) { - t.Fatalf(extraNodesIndexedErr, indexedStateNodesCount, maxStateNodesCount) - } - } - - testCases := []int{1, 2, 4, 8, 16, 32} - - for _, tc := range testCases { - t.Run(fmt.Sprint("case", tc, 1), func(t *testing.T) { runCase(t, tc, 1) }) + for _, tc := range subtrieWorkerCases { + t.Run( + fmt.Sprintf("with %d subtries", tc), + func(t *testing.T) { runCase(t, tc, 1) }, + ) } } diff --git a/test/helper.go b/test/helper.go deleted file mode 100644 index e9391b2..0000000 --- a/test/helper.go +++ /dev/null @@ -1,59 +0,0 @@ -package test - -import ( - "bytes" - "os" - "reflect" - "testing" - - "github.com/cerc-io/plugeth-statediff/indexer/database/sql/postgres" - ethnode "github.com/cerc-io/plugeth-statediff/indexer/node" -) - -var ( - DefaultNodeInfo = ethnode.Info{ - ID: "test_nodeid", - ClientName: "test_client", - GenesisBlock: "TEST_GENESIS", - NetworkID: "test_network", - ChainID: 0, - } - DefaultPgConfig = postgres.Config{ - Hostname: "localhost", - Port: 8077, - DatabaseName: "cerc_testing", - Username: "vdbm", - Password: "password", - - MaxIdle: 0, - MaxConnLifetime: 0, - MaxConns: 4, - } -) - -func NeedsDB(t *testing.T) { - t.Helper() - if os.Getenv("TEST_WITH_DB") == "" { - t.Skip("set TEST_WITH_DB to enable test") - } -} - -func NoError(t *testing.T, err error) { - t.Helper() - if err != nil { - t.Fatal(err) - } -} - -// ExpectEqual asserts the provided interfaces are deep equal -func ExpectEqual(t *testing.T, want, got interface{}) { - if !reflect.DeepEqual(want, got) { - t.Fatalf("Values not equal:\nExpected:\t%+v\nActual:\t\t%+v", want, got) - } -} - -func ExpectEqualBytes(t *testing.T, want, got []byte) { - if !bytes.Equal(want, got) { - t.Fatalf("Bytes not equal:\nExpected:\t%v\nActual:\t\t%v", want, got) - } -}